0

I am new be in RCP development.

I want to create two tables with, each table contains different data. Data from two tables have either 1 to 1 , 1 to many or many to 1 relationship. And that can be done by drawing arrows between two tables. For example,

         **Row 1**                  **Row 2**
           R1 V1                      R2 V1
           R1 V2                      R2 V2
           R1 V3                      R2 V3

I want to draw arrows from R1V1 to ( R2V1 and R2V3 ) or vice a versa. How can I show it graphically.

How can I find that which rows are combined by arrows.

Any help is appreciated.

--- Mandar

Mandy
  • 1,087
  • 1
  • 10
  • 14

3 Answers3

2

This is quite a difficult component to implement, I did one of these for Tibco Business Studio some time ago.

You'll need to place a Canvas between your two tables to draw the links on. You presumably have data models for your two tables, you'll also need a third model for storing the links and ensure that any modifications to this model trigger a refresh of the Canvas.

Next add drag and drop support to the two tables, dropping an item from table 1 onto table 2 should create a new item in your link model (thus triggering a Canvas refresh to draw the link).

Actually drawing the links in the right locations you'll have to work out yourself, but hopefully this gives you some ideas to start with.

Nick Wilson
  • 4,959
  • 29
  • 42
  • I guess my main problem is to place a canvas and draw links between them. I will try this and let you know. – Mandy Sep 24 '12 at 10:57
  • Nick it works for me, except the lines drawn with the points captured are not showing the exact match. But still it works. Thanks for the clue. --- Mandar – Mandy Sep 24 '12 at 13:46
2

Here is the code that is based on the idea proposed by Nick. It is just to give an idea for someone who might wonder where to start to implement something like this shown below

enter image description here

This would let you click on any column on the left hand side table, then draws a line as your mouse moves on towards the right table, and anchors the line as soon as a column on the right hand side table is selected. It keeps a mapping between the left table row and right table row in a linked list as the mapping data model.

package sample;

import java.util.LinkedList;

import org.eclipse.draw2d.AutomaticRouter;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayeredPane;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.LightweightSystem;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.draw2d.PolylineDecoration;
import org.eclipse.draw2d.XYAnchor;
import org.eclipse.draw2d.geometry.PointList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

public class GraphicTableMapper {
    private static Point sourcePosition;
    private static PathFigure currentPath;
    private static Figure bf;
    private static Canvas canvas;
    private static int sourceRow;
    private static int targetRow;
    private static LinkedList<RowMapper> rowmapList = new LinkedList<RowMapper>();

    public static void main(String[] args) {
        Display display = Display.getDefault();
        final Shell shell = new Shell(display);
        shell.setSize(550, 500);
        shell.setLayout(new GridLayout(3, false));
        final Table table = new Table(shell, SWT.MULTI | SWT.BORDER
                | SWT.FULL_SELECTION);
        table.setLinesVisible(true);
        table.setHeaderVisible(true);
        final String[] titles = { "Serial Number", "Whatever" };
        for (int i = 0; i < titles.length; i++) {
            TableColumn column = new TableColumn(table, SWT.NONE);
            column.setText(titles[i]);
        }
        int count = 100;// create 100 rows in table
        for (int i = 0; i < count; i++) {
            TableItem item = new TableItem(table, SWT.NONE);
            item.setText(0, "x");
            item.setText(1, "y");
            item.setText(2, "!");
            item.setText(3, "this stuff behaves the way I expect");
            item.setText(4, "almost everywhere");
            item.setText(5, "some.folder");
            item.setText(6, "line " + i + " in nowhere");
        }
        for (int i = 0; i < titles.length; i++) {
            table.getColumn(i).pack();
        }
        table.addListener(SWT.MouseDown, new Listener() {
            public void handleEvent(Event event) {
                Point pt = new Point(event.x, event.y);
                TableItem item = table.getItem(pt);
                if (item == null)
                    return;
                for (int i = 0; i < titles.length; i++) {
                    Rectangle rect = item.getBounds(i);
                    if (rect.contains(pt)) {
                        int index = table.indexOf(item);
                        System.out.println("Item " + index + "-" + i);
                        sourcePosition = pt;
                        sourceRow = index;
                        currentPath = new PathFigure();
                        currentPath.setSourceAnchor(new XYAnchor(
                                new org.eclipse.draw2d.geometry.Point(-10,
                                        event.y)));
                        currentPath
                                .setTargetAnchor(new XYAnchor(
                                        new org.eclipse.draw2d.geometry.Point(
                                                0, pt.y)));
                        bf.add(currentPath);
                    }
                }
            }
        });

        table.addMouseMoveListener(new MouseMoveListener() {
            public void mouseMove(MouseEvent arg0) {
                if (currentPath != null) {
                    ((XYAnchor) (currentPath.getTargetAnchor()))
                            .setLocation(new org.eclipse.draw2d.geometry.Point(
                                    0, arg0.y));
                }
            }
        });

        canvas = new Canvas(shell, SWT.None);       
        canvas.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_GREEN));
        LightweightSystem lws = new LightweightSystem(canvas);
        bf = new BaseFigure();
        lws.setContents(bf);

        canvas.addMouseMoveListener(new MouseMoveListener() {
            public void mouseMove(MouseEvent arg0) {
                if (currentPath != null) {
                    ((XYAnchor) (currentPath.getTargetAnchor()))
                            .setLocation(new org.eclipse.draw2d.geometry.Point(
                                    arg0.x > canvas.getSize().x - 5 ? canvas
                                            .getSize().x - 5 : arg0.x, arg0.y));
                }
            }
        });
        GridData data2 = new GridData();
        data2.verticalAlignment = SWT.TOP;
        data2.grabExcessHorizontalSpace = false;
        data2.grabExcessVerticalSpace = true;
        data2.horizontalIndent = -10;
        data2.widthHint = 200;
        data2.heightHint = 1000;
        canvas.setLayoutData(data2);
        final Table table2 = new Table(shell, SWT.MULTI | SWT.BORDER
                | SWT.FULL_SELECTION);
        table2.setLinesVisible(true);
        table2.setHeaderVisible(true);
        data2 = new GridData();
        data2.grabExcessHorizontalSpace = false;
        data2.horizontalIndent = -10;
        table2.setLayoutData(data2);
        final String[] titles2 = { "Serial Number", "Whatever" };
        for (int i = 0; i < titles.length; i++) {
            TableColumn column = new TableColumn(table2, SWT.NONE);
            column.setText(titles[i]);
            canvas.redraw();
        }
        table2.addMouseMoveListener(new MouseMoveListener() {
            public void mouseMove(MouseEvent event) {
                if (currentPath != null) {
                    Point pt = new Point(event.x, event.y);
                    TableItem item = table2.getItem(pt);
                    if (item == null)
                        return;
                    for (int i = 0; i < titles2.length; i++) {
                        Rectangle rect = item.getBounds(i);
                        if (rect.contains(pt)) {
                            ((XYAnchor) (currentPath.getTargetAnchor()))
                                    .setLocation(new org.eclipse.draw2d.geometry.Point(
                                            canvas.getSize().x - 5, event.y));
                        }
                    }
                }
            }
        });

        int count2 = 100;// create 100 rows in table 2
        for (int i = 0; i < count2; i++) {
            TableItem item = new TableItem(table2, SWT.NONE);
            item.setText(0, "x");
            item.setText(1, "y");
            item.setText(2, "!");
            item.setText(3, "this stuff behaves the way I expect");
            item.setText(4, "almost everywhere");
            item.setText(5, "some.folder");
            item.setText(6, "line " + i + " in nowhere");
        }
        for (int i = 0; i < titles.length; i++) {
            table2.getColumn(i).pack();
        }
        table2.addListener(SWT.MouseDown, new Listener() {
            public void handleEvent(Event event) {
                try {
                    Point pt = new Point(event.x, event.y);
                    TableItem item = table2.getItem(pt);
                    if (item == null)
                        return;
                    for (int i = 0; i < titles2.length; i++) {
                        Rectangle rect = item.getBounds(i);
                        if (rect.contains(pt)) {
                            int index = table2.indexOf(item);
                            targetRow = index;
                            System.out.println("Item " + index + "-" + i);
                            if (sourcePosition != null) {
                                add(event);
                            }
                        }
                    }
                } finally {
                    sourcePosition = null;
                    sourceRow = -1;
                    targetRow = -1;
                }
            }
        });
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
    }

    public static void add(Event event) {
        bf.remove(currentPath);
        PathFigure figure = new PathFigure();
        figure.setSourceAnchor(currentPath.getSourceAnchor());
        figure.setTargetAnchor(currentPath.getTargetAnchor());
        bf.add(figure);
        currentPath = null;
        RowMapper mapper = new RowMapper();
        mapper.sourceRow = sourceRow;
        mapper.targetRow = targetRow;
        if (!rowmapList.contains(mapper)) {
            rowmapList.add(mapper);
        }
    }


    class BaseFigure extends FreeformLayeredPane {
    public BaseFigure() {
        setLayoutManager(new FreeformLayout());
        setBorder(new MarginBorder(5));
        setBackgroundColor(ColorConstants.white);
        setOpaque(true);
    }
}

class PathFigure extends PolylineConnection {
    public PathFigure() {
        setTargetDecoration(new PolylineDecoration());
        setConnectionRouter(new AutomaticRouter() {
            @Override
            protected void handleCollision(PointList list, int index) {
            }
        });
    }
}

class RowMapper {
    int sourceRow;
    int targetRow;

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof RowMapper) {
            RowMapper mapper = (RowMapper) obj;
            return (sourceRow == mapper.sourceRow && targetRow == mapper.targetRow);
        }
        return false;
    }

}
Droidman
  • 540
  • 4
  • 7
0

Am I right in thinking that this implementation uses the mouse location to draw the arrows? So if you wanted to save / load a relationship you would have to save the x,y positions of the arrows and you'd have to make sure your components always stayed the same size?

Link19
  • 586
  • 1
  • 18
  • 47
  • I've played around with thin myself, but I can't work out how to get the on screen location of the Row you're after. – Link19 Nov 30 '12 at 09:42
  • The best answer I had was that you'll have to make your own table widget, Depending on how much functionality the table needs this could be fairly simple or very difficult, but once it's there you should be able to get hold of on screen locations of rows, etc. – Link19 Nov 30 '12 at 09:59