2

We are facing a problem, in handling a large number of Draw2d Figures, in a single Canvas. We are building a Tree of the nodes, with Connections between a parent, and a child node. The number of figures, in the canvas are of the order of 10000 (just the "Node" Figures, there are about another 10000 "Connection" figures too, that I am not counting).

I am attaching a part of one of our diagrams in Image:

enter image description here

The problem is this: the nodes in the tree can be collapsed or expanded. When the number of Nodes in the Tree are of the order of 1000-2000, then the Collapse/Expand takes place momentarily. However, when the node count goes higher, it takes more and more time to Collapse/Expand any particular node, which is irritating.

I have written some sample code to see, if the problem is with our code, or, that draw2d performance degrades in general with more number of widgets. The same problem exists within the sample application, which indicates that we may have to do some optimizations within the draw2d codebase itself. I made a View in Eclipse to demonstrate that. The code of the same is attached below.

import java.util.ArrayList;
import java.util.List;

import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FigureCanvas;
import org.eclipse.draw2d.GridData;
import org.eclipse.draw2d.GridLayout;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.LineBorder;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.Panel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

public class View extends ViewPart {
    public static final String ID = "GridLayoutTest.view";

    /**
     * This is a callback that will allow us to create the viewer and initialize
     * it.
     */
    public void createPartControl(Composite parent) {
        Composite composite = new Composite(parent, SWT.NONE);
        composite.setLayout(new FillLayout());
        FigureCanvas canvas = new FigureCanvas(composite);
        Figure baseFigure = new Figure();
        baseFigure.setLayoutManager(new GridLayout(3, true));
        Panel contentPanel = new Panel();
        contentPanel.setLayoutManager(new GridLayout(1, true));
        baseFigure.add(new Figure());
        baseFigure.add(contentPanel);
        baseFigure.add(new Figure());
        fillContents(contentPanel);
        canvas.setContents(baseFigure);
    }

    private void fillContents(Panel contentPanel) {
        int margin;
        String text;
        CollapsibleFigure prevParent = null;
        for(int i = 1; i <= 2500; i++) {
            if(i%5 == 1) {
                text = "Parent " + (i/5 + 1);
                margin = 50;
                prevParent = new CollapsibleFigure(contentPanel, text, margin);
            } else {
                text = "Child " + (i%5 - 1);
                margin = 100;
                CollapsibleFigure child = new CollapsibleFigure(contentPanel, text, margin);
                prevParent.addChild(child);
            }
        }

        for(int i = 2501; i <= 7500; i++) {
            if(i == 2501) {
                text = "Parent " + (i/5 + 1);
                margin = 50;
                prevParent = new CollapsibleFigure(contentPanel, text, margin);
            } else {
                text = "Child " + (i - 2501);
                margin = 100;
                CollapsibleFigure child = new CollapsibleFigure(contentPanel, text, margin);
                prevParent.addChild(child);
            }
        }

        for(int i = 7501; i <= 10000; i++) {
            if(i%5 == 1) {
                text = "Parent " + (i/5 + 1);
                margin = 50;
                prevParent = new CollapsibleFigure(contentPanel, text, margin);
            } else {
                text = "Child " + (i%5 - 1);
                margin = 100;
                CollapsibleFigure child = new CollapsibleFigure(contentPanel, text, margin);
                prevParent.addChild(child);
            }
        }
    }

    private class CollapsibleFigure extends Panel {
        private List<CollapsibleFigure> children; 

        private int margin;

        private CollapsibleFigure(Panel contentPanel, String text, int margin) {
            children = new ArrayList<CollapsibleFigure>();
            setBorder(new LineBorder(2));
            setBackgroundColor(new Color(null, 255, 255, 255));
            this.margin = margin;
            GridLayout layout = new GridLayout(2, false);
            GridData layoutData;
            setLayoutManager(layout);
            Label label;
            label = new Label();
            label.setText("x");
            add(label);
            label.setCursor(Cursors.HAND);
            label.addMouseListener(new MouseListener.Stub() {
                public void mouseReleased(MouseEvent e) {
                    Label label = (Label) e.getSource();
                    if(label.getText().equals("x"))
                        collapseChildren();
                    else
                        showChildren();
                }
            });
            label = new Label();
            label.setText(text);
            add(label);
            layoutData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
            layout.setConstraint(label, layoutData);
            label = new Label();
            label.setText("Some Content");
            add(label);
            layoutData = new GridData(SWT.CENTER, SWT.CENTER, true, true);
            layoutData.horizontalSpan = 2;
            layout.setConstraint(label, layoutData);
            contentPanel.add(this);
            layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, true);
            layoutData.horizontalIndent = margin;
            contentPanel.getLayoutManager().setConstraint(this, layoutData);
        }

        private void addChild(CollapsibleFigure child) {
            children.add(child);
        }

        private void collapseChildren() {
            Panel contentPanel = (Panel) getParent();
            for(CollapsibleFigure child : children)
                contentPanel.remove(child);
            ((Label)(getChildren().get(0))).setText(">");
        }

        private void showChildren() {
            Panel contentPanel = (Panel) getParent();
            int index = contentPanel.getChildren().indexOf(this) + 1;
            for(CollapsibleFigure child : children) {
                contentPanel.add(child, index);
                GridData layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, true);
                layoutData.horizontalIndent = margin + 50;
                contentPanel.getLayoutManager().setConstraint(child, layoutData);
                index++;
            }
            ((Label)(getChildren().get(0))).setText("x");
        }
    }

    @Override
    public void setFocus() {

    }
}

Try to expand/collapse figures in the View (by clicking on the "x" or ">" buttons), it'll take time (won't occur instantaneously). Can anyone please provide some pointers as to how this problem can be solved?

Baz
  • 36,440
  • 11
  • 68
  • 94
Saurabh
  • 63
  • 8

1 Answers1

3

I figured it out. I am posting it here in case anyone faces similar performance issues. I received help in this regard on the Eclipse forum. The link, and full code is provided at the eclipse forum here: http://www.eclipse.org/forums/index.php/m/1064195/

Saurabh
  • 63
  • 8
  • +1, but please post the solution here. Links tend to be dead after a certain amount of time, which would render your answer useless. – Baz Jun 19 '13 at 08:23
  • 1
    The Solution for the Problem is this: When a large number of widgets are added to a "same parent", such a problem will occur, because every time, there is even a slight modification in any of its children, a revalidation is performed for all the siblings. The way to deal such situations, is to use some kind of _Paging_, i.e. Divide children in a number of panels and then add them to the parent. This will reduce the amount of revalidation work significantly, and hence there would be a marked improvement in the overall performance. The link I provided, contains a ZIP file, which is sample code. – Saurabh Jun 20 '13 at 08:49
  • I am not able to reach the zip file. Can you post it on dropbox or something similar? – JustBeingHelpful Sep 03 '14 at 22:39