Justplayit94
Justplayit94

Reputation: 423

Java SWT Tree Menu Shown only for one level of the tree

I am making a program that makes use of the java SWT's Tree structure. This is tree is build upon data that is read from external files and user input. To this tree I've also attached a right-click menu.

The main problem is that this tree's menu is spanned all over his items, and I would want it to be shown only on some level.

I also want to have different menus or menu options for different tree levels.

All the tree's creation is in a function:

public void createTree(final Composite container){
    try{
        for(Object element : container.getChildren()){
            if(element instanceof Tree){
                ((Tree) element).dispose();
            }
        }
        // function to verify if the tree is still in my container composite, and if so, I'll dispose the tree, because I am going to construct a new one

        final Tree variantTree = new Tree(container, SWT.CHECK | SWT.V_SCROLL | SWT.H_SCROLL);//creating new tree object
        variantTree.setBounds(10, 65, 400, 400);//dimensions
        //variantTree.setData("variant"); -- wanted to abuse this method to make a difference between the tree's level, 
             //but this attribute is shared across all the tree, and I cannot make a distinction between my levels

        if(..){
            //here I am using the data saved in a tree data structure to populate my SWT Tree
        }

        variantTree.addListener(SWT.Selection, new Listener(){
            //this is a listener used for the tree's checkboxes, using them to select different items from my tree
        });

        final Menu treeMenu = new Menu(variantTree);
        variantTree.setMenu(treeMenu);//adding the right click menu

        treeMenu.addMenuListener(new MenuAdapter(){
            //the menu's items are declared here: the buttons that I want to have and the their listeners
            //i am disposing the menu's items if there are any

                MenuItem newItem = new MenuItem(treeMenu, SWT.NONE);
                newItem.setText("new button...  ");
                newItem.addListener(SWT.Selection, new Listener(){

                    @Override
                    public void handleEvent(Event event) {
                            String item = variantTree.getSelection()[0].getText();//can I use this to make different menus for different tree levels?
                            for(Node element : TestControl.getTree().getChildren()){//getting the tree data structure that I have saved in a static way via a class
                                if(element.getName().equals(item)){
                            //opening a file dialog here and doing some operations
                            }
                      }
                });
        });

        //this is where I want to make the distinction between the levels of the tree, such as that I will have this menu show up only for the root of my tree, or the first level of the tree, since I will have multiple trees
        variantTree.addMenuDetectListener(new MenuDetectListener(){

            @Override
            public void menuDetected(MenuDetectEvent event) {
                // TODO Auto-generated method stub
                if(/*condition*/){ //I messed around with the tree's methods and attributes, nothing so far has come in handy to help me make a distinction between my tree's levels
                    event.doit = true;
                    //System.out.println(variantTree.getSelectionCount()); --I don't know if this can help me either, I tried to see if this will return differently for every level of the tree, but the return values is always 0
                    //find some kind of handle
                }else{
                    event.doit = false;
                }
            }

        });

Also, I want to have another menu being displayed for the second level of the tree, could I be using the String item = variantTree.getSelection()[0].getText();, modified in a sort of way to match my needs? Let's say, String item = variantTree.getSelection()[1].getText(); for the second level?

My SWT Tree will have a maximum depth of 3 for each root, and it looks something like this:

root1 - want the menu only for this item
|---child - level 1
|------child - level 2

root2 - want the menu only for this item
|---child - level 1
|-------child - level 2

Thank you.

Upvotes: 1

Views: 1013

Answers (2)

Baz
Baz

Reputation: 36904

No need to compare TreeItem texts, just check the level of the item by e.g. checking if it's got a parent.

public static void main(String[] args)
{
    Display display = Display.getDefault();
    final Shell shell = new Shell(display);
    shell.setText("StackOverflow");
    shell.setLayout(new FillLayout());

    final Tree tree = new Tree(shell, SWT.NONE);

    for (int i = 0; i < 10; i++)
    {
        TreeItem item = new TreeItem(tree, SWT.NONE);
        item.setText("Parent " + i);

        for (int j = 0; j < 3; j++)
        {
            TreeItem child = new TreeItem(item, SWT.NONE);
            child.setText("Child " + i + " " + j);

            for (int k = 0; k < 3; k++)
            {
                TreeItem grandChild = new TreeItem(child, SWT.NONE);
                grandChild.setText("Child " + i + " " + j + " " + k);
            }
        }
    }

    final Menu menu = new Menu(tree);
    tree.setMenu(menu);
    tree.addMenuDetectListener(new MenuDetectListener()
    {
        @Override
        public void menuDetected(MenuDetectEvent e)
        {
            TreeItem treeItem = tree.getSelection()[0];

            e.doit = getLevelOfItem(treeItem) < 2;
        }
    });
    menu.addMenuListener(new MenuAdapter()
    {
        public void menuShown(MenuEvent e)
        {
            TreeItem item = tree.getSelection()[0];

            setMenu(menu, item);
        }
    });

    shell.pack();
    shell.open();
    while (!shell.isDisposed())
    {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
}

private static void setMenu(Menu menu, TreeItem item)
{
    int level = getLevelOfItem(item);

    MenuItem[] items = menu.getItems();
    for (MenuItem i : items)
    {
        i.dispose();
    }

    switch (level)
    {
        case 0:
            for(int i = 0; i < 2; i++)
            {
                MenuItem newItem = new MenuItem(menu, SWT.NONE);
                newItem.setText("Menu item " + i);
            }
            break;
        case 1:
            for(int i = 0; i < 4; i++)
            {
                MenuItem newItem = new MenuItem(menu, SWT.NONE);
                newItem.setText("Menu item " + i);
            }
            break;
    }
}

private static int getLevelOfItem(TreeItem item)
{
    int counter = 0;

    while(item.getParentItem() != null)
    {
        item = item.getParentItem();
        counter++;
    }

    return counter;
}

This will show a different menu for level 0 and 1 and no menu for level 2.

Upvotes: 2

Justplayit94
Justplayit94

Reputation: 423

I have solved my problem in the following way. If you actually see my code, there are the following lines:

for(Node element : TestControl.getTree().getChildren()){//getting the tree data structure that I have saved in a static way via a class
   if(element.getName().equals(item)){
         //opening a file dialog here and doing some operations
   }
}

I am getting the first level of my tree data structure, and then I'm verifying if the root names of my SWT tree are equal to the roots of the tree data structure.

Using the same method, this is what will result in the end for the SWT Tree's menu listener:

variantTree.addMenuDetectListener(new MenuDetectListener(){

            @Override
            public void menuDetected(MenuDetectEvent event) {
                // TODO Auto-generated method stub
                for(Node element : TestControl.getTree().getChildren()){
                    if(variantTree.getSelection()[0].getText().equals(element.getName())){
                        event.doit = true;
                        break;//need this, because it will propagate only to the last item, or it will have a strange behaviour
                    }else{
                        event.doit = false;
                    }
                }
            }

        });

where element is a node from my tree data structure. Hope it helps anyone that will have the same problem.

Upvotes: 0

Related Questions