简体   繁体   中英

Is it somehow possible to have two master views and one detail view?

If I have for example one master view on the left and one in the middle, each showing oder Java Beans/POJOs, can I use a shared detail view that somehow listens to the active beans of each view and then displays the currently selected one in more detail? A one to one relation is quite easy to manage by using your Context library.

@ViewDocking(areaId ="left", position=1, displayName="Profiles", menuEntry = @WindowMenuEntry(path = "", position=0), accelerator="Shortcut+1")
public class ProfileListView extends BorderPane implements LocalContextProvider {

private final SimpleContextContent content = new SimpleContextContent();

private final SimpleContext context = new SimpleContext(content);

@FXML
private ListView<Profile> listview;

public ProfileListView() {
    load();
    // add some profiles
    listview.getItems().add(new Profile("Profile1"));
    listview.getItems().add(new Profile("Profile2"));
    listview.getItems().add(new Profile("Profile3"));

    // setup selection listener
    listview.getSelectionModel().selectedItemProperty().addListener((value, oldProfile, newProfile) -> {
        // set active profile and remove old one
        content.remove(oldProfile);
        content.add(newProfile);
    });

    // setup double click listener
    configureClickListener();
}

private Profile getSelectedProfile() {
    return listview.getSelectionModel().getSelectedItem();
}

private void configureClickListener() {
    listview.setOnMouseClicked(event -> {
        // check if it was a double click
        if(event.getClickCount() == 2) {
            System.out.println(getSelectedProfile());
            // inject into editor pane
            // calls the procedure to create a tab in the center area...
        }
    });
}

private void load() {
    FXMLLoaders.loadRoot(this);
}

@Override
public Context getLocalContext() {
    return context;
}
}

This is one master view holding a list view of items. The other one would be the same, docking to the right as another tab and holding POJOs of type 'Action'.

The detail view is here:

@ViewDocking(areaId = "right", displayName = "Properties", accelerator = "Shortcut+2", menuEntry = @WindowMenuEntry(path = "", position = 0), position = 1)
public class ProfilePropertiesView extends BorderPane implements LocalContextProvider, ActiveContextSensitive {

private Context activeContext;

private SimpleContextContent content = new SimpleContextContent();

private SimpleContext context = new SimpleContext(content);

private Profile profile;

private IWindowService service = new NullWindowService();

@FXML
private PropertySheet propertysheet;

public ProfilePropertiesView() {
    load();
    // retrieve framework service, TODO: use tracker
    BundleContext ctx = FrameworkUtil.getBundle(getClass()).getBundleContext();
    service = ctx.getService(ctx.getServiceReference(IWindowService.class));
    // initialize callback
    service.addCallback(title -> {
        System.out.println("callback called " + title);
        // update the property sheet ui by re-creating the items list
       // updateUI();
        // we can safely return null
        return null;
    });

    // configure editor factory so the user is able to use a combobox
    propertysheet.setPropertyEditorFactory(new CustomPropertyEditorFactory(service));
}

private void load() {
    FXMLLoaders.loadRoot(this);
}

@Override
public Context getLocalContext() {
    return context;
}

private void contextChanged() {
    // find profile information
    Profile found = activeContext.find(Profile.class);
    // if the found profile is null, ignore it
    if (found != null) {
        // reset if profile is valid
        if (profile != null) {
            reset();
        }
        // create reference and register
        profile = found;
        register();
    }
}

private void register() {
    // retrieve observablelist of bean properties if some profile is selected
    if(profile != null) {
        ObservableList<Item> items = createDetailedList(profile);
        propertysheet.getItems().setAll(items);
    }
}

private void updateUI() {
    // clear property elements and re-create them
    reset();
    // re-create items
    ObservableList<Item> items = createDetailedList(profile);
    propertysheet.getItems().addAll(items);
}

private ObservableList<Item> createDetailedList(Object bean) {
    ObservableList<Item> list = FXCollections.observableArrayList();
    try {
        BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
        Arrays.stream(beanInfo.getPropertyDescriptors()).map(pd -> new DetailedBeanProperty(bean, pd)).forEach(list::add);
    } catch (IntrospectionException e) {
        e.printStackTrace();
    }

    return list;
}

private void reset() {
    propertysheet.getItems().clear();
}

@Override
public void setActiveContext(Context activeContext) {
    this.activeContext = activeContext;
    this.activeContext.addContextListener(Profile.class, event -> contextChanged());
    // trigger change
    contextChanged();
}
}

The current ProfilePropertiesView is just configured to display the properties of the selected profile. I want it to be able to display the current information of the last selected POJO in the UI. That means that if the user selected a Profile from the ListView, that profile should be displayed in the properties view. If he selected an Action from the Table (which is displayed in the center), the properties of the Action should be displayed.

Do I just need to register a new ContextListener for the Action.class POJO and then call a method to populate the PropertiesView? I was unsure if this is the right solution...

Yes, just add another ContextListener to the activeContext for every POJO type you want to observe.

Also note that in the constructor of views it's better to use a ServiceTracker instead of looking for the service via BundleContext as the service might not be available yet, depending on the order the bundles are loaded.

You can find a sample which uses a ServiceTracker here: https://stackoverflow.com/a/35974498/506855

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM