Package lupos.gui.operatorgraph

Source Code of lupos.gui.operatorgraph.OperatorGraph

/**
* Copyright (c) 2013, Institute of Information Systems (Sven Groppe and contributors of LUPOSDATE), University of Luebeck
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
*   - Redistributions of source code must retain the above copyright notice, this list of conditions and the following
*     disclaimer.
*   - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
*     following disclaimer in the documentation and/or other materials provided with the distribution.
*   - Neither the name of the University of Luebeck nor the names of its contributors may be used to endorse or promote
*     products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package lupos.gui.operatorgraph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;

import lupos.gui.debug.AbstractCommentPanel;
import lupos.gui.operatorgraph.GraphBox.GraphBoxCreator;
import lupos.gui.operatorgraph.GraphBox.StandardGraphBoxCreator;
import lupos.gui.operatorgraph.arrange.Arrange;
import lupos.gui.operatorgraph.arrange.GraphHelper;
import lupos.gui.operatorgraph.graphwrapper.GraphWrapper;
import lupos.gui.operatorgraph.guielements.ContainerArrange;
import lupos.misc.Tuple;
import xpref.IXPref;
import xpref.XPref;
import xpref.datatypes.BooleanDatatype;
import xpref.datatypes.FontDatatype;
import xpref.datatypes.IntegerDatatype;

/**
* This class constructs the QueryGraph recursively by going through the given
* start operators and there children. It arranges the operators so they don't
* overlap. At the end the QueryGraph is a JPanel with JLabels and other JPanels
* on it.
*
* @author schleife
*/
public class OperatorGraph extends JPanel implements IXPref {
  /**
   * The serial version uid.
   */
  private static final long serialVersionUID = 1L;

  /**
   * Holds the list of operators which are the root level.
   */
  protected LinkedList<GraphWrapper> rootList = new LinkedList<GraphWrapper>();

  /**
   * Associated list of all boxes in the QueryGraph. The association is
   * GraphWrapper to corresponding GraphBox.
   */
  protected LinkedHashMap<GraphWrapper, GraphBox> boxes = new LinkedHashMap<GraphWrapper, GraphBox>();

  protected Hashtable<GraphWrapper, LinkedList<GraphWrapper>> drawnLineAnnotations = new Hashtable<GraphWrapper, LinkedList<GraphWrapper>>();

  /**
   * Space between boxes.
   */
  public double SPACING_X = 60;

  /**
   * Space between rows.
   */
  public double SPACING_Y = 90;

  /**
   * Padding of the main window.
   */
  public double PADDING = 5;

  /**
   * Flag for line color usage.
   */
  private boolean useLineColors = false;

  /**
   * Current zoom factor.
   */
  private double zoomFactor = 1.0;

  /**
   * Font size of the elements of the OperatorGraph.
   */
  protected double FONTSIZE = 16;

  /**
   * Font of the elements of the OperatorGraph.
   */
  private Font FONT = new Font("serif", Font.PLAIN, (int) this.FONTSIZE);

  protected LinkedHashSet<OperatorGraph> childComponents = new LinkedHashSet<OperatorGraph>();

  private final LinkedList<AbstractCommentPanel> comments = new LinkedList<AbstractCommentPanel>();

  private final LinkedHashMap<GraphWrapper, JPopupMenu> contextMenus = new LinkedHashMap<GraphWrapper, JPopupMenu>();

  /**
   * used to lock accesses to the comments list!
   */
  private final ReentrantLock commentsLock = new ReentrantLock();

  public GraphBoxCreator graphBoxCreator = new StandardGraphBoxCreator();

  protected OperatorGraph() {
    try {
      this.setLayout(null); // we don't want any LayoutManager
      this.setBackground(Color.WHITE);

      XPref.getInstance().registerComponent(this);
      this.preferencesChanged();
    } catch (final Exception e) {
      System.err.println(e);
      e.printStackTrace();
    }
  }

  /**
   * Sets a new root list of GraphWrapper objects to be displayed...
   * (Root elements are top elements of graphs, if they are in a cycle, one of them must be the root element.)
   * @param newRootList the new root list
   */
    public void setRootList(final LinkedList<GraphWrapper> newRootList) {
        this.rootList = newRootList;
    }

  /**
   * This is one way to get a OperatorGraph. This method should be used if you
   * have one root element.
   *
   * @param root
   *            the root element
   *
   * @return the JPanel with the QueryGraph on it
   */
  public JPanel createGraph(final GraphWrapper root, final Arrange arrange) {
    // create rootList for the one root operator...
    final LinkedList<GraphWrapper> rootList = new LinkedList<GraphWrapper>();
    rootList.add(root);

    return this.createGraph(rootList, arrange); // create the QueryGraph and return it
  }

  /**
   * This is one way to get a OperatorGraph. This method should be used if you
   * have a List of root elements.
   *
   * @param rootList
   *            the List of root elements
   *
   * @return the JPanel with the QueryGraph on it
   */
  public JPanel createGraph(final LinkedList<GraphWrapper> newRootList,
      final Arrange arrange) {
    return this.createGraph(newRootList, arrange, -1.0, null);
  }


  /**
   * This is one way to get a OperatorGraph. This method should be used if you
   * have a List of root elements.
   *
   * @param rootList
   *            the List of root elements
   *
   * @return the JPanel with the QueryGraph on it
   */
  public JPanel createGraph(final LinkedList<GraphWrapper> newRootList,
      final Arrange arrange, final double factor, final Map<GraphWrapper, GraphBox> oldBoxes) {

    this.rootList = newRootList;

    this.removeAll();

    if(factor<=0){

      this.boxes.clear();

      this.arrange(arrange);

    } else {

      final LinkedHashMap<GraphWrapper, GraphBox> newBoxes = new LinkedHashMap<GraphWrapper, GraphBox>();

      for(final GraphBox box: oldBoxes.values()){
        final GraphBox newBox = this.graphBoxCreator.createGraphBox(this, box.op);
        newBoxes.put(box.op, newBox);
        newBox.x = (int) (box.x*factor);
        newBox.y = (int) (box.y*factor);
      }

      this.boxes = newBoxes;

      GraphHelper.fitToWindow(this);

      for (final GraphBox box : this.boxes.values()) {
        box.arrangeWithoutUpdatingParentsSize();
      }

      this.updateSize();

      this.repaint(); // repaint the panel to trigger G2D redraw
    }

    this.setPreferredSize(new Dimension(this.getPreferredSize().width + 5, this.getPreferredSize().height + 5));
    return this;
  }

  public JPanel rotate(final int degree, final LinkedList<GraphWrapper> newRootList, final Map<GraphWrapper, GraphBox> oldBoxes){
    if(degree==0){
      return this;
    }
    final double radians = (degree/360.0)*2*Math.PI;
    final double sin = Math.sin(radians);
    final double cos = Math.cos(radians);

    this.rootList = newRootList;

    this.removeAll();

    final LinkedHashMap<GraphWrapper, GraphBox> newBoxes = new LinkedHashMap<GraphWrapper, GraphBox>();

    for(final GraphBox box: oldBoxes.values()){
      final GraphBox newBox = this.graphBoxCreator.createGraphBox(this, box.op);
      newBoxes.put(box.op, newBox);
      final int x = box.x;
      final int y = box.y;
      newBox.x = (int) (x*cos+y*sin);
      newBox.y = (int) (-x*sin+y*cos);
    }

    this.boxes = newBoxes;

    GraphHelper.fitToWindow(this);

    for (final GraphBox box : this.boxes.values()) {
      box.arrangeWithoutUpdatingParentsSize();
    }

    this.updateSize();

    this.repaint(); // repaint the panel to trigger G2D redraw

    this.setPreferredSize(new Dimension(this.getPreferredSize().width + 5, this.getPreferredSize().height + 5));

    return this;
  }

  protected void createInternalNewGraph(final Arrange arrange) {
    this.createGraph(new LinkedList<GraphWrapper>(), arrange);
    // create the QueryGraph and return it
  }

  public int getMax(final boolean X) {
    int max = 0;
    for (final Map.Entry<GraphWrapper, GraphBox> entry : this.boxes
        .entrySet()) {
      final GraphBox graphBox = entry.getValue();
      final int compare = X ? graphBox.getX() + graphBox.width : graphBox
          .getY() + graphBox.height;
      if (compare > max) {
        max = compare;
      }
    }
    return max;
  }

  public void addNewBoxes(final HashSet<GraphWrapper> visited,
      final GraphWrapper op) {
    if (visited.contains(op)) { // if current operator was visited before...
      return; // abort
    }
    visited.add(op);

    if (!this.boxes.containsKey(op)) {
      this.boxes.put(op, this.graphBoxCreator.createGraphBox(this, op));
    }

    // walk trough the children of the current operator and add them
    // recursively...
    for (final GraphWrapperIDTuple child : op.getSucceedingElements()) {
      this.addNewBoxes(visited, child.getOperator());
    }
  }

  public void addNewBoxes() {
    final HashSet<GraphWrapper> visited = new HashSet<GraphWrapper>();
    for (final GraphWrapper op : this.rootList) {
      this.addNewBoxes(visited, op);
    }
  }

  public synchronized void arrange(final Arrange arrange) {

    this.addNewBoxes();

    for (final GraphBox box : this.boxes.values()) {
      if (box.getElement() instanceof ContainerArrange) {
        ((ContainerArrange) box.getElement()).arrange(arrange);
      }
    }

    arrange.arrange(this);

    GraphHelper.fitToWindow(this);

    for (final GraphBox box : this.boxes.values()) {
      box.arrangeWithoutUpdatingParentsSize();
    }

    this.updateSize();

    this.repaint(); // repaint the panel to trigger G2D redraw
  }


  public String serializeGraph() {
    final StringBuffer ret = new StringBuffer();

    for (int i = 0; i < this.rootList.size(); ++i) {
      if (i > 1) {
        ret.append("\n");
      }

      ret.append(this.rootList.get(i).serializeObjectAndTree());
    }

    return ret.toString();
  }



  public void clearAll() {
    this.removeAll();
    this.rootList.clear();
    this.boxes.clear();
    this.drawnLineAnnotations.clear();
    GraphBox.resetLineColorIndex();

    this.createInternalNewGraph(Arrange.values()[0]);
  }

  public boolean hasElements() {
    return !this.boxes.isEmpty();
  }

  /**
   * This returns the boxes.
   *
   * @return the HashMap GraphWrapper to GraphBox for all boxes
   */
  public HashMap<GraphWrapper, GraphBox> getBoxes() {
    return this.boxes;
  }

  public void removeFromRootList(final GraphWrapper gw) {
    this.rootList.remove(gw);
  }

  public void addToRootList(final GraphWrapper gw) {
    if(!this.rootList.contains(gw)){
      this.rootList.add(gw);
    }
  }

  /**
   * This overrides the paintComponent() method from JComponent to add redraw
   * features for the GraphBox elements in the GraphRows that need the
   * Graphics2D component.
   */
  @Override
  protected synchronized void paintComponent(final Graphics g) {
    super.paintComponent(g);

    final Graphics2D g2d = (Graphics2D) g;

    this.drawnLineAnnotations.clear();

    // draw the Graphics2D part of the boxes...
    for (final GraphBox box : this.boxes.values()) {
      box.draw(g2d);
    }

    // set context menu to panel again, if it is not set...
    for (final GraphWrapper graphWrapper : this.contextMenus.keySet()) {
      final AbstractSuperGuiComponent asgc = this.boxes.get(graphWrapper)
      .getElement();

      if (!asgc.hasContextMenu()) {
        asgc.setContextMenu(this.contextMenus.get(graphWrapper));
      }
    }

    // add comment panels again...
    final HashSet<Component> components = new HashSet<Component>();
    for (final Component component : this.getComponents()) {
      components.add(component);
    }
    for (final JPanel commentPanel : this.comments) {
      if (!components.contains(commentPanel)) {
        this.add(commentPanel, 0);
      }
    }
  }

  /**
   * lock the paint call, such that no comment panels are added or removed
   * during painting the child components...
   */
  @Override
  public void paint(final Graphics g) {
    this.commentsLock.lock();
    try {
      super.paint(g);
    } finally {
      this.commentsLock.unlock();
    }
  }

  public boolean annotationWasProcessed(final GraphWrapper from,
      final GraphWrapper to) {
    if (!this.drawnLineAnnotations.containsKey(from)) {
      return false;
    }

    if (!this.drawnLineAnnotations.get(from).contains(to)) {
      return false;
    }

    return true;
  }

  public void addProcessedAnnotation(final GraphWrapper from,
      final GraphWrapper to) {
    if (!this.drawnLineAnnotations.containsKey(from)) {
      this.drawnLineAnnotations.put(from, new LinkedList<GraphWrapper>());
    }

    if (!this.drawnLineAnnotations.get(from).contains(to)) {
      this.drawnLineAnnotations.get(from).add(to);
    }
  }

  public int getMaxY() {
    int y = 0;
    for (final Map.Entry<GraphWrapper, GraphBox> entry : this.boxes
        .entrySet()) {
      y = Math.max(y, entry.getValue().getY() + entry.getValue().height);
    }
    return y;
  }

  /**
   * Updates the size of the Canvas and sets it to the minimum needed size.
   */
  public void updateSize() {
    int width = 0;
    int height = 0;

    for (final GraphBox box : this.boxes.values()) {
      height = Math.max(height, box.getY() + box.height
          + (int) (2 * this.PADDING));
      width = Math.max(width, box.getX() + box.width
          + (int) (2 * this.PADDING));

      for (final GraphWrapper gw : box.getLineAnnotations().keySet()) {
        width = Math.max(width, box.getLineAnnotations().get(gw)
            .getPreferredSize().width
            + (int) (2 * this.PADDING));
      }
    }

    this.commentsLock.lock();
    try {
      for (final AbstractCommentPanel acp : this.comments) {
        final Point location = acp.getLocation();
        final Dimension dimension = acp.getPreferredSize();

        height = Math.max(height, location.y + dimension.height + 2
            * (int) this.PADDING);
        width = Math.max(width, location.x + dimension.width + 2
            * (int) this.PADDING);
      }
    } finally {
      this.commentsLock.unlock();
    }

    // if (width < this.getMinimumSize().width) {
    // width = this.getMinimumSize().width;
    // }
    //
    // if (height < this.getMinimumSize().height) {
    // height = this.getMinimumSize().height;
    // }

    final Dimension d = new Dimension(width, height);

    this.setSize(d);
    this.setPreferredSize(d);

    this.revalidate();
  }

  /**
   * Method to update the zoom factor of the OperatorGraph.
   *
   * @param zFactor
   *            the new zoom factor
   *
   * @return true, if the zoom factor was different then the previous, false
   *         otherwise
   */
  public boolean updateZoomFactor(final double zFactor) {
    // disable zoom to 0%...
    if(zFactor == 0.0) {
      return false;
    }

    // update zoom factor in child operator graphs...
    for(final OperatorGraph opGraph : this.childComponents) {
      opGraph.updateZoomFactor(zFactor);
    }

    if(zFactor != this.zoomFactor) { // if zoom factor changed...
      if(this.zoomFactor != 1.0) { // if old zoom factor is not 1...
        // reset variables to zoom factor 1...
        this.setZoomFactors(1 / this.zoomFactor);
      }

      if(zFactor != 1.0) { // if zoom factor is not 1...
        this.setZoomFactors(zFactor); // set variables to zoom factor
      }

      this.zoomFactor = zFactor; // save zoom factor

      return true;
    }

    return false;
  }

  /**
   * This internal method resets some displacement variables according to the
   * given zoomFactor.
   *
   * @param zoomFactor
   *            the zoom factor
   */
  protected void setZoomFactors(final double zoomFactor) {
    this.SPACING_X = zoomFactor * this.SPACING_X;
    this.SPACING_Y = zoomFactor * this.SPACING_Y;
    this.PADDING = zoomFactor * this.PADDING;

    this.FONTSIZE *= zoomFactor;
    this.FONT = new Font(this.FONT.getFontName(), this.FONT.getStyle(), (int) Math.ceil(this.FONTSIZE));
  }

  public double getSPACING_X() {
    return this.SPACING_X;
  }

  public double getSPACING_Y() {
    return this.SPACING_Y;
  }

  public Font getFONT() {
    return this.FONT;
  }

  public double getFONTSize() {
    return this.FONTSIZE;
  }

  public double getZoomFactor() {
    return this.zoomFactor;
  }

  /**
   * Returns the root list of GraphWrappers of the OperatorGraph.
   *
   * @param clone
   *            true if the list should be cloned (needed for zoom update).
   *
   * @return list of root GraphWrapper elements
   */
  @SuppressWarnings("unchecked")
  public LinkedList<GraphWrapper> getRootList(final boolean clone) {
    if(clone) {
      return (LinkedList<GraphWrapper>) this.rootList.clone();
    }
    else {
      return this.rootList;
    }
  }

  public void addChildComponent(final OperatorGraph child) {
    this.childComponents.add(child);

    child.zoomFactor = this.zoomFactor;
    child.setZoomFactors(this.zoomFactor);
  }

  public void setLineColorStatus(final boolean newStatus) {
    this.useLineColors = newStatus;

    for(final OperatorGraph opGraph : this.childComponents) {
      opGraph.setLineColorStatus(newStatus);
    }
  }

  public boolean useLineColors() {
    return this.useLineColors;
  }

  @Override
  public void preferencesChanged() {
    try {
      this.SPACING_X = IntegerDatatype.getFirstValue("viewer_spacing_X") * this.zoomFactor;
      this.SPACING_Y = IntegerDatatype.getFirstValue("viewer_spacing_Y") * this.zoomFactor;
      this.useLineColors = BooleanDatatype.getValues("viewer_useColoredArrows").get(0).booleanValue();

      // --- resetting zoom - begin ---
      final double oldZoomFactor = this.zoomFactor;

      this.updateZoomFactor(1.0);
      // --- resetting zoom - end ---

      // --- updating font - begin ---
      this.FONT = FontDatatype.getValues("viewer_font").get(0);
      this.FONTSIZE = this.FONT.getSize();
      // --- updating font - end ---

      // --- updating zoom - begin ---
      if (oldZoomFactor != 1.0) {
        this.updateZoomFactor(oldZoomFactor);
      }

      this.removeAll();
      this.boxes.clear();
      this.drawnLineAnnotations.clear();
      GraphBox.resetLineColorIndex();
      GraphWrapper.clearColorCache();

      // --- updating zoom - end ---
    } catch (final Exception e) {
      System.err.println(e);
      e.printStackTrace();
    }
  }

  /**
   * Internal method to create the graph from the given start node and wrap it
   * in a JScrollPane.
   */
  public void updateMainPanel(final JPanel mainPanel) {
    final JComponent containingMainPanel = (JComponent) mainPanel.getParent().getParent().getParent();

    containingMainPanel.removeAll();

    // create scrollPane for main panel set speed of scrollPane...
    final JScrollPane operatorGraphScrollPane = new JScrollPane(mainPanel);
    operatorGraphScrollPane.getVerticalScrollBar().setUnitIncrement(10);
    operatorGraphScrollPane.getHorizontalScrollBar().setUnitIncrement(10);

    operatorGraphScrollPane.getViewport().setBackground(Color.WHITE);

    containingMainPanel.add(operatorGraphScrollPane, BorderLayout.CENTER);
    containingMainPanel.revalidate();

    // update comments...
    this.commentsLock.lock();

    try {
      for(final AbstractCommentPanel acp : this.comments) {
        acp.setFont(this.FONT);
        acp.determinePosition();
      }
    }
    finally {
      this.commentsLock.unlock();
    }

    this.updateSize();
  }

  public Tuple<Point, Dimension> getPositionAndDimension(final GraphWrapper gw) {
    if (this.boxes.containsKey(gw)) {
      final AbstractSuperGuiComponent panel = this.boxes.get(gw)
      .getElement();

      if (panel != null) {
        return panel.getPositionAndDimension();
      } else {
        return new Tuple<Point, Dimension>(new Point(0, 0),
            new Dimension(0, 0));
      }
    } else {
      return new Tuple<Point, Dimension>(new Point(0, 0), new Dimension(
          0, 0));
    }
  }

  /**
   * Method to add a comment to the operator graph.
   *
   * @param commentPanel
   *            the AbstractCommentPanel, that defines the comment
   */
  public void addComment(final AbstractCommentPanel commentPanel) {
    this.commentsLock.lock();

    try {
      this.comments.add(commentPanel);
    } finally {
      this.commentsLock.unlock();
    }

    commentPanel.setFont(this.FONT);
    commentPanel.setVisible(true);

    this.updateSize();
    this.repaint();
  }

  /**
   * Method to remove the given comment panel from the operator graph.
   *
   * @param commentPanel
   *            the comment panel to be removed.
   */
  public void removeComment(final AbstractCommentPanel commentPanel) {
    commentPanel.setVisible(false);

    this.commentsLock.lock();

    try {
      this.comments.remove(commentPanel);
    } finally {
      this.commentsLock.unlock();
    }

    this.repaint();
  }

  /**
   * This method sets the given context menu to the operator wrapped in the
   * given GraphWrapper.
   *
   * @param graphWrapper
   *            the element to set the context menu of
   * @param contextMenu
   *            the context menu to add
   */
  public void setContextMenuOfOperator(final GraphWrapper graphWrapper,
      final JPopupMenu contextMenu) {
    if (this.boxes.containsKey(graphWrapper)) {
      this.boxes.get(graphWrapper).getElement().setContextMenu(
          contextMenu);

      this.contextMenus.put(graphWrapper, contextMenu);
    }
  }

  /**
   * This method unsets the context menu of the operator wrapped in the given
   * GraphWrapper.
   *
   * @param graphWrapperthe
   *            element to unset the context menu of
   */
  public void unsetContextMenuOfOperator(final GraphWrapper graphWrapper) {
    if (this.boxes.containsKey(graphWrapper)) {
      this.boxes.get(graphWrapper).getElement().unsetContextMenu();

      this.contextMenus.remove(graphWrapper);
    }
  }

  /**
   * Internal method to save the graph to the given filename.
   *
   * @param filename
   *            filename to save the file to
   * @throws IOException
   */
  public void saveGraph(String filename) throws IOException {
    // add file extension, if necessary...
    if (!(filename.endsWith(".png") || filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".gif"))) {
      filename += ".png";
    }

    final String format = filename.endsWith(".jpeg")?"jpeg":filename.substring(filename.length()-3);

    final OutputStream out = new FileOutputStream(new File(filename));

    this.saveGraph(format, out);

    out.close();
  }

  /**
   * Internal method to save the graph to an outputstream.
   *
   * @param format
   *            the format of the picture (png, jpg or gif)
   * @param out
   *            the outputstream to save the file to
   */
  public void saveGraph(String format, final OutputStream out) {
    // add file extension, if necessary...
    if (!(format.compareTo("png")==0 || format.compareTo("jpeg")==0 || format.compareTo("jpg")==0 || format.compareTo("gif")==0)) {
      format = "png";
    }

    try {
      // create image of graph to save it...
      final BufferedImage img = new BufferedImage(this.getPreferredSize().width, this.getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
      this.printComponents(img.createGraphics());
      this.paint(img.createGraphics()); // paint main panel with graph image

      ImageIO.write(img, format, out);
    } catch (final Exception e) {
      e.printStackTrace();
    }
  }

  public Hashtable<GraphWrapper, LinkedList<GraphWrapper>> getDrawnLineAnnotations() {
    return this.drawnLineAnnotations;
  }

  public boolean isEmpty() {
    return this.boxes.size() == 0;
  }
}
TOP

Related Classes of lupos.gui.operatorgraph.OperatorGraph

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.