Package org.eclipse.zest.layouts.exampleUses

Source Code of org.eclipse.zest.layouts.exampleUses.SimpleSWTExample$GraphPaintListener

/*******************************************************************************
* Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: The Chisel Group, University of Victoria
******************************************************************************/
package org.eclipse.zest.layouts.exampleUses;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.zest.layouts.InvalidLayoutConfiguration;
import org.eclipse.zest.layouts.LayoutAlgorithm;
import org.eclipse.zest.layouts.LayoutBendPoint;
import org.eclipse.zest.layouts.LayoutEntity;
import org.eclipse.zest.layouts.LayoutRelationship;
import org.eclipse.zest.layouts.LayoutStyles;
import org.eclipse.zest.layouts.algorithms.GridLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.HorizontalLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
import org.eclipse.zest.layouts.algorithms.VerticalLayoutAlgorithm;
import org.eclipse.zest.layouts.exampleStructures.SimpleNode;
import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship;
import org.eclipse.zest.layouts.progress.ProgressEvent;
import org.eclipse.zest.layouts.progress.ProgressListener;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

/**
* @author Rob Lintern
* @author Ian Bull
* A simple example of using layout algorithms with a SWT application.
*/
public class SimpleSWTExample {

  private static final Color BLACK = new Color(Display.getDefault(), 0, 0, 0);
  private static final Color NODE_NORMAL_COLOR = new Color(Display.getDefault(), 225, 225, 255);
  private static final Color NODE_SELECTED_COLOR = new Color(Display.getDefault(), 255, 125, 125);
  private static final Color NODE_ADJACENT_COLOR = new Color(Display.getDefault(), 255, 200, 125);
  private static final Color BORDER_NORMAL_COLOR = new Color(Display.getDefault(), 0, 0, 0);
  private static final Color BORDER_SELECTED_COLOR = new Color(Display.getDefault(), 255, 0, 0);
  private static final Color BORDER_ADJACENT_COLOR = new Color(Display.getDefault(), 255, 128, 0);
  private static final Color RELATIONSHIP_COLOR = new Color(Display.getDefault(), 192, 192, 225);
  private static final Color RELATIONSHIP_HIGHLIGHT_COLOR = new Color(Display.getDefault(), 255, 200, 125);

  private static final String[] NAMES = new String[] { "Peggy", "Rob", "Ian", "Chris", "Simon", "Wendy", "Steven", "Kim", "Neil", "Dave", "John", "Suzanne", "Jody", "Casey", "Bjorn", "Peter", "Erin", "Lisa", "Jennie", "Liz", "Bert", "Ryan", "Nick", "Amy", "Lee", "Me", "You", "Max", "NCI", "OWL",
      "Ed", "Jamie", "Protege", "Matt", "Bryan", "Pete", "Sam", "Bob", "Katie", "Bill", "Josh", "Davor", "Ken", "Jacob", "Norm", "Jim", "Maya", "Jill", "Kit", "Jo", "Joe", "Andrew", "Charles", "Pat", "Patrick", "Jeremy", "Mike", "Michael", "Patricia", "Marg", "Terry", "Emily", "Ben", "Holly",
      "Joanna", "Joanne", "Evan", "Tom", "Dan", "Eric", "Corey", "Meghan", "Kevin", "Nina", "Ron", "Daniel", "David", "Jeff", "Nathan", "Amanda", "Phil", "Tricia", "Steph", "Stewart", "Stuart", "Bull", "Lintern", "Callendar", "Thompson", "Rigby", "Adam", "Judith", "Cynthia", "Sarah", "Sara",
      "Roger", "Andy", "Kris", "Mark", "Shane", "Spence", "Ivy", "Ivanna", "Julie", "Justin", "Emile", "Toby", "Robin", "Rich", "Kathy", "Cathy", "Nicky", "Ricky", "Danny", "Anne", "Ann", "Jen", "Robert", "Calvin", "Alvin", "Scott", "Kumar" };

  //private static final boolean RENDER_HIGH_QUALITY = true;

  private static final int INITIAL_PANEL_WIDTH = 800;
  private static final int INITIAL_PANEL_HEIGHT = 600;
  private static final double INITIAL_NODE_WIDTH = 20;
  private static final double INITIAL_NODE_HEIGHT = 15;

  protected static ArrayList algorithms = new ArrayList();
  {
    algorithms.add(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
    algorithms.add(new TreeLayoutAlgorithm(LayoutStyles.NONE));
    algorithms.add(new HorizontalTreeLayoutAlgorithm(LayoutStyles.NONE));
    algorithms.add(new RadialLayoutAlgorithm(LayoutStyles.NONE));
    algorithms.add(new GridLayoutAlgorithm(LayoutStyles.NONE));
    algorithms.add(new HorizontalLayoutAlgorithm(LayoutStyles.NONE));
    algorithms.add(new VerticalLayoutAlgorithm(LayoutStyles.NONE));
  }

  protected static ArrayList algorithmNames = new ArrayList();
  {
    algorithmNames.add("Spring");
    algorithmNames.add("Fade");
    algorithmNames.add("Tree - V");
    algorithmNames.add("Tree - H");
    algorithmNames.add("Radial");
    algorithmNames.add("Grid");
    algorithmNames.add("Horizontal");
    algorithmNames.add("Vertical");
  }

  protected static ArrayList algorithmAnimates = new ArrayList();
  {
    algorithmAnimates.add(Boolean.TRUE);
    algorithmAnimates.add(Boolean.TRUE);
    algorithmAnimates.add(Boolean.FALSE);
    algorithmAnimates.add(Boolean.FALSE);
    algorithmAnimates.add(Boolean.FALSE);
    algorithmAnimates.add(Boolean.FALSE);
    algorithmAnimates.add(Boolean.FALSE);
    algorithmAnimates.add(Boolean.FALSE);
  }

  //private long updateGUICount = 0;
  private boolean animate = true;
  private static boolean continuous = false;
  private static boolean asynchronously = false;

  private Shell mainShell;
  private Composite mainComposite;
  private List entities;
  private List relationships;

  private ToolBar toolBar;
  private Label lblProgress;

  private LayoutAlgorithm currentLayoutAlgorithm;
  protected SimpleNode selectedEntity;
  protected SimpleNode hoverEntity;

  protected Point mouseDownPoint;
  protected Point selectedEntityPositionAtMouseDown;
  private long idCount = 0;

  public SimpleSWTExample(Display display) {
    mainShell = new Shell(display);
    mainShell.addControlListener(new ControlListener() {
      public void controlMoved(ControlEvent e) {
      }

      public void controlResized(ControlEvent e) {
        mainShell.layout(true);
      }
    });
    GridLayout gridLayout = new GridLayout(1, true);
    mainShell.setLayout(gridLayout);
    GridData toolbarGridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER, GridData.VERTICAL_ALIGN_BEGINNING, true, true);
    toolBar = new ToolBar(mainShell, SWT.HORIZONTAL);
    toolBar.setLayoutData(toolbarGridData);
    toolBar.setLayout(new FillLayout(SWT.HORIZONTAL));

    GridData progressGridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER, GridData.VERTICAL_ALIGN_END, true, false);
    progressGridData.widthHint = 300;
    lblProgress = new Label(mainShell, SWT.NONE);
    lblProgress.setLayoutData(progressGridData);
    lblProgress.setText("Progress: ");

    for (int i = 0; i < algorithms.size(); i++) {
      final LayoutAlgorithm algorithm = (LayoutAlgorithm) algorithms.get(i);
      String algorithmName = (String) algorithmNames.get(i);
      final boolean algorithmAnimate = ((Boolean) algorithmAnimates.get(i)).booleanValue();
      ToolItem algorithmButton = new ToolItem(toolBar, SWT.PUSH);
      algorithmButton.setText(algorithmName);

      new ToolItem(toolBar, SWT.SEPARATOR);

      algorithmButton.addSelectionListener(new SelectionListener() {
        public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
          currentLayoutAlgorithm = algorithm;
          algorithm.setEntityAspectRatio((double) mainComposite.getClientArea().width / (double) mainComposite.getClientArea().height);
          animate = algorithmAnimate;
          performLayout(false);
        }

        public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) {
        }
      });
    }

    ToolItem redrawButton = new ToolItem(toolBar, SWT.PUSH);
    redrawButton.setText("Redraw");
    redrawButton.addSelectionListener(new SelectionListener() {
      public void widgetSelected(SelectionEvent e) {
        mainComposite.redraw();
      }

      public void widgetDefaultSelected(SelectionEvent e) {
      }
    });

    ToolItem stopButton = new ToolItem(toolBar, SWT.PUSH);
    stopButton.setText("Stop");
    stopButton.addSelectionListener(new SelectionListener() {
      public void widgetSelected(SelectionEvent e) {
        currentLayoutAlgorithm.stop();
      }

      public void widgetDefaultSelected(SelectionEvent e) {
      }
    });

    ToolItem continuousButton = new ToolItem(toolBar, SWT.CHECK);
    continuousButton.setText("Continuous");
    continuousButton.addSelectionListener(new SelectionListener() {
      public void widgetSelected(SelectionEvent e) {
        setContinuous();
      }

      public void widgetDefaultSelected(SelectionEvent e) {
      }
    });

    ToolItem asynchronousButton = new ToolItem(toolBar, SWT.CHECK);
    asynchronousButton.setText("Asynchronous");
    asynchronousButton.addSelectionListener(new SelectionListener() {
      public void widgetSelected(SelectionEvent e) {
        setAsynchronously();
      }

      public void widgetDefaultSelected(SelectionEvent e) {
      }
    });

    createMainPanel();
    SimpleNode.setNodeColors(NODE_NORMAL_COLOR, BORDER_NORMAL_COLOR, NODE_SELECTED_COLOR, NODE_ADJACENT_COLOR, BORDER_SELECTED_COLOR, BORDER_ADJACENT_COLOR);
    SimpleRelationship.setDefaultColor(RELATIONSHIP_COLOR);
    SimpleRelationship.setDefaultHighlightColor(RELATIONSHIP_HIGHLIGHT_COLOR);
    createTreeGraph(4, 3, false);
    mainShell.pack();
    //mainShell.setSize(INITIAL_PANEL_WIDTH + 100, INITIAL_PANEL_HEIGHT + 200);
  }

  public void setAsynchronously() {
    if (asynchronously) {
      asynchronously = false;
    } else {
      asynchronously = true;
    }

  }

  public void setContinuous() {
    if (continuous) {
      continuous = false;
    } else {
      continuous = true;
    }
  }

  IProgressMonitor progressMonitor = null;
  ProgressMonitorDialog pmd = null;
  boolean GUI_UPDATING = false;

  private void performLayout(boolean placeRandomly) {

    if (!continuous) {
    }

    if (currentLayoutAlgorithm.isRunning()) {
      throw new RuntimeException("Layout is already running");
    }
    if (placeRandomly) {
      placeRandomly();
    }
    ProgressListener progressListener = new ProgressListener() {

      int lastStep = 0;

      class progressSync implements Runnable {

        public static final int PROGRESS_UPDATED = 1;
        public static final int PROGRESS_STARTED = 2;
        public static final int PROGRESS_ENDED = 3;
        public static final int UPDATE_GUI = 4;

        private int progressState = -1;
        private ProgressEvent e;

        public progressSync(int progressState, final ProgressEvent e) {
          this.progressState = progressState;
          this.e = e;

        }

        public void run() {

          switch (progressState) {
          case PROGRESS_STARTED:
            if (!continuous) {
              pmd = new ProgressMonitorDialog(getShell());
              progressMonitor = pmd.getProgressMonitor();
              pmd.open();
              progressMonitor.beginTask("Layout Running...", e.getTotalNumberOfSteps());
            }
            break;

          case PROGRESS_UPDATED:
            if (!continuous) {
              progressMonitor.worked(e.getStepsCompleted() - lastStep);
              lastStep = e.getStepsCompleted();
            }
            break;

          case PROGRESS_ENDED:
            if (!continuous) {
              progressMonitor.done();
              pmd.close();
            }
            updateGUI();
            mainShell.redraw();
            break;
          case UPDATE_GUI:
            updateGUI();
            GUI_UPDATING = false;
            break;
          }
          mainComposite.redraw();

        }

      }

      public void progressUpdated(final ProgressEvent e) {
        if (asynchronously) {
          if (!mainComposite.isDisposed()) {
            Display.getDefault().asyncExec(new progressSync(progressSync.PROGRESS_UPDATED, e));
            if (!GUI_UPDATING) {
              GUI_UPDATING = true;
              Display.getDefault().asyncExec(new progressSync(progressSync.UPDATE_GUI, e));
            }
          }
        } else {
          if (!mainComposite.isDisposed()) {
            new progressSync(progressSync.PROGRESS_UPDATED, e).run();
          }
        }

      }

      public void progressStarted(ProgressEvent e) {
        if (asynchronously) {
          if (!mainComposite.isDisposed()) {
            Display.getDefault().asyncExec(new progressSync(progressSync.PROGRESS_STARTED, e));
          }
        } else {
          if (!mainComposite.isDisposed()) {
            new progressSync(progressSync.PROGRESS_STARTED, e).run();
          }
        }

      }

      public void progressEnded(ProgressEvent e) {
        if (asynchronously) {
          if (!mainComposite.isDisposed()) {
            Display.getDefault().asyncExec(new progressSync(progressSync.PROGRESS_ENDED, e));
          }
        } else {
          if (!mainComposite.isDisposed()) {
            new progressSync(progressSync.PROGRESS_ENDED, e).run();
          }
        }
        currentLayoutAlgorithm.removeProgressListener(this);
        Display.getDefault().asyncExec(new progressSync(progressSync.PROGRESS_UPDATED, e));
      }
    };
    currentLayoutAlgorithm.addProgressListener(progressListener);

    try {
      LayoutEntity[] layoutEntities = new LayoutEntity[entities.size()];
      entities.toArray(layoutEntities);
      LayoutRelationship[] layoutRelationships = new LayoutRelationship[relationships.size()];
      relationships.toArray(layoutRelationships);
      currentLayoutAlgorithm.applyLayout(layoutEntities, layoutRelationships, 0, 0, mainComposite.getClientArea().width - 30, mainComposite.getClientArea().height - 17, asynchronously, continuous);
      if (!animate) {
        updateGUI();
      }
    } catch (InvalidLayoutConfiguration e) {
      e.printStackTrace();
    }
  }

  private Shell getShell() {
    return mainShell;
  }

  private void createMainPanel() {
    mainComposite = new Canvas(mainShell, SWT.NO_BACKGROUND);
    GridData mainGridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL, GridData.VERTICAL_ALIGN_FILL, true, true);
    mainGridData.widthHint = INITIAL_PANEL_WIDTH;
    mainGridData.heightHint = INITIAL_PANEL_HEIGHT;
    mainComposite.setLayoutData(mainGridData);
    mainComposite.addPaintListener(new GraphPaintListener());

    mainComposite.setBackground(new Color(Display.getCurrent(), 255, 255, 255));
    mainComposite.setLayout(null);

    mainComposite.addMouseMoveListener(new MouseMoveListener() {

      public void mouseMove(MouseEvent e) {

        if (selectedEntity == null) {
          // Nothing selected, lets use a mouse hover
          SimpleNode oldEntity = hoverEntity;
          hoverEntity = null;

          for (Iterator iter = entities.iterator(); iter.hasNext() && selectedEntity == null;) {
            SimpleNode entity = (SimpleNode) iter.next();
            double x = entity.getX();
            double y = entity.getY();
            double w = entity.getWidth();
            double h = entity.getHeight();
            Rectangle rect = new Rectangle((int) x, (int) y, (int) w, (int) h);
            if (rect.contains(e.x, e.y)) {
              hoverEntity = entity;
              hoverEntity.ignoreInLayout(true);
              hoverEntity.setSelected();
              break;
            }
          }
          if (oldEntity != null && oldEntity != hoverEntity) {
            oldEntity.ignoreInLayout(false);
            oldEntity.setUnSelected();
          }
        }

      }

    });
    mainComposite.addMouseListener(new MouseListener() {

      public void mouseDoubleClick(MouseEvent e) {
      }

      public void mouseDown(MouseEvent e) {
        selectedEntity = null;
        hoverEntity = null;
        for (Iterator iter = entities.iterator(); iter.hasNext() && selectedEntity == null;) {
          SimpleNode entity = (SimpleNode) iter.next();
          double x = entity.getX();
          double y = entity.getY();
          double w = entity.getWidth();
          double h = entity.getHeight();
          Rectangle rect = new Rectangle((int) x, (int) y, (int) w, (int) h);
          if (rect.contains(e.x, e.y)) {
            selectedEntity = entity;
          }
        }
        if (selectedEntity != null) {
          mouseDownPoint = new Point(e.x, e.y);
          selectedEntityPositionAtMouseDown = new Point((int) selectedEntity.getX(), (int) selectedEntity.getY());
          selectedEntity.ignoreInLayout(true);
          selectedEntity.setSelected();
        } else {
          mouseDownPoint = null;
          selectedEntityPositionAtMouseDown = null;
        }
      }

      public void mouseUp(MouseEvent e) {
        if (selectedEntity != null) {
          selectedEntity.ignoreInLayout(false);
          selectedEntity.setUnSelected();
          List relatedNodes = selectedEntity.getRelatedEntities();
          for (Iterator iter = relatedNodes.iterator(); iter.hasNext();) {
            SimpleNode element = (SimpleNode) iter.next();
            element.setUnSelected();
          }
          SimpleRelationship[] rels = selectedEntity.getRelationships();
          for (int i = 0; i < rels.length; i++) {
            rels[i].resetLineWidth();
          }
        }
        selectedEntity = null;
        mouseDownPoint = null;
        selectedEntityPositionAtMouseDown = null;
      }
    });

    // stops the algorithm when the window is closed
    mainComposite.addDisposeListener(new DisposeListener() {
      public void widgetDisposed(DisposeEvent e) {
        if (currentLayoutAlgorithm != null) {
          currentLayoutAlgorithm.stop();
        }
      }
    });

    mainComposite.addMouseMoveListener(new MouseMoveListener() {

      public void mouseMove(MouseEvent e) {
        if (selectedEntity != null && mouseDownPoint != null) {
          double dx = e.x - mouseDownPoint.x;
          double dy = e.y - mouseDownPoint.y;

          selectedEntity.setLocation(selectedEntityPositionAtMouseDown.x + dx, selectedEntityPositionAtMouseDown.y + dy);
          mainComposite.redraw();
        }
      }
    });
  }

  static int lastUpdateCall = 0;

  /**
   *
   * @param maxLevels Max number of levels wanted in tree 
   * @param maxChildren Max number of children for each node in the tree
   * @param random Whether or not to pick random number of levels (from 1 to maxLevels) and
   * random number of children (from 1 to maxChildren)
   */
  private void createTreeGraph(int maxLevels, int maxChildren, boolean random) {
    entities = new ArrayList();
    relationships = new ArrayList();

    // ccallendar - testing out having 2 roots
    SimpleNode root = createSimpleNode(getNextID());
    entities.add(root);
    SimpleNode root2 = createSimpleNode(getNextID());
    entities.add(root2);
    // end

    SimpleNode currentParent = createSimpleNode(getNextID());
    entities.add(currentParent);

    // ccallendar - adding relationships from the parent to the 2 roots
    SimpleRelationship rel = new SimpleRelationship(root, currentParent, false);
    root.addRelationship(rel);
    currentParent.addRelationship(rel);
    relationships.add(rel);
    rel = new SimpleRelationship(root2, currentParent, false);
    root2.addRelationship(rel);
    currentParent.addRelationship(rel);
    relationships.add(rel);
    // end

    int levels = random ? (int) (Math.random() * maxLevels + 1) : maxLevels;
    createTreeGraphRecursive(currentParent, maxChildren, levels, 1, random);
  }

  private void createTreeGraphRecursive(SimpleNode currentParentNode, int maxChildren, int maxLevel, int level, boolean random) {
    if (level > maxLevel) {
      return;
    }

    int numChildren = random ? (int) (Math.random() * maxChildren + 1) : maxChildren;
    for (int child = 0; child < numChildren; child++) {
      SimpleNode childNode = createSimpleNode(getNextID());
      entities.add(childNode);
      SimpleRelationship rel = new SimpleRelationship(currentParentNode, childNode, false);
      childNode.addRelationship(rel);
      currentParentNode.addRelationship(rel);
      relationships.add(rel);
      SimpleRelationship.setDefaultSize(2);
      createTreeGraphRecursive(childNode, maxChildren, maxLevel, level + 1, random);
    }
  }

  private int repeats = 0;

  /**
   * Gets the next name from the names list.
   * Once all the names have been used up the names are
   * repeated with a '1' after the name.
   * @return String name
   */
  private String getNextID() {
    if (idCount >= NAMES.length) {
      idCount = 0;
      repeats++;
    }
    String id = NAMES[(int) idCount];
    if (repeats > 0) {
      id += "_" + repeats;
    }
    idCount++;
    return id;
  }

  /** Places nodes randomly on the screen **/
  private void placeRandomly() {
    for (Iterator iter = entities.iterator(); iter.hasNext();) {
      SimpleNode simpleNode = (SimpleNode) iter.next();
      double x = Math.random() * INITIAL_PANEL_WIDTH - INITIAL_NODE_WIDTH;
      double y = Math.random() * INITIAL_PANEL_HEIGHT - INITIAL_NODE_HEIGHT;
      simpleNode.setLocationInLayout(x, y);
    }
  }

  /**
   * Creates a SimpleNode
   * @param name
   * @return SimpleNode
   */
  private SimpleNode createSimpleNode(String name) {
    SimpleNode simpleNode = new SimpleNode(name);
    int w = name.length() * 8; // an initial approximation of the width
    simpleNode.setSizeInLayout(Math.max(w, INITIAL_NODE_WIDTH), INITIAL_NODE_HEIGHT);
    return simpleNode;
  }

  private void updateGUI() {
    if (!mainComposite.isDisposed()) {
      mainComposite.redraw();
      //mainComposite.update();
    }
  }

  static Display display = null;

  public static void main(String[] args) {
    display = Display.getDefault();
    SimpleSWTExample simpleSWTExample = new SimpleSWTExample(display);
    Shell shell = simpleSWTExample.getShell();
    //shell.pack();
    shell.open();
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        display.sleep();
      }
    }
    display.dispose();
  }

  /**
   * Implements a paint listener to display nodes and edges 
   */
  private class GraphPaintListener implements PaintListener {

    long lastPaint;

    public void paintControl(PaintEvent e) {
      Date date = new Date();
      long currentTime = date.getTime();
      if (currentTime - lastPaint < 40) {
        return;
      } else {
        lastPaint = currentTime;
      }
      if (Display.getDefault() == null || e.width == 0 || e.height == 0) {
        return;
      }
      long startTime = date.getTime();

      // do a bit of our own double-buffering to stop flickering
      Image imageBuffer;

      try {
        imageBuffer = new Image(Display.getDefault(), e.width, e.height);
      } catch (SWTError noMoreHandles) {
        imageBuffer = null;
        noMoreHandles.printStackTrace();
        return;
      } catch (IllegalArgumentException tooBig) {
        imageBuffer = null;
        tooBig.printStackTrace();
        return;
      }

      GC gcBuffer = new GC(imageBuffer);

      // paint the relationships
      for (Iterator iter = relationships.iterator(); iter.hasNext();) {
        SimpleRelationship rel = (SimpleRelationship) iter.next();
        SimpleNode src = (SimpleNode) rel.getSourceInLayout();
        SimpleNode dest = (SimpleNode) rel.getDestinationInLayout();

        // highlight the adjacent nodes if one of the nodes is selected
        if (src.equals(selectedEntity)) {
          dest.setAdjacent();
          rel.setSelected();
        } else if (dest.equals(selectedEntity)) {
          src.setAdjacent();
          rel.setSelected();
        } else {
          rel.setUnSelected();
        }

        // Add bend points if required
        if ((rel).getBendPoints() != null && (rel).getBendPoints().length > 0) {
          src = drawBendPoints(rel, gcBuffer); // change source to last bendpoint
        }

        double srcX = src.getX() + src.getWidth() / 2.0;
        double srcY = src.getY() + src.getHeight() / 2.0;
        double destX = dest.getX() + dest.getWidth() / 2.0;
        double destY = dest.getY() + dest.getHeight() / 2.0;
        drawEdge(srcX, srcY, destX, destY, rel, gcBuffer);

      }

      // paint the nodes
      for (Iterator iter = entities.iterator(); iter.hasNext();) {
        SimpleNode entity = (SimpleNode) iter.next();

        String name = entity.toString();
        Point textSize = gcBuffer.stringExtent(name);
        int entityX = (int) entity.getX();
        int entityY = (int) entity.getY();
        //TODO: What about resize from the layout algorithm
        int entityWidth = Math.max((int) entity.getWidth(), textSize.x + 8);
        int entityHeight = Math.max((int) entity.getHeight(), textSize.y + 2);

        gcBuffer.setBackground((Color) entity.getColor());
        gcBuffer.fillRoundRectangle(entityX, entityY, entityWidth, entityHeight, 8, 8);

        // position the text in the middle of the node
        int x = (int) (entityX + (entityWidth / 2.0)) - (textSize.x / 2);
        gcBuffer.setForeground(BLACK);
        gcBuffer.drawString(name, x, entityY);
        gcBuffer.setForeground((Color) entity.getBorderColor());
        gcBuffer.setLineWidth(entity.getBorderWidth());
        gcBuffer.drawRoundRectangle(entityX, entityY, entityWidth, entityHeight, 8, 8);
      }

      e.gc.drawImage(imageBuffer, 0, 0);
      imageBuffer.dispose();
      gcBuffer.dispose();

      long time = date.getTime() - startTime;
      if (time > 200) {
      }
    }

    /**
     * Draw an edge
     * @param gcBuffer
     * @param srcX
     * @param srcY
     * @param destX
     * @param destY
     * @param rel
     */
    private void drawEdge(double srcX, double srcY, double destX, double destY, SimpleRelationship rel, GC gcBuffer) {
      gcBuffer.setForeground((Color) rel.getColor());
      gcBuffer.setLineWidth(rel.getLineWidth());
      gcBuffer.drawLine((int) srcX, (int) srcY, (int) destX, (int) destY);
    }

    /**
     * Draws a set of lines between bendpoints
     * TODO - This does not always draw outside the node.
     * @param relationship
     * @param bendNodes
     * @param bendEdges
     * @return the last bendpoint entity or null if there are no bendpoints
     */
    private SimpleNode drawBendPoints(SimpleRelationship rel, GC gcBuffer) {
      final String DUMMY_TITLE = "dummy";
      LayoutBendPoint[] bendPoints = (rel).getBendPoints();
      LayoutBendPoint bp;
      SimpleNode startEntity = (SimpleNode) rel.getSourceInLayout();
      SimpleNode destEntity = null;

      double srcX = startEntity.getX() + startEntity.getWidth() / 2.0;
      double srcY = startEntity.getY() + startEntity.getHeight() / 2.0;
      for (int i = 1; i < bendPoints.length - 1; i++) {
        bp = bendPoints[i];
        destEntity = new SimpleNode(DUMMY_TITLE, bp.getX(), bp.getY(), 0.01, 0.01);
        drawEdge(srcX, srcY, bp.getX(), bp.getY(), rel, gcBuffer);
        startEntity = destEntity;
        srcX = startEntity.getX();
        srcY = startEntity.getY();
      }
      return destEntity;
    }

  }

}
TOP

Related Classes of org.eclipse.zest.layouts.exampleUses.SimpleSWTExample$GraphPaintListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.