I have a TreeViewer with Object which I want to show information in the default PropertiesView in Eclipse.
I created an AdapterFactory which implements the IAdapterFactory Interface with the Override method:
#Override
public Object getAdapter(Object adaptableObject, Class adapterType)
{
if(adapterType == IPropertySource.class && adaptableObject instanceof UATreeNode)
{
return new UATreeNodeAdapter((UATreeNode) adaptableObject);
}
return null;
}
Then I created an adapter which implements the IPropertySource Interface with my own PropertyDescriptors, for example:
public static final String OBJECT_ID_ACCESSLEVEL = "Obj.accessLevel";
private static final String OBJECT_LABEL_ACCESSLEVEL = "AccessLevel";
protected PropertyDescriptor objectAccessLevelDescriptor = new PropertyDescriptor(OBJECT_ID_ACCESSLEVEL, OBJECT_LABEL_ACCESSLEVEL);
#Override
public IPropertyDescriptor[] getPropertyDescriptors()
{
return new IPropertyDescriptor[] { objectAccessLevelDescriptor };
}
#Override
public Object getPropertyValue(Object id)
{
if(id.equals(OBJECT_ID_ACCESSLEVEL))
return uaTreeNode.getAccessLevel();
}
I got more of those PropertyDescriptors and now I want to show some of them only if the "Show Advanced Properties" menu button in the PropertiesView is activated.
So my question, is this possible to do, if so what do I have to implement to show my Properties only if "Show Advanced Properties" is activated?
Call the PropertyDescriptor.setFilterFlags method to set the expert filter property:
PropertyDescriptor desc = ...
desc.setFilterFlags(new String [] {IPropertySheetEntry.FILTER_ID_EXPERT});
Related
I am still new to Vaadin so, please bear with it.
We are currently migrating from Vaadin framework 8.0 to 8.3.2. One of the reasons of doing is that there's a requirement of using tree for the menu. Since 8.0 doesn't have tree, the workaround for generating a menu is by instantiating an inner Button class with the help of an Enum class in a loop (for user permission control):
public final class ValoMenuItemButton extends Button {
private static final String STYLE_SELECTED = "selected";
private final DashboardViewType view;
public ValoMenuItemButton(final DashboardViewType view) {
this.view = view;
setPrimaryStyleName("valo-menu-item");
setIcon(view.getIcon());
setCaption(view.getViewName().substring(0, 1).toUpperCase()
+ view.getViewName().substring(1));
DashboardEventBus.register(this);
addClickListener(new ClickListener() {
#Override
public void buttonClick(final ClickEvent event) {
UI.getCurrent().getNavigator()
.navigateTo(view.getViewName());
}
});
}
#Subscribe
public void postViewChange(final PostViewChangeEvent event) {
removeStyleName(STYLE_SELECTED);
if (event.getView() == view) {
addStyleName(STYLE_SELECTED);
}
}
}
The enum class structure is built in this manner:
AUDIT("Receipt Validation", RcptValidation.class, FontAwesome.BAR_CHART_O, false),
AUDIT1("Matching - Receipt not in SYCARDA", RcptNotInSycarda.class, FontAwesome.BAR_CHART_O, false),
AUDIT2("Matching - Receipt not in POS", RcptNotInPos.class, FontAwesome.BAR_CHART_O, false),
AUDIT3("Missing Sequence", MissSequence.class, FontAwesome.BAR_CHART_O, false),
AUDIT4("*Debug Purposes", LineAmtVsTotal.class, FontAwesome.BAR_CHART_O, false);
private DashboardViewType(final String viewName,
final Class<? extends View> viewClass, final Resource icon,
final boolean stateful) {
this.viewName = viewName;
this.viewClass = viewClass;
this.icon = icon;
this.stateful = stateful;
}
So far, I've not found any examples that are written around the v8 framework, while most of the sample code that I've seen are based on v7 framework.
I've attempted to write something like this, but the tree sub menus do not come out as it is (I've left out the expand and collapse event as that can be handled later).
My attempted code on the tree is this:
TreeData <String> treeData = new TreeData();
treeData.addRootItems("Dashboard","Sales","Sales Pattern","Top SKUs","Audit");
// The loop starts here (for DashboardViewType view: DashboardViewType.values)
if(enabled){
if(StringUtils.startsWith(view.getViewName(), "SALES")){
if (StringUtils.contains(view.getViewName(),"SALES_PATTERN")){
treeData.addItem( "Sales Pattern", view.getViewName());
}else{ treeData.addItem( "Sales", view.getViewName());
}
}else if (StringUtils.startsWith(view.getViewName(), "TOP_SKUS")){
treeData.addItem( "Top SKUs", view.getViewName());
}else if (StringUtils.startsWith(view.getViewName(), "AUDIT")){
treeData.addItem( "Audit", view.getViewName());
}else if (StringUtils.startsWith(view.getViewName(), "DASHBOARD")){
treeData.addItem( "Dashboard", view.getViewName());
}
DashboardEventBus.register(view);
}
// loop ends here
Tree<String> tree = new Tree<>("Sycarda Dashboard");
tree.setDataProvider(new TreeDataProvider<>(treeData));
tree.setItemIconGenerator(item -> { return FontAwesome.BAR_CHART_O; });
tree.expand("Sales","Sales Pattern","Top SKUs","Audit");
tree.addSelectionListener(e -> new Button.ClickListener() {
#Override public void buttonClick(Button.ClickEvent event) {
DashboardEventBus.register(event);
UI.getCurrent().getNavigator().navigateTo(event.getClass().getName());
}
});
This was posted originally at the Vaadin forum, but since there were no answers to that, I am putting it here. I'd appreciate if there's any input or another approach for this problem.
Thanks in advance.
In Vaadin 8 you can simply define the "get children" method when adding the data. In your case the enum class should provide some method like "getSubItems", which you could then set as the value provider. The following example shows it in a similar way, where "rootItems" is simply the same as your top level enum instances and MenuItem the same as your enumeration.
static {
rootItems = Arrays.asList(...);
}
#PostConstruct
private void init() {
Tree<MenuItem> tree = new Tree<>();
tree.setItems(rootItems, MenuItem::getSubItems);
}
private class MenuItem {
private String name;
private Resource icon;
private Collection<MenuItem> subItems;
public Collection<MenuItem> getSubItems() {
return subItems;
}
// ... other getter and constructor omitted;
}
Someone has shown an example and it is similar to what Stefan mentioned. In context with my requirement, the steps involved include:
Create a wrapper class that includes:
private DashboardViewType view;
private Resource icon;
private boolean stateful;
private Class<? extends View> viewClass;
private String viewName;
//Create the get / set methods for those attributes above
//Constructor for the wrapper class is below.
public TreeMenuItem(DashboardViewType view){
this.view = view;
}
For the Enum class additional main menu items are added. Default main class can be used since you can't put a null.
public enum DashboardViewType {
SALES("Sales",DashboardView.class,FontAwesome.HOME,false),
SALES_PATTERN("Sales Pattern",DashboardView.class,FontAwesome.HOME,false),
TOP_SKUs("Top SKUs",DashboardView.class,FontAwesome.HOME,false),
AUDIT("Audit",DashboardView.class,FontAwesome.HOME,false)
}
The tree is built in this manner:
private Component buildTree(){
Tree<TreeMenuItem> tree = new Tree<>();
TreeData<TreeMenuItem> treeData = new TreeData<>();
//This is for items that have no child.
TreeMenuItem dashboardItem = new TreeMenuItem(DashboardViewType.DASHBOARD);
dashboardItem.setIcon(VaadinIcons.HOME_O);
dashboardItem.setStateful(DashboardViewType.DASHBOARD.isStateful());
dashboardItem.setViewName(DashboardViewType.DASHBOARD.getViewName());
treeData.addItem(null, dashboardItem);
for (DashboardViewType type : DashboardViewType.values()) {
TreeMenuItem menuItem = new TreeMenuItem(type);
menuItem.setIcon(VaadinIcons.HOME_O);
menuItem.setViewName(type.getViewName());
menuItem.setStateful(false);
treeData.addItem(null, menuItem);
getSubMenuItems(type).forEach(subView -> {
TreeMenuItem subItem = new TreeMenuItem(subView);
subItem.setViewName(subView.getViewName().substring(0, 1).toUpperCase()
+ subView.getViewName().substring(1));
subItem.setIcon(subView.getIcon());
subItem.setStateful(subView.isStateful());
subItem.setView(subView);
subItem.setViewClass(subView.getViewClass());
treeData.addItem(menuItem, subItem);
});
}
}
tree.setDataProvider(new TreeDataProvider<>(treeData));
tree.setItemIconGenerator(TreeMenuItem::getIcon);
tree.setItemCaptionGenerator(TreeMenuItem::getViewName);
tree.addItemClickListener((Tree.ItemClick<TreeMenuItem> event) -> {
DashboardEventBus.register(event.getItem().getView()); UI.getCurrent().getNavigator().navigateTo(event.getItem().getViewName());
});
}
The logic to create subviews:
private List getSubMenuItems(DashboardViewType type) {
List<DashboardViewType> dashboardList;
switch(type){
case TOP_SKUs:
dashboardList = new LinkedList<>(Arrays.asList(DashboardViewType.TOP_SKUs1,
DashboardViewType.TOP_SKUs2,
DashboardViewType.TOP_SKUs3,
DashboardViewType.TOP_SKUs4));
filterByUserLevel(dashboardList,subACL4);
return dashboardList;
case AUDIT:
dashboardList = new LinkedList<>(Arrays.asList(DashboardViewType.AUDIT1,
DashboardViewType.AUDIT2,
DashboardViewType.AUDIT3,
DashboardViewType.AUDIT4,
DashboardViewType.AUDIT5));
filterByUserLevel(dashboardList,subACL5);
return dashboardList;
case DASHBOARD:
break;
default:
break;
}
return Collections.emptyList();
}
Add additional cases if required so. After that, the function controls remove the elements that are not part of the user level:
private List<DashboardType> filterByUserLevel(List<DashboardType>list, String u){
if(list.size() == subACL.length()){
for(int i=0; i<list.size(); i++){
if(StringUtils.substring(subACL, i, i+1).equalsIgnoreCase("0")){
list.remove(i);
}
}
Collections.sort(list);
return list;
//this removes unwanted sub-menu items according current user level.
}
}
Lets say I have a class:
public class Dummy {
private String name;
private String someOtherProperty;
public String getName() {
return name;
}
}
I have an ArrayList of this class ArrayList<Dummy> dummyList;
Can I create a JavaFX ComboBox with the Object name property as selection options without creating a new ArrayList<String> with the object names?
Pseudocode:
ObservableList<Dummy> dummyO = FXCollections.observableArrayList(dummyList);
final ComboBox combo = new ComboBox(dummyO); // -> here dummyO.name?
(Optional) Ideally, while the name should be displayed, when an option has been selected, the combo.getValue() should return me the reference of the selected Dummy and not only the name. Is that possible?
You can use a custom cellFactory to display the items in a way that suits your needs:
ComboBox<Dummy> comboBox = ...
Callback<ListView<Dummy>, ListCell<Dummy>> factory = lv -> new ListCell<Dummy>() {
#Override
protected void updateItem(Dummy item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? "" : item.getName());
}
};
comboBox.setCellFactory(factory);
comboBox.setButtonCell(factory.call(null));
I'm assuming the ComboBox you're referring to is this: http://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/ComboBoxBase.html. As getValue() is public, you can do:
public class MyComboBox<T> extends ComboBox<T> {
private final Dummy dummy;
public MyComboBox(Dummy dummy) {
this.dummy = dummy;
}
public T getValue() {
return dummy.getName();
}
}
Basically the idea is that I need some sort of session/cookie imitation for Java. I have to develop some kind of a blogging program for a university project. It does not have to be for Web, I mean that I don't need servlet's and other Java EE stuff. The whole interface has to be in the console.
So here is the problem, I've developed a Menu class in which I add a MenuItem object for every menu option I want to be added, after I navigate my menu and I want to log into my account, I need something like a session, otherwise I cannot hide the "Login" and "Register" options, and can't decide whether to show the "Logout" option. Since the Menu class is instantiated only once, there is no way it could be updated on the go(or at least I think so, still learning Java).
If there is someone who can give me an advice or an idea, that would help me a lot.
Here is the Menu class:
package my.app;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import my.toolbox.InputHandler;
public class Menu extends MenuItem {
protected SessionImitator SESSION = SessionImitator.getInstance();
protected String title;
private static final String OUT_OF_RANGE = "Please select an option within the range";
private static final MenuItem SEPARATOR = new MenuItem("---------------------");
private static final MenuItem BACK = new MenuItem("Go Back");
private static final MenuItem EXIT = new MenuItem("Exit", new Runnable() {
public void run() {
System.exit(0);
}
});
List<MenuItem> items;
public Menu(String title, MenuItem ... items) {
this(title, false, true, items);
}
public Menu(String title, boolean addBack, boolean addExit, MenuItem ... items) {
super(title);
setExecutable(this);
init(addBack, addExit, items);
}
private void init(boolean addBack, boolean addExit, MenuItem ... items) {
this.items = new ArrayList<MenuItem>(Arrays.asList());
for (MenuItem item : items) {
if (item.isSessionDependent()) {
if (!item.getSessionAction() && SESSION.isSet()) {
continue;
}
}
this.items.add(item);
}
if (SESSION.isSet()) {
System.out.println("THIS PART DOES NOT WORK SINCE THE OBJECT IT's NOT UPDATED AFTER THE SESSION IS SET!");
}
if (addBack) this.items.add(BACK);
if (addExit) this.items.add(EXIT);
}
private void display() {
int option = 0;
System.out.println(SEPARATOR.getTitle());
System.out.println(getTitle() + ":");
System.out.println(SEPARATOR.getTitle());
for (MenuItem item : items) {
System.out.println((option++) + ": " + item.getTitle());
}
System.out.println(SEPARATOR.getTitle());
System.out.println("select an option: ");
System.out.flush();
}
private MenuItem prompt() {
display();
int option = InputHandler.readInt();
if (option >= 0 && option < items.size()) {
return items.get(option);
}
System.out.println(OUT_OF_RANGE);
return null;
}
public void run() {
try {
for (MenuItem item = prompt(); item.isExecutable(); item = prompt()) {
item.run();
}
} catch (Throwable t) {
t.printStackTrace(System.out);
}
}
}
The MenuItem class:
package my.app;
public class MenuItem implements Runnable {
private String title;
private Runnable executable;
private boolean sessionDependent;
private boolean sessionAction;
protected MenuItem(String title) {
this(title, null, false, false);
}
protected MenuItem(String title, boolean sessionDependent, boolean sessionAction) {
this(title, null, sessionDependent, sessionAction);
}
protected MenuItem(String title, Runnable executable) {
this(title, executable, false, false);
}
public MenuItem(String title, Runnable executable, boolean sessionDependent, boolean sessionAction) {
this.title = title;
this.executable = executable;
this.sessionDependent = sessionDependent;
this.sessionAction = sessionAction;
}
public void run() {
try {
executable.run();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
public boolean isExecutable() {
return executable != null;
}
protected void setExecutable(Runnable executable) {
this.executable = executable;
}
public String getTitle() {
return title;
}
public boolean isSessionDependent() {
return sessionDependent;
}
public boolean getSessionAction() {
return sessionAction;
}
}
And the SessionImitator class:
package my.app;
public class SessionImitator {
private static SessionImitator instance = null;
protected int userId;
protected boolean locked = false;
protected SessionImitator() {
}
public static SessionImitator getInstance() {
if (instance == null) {
instance = new SessionImitator();
}
return instance;
}
public int getUserId() {
return userId;
}
public void setUserId(String id) {
if (!locked) {
this.userId = Integer.parseInt(id);
}
}
public boolean isSet() {
return locked;
}
}
What you are describing seems like you want to save a "state" of the program. But specifically of the state of the menu.
A simple implementation is to make your menu serializable, then save the serialized menu object to a file and reload it on login, if the file exists.
The above example would work for a user on a computer. If you wanted to persist across networks, etc. You might want to write the serialized object to a blob in a db table and then load it from there.
If your program is standalone, what you need is a container to hold current state of the application. There are different ways to obtain that:
a singleton: a dedicated class stores the state in its attributes and has a static member of its own class. That way you can get access to the state with code like State state = State.getInstance() - that is what your SessionImitator currently is.
a simple object injected in all other classes that could need it. A way to build that is to create an instance of a class holding state and pass it (for example in constructor) of other classes:
State state = new State();
...
Menu menu = new Menu(state);
a dependancy injection framework like Spring or Guice. It can help you to use the injection pattern but is really worthy when you have complex dependencies.
I am facing a design problem. If I have (for example) on the left dockable view a list view that contains some pojo's, how do I notify the center dockable which one is selected? I am trying to implement some kind of Master-Detail-View where the user selects one item and then can configure it in the center area and the right area.
Thanks in advance :)
It depends on how you want to design your application.
If you want to create a separate Editor for each pojo then you can have a look at the LeftTestPane provided by the drombler fx archetype for a sample.
#FXML
private void onNewSampleAction(ActionEvent event) {
sampleCounter++;
Sample sample = new Sample("Sample " + sampleCounter);
SampleEditorPane sampleEditorPane = new SampleEditorPane(sample);
Dockables.inject(sampleEditorPane);
Dockables.open(sampleEditorPane);
}
There is currently no API for selecting an already opened editor, but please note that editors are currently being improved with the work done for issue #111.
If you want a single detail view then you can use the Context Framework, which allows components such as Dockables and Actions to communicate in a loosly coupled way.
The ListView should implement LocalContextProvider and keep the selected pojo in its local Context.
#ViewDocking(...)
public class ListView extends SomeNode implements LocalContextProvider {
private final SimpleContextContent contextContent = new SimpleContextContent();
private final SimpleContext context = new SimpleContext(contextContent);
private MyPojo currentSelection;
...
#Override
public Context getLocalContext() {
return context;
}
...
if (currentSelection != null){
contextContent.remove(currentSelection);
}
currentSelection = <current selection>
if (currentSelection != null){
contextContent.add(currentSelection);
}
...
}
In this case, the DetailsView should be registered as a view (singleton), too, and implement LocalContextProvider as well as ActiveContextSensitive:
#ViewDocking(...)
public class DetailsPane extends SomeNode implements ActiveContextSensitive, LocalContextProvider {
private final SimpleContextContent contextContent = new SimpleContextContent();
private final SimpleContext context = new SimpleContext(contextContent);
private Context activeContext;
private MyPojo myPojo;
...
#Override
public Context getLocalContext() {
return context;
}
#Override
public void setActiveContext(Context activeContext) {
this.activeContext = activeContext;
this.activeContext.addContextListener(MyPojo.class, (ContextEvent event) -> contextChanged());
contextChanged();
}
private void contextChanged() {
MyPojo newMyPojo = activeContext.find(MyPojo.class);
if ((myPojo == null && newMyPojo != null) || (myPojo null && !sample.equals(newMyPojo))) {
if (myPojo != null) {
unregister();
}
myPojo = newMyPojo;
if (myPojo != null) {
register();
}
}
}
private void unregister() {
contextContent.remove(myPojo);
//reset DetailsView
}
private void register() {
// configure DetailsView
contextContent.add(myPojo);
}
...
}
Have a look at the RightTestPane provided by the drombler fx archetype for a sample.
I have an object, Supply, that can either be an ElecSupply or GasSupply (see related question).
Regardless of which subclass is being edited, they all have a list of BillingPeriods.
I now need to instantiate N number of BillingPeriodEditors based on the contents of that list, and am pretty baffled as to how I should do it.
I am using GWTP. Here is the code of the SupplyEditor I have just got working:
public class SupplyEditor extends Composite implements ValueAwareEditor<Supply>
{
private static SupplyEditorUiBinder uiBinder = GWT.create(SupplyEditorUiBinder.class);
interface SupplyEditorUiBinder extends UiBinder<Widget, SupplyEditor>
{
}
#Ignore
final ElecSupplyEditor elecSupplyEditor = new ElecSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor> elecSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor>(
elecSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof ElecSupply);
if(!(value instanceof ElecSupply))
{
showGasFields();
}
else
{
showElecFields();
}
}
};
#Ignore
final GasSupplyEditor gasSupplyEditor = new GasSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor> gasSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor>(
gasSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof GasSupply);
if(!(value instanceof GasSupply))
{
showElecFields();
}
else
{
showGasFields();
}
}
};
#UiField
Panel elecPanel, gasPanel, unitSection;
public SupplyEditor()
{
initWidget(uiBinder.createAndBindUi(this));
gasPanel.add(gasSupplyEditor);
elecPanel.add(elecSupplyEditor);
}
// functions to show and hide depending on which type...
#Override
public void setValue(Supply value)
{
if(value instanceof ElecSupply)
{
showElecFields();
}
else if(value instanceof GasSupply)
{
showGasFields();
}
else
{
showNeither();
}
}
}
Now, as the list of BillingPeriods is a part of any Supply, I presume the logic for this should be in the SupplyEditor.
I got some really good help on the thread How to access PresenterWidget fields when added dynamically, but that was before I had implemented the Editor Framework at all, so I think the logic is in the wrong places.
Any help greatly appreciated. I can post more code (Presenter and View) but I didn't want to make it too hard to read and all they do is get the Supply from the datastore and call edit() on the View.
I have had a look at some examples of ListEditor but I don't really get it!
You need a ListEditor
It depends of how you want to present them in your actual view, but the same idea apply:
public class BillingPeriodListEditor implements isEditor<ListEditor<BillingPeriod,BillingPeriodEditor>>, HasRequestContext{
private class BillingPeriodEditorSource extends EditorSource<BillingPeriodEditor>{
#Override
public EmailsItemEditor create(final int index) {
// called each time u add or retrive new object on the list
// of the #ManyToOne or #ManyToMany
}
#Override
public void dispose(EmailsItemEditor subEditor) {
// called each time you remove the object from the list
}
#Override
public void setIndex(EmailsItemEditor editor, int index) {
// i would suggest track the index of the subeditor.
}
}
private ListEditor<BillingPeriod, BillingPeriodEditor> listEditor = ListEditor.of(new BillingPeriodEditorSource ());
// on add new one ...
// apply or request factory
// you must implement the HasRequestContext to
// call the create.(Proxy.class)
public void createNewBillingPeriod(){
// create a new one then add to the list
listEditor.getList().add(...)
}
}
public class BillingPeriodEditor implements Editor<BillingPeriod>{
// edit you BillingPeriod object
}
Then in you actual editor edit as is in the path Example getBillingPeriods();
BillingPeriodListEditor billingPeriods = new BillingPeriodListEditor ();
// latter on the clickhandler
billingPeriods.createNewBillingPeriod()
You are done now.