summaryrefslogtreecommitdiff
path: root/modules/graph/src/java
diff options
context:
space:
mode:
authorShashank2017-05-29 12:40:26 +0530
committerShashank2017-05-29 12:40:26 +0530
commit0345245e860375a32c9a437c4a9d9cae807134e9 (patch)
treead51ecbfa7bcd3cc5f09834f1bb8c08feaa526a4 /modules/graph/src/java
downloadscilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.gz
scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.bz2
scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.zip
CMSCOPE changed
Diffstat (limited to 'modules/graph/src/java')
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/ScilabCanvas.java343
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/ScilabComponent.java240
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/ScilabGraph.java388
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/ScilabGraphUniqueObject.java85
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/CopyAction.java72
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/CutAction.java72
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/DeleteAction.java85
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/GroupAction.java70
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/InvertSelectionAction.java73
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/PasteAction.java75
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/RedoAction.java153
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/SelectAllAction.java65
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/UnGroupAction.java71
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/UndoAction.java153
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/ZoomInAction.java158
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/ZoomOutAction.java162
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/ActionConstraint.java86
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/DefaultAction.java271
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/EdgeSelectionDependantAction.java97
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/GraphActionManager.java220
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/MinimalNumberOfCellsConstraint.java68
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/MultiSelectionDependantAction.java38
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/OneBlockDependantAction.java31
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/OneSelectionDependantAction.java38
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/SelectedNumberOfCellsConstraint.java64
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/SpecificCellSelectedConstraint.java72
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/actions/base/VertexSelectionDependantAction.java97
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/event/ArrowKeyListener.java212
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabBooleanCodec.java178
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabDoubleCodec.java202
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabGraphCodec.java120
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabIntegerCodec.java332
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabListCodec.java178
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabObjectCodec.java237
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/io/ScilabStringCodec.java178
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/shape/LatexTextShape.java115
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/shape/MathMLTextShape.java89
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/shape/SvgShape.java85
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/Font.java181
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/MathMLRenderUtils.java81
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/ScilabExported.java34
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphConstants.java78
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphMessages.java40
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphRenderer.java131
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphUtils.java230
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/utils/StyleMap.java85
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/view/ScilabGraphView.java169
-rwxr-xr-xmodules/graph/src/java/org/scilab/modules/graph/view/SupportedLabelType.java155
48 files changed, 6457 insertions, 0 deletions
diff --git a/modules/graph/src/java/org/scilab/modules/graph/ScilabCanvas.java b/modules/graph/src/java/org/scilab/modules/graph/ScilabCanvas.java
new file mode 100755
index 000000000..72979f46b
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/ScilabCanvas.java
@@ -0,0 +1,343 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.Dimension2D;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.apache.batik.gvt.GraphicsNode;
+import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.modules.graph.shape.LatexTextShape;
+import org.scilab.modules.graph.shape.MathMLTextShape;
+import org.scilab.modules.graph.shape.SvgShape;
+import org.scilab.modules.graph.utils.MathMLRenderUtils;
+import org.scilab.modules.graph.utils.ScilabGraphConstants;
+import org.scilab.modules.graph.utils.ScilabGraphUtils;
+import org.scilab.modules.graph.view.SupportedLabelType;
+import org.xml.sax.SAXException;
+
+import com.mxgraph.canvas.mxGraphics2DCanvas;
+import com.mxgraph.shape.mxITextShape;
+import com.mxgraph.swing.view.mxInteractiveCanvas;
+import com.mxgraph.util.mxConstants;
+import com.mxgraph.util.mxRectangle;
+import com.mxgraph.util.mxUtils;
+import com.mxgraph.view.mxCellState;
+
+/**
+ * Painter for each vertex and edge
+ *
+ * This is tightly coupled to jgraphx internals.
+ */
+public class ScilabCanvas extends mxInteractiveCanvas {
+
+ /** The rotation step of the clockwise and anticlockwise rotation */
+ public static final int ROTATION_STEP = 90;
+ /** The max valid rotation value (always 360 degres) */
+ public static final int MAX_ROTATION = 360;
+
+ /** The border ratio between the background image and the icon image */
+ private static final double BORDER_RATIO = 0.9;
+
+ static {
+ putShape(mxConstants.SHAPE_LABEL, new SvgShape());
+ putTextShape(SupportedLabelType.Latex.name(), new LatexTextShape());
+ putTextShape(SupportedLabelType.MathML.name(), new MathMLTextShape());
+ }
+
+ private URL urlBasePath;
+
+ /** Default constructor */
+ public ScilabCanvas() {
+ }
+
+ /**
+ * Get the text shape associated with the text
+ *
+ * @param text
+ * the associated text
+ * @param style
+ * the current style
+ * @param html
+ * true, if the text is html formatted, false otherwise.
+ * @return the associated text shape
+ */
+ public mxITextShape getTextShape(String text, Map<String, Object> style, boolean html) {
+ final mxITextShape ret;
+
+ final SupportedLabelType type;
+ if (html) {
+ type = SupportedLabelType.getFromHTML(text);
+ } else {
+ type = SupportedLabelType.getFromText(text);
+ }
+
+ switch (type) {
+ case Latex:
+ try {
+ // parse the text and cache it if valid. Will throw an exception
+ // if the text is not valid.
+ new TeXFormula(SupportedLabelType.Latex.escape(text));
+
+ ret = textShapes.get(type.name());
+ } catch (RuntimeException e) {
+ return super.getTextShape(style, html);
+ }
+ break;
+
+ case MathML:
+ try {
+ // parse the text and cache it if valid. Will throw an exception
+ // if the text is not valid.
+ MathMLRenderUtils.getMathMLComponent(text);
+
+ ret = textShapes.get(type.name());
+ } catch (SAXException e) {
+ return super.getTextShape(style, html);
+ }
+ break;
+
+ default:
+ ret = super.getTextShape(style, html);
+ break;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Scale the graphic context depending on the "flip and "mirror" properties
+ *
+ * @param temporaryGraphics
+ * the current graphic surface
+ * @param style
+ * Style contents
+ * @param bounds
+ * the current bounds
+ */
+ private void applyFlipAndMirror(Graphics2D temporaryGraphics, Map<String, Object> style, mxRectangle bounds) {
+ if (bounds == null) {
+ return;
+ }
+
+ final boolean flip = mxUtils.isTrue(style, ScilabGraphConstants.STYLE_FLIP, false);
+ final boolean mirror = mxUtils.isTrue(style, ScilabGraphConstants.STYLE_MIRROR, false);
+
+ final double x = bounds.getCenterX();
+ final double y = bounds.getCenterY();
+
+ temporaryGraphics.translate(x, y);
+
+ // scale, 1st flip, 2nd mirror
+ // The scale operation concatenate AffineTransforms.
+
+ if (flip) {
+ temporaryGraphics.scale(1.0, -1.0);
+ }
+
+ if (mirror) {
+ temporaryGraphics.scale(-1.0, 1.0);
+ }
+
+ temporaryGraphics.translate(-x, -y);
+ }
+
+ /**
+ * Allocate a new graphic surface and set some properties on it.
+ *
+ * This method handle the flip and the mirror properties.
+ *
+ * @param style
+ * the current style
+ * @param opacity
+ * the opacity
+ * @param bounds
+ * the bounds
+ * @return a graphic surface
+ * @see com.mxgraph.canvas.mxGraphics2DCanvas#createTemporaryGraphics(java.util.Map,
+ * float, com.mxgraph.util.mxRectangle)
+ */
+ @Override
+ public Graphics2D createTemporaryGraphics(Map<String, Object> style, float opacity, mxRectangle bounds) {
+ Graphics2D temporaryGraphics = super.createTemporaryGraphics(style, opacity, bounds);
+
+ applyFlipAndMirror(temporaryGraphics, style, bounds);
+
+ return temporaryGraphics;
+ }
+
+ /**
+ * Draw the text label on the cell state.
+ *
+ * This method is extracted from {@link mxGraphics2DCanvas} to add a text
+ * argument to {@link #getTextShape(Map, boolean)}.
+ *
+ * @param text
+ * the current text
+ * @param state
+ * the cell state
+ * @param html
+ * true, if the text may be HTML, false otherwise.
+ * @return the associated shape
+ * @see com.mxgraph.canvas.mxGraphics2DCanvas#drawLabel(java.lang.String,
+ * com.mxgraph.view.mxCellState, boolean)
+ */
+ @Override
+ public Object drawLabel(String text, mxCellState state, boolean html) {
+ Map<String, Object> style = state.getStyle();
+ mxITextShape shape = getTextShape(text, style, html);
+
+ if (g != null && shape != null && drawLabels && text != null && text.length() > 0) {
+ // Creates a temporary graphics instance for drawing this shape
+ float opacity = mxUtils.getFloat(style, mxConstants.STYLE_TEXT_OPACITY, 100);
+ Graphics2D previousGraphics = g;
+ g = createTemporaryGraphics(style, opacity, null);
+
+ // Draws the label background and border
+ Color bg = mxUtils.getColor(style, mxConstants.STYLE_LABEL_BACKGROUNDCOLOR);
+ Color border = mxUtils.getColor(style, mxConstants.STYLE_LABEL_BORDERCOLOR);
+ paintRectangle(state.getLabelBounds().getRectangle(), bg, border);
+
+ // Paints the label and restores the graphics object
+ shape.paintShape(this, text, state, style);
+ g.dispose();
+ g = previousGraphics;
+ }
+
+ return shape;
+ }
+
+ /**
+ * Paint the foreground image.
+ *
+ * This method paint an iso-scaled and centered image.
+ *
+ * @param w
+ * the width
+ * @param h
+ * the height
+ * @param image
+ * the current image
+ */
+ public void paintSvgForegroundImage(int w, int h, String image) {
+ /*
+ * Fetch SVG file representation
+ */
+ URL url;
+ try {
+ url = new URL(image);
+ } catch (MalformedURLException e) {
+ Logger.getLogger(ScilabCanvas.class.getName()).severe(e.toString());
+ return;
+ }
+ GraphicsNode icon = ScilabGraphUtils.getSVGComponent(url);
+
+ if (icon == null || icon.getBounds() == null) {
+ return;
+ }
+
+ /*
+ * Perform calculations
+ */
+
+ // Iso scale to the bounds - border size
+ Dimension2D bounds = ScilabGraphUtils.getSVGDocumentSizes(url);
+
+ // Calculating icon bordered bounds
+ final double ih = bounds.getHeight();
+ final double iw = bounds.getWidth();
+
+ // Calculate per axis scaling factor
+ final double shFactor = h / ih;
+ final double swFactor = w / iw;
+
+ // Calculate the default ratio (iso scaling)
+ double ratio;
+ if (shFactor > swFactor) {
+ ratio = swFactor;
+ } else {
+ ratio = shFactor;
+ }
+
+ // Adding borders
+ ratio *= BORDER_RATIO;
+
+ // Calculate scaled height and width
+ final double sh = ratio * ih;
+ final double sw = ratio * iw;
+
+ // Center the image on the block
+ double tx = (w - sw) / 2;
+ double ty = (h - sh) / 2;
+
+ /*
+ * Everything has been calculated, render now.
+ */
+
+ // Translate from base point to centered base point
+ g.translate(tx, ty);
+
+ // scale to the ratio
+ g.scale(ratio, ratio);
+
+ // Paint
+ icon.paint(g);
+ }
+
+ /**
+ * Set the image path and store the path as a URL.
+ *
+ * @param imageBasePath
+ * the new path
+ * @see com.mxgraph.canvas.mxBasicCanvas#setImageBasePath(java.lang.String)
+ */
+ @Override
+ public void setImageBasePath(String imageBasePath) {
+ super.setImageBasePath(imageBasePath);
+
+ try {
+ this.urlBasePath = new URL(imageBasePath);
+ } catch (MalformedURLException e) {
+ Logger.getLogger(ScilabCanvas.class.getName()).severe(e.toString());
+ }
+ }
+
+ /**
+ * Gets the image path from the given style. If the path is relative (does
+ * not start with a slash) then it is appended to the imageBasePath.
+ *
+ * @param style
+ * the current style
+ * @return the image path
+ */
+ @Override
+ public String getImageForStyle(Map<String, Object> style) {
+ String filename = mxUtils.getString(style, mxConstants.STYLE_IMAGE);
+
+ if (filename == null) {
+ return null;
+ }
+
+ try {
+ return new URL(this.urlBasePath, filename).toExternalForm();
+ } catch (MalformedURLException e) {
+ }
+
+ return null;
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/ScilabComponent.java b/modules/graph/src/java/org/scilab/modules/graph/ScilabComponent.java
new file mode 100755
index 000000000..b8dc823b8
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/ScilabComponent.java
@@ -0,0 +1,240 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GraphicsEnvironment;
+import java.awt.event.MouseEvent;
+
+import com.mxgraph.model.mxICell;
+import com.mxgraph.model.mxIGraphModel;
+import com.mxgraph.swing.mxGraphComponent;
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.util.mxEventSource;
+import com.mxgraph.util.mxRectangle;
+import com.mxgraph.view.mxCellState;
+import com.mxgraph.view.mxGraphView;
+
+/**
+ * Implement the default component for the {@link ScilabGraph}.
+ */
+@SuppressWarnings(value = { "serial" })
+public class ScilabComponent extends mxGraphComponent {
+ /**
+ * Color use to mask the graph when the graph is locked
+ */
+ private static final Color MASK_COLOR = new Color(240, 240, 240, 100);
+
+ private static final double SCALE_MULTIPLIER = 1.1;
+
+ /**
+ * Construct the component with the associated graph
+ *
+ * @param graph
+ * The associated graph
+ */
+ public ScilabComponent(ScilabGraph graph) {
+ super(graph);
+ }
+
+ /**
+ * @return the associated graph control
+ * @see com.mxgraph.swing.mxGraphComponent#createGraphControl()
+ */
+ @Override
+ protected mxGraphControl createGraphControl() {
+ return new ScilabGraphControl();
+ }
+
+ /**
+ * Create the associated canvas
+ *
+ * @return the canvas
+ */
+ @Override
+ public ScilabCanvas createCanvas() {
+ return new ScilabCanvas();
+ }
+
+ /**
+ * Zoom the whole graph and center the view on it.
+ *
+ * @param cells
+ * the cells to center on
+ */
+ public void zoomAndCenterToCells(final Object[] cells) {
+ final mxRectangle preference = zoomBounds(cells);
+ final Dimension actual = getViewport().getSize();
+
+ final double newScale;
+ final double heightScale = actual.getHeight() / preference.getHeight();
+ final double widthScale = actual.getWidth() / preference.getWidth();
+
+ if (heightScale > 1.0) {
+ if (widthScale > 1.0) {
+ // We need to zoom in (the max applicable zoom is the lowest)
+ newScale = Math.min(heightScale, widthScale);
+ } else {
+ // we need to zoom out (only widthScale is < 1.0)
+ newScale = widthScale;
+ }
+ } else {
+ if (widthScale > 1.0) {
+ // we need to zoom out (only heightScale is < 1.0)
+ newScale = heightScale;
+ } else {
+ // We need to zoom out (the max applicable zoom is the lowest)
+ newScale = Math.min(heightScale, widthScale);
+ }
+ }
+
+ // do not apply small zoom values
+ if (Math.abs(1.0 - newScale) < 0.2) {
+ getGraphControl().scrollRectToVisible(zoomBounds(cells).getRectangle(), true);
+ return;
+ }
+
+ zoom(newScale / SCALE_MULTIPLIER);
+ getGraphControl().scrollRectToVisible(zoomBounds(cells).getRectangle(), true);
+ }
+
+ private final mxRectangle zoomBounds(final Object[] cells) {
+ final mxRectangle preference;
+ final Object[] c;
+ if (cells == null || cells.length == 0) {
+ c = graph.getChildCells(graph.getDefaultParent());
+ } else {
+ c = cells;
+ }
+ preference = getChildrenBounds(c);
+
+ return preference;
+ }
+
+ /**
+ * Get the children bound for the cells
+ *
+ * @param cells
+ * the root of the graph
+ * @return the rectangle or null if not applicable
+ */
+ private mxRectangle getChildrenBounds(final Object[] cells) {
+ mxRectangle result = null;
+
+ if (cells != null && cells.length > 0) {
+ final mxGraphView view = graph.getView();
+ final mxIGraphModel model = graph.getModel();
+
+ for (int i = 0; i < cells.length; i++) {
+ if (model.isVertex(cells[i]) || model.isEdge(cells[i])) {
+ final mxICell parent = ((mxICell) cells[i]);
+ final int childCount = parent.getChildCount();
+
+ for (int j = 0; j < childCount; j++) {
+ final mxICell child = parent.getChildAt(j);
+
+ result = updateRectangle(result, view, child);
+ }
+
+ result = updateRectangle(result, view, parent);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Update the rectangle parameter with the cell status
+ *
+ * @param result
+ * the previous result
+ * @param view
+ * the current view
+ * @param child
+ * the child we have to work on
+ * @return the updated rectangle
+ */
+ private mxRectangle updateRectangle(mxRectangle result, final mxGraphView view, final mxICell child) {
+ final mxCellState state = view.getState(child);
+ mxRectangle rect = result;
+
+ if (state != null) {
+ if (rect == null) {
+ rect = new mxRectangle(state);
+ } else {
+ rect.add(state);
+ }
+ }
+ return rect;
+ }
+
+ /**
+ * Implement a graph control which paint a foreground on top of the view
+ * when the graph is locked.
+ */
+ @SuppressWarnings(value = { "serial" })
+ public class ScilabGraphControl extends mxGraphControl {
+
+ /**
+ * Default constructor
+ */
+ public ScilabGraphControl() {
+ super();
+
+ // Paint the foreground color after the real paint
+ addListener(mxEvent.AFTER_PAINT, new mxEventSource.mxIEventListener() {
+ @Override
+ public void invoke(Object sender, mxEventObject evt) {
+
+ Graphics g = (Graphics) evt.getProperty("g");
+ if (getGraph().isCellsLocked()) {
+ g.setColor(MASK_COLOR);
+
+ Dimension b = getGraphControl().getSize();
+
+ g.fillRect(0, 0, b.width, b.height);
+ }
+ }
+ });
+ }
+
+ /**
+ * @see javax.swing.JComponent#processMouseMotionEvent(java.awt.event.MouseEvent)
+ *
+ * Overloaded to filter out any cursor update if the graph is locked
+ */
+ @Override
+ protected void processMouseMotionEvent(MouseEvent e) {
+ if (!getGraph().isCellsLocked()) {
+ super.processMouseMotionEvent(e);
+ }
+ }
+ }
+
+ /*
+ * Disable some handlers in case of an headless env.
+ */
+
+ @Override
+ protected void createHandlers() {
+ if (GraphicsEnvironment.isHeadless()) {
+ return;
+ }
+
+ super.createHandlers();
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/ScilabGraph.java b/modules/graph/src/java/org/scilab/modules/graph/ScilabGraph.java
new file mode 100755
index 000000000..3fefbd6f1
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/ScilabGraph.java
@@ -0,0 +1,388 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.scilab.modules.graph.utils.ScilabGraphConstants;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.graph.view.ScilabGraphView;
+
+import com.mxgraph.model.mxGraphModel;
+import com.mxgraph.model.mxGraphModel.mxChildChange;
+import com.mxgraph.model.mxGraphModel.mxCollapseChange;
+import com.mxgraph.model.mxGraphModel.mxGeometryChange;
+import com.mxgraph.model.mxGraphModel.mxStyleChange;
+import com.mxgraph.model.mxGraphModel.mxTerminalChange;
+import com.mxgraph.model.mxGraphModel.mxValueChange;
+import com.mxgraph.model.mxGraphModel.mxVisibleChange;
+import com.mxgraph.swing.mxGraphComponent;
+import com.mxgraph.swing.handler.mxRubberband;
+import com.mxgraph.swing.util.mxGraphActions;
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.util.mxUndoManager;
+import com.mxgraph.util.mxUndoableEdit;
+import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
+import com.mxgraph.view.mxGraph;
+import com.mxgraph.view.mxGraphView;
+
+/**
+ * Represent the base diagram of Xcos.
+ *
+ * It performs generic operations like undo/redo management, action clean-up,
+ * modification state management, SwingScilabTab association, etc...
+ */
+public class ScilabGraph extends mxGraph {
+ /**
+ * The default component of a scilab graph
+ */
+ private ScilabComponent component;
+
+ private final mxUndoManager undoManager = new mxUndoManager();
+
+ private String title = null;
+ private File savedFile;
+ private boolean modified;
+ private boolean opened;
+ private boolean readOnly;
+
+ private transient mxRubberband rubberBand;
+
+ private transient String graphTab;
+ private transient String viewPortTab;
+
+ /**
+ * Manage the modification state on change
+ */
+ private final mxIEventListener changeTracker = new mxIEventListener() {
+ @Override
+ public void invoke(Object source, mxEventObject evt) {
+ setModified(true);
+ }
+ };
+
+ /**
+ * Manage the undo/redo on change
+ */
+ private final mxIEventListener undoHandler = new mxIEventListener() {
+ @Override
+ public void invoke(Object source, mxEventObject evt) {
+ undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty(ScilabGraphConstants.EVENT_CHANGE_EDIT));
+ }
+ };
+
+ /**
+ * Remove the undo handler from the component
+ */
+ public void removeUndoHandler() {
+ getModel().removeListener(undoHandler, mxEvent.UNDO);
+ }
+
+ /**
+ * Register the undo handler on the right component
+ */
+ public void registerUndoHandler() {
+ // Undo / Redo capabilities
+ getModel().addListener(mxEvent.UNDO, undoHandler);
+ }
+
+ /**
+ * Update the selection on undo/redo
+ */
+ private final mxIEventListener selectionHandler = new mxIEventListener() {
+ @Override
+ public void invoke(Object source, mxEventObject evt) {
+ List<mxUndoableChange> changes = ((mxUndoableEdit) evt.getProperty(ScilabGraphConstants.EVENT_CHANGE_EDIT)).getChanges();
+ getSelectionModel().setCells(getSelectionCellsForChanges(changes));
+ }
+ };
+
+ /**
+ * Update the component when the graph is locked
+ */
+ private final PropertyChangeListener cellLockBackgroundUpdater = new PropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getPropertyName().equals("cellsLocked")) {
+ getAsComponent().getGraphControl().repaint();
+ }
+ }
+ };
+
+ /**
+ * /** Default constructor: - disable unused actions - install listeners -
+ * Replace JGraphX components by specialized components if needed.
+ */
+ public ScilabGraph() {
+ super();
+
+ // Disabling the default connected action and event listeners.
+ mxGraphActions.getSelectNextAction().setEnabled(false);
+ mxGraphActions.getSelectPreviousAction().setEnabled(false);
+ mxGraphActions.getSelectChildAction().setEnabled(false);
+ mxGraphActions.getSelectParentAction().setEnabled(false);
+
+ registerUndoHandler();
+
+ // Keeps the selection in sync with the command history
+ undoManager.addListener(mxEvent.UNDO, selectionHandler);
+ undoManager.addListener(mxEvent.REDO, selectionHandler);
+
+ setComponent(new ScilabComponent(this));
+
+ // graph locked change support
+ changeSupport.addPropertyChangeListener(cellLockBackgroundUpdater);
+
+ // Modified property change
+ getModel().addListener(mxEvent.CHANGE, changeTracker);
+ }
+
+ /**
+ * @return The previously saved file or null.
+ */
+ public File getSavedFile() {
+ return savedFile;
+ }
+
+ /**
+ * @param savedFile
+ * The new saved file
+ */
+ public void setSavedFile(final File savedFile) {
+ this.savedFile = savedFile;
+
+ // register the saved dir as the image base path (for relative images
+ // location).
+ if (savedFile != null && savedFile.getParentFile() != null) {
+ getAsComponent().getCanvas().setImageBasePath(savedFile.getParentFile().toURI().toASCIIString());
+ }
+ }
+
+ /**
+ * @return true, if the graph has been modified ; false otherwise.
+ */
+ public boolean isModified() {
+ return modified;
+ }
+
+ /**
+ * Modify the state of the diagram.
+ *
+ * @param modified
+ * The new modified state.
+ * @category UseEvent
+ */
+ public void setModified(boolean modified) {
+ boolean oldValue = this.modified;
+ this.modified = modified;
+
+ if (getAsComponent() != null) {
+ getAsComponent().firePropertyChange("modified", oldValue, modified);
+ }
+ }
+
+ /**
+ * @param title
+ * The new title of the tab
+ */
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ /**
+ * @return The current Tab title
+ */
+ public String getTitle() {
+ if (title == null) {
+ final Date d = Calendar.getInstance().getTime();
+ final String time = DateFormat.getTimeInstance().format(d);
+ title = String.format(ScilabGraphMessages.UNTITLED, time);
+ }
+ return title;
+ }
+
+ /**
+ * Get the graph tab uuid
+ *
+ * @return
+ */
+ public String getGraphTab() {
+ return graphTab;
+ }
+
+ /**
+ * Set the graph tab uuid
+ *
+ * @param uuid
+ * the diagram tab
+ */
+ public void setGraphTab(String uuid) {
+ this.graphTab = uuid;
+ }
+
+ /**
+ * Get the view port tab uuid
+ *
+ * @return the view port tab
+ */
+ public String getViewPortTab() {
+ return viewPortTab;
+ }
+
+ /**
+ * Set the view port tab uuid
+ *
+ * @param uuid
+ * the view port tab
+ */
+ public void setViewPortTab(String uuid) {
+ this.viewPortTab = uuid;
+ }
+
+ /**
+ * @return The component associated with the current graph.
+ */
+ public mxGraphComponent getAsComponent() {
+ return component;
+ }
+
+ /**
+ * @param component
+ * The graphical component associated with this graph
+ */
+ public void setComponent(ScilabComponent component) {
+ this.component = component;
+
+ if (component != null) {
+ // Adds rubberband selection
+ rubberBand = new mxRubberband(component);
+ } else {
+ rubberBand = null;
+ }
+ }
+
+ /**
+ * The instance can be not visible but used (when using SuperBlock). The
+ * openned flag is true in this case and also when the Window/Tab is
+ * visible.
+ *
+ * @param opened
+ * Openned state
+ */
+ public void setOpened(boolean opened) {
+ this.opened = opened;
+ }
+
+ /**
+ * @return Openned state
+ */
+ public boolean isOpened() {
+ return opened;
+ }
+
+ /**
+ * A read-only state will disable all actions in the graph.
+ *
+ * @param readOnly
+ * Read-only state
+ */
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+
+ setCellsLocked(readOnly);
+ }
+
+ /**
+ * @return True if actions are not allowed, false otherwise.
+ */
+ public boolean isReadonly() {
+ return readOnly;
+ }
+
+ /**
+ * @return The associated RubberBand
+ * @see com.mxgraph.swing.handler.mxRubberband
+ */
+ public mxRubberband getRubberBand() {
+ return rubberBand;
+ }
+
+ /**
+ * @return The undo manager associated with this graph
+ */
+ public final mxUndoManager getUndoManager() {
+ return undoManager;
+ }
+
+ /**
+ * @return the newly allocated graph
+ * @see com.mxgraph.view.mxGraph#createGraphView()
+ */
+ @Override
+ protected mxGraphView createGraphView() {
+ return new ScilabGraphView(this);
+ }
+
+ /*
+ * Utils
+ */
+ /**
+ * Returns the cells to be selected for the given list of changes.
+ *
+ * @param changes
+ * the changes
+ * @param model
+ * the model to work on
+ * @return the cells
+ */
+ public static Object[] getSelectionCellsForChanges(final List<mxUndoableChange> changes, final mxGraphModel model) {
+ List<Object> cells = new ArrayList<Object>();
+ Iterator<mxUndoableChange> it = changes.iterator();
+
+ while (it.hasNext()) {
+ Object change = it.next();
+
+ if (change instanceof mxChildChange) {
+ cells.add(((mxChildChange) change).getChild());
+ } else if (change instanceof mxTerminalChange) {
+ cells.add(((mxTerminalChange) change).getCell());
+ } else if (change instanceof mxValueChange) {
+ cells.add(((mxValueChange) change).getCell());
+ } else if (change instanceof mxStyleChange) {
+ cells.add(((mxStyleChange) change).getCell());
+ } else if (change instanceof mxGeometryChange) {
+ cells.add(((mxGeometryChange) change).getCell());
+ } else if (change instanceof mxCollapseChange) {
+ cells.add(((mxCollapseChange) change).getCell());
+ } else if (change instanceof mxVisibleChange) {
+ mxVisibleChange vc = (mxVisibleChange) change;
+
+ if (vc.isVisible()) {
+ cells.add(((mxVisibleChange) change).getCell());
+ }
+ }
+ }
+
+ return mxGraphModel.getTopmostCells(model, cells.toArray());
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/ScilabGraphUniqueObject.java b/modules/graph/src/java/org/scilab/modules/graph/ScilabGraphUniqueObject.java
new file mode 100755
index 000000000..7e54b9ef7
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/ScilabGraphUniqueObject.java
@@ -0,0 +1,85 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph;
+
+import java.awt.geom.Point2D;
+import java.io.Serializable;
+import java.rmi.server.UID;
+
+import com.mxgraph.model.mxCell;
+import com.mxgraph.model.mxGeometry;
+
+/**
+ * Implement a unique object.
+ *
+ * All cells in a ScilabGraph must follow this signature in order to be unique
+ * in the graph.
+ */
+public abstract class ScilabGraphUniqueObject extends mxCell implements Comparable<ScilabGraphUniqueObject>, Serializable {
+
+ private static final long serialVersionUID = -2915277403393545917L;
+
+ /**
+ * Constructor
+ */
+ public ScilabGraphUniqueObject() {
+ super();
+ generateId();
+ }
+
+ /**
+ * Generated a new id and set it to the current cell.
+ *
+ * @see com.mxgraph.model.mxCell#setId(java.lang.String)
+ */
+ public void generateId() {
+ super.setId(new UID().toString());
+ }
+
+ /**
+ * Compare this object with another one.
+ *
+ * @param o
+ * the object to compare to.
+ * @return True if instance are the same; False otherwise.
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(ScilabGraphUniqueObject o) {
+ mxGeometry geom1 = getGeometry();
+ mxGeometry geom2 = o.getGeometry();
+
+ final Point2D.Double p1 = new Point2D.Double(geom1.getCenterX(), geom1.getCenterY());
+ final Point2D.Double p2 = new Point2D.Double(geom2.getCenterX(), geom2.getCenterY());
+
+ return (int) p1.distanceSq(p2);
+ }
+
+ /**
+ * @return a clone of the cell.
+ * @throws CloneNotSupportedException
+ * Thrown to indicate that the clone method in class Object has
+ * been called to clone an object, but that the object's class
+ * does not implement the Cloneable interface.
+ * @see com.mxgraph.model.mxCell#clone()
+ */
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ ScilabGraphUniqueObject clone = (ScilabGraphUniqueObject) super.clone();
+
+ /* regenerate a new id for the clone */
+ clone.generateId();
+
+ return clone;
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/CopyAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/CopyAction.java
new file mode 100755
index 000000000..50d70668c
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/CopyAction.java
@@ -0,0 +1,72 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.GraphActionManager;
+import org.scilab.modules.graph.actions.base.VertexSelectionDependantAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.swing.handler.mxGraphTransferHandler;
+
+/**
+ * Copy manager
+ */
+@SuppressWarnings(value = { "serial" })
+public final class CopyAction extends VertexSelectionDependantAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.COPY;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-copy";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_C;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public CopyAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem copyMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, CopyAction.class);
+ }
+
+ /**
+ * Action associated
+ * @param e the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ mxGraphTransferHandler.getCopyAction().actionPerformed(new ActionEvent(getGraph(e).getAsComponent(), e.getID(), e.getActionCommand()));
+
+ // Enable the paste action
+ GraphActionManager.setEnable(PasteAction.class, true);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/CutAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/CutAction.java
new file mode 100755
index 000000000..6a699fc3c
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/CutAction.java
@@ -0,0 +1,72 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.GraphActionManager;
+import org.scilab.modules.graph.actions.base.VertexSelectionDependantAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.swing.handler.mxGraphTransferHandler;
+
+/**
+ * Cut manager
+ */
+@SuppressWarnings(value = { "serial" })
+public final class CutAction extends VertexSelectionDependantAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.CUT;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-cut";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_X;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public CutAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem cutMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, CutAction.class);
+ }
+
+ /**
+ * Action associated
+ * @param e the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ mxGraphTransferHandler.getCutAction().actionPerformed(new ActionEvent(getGraph(e).getAsComponent(), e.getID(), e.getActionCommand()));
+
+ // Enable the paste action
+ GraphActionManager.setEnable(PasteAction.class, true);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/DeleteAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/DeleteAction.java
new file mode 100755
index 000000000..60b6952b5
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/DeleteAction.java
@@ -0,0 +1,85 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.JButton;
+
+import org.scilab.modules.graph.ScilabComponent;
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.OneSelectionDependantAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+/**
+ * Delete manager
+ */
+@SuppressWarnings(value = { "serial" })
+public final class DeleteAction extends OneSelectionDependantAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.DELETE;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-delete";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_DELETE;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = 0;
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public DeleteAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem createMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, DeleteAction.class);
+ }
+
+ /**
+ * Create a button for a graph toolbar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the button
+ */
+ public static JButton createButton(ScilabGraph scilabGraph) {
+ return createButton(scilabGraph, DeleteAction.class);
+ }
+
+ /**
+ * Action associated
+ * @param e the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final ScilabGraph graph = getGraph(e);
+
+ // action disabled when the cell is edited
+ final ScilabComponent comp = ((ScilabComponent) graph.getAsComponent());
+ if (comp.isEditing()) {
+ return;
+ }
+
+ graph.removeCells(graph.getSelectionCells());
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/GroupAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/GroupAction.java
new file mode 100755
index 000000000..ede74c9aa
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/GroupAction.java
@@ -0,0 +1,70 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.MultiSelectionDependantAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.swing.util.mxGraphActions;
+
+/**
+ * Group any blocks and ease the manipulation of them.
+ */
+@SuppressWarnings(value = { "serial" })
+public class GroupAction extends MultiSelectionDependantAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.GROUP;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_G;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * The associated graph
+ */
+ public GroupAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create the menu associated with this action.
+ * @param scilabGraph the associated graph
+ * @return The associated menu
+ */
+ public static MenuItem groupMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, GroupAction.class);
+ }
+
+ /**
+ * Action to be done
+ * @param e Event descriptor
+ */
+ public void actionPerformed(ActionEvent e) {
+ mxGraphActions.getGroupAction().actionPerformed(new ActionEvent(getGraph(e).getAsComponent(),
+ e.getID(), e.getActionCommand()));
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/InvertSelectionAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/InvertSelectionAction.java
new file mode 100755
index 000000000..a4f56b923
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/InvertSelectionAction.java
@@ -0,0 +1,73 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.event.ActionEvent;
+
+import org.scilab.modules.graph.ScilabComponent;
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.VertexSelectionDependantAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+/**
+ * Selection management
+ */
+@SuppressWarnings(value = { "serial" })
+public final class InvertSelectionAction extends VertexSelectionDependantAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.INVERT_SELECTION;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = 0;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = 0;
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public InvertSelectionAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem createMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, InvertSelectionAction.class);
+ }
+
+ /**
+ * Action associated
+ * @param e the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ public void actionPerformed(ActionEvent e) {
+ final ScilabGraph graph = getGraph(e);
+
+ // action disabled when the cell is edited
+ final ScilabComponent comp = ((ScilabComponent) graph.getAsComponent());
+ if (comp.isEditing()) {
+ return;
+ }
+
+ Object[] all = graph.getSelectionCells();
+ graph.selectAll();
+ graph.removeSelectionCells(all);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/PasteAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/PasteAction.java
new file mode 100755
index 000000000..96620494c
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/PasteAction.java
@@ -0,0 +1,75 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.TransferHandler;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.DefaultAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.swing.handler.mxGraphTransferHandler;
+
+/**
+ * Paste manager
+ *
+ * This action is enabled by the {@link CutAction} and {@link CopyAction}.
+ */
+@SuppressWarnings(value = { "serial" })
+public final class PasteAction extends DefaultAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.PASTE;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-paste";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_V;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public PasteAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ setEnabled(TransferHandler.getPasteAction().isEnabled());
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem pasteMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, PasteAction.class);
+ }
+
+ /**
+ * Action associated
+ * @param e the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ mxGraphTransferHandler.getPasteAction().actionPerformed(new ActionEvent(getGraph(e).getAsComponent(),
+ e.getID(), e.getActionCommand()));
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/RedoAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/RedoAction.java
new file mode 100755
index 000000000..f85ce6da2
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/RedoAction.java
@@ -0,0 +1,153 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.lang.ref.WeakReference;
+
+import javax.swing.JButton;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.ActionConstraint;
+import org.scilab.modules.graph.actions.base.DefaultAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.util.mxUndoManager;
+
+/**
+ * Redo manager
+ */
+@SuppressWarnings(value = { "serial" })
+public class RedoAction extends DefaultAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.REDO;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-redo";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_Y;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Manage enable modification
+ */
+ private final class RedoConstraint extends ActionConstraint {
+ private final WeakReference<ScilabGraph> scilabGraph;
+
+ /**
+ * Default constructor
+ * @param scilabGraph the graph to work on
+ */
+ public RedoConstraint(ScilabGraph scilabGraph) {
+ this.scilabGraph = new WeakReference<ScilabGraph>(scilabGraph);
+ }
+
+ /**
+ * @param action
+ * the current action
+ * @param scilabGraph
+ * the associated graph
+ * @see org.scilab.modules.graph.actions.base.ActionConstraint#install(org.scilab.modules.graph.actions.base.DefaultAction,
+ * org.scilab.modules.graph.ScilabGraph)
+ */
+ @Override
+ public void install(DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+
+ registerAsListener(scilabGraph.getUndoManager());
+ }
+
+ /**
+ * @param manager the associated UndoManager
+ */
+ public void registerAsListener(mxUndoManager manager) {
+ manager.addListener(mxEvent.UNDO, this);
+ manager.addListener(mxEvent.REDO, this);
+ manager.addListener(mxEvent.ADD, this);
+ manager.addListener(mxEvent.CLEAR, this);
+ }
+
+ /**
+ * To be checked
+ * @param sender the event sender
+ * @param evt the current event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object, com.mxgraph.util.mxEventObject)
+ */
+ @Override
+ public void invoke(Object sender, mxEventObject evt) {
+ final ScilabGraph graph = scilabGraph.get();
+ if (graph == null) {
+ return;
+ }
+
+ boolean canRedo = graph.getUndoManager().canRedo();
+ super.setEnabled(canRedo);
+ }
+ }
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public RedoAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ RedoConstraint c = new RedoConstraint(scilabGraph);
+ c.install(this, scilabGraph);
+ }
+
+ /**
+ * Create a button for a graph toolbar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the button
+ */
+ public static JButton redoButton(ScilabGraph scilabGraph) {
+ return createButton(scilabGraph, RedoAction.class);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem redoMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, RedoAction.class);
+ }
+
+ /**
+ * Action associated
+ *
+ * @param e
+ * the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final ScilabGraph graph = getGraph(e);
+
+ graph.removeUndoHandler();
+ graph.getUndoManager().redo();
+ graph.registerUndoHandler();
+
+ // revalidate the graph
+ graph.getAsComponent().clearCellOverlays();
+ graph.getAsComponent().validateGraph();
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/SelectAllAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/SelectAllAction.java
new file mode 100755
index 000000000..3f172f639
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/SelectAllAction.java
@@ -0,0 +1,65 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.OneBlockDependantAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+/**
+ * Selection management
+ */
+@SuppressWarnings(value = { "serial" })
+public final class SelectAllAction extends OneBlockDependantAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.SELECT_ALL;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-select-all";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_A;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public SelectAllAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem createMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, SelectAllAction.class);
+ }
+
+ /**
+ * Action associated
+ * @param e the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ getGraph(e).selectAll();
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/UnGroupAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/UnGroupAction.java
new file mode 100755
index 000000000..a45068520
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/UnGroupAction.java
@@ -0,0 +1,71 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.DefaultAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.swing.util.mxGraphActions;
+
+/**
+ * Ungroup any blocks and ease the manipulation of them.
+ */
+@SuppressWarnings(value = { "serial" })
+public class UnGroupAction extends DefaultAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.UNGROUP;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_G;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = KeyEvent.SHIFT_DOWN_MASK
+ | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * The associated graph
+ */
+ public UnGroupAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+ }
+
+ /**
+ * Create the menu associated with this action.
+ * @param scilabGraph the associated graph
+ * @return The associated menu
+ */
+ public static MenuItem ungroupMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, UnGroupAction.class);
+ }
+
+ /**
+ * Action to be done
+ * @param e Event descriptor
+ */
+ public void actionPerformed(ActionEvent e) {
+ mxGraphActions.getUngroupAction().actionPerformed(new ActionEvent(getGraph(e).getAsComponent(),
+ e.getID(), e.getActionCommand()));
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/UndoAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/UndoAction.java
new file mode 100755
index 000000000..487c79974
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/UndoAction.java
@@ -0,0 +1,153 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.lang.ref.WeakReference;
+
+import javax.swing.JButton;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.ActionConstraint;
+import org.scilab.modules.graph.actions.base.DefaultAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.util.mxUndoManager;
+
+/**
+ * Undo manager
+ */
+@SuppressWarnings(value = { "serial" })
+public class UndoAction extends DefaultAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.UNDO;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "edit-undo";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_Z;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /**
+ * Manage enable modification
+ */
+ private final class UndoConstraint extends ActionConstraint {
+ private final WeakReference<ScilabGraph> scilabGraph;
+
+ /**
+ * Default constructor
+ * @param scilabGraph the associated scilab graph
+ */
+ public UndoConstraint(ScilabGraph scilabGraph) {
+ this.scilabGraph = new WeakReference<ScilabGraph>(scilabGraph);
+ }
+
+ /**
+ * @param action
+ * the current action
+ * @param scilabGraph
+ * the associated graph
+ * @see org.scilab.modules.graph.actions.base.ActionConstraint#install(org.scilab.modules.graph.actions.base.DefaultAction,
+ * org.scilab.modules.graph.ScilabGraph)
+ */
+ @Override
+ public void install(DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+ registerAsListener(scilabGraph.getUndoManager());
+ }
+
+ /**
+ * @param manager the associated UndoManager
+ */
+ private void registerAsListener(mxUndoManager manager) {
+ manager.addListener(mxEvent.UNDO, this);
+ manager.addListener(mxEvent.REDO, this);
+ manager.addListener(mxEvent.ADD, this);
+ manager.addListener(mxEvent.CLEAR, this);
+ }
+
+ /**
+ * To be checked
+ * @param sender the event sender
+ * @param evt the current event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object, com.mxgraph.util.mxEventObject)
+ */
+ @Override
+ public void invoke(Object sender, mxEventObject evt) {
+ final ScilabGraph graph = scilabGraph.get();
+ if (graph == null) {
+ return;
+ }
+
+ boolean canUndo = graph.getUndoManager().canUndo();
+ super.setEnabled(canUndo);
+ }
+ }
+
+ /**
+ * Constructor
+ * @param scilabGraph corresponding Scilab Graph
+ */
+ public UndoAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ UndoConstraint c = new UndoConstraint(scilabGraph);
+ c.install(this, scilabGraph);
+ }
+
+ /**
+ * Create a button for a graph toolbar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the button
+ */
+ public static JButton undoButton(ScilabGraph scilabGraph) {
+ return createButton(scilabGraph, UndoAction.class);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ * @param scilabGraph corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem undoMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, UndoAction.class);
+ }
+
+ /**
+ * Action associated
+ *
+ * @param e
+ * the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ final ScilabGraph graph = getGraph(e);
+
+ graph.removeUndoHandler();
+ graph.getUndoManager().undo();
+ graph.registerUndoHandler();
+
+ // revalidate the graph
+ graph.getAsComponent().clearCellOverlays();
+ graph.getAsComponent().validateGraph();
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/ZoomInAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/ZoomInAction.java
new file mode 100755
index 000000000..3d92baf8e
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/ZoomInAction.java
@@ -0,0 +1,158 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import static org.scilab.modules.commons.OS.MAC;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.KeyStroke;
+
+import org.scilab.modules.commons.OS;
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.DefaultAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+/**
+ * Zoom management
+ */
+@SuppressWarnings(value = { "serial" })
+public class ZoomInAction extends DefaultAction {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.ZOOM_IN;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "zoom-in";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_ADD;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /** key used on {@link InputMap} for this action */
+ private static final String ZOOM_IN = "zoomIn";
+
+ /**
+ * Implement custom mouse handling for the zoom
+ */
+ private static final class CustomMouseWheelListener implements MouseWheelListener {
+ private final ScilabGraph scilabGraph;
+
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * the current graph
+ */
+ public CustomMouseWheelListener(ScilabGraph scilabGraph) {
+ this.scilabGraph = scilabGraph;
+ }
+
+ /**
+ * When the wheel is used
+ *
+ * @param e
+ * the parameters
+ * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
+ */
+ @Override
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if ((e.getModifiers() & ACCELERATOR_KEY) != 0) {
+ if (e.getWheelRotation() < 0) {
+ scilabGraph.getAsComponent().zoomIn();
+ }
+ }
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ */
+ public ZoomInAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ MouseWheelListener mouseListener = new CustomMouseWheelListener(scilabGraph);
+ scilabGraph.getAsComponent().addMouseWheelListener(mouseListener);
+
+ // Multi-shortcut action
+ final ActionMap am = scilabGraph.getAsComponent().getActionMap();
+ final InputMap map = scilabGraph.getAsComponent().getInputMap();
+
+ // register the action to a unique action keyword
+ am.put(ZOOM_IN, this);
+
+ // add custom key stroke for this action
+ final KeyStroke[] keystrokes;
+ if (OS.get() == MAC) {
+ /*
+ * AZERTY for Mac has a non-supported classic layout
+ */
+ keystrokes = new KeyStroke[] { KeyStroke.getKeyStroke('/', ACCELERATOR_KEY),
+ KeyStroke.getKeyStroke('/', ACCELERATOR_KEY | KeyEvent.SHIFT_DOWN_MASK),
+ };
+ } else {
+ keystrokes = new KeyStroke[] { KeyStroke.getKeyStroke('=', ACCELERATOR_KEY),
+ KeyStroke.getKeyStroke('=', ACCELERATOR_KEY | KeyEvent.SHIFT_DOWN_MASK), KeyStroke.getKeyStroke('+', ACCELERATOR_KEY),
+ KeyStroke.getKeyStroke('+', ACCELERATOR_KEY | KeyEvent.SHIFT_DOWN_MASK),
+ };
+ }
+
+ for (KeyStroke k : keystrokes) {
+ map.put(k, ZOOM_IN);
+ }
+ }
+
+ /**
+ * Create a button for a graph toolbar
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ * @return the button
+ */
+ public static JButton zoominButton(ScilabGraph scilabGraph) {
+ return createButton(scilabGraph, ZoomInAction.class);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem zoominMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, ZoomInAction.class);
+ }
+
+ /**
+ * Action associated
+ *
+ * @param e
+ * the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ getGraph(e).getAsComponent().zoomIn();
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/ZoomOutAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/ZoomOutAction.java
new file mode 100755
index 000000000..6625874b8
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/ZoomOutAction.java
@@ -0,0 +1,162 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions;
+
+import static org.scilab.modules.commons.OS.MAC;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.KeyStroke;
+
+import org.scilab.modules.commons.OS;
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.graph.actions.base.DefaultAction;
+import org.scilab.modules.graph.utils.ScilabGraphMessages;
+import org.scilab.modules.gui.menuitem.MenuItem;
+
+/**
+ * Zoom management
+ *
+ * @author Bruno JOFFRET
+ */
+@SuppressWarnings(value = { "serial" })
+public class ZoomOutAction extends DefaultAction implements ActionListener {
+ /** Name of the action */
+ public static final String NAME = ScilabGraphMessages.ZOOM_OUT;
+ /** Icon name of the action */
+ public static final String SMALL_ICON = "zoom-out";
+ /** Mnemonic key of the action */
+ public static final int MNEMONIC_KEY = KeyEvent.VK_SUBTRACT;
+ /** Accelerator key for the action */
+ public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
+
+ /** key used on {@link InputMap} for this action */
+ private static final String ZOOM_OUT = "zoomOut";
+
+ /**
+ * Implement custom mouse handling for the zoom
+ */
+ private static final class CustomMouseWheelListener implements MouseWheelListener {
+ private final ScilabGraph scilabGraph;
+
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * the current graph
+ */
+ public CustomMouseWheelListener(ScilabGraph scilabGraph) {
+ this.scilabGraph = scilabGraph;
+ }
+
+ /**
+ * When the wheel is used
+ *
+ * @param e
+ * the parameters
+ * @see java.awt.event.MouseWheelListener#mouseWheelMoved(java.awt.event.MouseWheelEvent)
+ */
+ @Override
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if ((e.getModifiers() & ACCELERATOR_KEY) != 0) {
+ if (e.getWheelRotation() > 0) {
+ scilabGraph.getAsComponent().zoomOut();
+ }
+ }
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ */
+ public ZoomOutAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ MouseWheelListener mouseListener = new CustomMouseWheelListener(scilabGraph);
+ scilabGraph.getAsComponent().addMouseWheelListener(mouseListener);
+
+ // Multi-shortcut action
+ final ActionMap am = scilabGraph.getAsComponent().getActionMap();
+ final InputMap map = scilabGraph.getAsComponent().getInputMap();
+
+ // register the action to a unique action keyword
+ am.put(ZOOM_OUT, this);
+
+ // add custom key stroke for this action
+ final KeyStroke[] keystrokes;
+ if (OS.get() == MAC) {
+ /*
+ * AZERTY for Mac has a non-supported classic layout
+ */
+ keystrokes = new KeyStroke[] { KeyStroke.getKeyStroke('=', ACCELERATOR_KEY),
+ KeyStroke.getKeyStroke('=', ACCELERATOR_KEY | KeyEvent.SHIFT_DOWN_MASK),
+ };
+ } else {
+ keystrokes = new KeyStroke[] { KeyStroke.getKeyStroke('-', ACCELERATOR_KEY),
+ KeyStroke.getKeyStroke('-', ACCELERATOR_KEY | KeyEvent.SHIFT_DOWN_MASK), KeyStroke.getKeyStroke('_', ACCELERATOR_KEY),
+ KeyStroke.getKeyStroke('_', ACCELERATOR_KEY | KeyEvent.SHIFT_DOWN_MASK),
+ };
+ }
+
+ for (KeyStroke k : keystrokes) {
+ map.put(k, ZOOM_OUT);
+ }
+ }
+
+ /**
+ * Create a button for a graph toolbar
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ * @return the button
+ */
+ public static JButton zoomoutButton(ScilabGraph scilabGraph) {
+ return createButton(scilabGraph, ZoomOutAction.class);
+ }
+
+ /**
+ * Create a menu for a graph menubar
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ * @return the menu
+ */
+ public static MenuItem zoomoutMenu(ScilabGraph scilabGraph) {
+ return createMenu(scilabGraph, ZoomOutAction.class);
+ }
+
+ /**
+ * Action associated
+ *
+ * @param e
+ * the event
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ getGraph(e).getAsComponent().zoomOut();
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/ActionConstraint.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/ActionConstraint.java
new file mode 100755
index 000000000..ed6664b4d
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/ActionConstraint.java
@@ -0,0 +1,86 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+import com.mxgraph.util.mxEventSource.mxIEventListener;
+
+/**
+ * Specify function called to add constraint on an action.
+ */
+public abstract class ActionConstraint implements mxIEventListener {
+ private boolean enabled;
+ private DefaultAction action;
+
+ /**
+ * Install this constraint on a graph for the specific action.
+ *
+ * Override to action to install the current listener on a graph. Call the
+ * super.install(...) in order to automatically register your action.
+ *
+ * @param action
+ * the constrained action
+ * @param scilabGraph
+ * where to install constraint
+ */
+ public void install(final DefaultAction action, ScilabGraph scilabGraph) {
+ this.action = action;
+
+ /**
+ * assume that at installation time, the constraint is not valid.
+ */
+ setEnabled(false);
+
+ /*
+ * Disable actions when cells are locked
+ */
+ scilabGraph.addPropertyChangeListener(new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (evt.getPropertyName().equals("cellsLocked")) {
+ boolean locked = (Boolean) evt.getNewValue();
+ action.setEnabled(!locked);
+ }
+ }
+ });
+
+ // If the current constraint is not valid : force setEnable(false).
+ // This will force the current constraint.
+ action.addPropertyChangeListener(new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent evt) {
+ if (!isEnabled()) {
+ action.setEnabled(false);
+ }
+ }
+ });
+ }
+
+ /**
+ * @return That status of the action according to implementation conditions.
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * @param enabled Update the enable status of this constraint.
+ */
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+
+ action.setEnabled(enabled);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/DefaultAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/DefaultAction.java
new file mode 100755
index 000000000..db5c2eaf2
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/DefaultAction.java
@@ -0,0 +1,271 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2009-2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.lang.ref.WeakReference;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.KeyStroke;
+
+import org.scilab.modules.commons.gui.FindIconHelper;
+import org.scilab.modules.commons.gui.ScilabLAF;
+import org.scilab.modules.graph.ScilabGraph;
+import org.scilab.modules.gui.bridge.checkboxmenuitem.SwingScilabCheckBoxMenuItem;
+import org.scilab.modules.gui.bridge.menuitem.SwingScilabMenuItem;
+import org.scilab.modules.gui.checkboxmenuitem.CheckBoxMenuItem;
+import org.scilab.modules.gui.checkboxmenuitem.ScilabCheckBoxMenuItem;
+import org.scilab.modules.gui.events.callback.CommonCallBack;
+import org.scilab.modules.gui.menuitem.MenuItem;
+import org.scilab.modules.gui.menuitem.ScilabMenuItem;
+
+import com.mxgraph.swing.mxGraphComponent;
+
+/**
+ * Default action for a Scilab Graph
+ */
+public abstract class DefaultAction extends CommonCallBack {
+ private final WeakReference<ScilabGraph> scilabGraph;
+
+ /**
+ * Default constructor.
+ *
+ * The {@link AbstractAction} object is configured using the reflection API.
+ * So you have to be sure that the following fields are declared as static
+ * final fields of each subclasses.
+ * <ul>
+ * <li>String NAME : The name of the action</li>
+ * <li>String SMALL_ICON : The associated icon name (located on
+ * $SCI/modules/gui/images/icons)</li>
+ * <li>int MNEMONIC_KEY : The key associated with the action (see
+ * {@link KeyEvent})</li>
+ * <li>int ACCELERATOR_KEY : The key mask to apply to the mnemonic</li>
+ * </ul>
+ *
+ * @param scilabGraph
+ * corresponding Scilab Graph
+ */
+ public DefaultAction(ScilabGraph scilabGraph) {
+ super("");
+ this.scilabGraph = new WeakReference<ScilabGraph>(scilabGraph);
+
+ installProperties();
+ }
+
+ /**
+ * Install the static actions properties on the instance
+ */
+ private void installProperties() {
+ String name = "";
+ ImageIcon icon = null;
+ int mnemonic = 0;
+ int accelerator = 0;
+ try {
+ name = (String) getClass().getField("NAME").get(null);
+
+ /*
+ * Getting icon from the registered icon path
+ */
+ String iconName = (String) getClass().getField("SMALL_ICON").get(null);
+ if (iconName != null && !iconName.isEmpty()) {
+ icon = new ImageIcon(FindIconHelper.findIcon(iconName));
+ }
+
+ mnemonic = getClass().getField("MNEMONIC_KEY").getInt(null);
+ accelerator = getClass().getField("ACCELERATOR_KEY").getInt(null);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+
+ assert !"".equals(name);
+ putValue(Action.NAME, name);
+ putValue(Action.SHORT_DESCRIPTION, name);
+ putValue(Action.LONG_DESCRIPTION, name);
+ if (icon != null) {
+ putValue(Action.SMALL_ICON, icon);
+ }
+
+ /*
+ * Set up the accelerator instead of the mnemonic as the menu is the
+ * preferred way on keyboard control. We are using Action.MNEMONIC_KEY
+ * as keyboard key and Action.ACCELERATOR_KEY as a mask.
+ *
+ * Install it only when there is a real shortcut (with a mnemonic).
+ */
+ if (mnemonic != 0) {
+ putValue(Action.MNEMONIC_KEY, mnemonic);
+ putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(mnemonic, accelerator));
+ }
+ }
+
+ /**
+ * Create a menu item associated with the graph
+ *
+ * @param graph
+ * the graph to work on
+ * @param klass
+ * the associated klass
+ * @return the menu item
+ */
+ protected static MenuItem createMenu(ScilabGraph graph, final Class <? extends DefaultAction > klass) {
+ DefaultAction action = GraphActionManager.getInstance(graph, klass);
+ MenuItem item = ScilabMenuItem.createMenuItem();
+
+ SwingScilabMenuItem swingItem = (SwingScilabMenuItem) item.getAsSimpleMenuItem();
+ swingItem.setAction(action);
+
+ return item;
+ }
+
+ /**
+ * Create a menu item associated with the graph
+ *
+ * @param graph
+ * the graph to work on
+ * @param klass
+ * the associated klass
+ * @return the push button
+ */
+ protected static JButton createButton(ScilabGraph graph, final Class <? extends DefaultAction > klass) {
+ DefaultAction action = GraphActionManager.getInstance(graph, klass);
+ JButton item = new JButton();
+
+ item.setAction(action);
+
+ // Hide the text on buttons
+ item.setHideActionText(true);
+
+ return item;
+ }
+
+ /**
+ * Create a menu item associated with the graph
+ *
+ * @param graph
+ * the graph to work on
+ * @param klass
+ * the associated klass
+ * @return the checkbox item
+ */
+ protected static CheckBoxMenuItem createCheckBoxMenu(ScilabGraph graph, Class <? extends DefaultAction > klass) {
+ DefaultAction action = GraphActionManager.getInstance(graph, klass);
+ CheckBoxMenuItem item = ScilabCheckBoxMenuItem.createCheckBoxMenuItem();
+
+ SwingScilabCheckBoxMenuItem swingItem = (SwingScilabCheckBoxMenuItem) item.getAsSimpleCheckBoxMenuItem();
+ swingItem.setAction(action);
+
+ return item;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param label
+ * action descriptor
+ * @param scilabGraph
+ * associated Scilab Graph
+ */
+ @Deprecated
+ protected DefaultAction(String label, ScilabGraph scilabGraph) {
+ super(label);
+ this.scilabGraph = new WeakReference<ScilabGraph>(scilabGraph);
+ }
+
+ /**
+ * Get associated graph
+ *
+ * @param e
+ * event
+ * @return Returns the graph for the given action event.
+ */
+ protected final ScilabGraph getGraph(ActionEvent e) {
+ final ScilabGraph graph = scilabGraph.get();
+ if (graph != null) {
+ return graph;
+ }
+
+ if (e == null) {
+ return null;
+ }
+
+ if (e.getSource() instanceof Component) {
+ Component component = (Component) e.getSource();
+
+ while (component != null && !(component instanceof mxGraphComponent)) {
+ component = component.getParent();
+ }
+
+ return (ScilabGraph) ((mxGraphComponent) component).getGraph();
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a button for a graph toolbar
+ *
+ * @param title
+ * label of the menu
+ * @param icon
+ * the path the an icon file
+ * @param listener
+ * action listener associated
+ * @param keyStroke
+ * menu shortcut
+ * @return the button
+ */
+ @Deprecated
+ protected static MenuItem createMenu(String title, String icon, DefaultAction listener, KeyStroke keyStroke) {
+ MenuItem menu = ScilabMenuItem.createMenuItem();
+ menu.setCallback(listener);
+ menu.setText(title);
+
+ if (keyStroke != null) {
+ ((SwingScilabMenuItem) menu.getAsSimpleMenuItem()).setAccelerator(keyStroke);
+ }
+
+ return menu;
+ }
+
+ /**
+ * Action
+ *
+ * @param e
+ * parameters
+ * @see org.scilab.modules.gui.events.callback.CallBack#actionPerformed(java.awt.event.ActionEvent)
+ */
+ @Override
+ public abstract void actionPerformed(ActionEvent e);
+
+ /**
+ * Not used
+ *
+ * @see org.scilab.modules.gui.events.callback.CallBack#callBack()
+ */
+ @Override
+ public void callBack() {
+ assert "Must never be called as we bypass Callback.java".equals("");
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/EdgeSelectionDependantAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/EdgeSelectionDependantAction.java
new file mode 100755
index 000000000..bd32df7db
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/EdgeSelectionDependantAction.java
@@ -0,0 +1,97 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+import com.mxgraph.model.mxCell;
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.view.mxGraphSelectionModel;
+
+/**
+ * Common class for selection dependent actions.
+ *
+ * Children of this class will be activated when there something selected. If
+ * not, the action will be disabled.
+ */
+public abstract class EdgeSelectionDependantAction extends DefaultAction {
+
+ /**
+ * Enable the selection if there is at least a vertex in the selection.
+ */
+ private final class EdgeSelectionDependantConstraint extends ActionConstraint {
+
+ /**
+ * Default constructor
+ */
+ public EdgeSelectionDependantConstraint() {
+ super();
+ }
+
+ /**
+ * @param action the action
+ * @param scilabGraph the current graph
+ * @see org.scilab.modules.graph.actions.base.ActionConstraint#install(org.scilab.modules.graph.actions.base.DefaultAction,
+ * org.scilab.modules.graph.ScilabGraph)
+ */
+ @Override
+ public void install(DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+
+ scilabGraph.getSelectionModel().addListener(mxEvent.UNDO, this);
+ }
+
+ /**
+ * @param sender the sender
+ * @param evt the event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object, com.mxgraph.util.mxEventObject)
+ */
+ public void invoke(Object sender, mxEventObject evt) {
+ mxGraphSelectionModel selection = (mxGraphSelectionModel) sender;
+ Object[] cells = selection.getCells();
+
+ boolean edgeFound = false;
+ if (cells != null) {
+ for (Object object : cells) {
+ if (object instanceof mxCell) {
+ mxCell cell = (mxCell) object;
+ edgeFound = cell.isEdge();
+ }
+
+ if (edgeFound) {
+ break;
+ }
+ }
+
+ setEnabled(edgeFound);
+ }
+ }
+
+ }
+
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * The associated graph
+ */
+ public EdgeSelectionDependantAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ if (scilabGraph != null) {
+ EdgeSelectionDependantConstraint c = new EdgeSelectionDependantConstraint();
+ c.install(this, scilabGraph);
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/GraphActionManager.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/GraphActionManager.java
new file mode 100755
index 000000000..a4b3c123e
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/GraphActionManager.java
@@ -0,0 +1,220 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.swing.Action;
+import javax.swing.KeyStroke;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+/**
+ * Implement construction methods for Actions.
+ */
+public final class GraphActionManager {
+ private static Map<ScilabGraph, Set<DefaultAction>> perGraphAction = new WeakHashMap<ScilabGraph, Set<DefaultAction>>();
+ private static Set<DefaultAction> nullGraphAction = Collections.newSetFromMap(new WeakHashMap<DefaultAction, Boolean>());
+
+ /**
+ * Static class so private constructor
+ */
+ private GraphActionManager() {
+ }
+
+ /**
+ * As each action is unique per graph, get the action instance for the
+ * graph.
+ *
+ * If the action has never been instantiated, use the
+ * DefaultAction(ScilabGraph) constructor and put it on the set.
+ *
+ * @param graph
+ * the graph to work on
+ * @param action
+ * the action class we are looking for.
+ * @param <T>
+ * the type to work with.
+ * @return the instance or null on error.
+ */
+ public static <T extends DefaultAction> T getInstance(ScilabGraph graph, Class<T> action) {
+ Set<DefaultAction> actionSet = getActionSet(graph);
+
+ for (DefaultAction defaultAction : actionSet) {
+ if (defaultAction.getClass() == action) {
+ // Here we can safely cast the action according to the test.
+ return (T) defaultAction;
+ }
+ }
+
+ T instance = null;
+ try {
+ instance = action.getConstructor(ScilabGraph.class).newInstance(graph);
+ actionSet.add(instance);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ } catch (InstantiationException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+
+ return instance;
+ }
+
+ /**
+ * Get the action set attached to the graph
+ *
+ * @param graph
+ * the graph where to search
+ * @return the {@link DefaultAction} set
+ */
+ private static Set<DefaultAction> getActionSet(ScilabGraph graph) {
+ Set<DefaultAction> actionSet;
+ if (graph == null) {
+ actionSet = nullGraphAction;
+ } else {
+ if (perGraphAction.containsKey(graph)) {
+ actionSet = perGraphAction.get(graph);
+ } else {
+ actionSet = Collections.newSetFromMap(new WeakHashMap<DefaultAction, Boolean>());
+ perGraphAction.put(graph, actionSet);
+ }
+ }
+ return actionSet;
+ }
+
+ /**
+ * As each action is unique per graph, get the action instance for the
+ * graph.
+ *
+ * If the action has never been instantiated, return null.
+ *
+ * @param graph
+ * the graph to work on
+ * @param action
+ * the action class we are looking for.
+ * @param <T>
+ * the type to work with.
+ * @return the instance or null if not found.
+ */
+ public static <T extends DefaultAction> T get(ScilabGraph graph, Class<T> action) {
+ Set<DefaultAction> actionSet = getActionSet(graph);
+
+ for (DefaultAction defaultAction : actionSet) {
+ if (defaultAction.getClass() == action) {
+ // Here we can safely cast the action according to the test.
+ return (T) defaultAction;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Enable or disable action on all registered graph.
+ *
+ * @param actionKlass
+ * The action type to enable
+ * @param enable
+ * the enable status
+ */
+ public static void setEnable(Class <? extends DefaultAction > actionKlass, boolean enable) {
+ // Handle null graph
+ for (DefaultAction action : nullGraphAction) {
+ if (actionKlass.isInstance(action)) {
+ action.setEnabled(enable);
+ }
+ }
+
+ // Handle non-null graph
+ for (Set<DefaultAction> actions : perGraphAction.values()) {
+ for (DefaultAction action : actions) {
+ if (actionKlass.isInstance(action)) {
+ action.setEnabled(enable);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get status action on all registered graph.
+ *
+ * @param actionKlass
+ * The action type to enable
+ * @return the status (true if all action are enabled, false otherwise)
+ */
+ public static boolean getEnable(Class <? extends DefaultAction > actionKlass) {
+ boolean result = true;
+
+ // Handle null graph
+ for (DefaultAction action : nullGraphAction) {
+ if (actionKlass.isInstance(action)) {
+ result &= action.isEnabled();
+ }
+ }
+
+ // Handle non-null graph
+ for (Set<DefaultAction> actions : perGraphAction.values()) {
+ for (DefaultAction action : actions) {
+ if (actionKlass.isInstance(action)) {
+ result &= action.isEnabled();
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Update the {@link KeyStroke} of all actions of class.
+ *
+ * @param actionKlass
+ * the action class to update
+ * @param key
+ * the {@link KeyStroke} to set
+ */
+ public static void updateActionKeyStroke(Class <? extends DefaultAction > actionKlass, KeyStroke key) {
+ /*
+ * Per graph action
+ */
+ final Set<Entry<ScilabGraph, Set<DefaultAction>>> entrySet = perGraphAction.entrySet();
+ for (Entry<ScilabGraph, Set<DefaultAction>> entry : entrySet) {
+ setKeyStroke(entry.getValue(), actionKlass, key);
+ }
+
+ /*
+ * Out of graphs actions
+ */
+ setKeyStroke(nullGraphAction, actionKlass, key);
+ }
+
+ private static final void setKeyStroke(final Set<DefaultAction> actions, final Class <? extends DefaultAction > actionKlass, final KeyStroke key) {
+ for (final DefaultAction a : actions) {
+ if (a.getClass() == actionKlass) {
+ a.putValue(Action.ACCELERATOR_KEY, key);
+ }
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/MinimalNumberOfCellsConstraint.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/MinimalNumberOfCellsConstraint.java
new file mode 100755
index 000000000..b042d9dea
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/MinimalNumberOfCellsConstraint.java
@@ -0,0 +1,68 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+import com.mxgraph.model.mxGraphModel;
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+
+/**
+ * Constraint which specify how many blocks must be present on a graph to enable
+ * the action.
+ */
+public final class MinimalNumberOfCellsConstraint extends ActionConstraint {
+ private final int minimalCount;
+ private int numberOfCells;
+
+ /**
+ * Default constructor
+ * @param minimalCount the minimal number of cells for the action to be enabled
+ */
+ public MinimalNumberOfCellsConstraint(int minimalCount) {
+ numberOfCells = 0;
+
+ // add the root and the default parent to the minimal count
+ this.minimalCount = minimalCount + 2;
+ }
+
+ /**
+ * Install this constraint on a graph for the specific action.
+ * @param action the constrained action
+ * @param scilabGraph where to install constraint
+ */
+ public void install(final DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+ scilabGraph.addListener(mxEvent.CELLS_ADDED, this);
+ scilabGraph.addListener(mxEvent.CELLS_REMOVED, this);
+ scilabGraph.addListener(mxEvent.ROOT, this);
+ }
+
+ /**
+ * Enable or disable the action.
+ *
+ * @param sender
+ * the sender
+ * @param evt
+ * the event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object,
+ * com.mxgraph.util.mxEventObject)
+ */
+ public void invoke(Object sender, mxEventObject evt) {
+ final mxGraphModel model = (mxGraphModel) ((ScilabGraph) sender).getModel();
+ numberOfCells = model.getCells().size();
+
+ setEnabled(numberOfCells >= minimalCount);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/MultiSelectionDependantAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/MultiSelectionDependantAction.java
new file mode 100755
index 000000000..936618dcc
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/MultiSelectionDependantAction.java
@@ -0,0 +1,38 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+/**
+ * Common class for multi-selection dependent actions.
+ *
+ * Children of this class will be activated when there something selected. If
+ * not, the action will be disabled.
+ */
+public abstract class MultiSelectionDependantAction extends DefaultAction {
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * the associated graph
+ */
+ public MultiSelectionDependantAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ if (scilabGraph != null) {
+ SelectedNumberOfCellsConstraint constraint = new SelectedNumberOfCellsConstraint(2);
+ constraint.install(this, scilabGraph);
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/OneBlockDependantAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/OneBlockDependantAction.java
new file mode 100755
index 000000000..993183438
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/OneBlockDependantAction.java
@@ -0,0 +1,31 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+/**
+ * Common class for actions that need at least 1 cell on the graph.
+ */
+public abstract class OneBlockDependantAction extends DefaultAction {
+ /**
+ * Default constructor
+ * @param scilabGraph the graph to work on
+ */
+ public OneBlockDependantAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ MinimalNumberOfCellsConstraint constraint = new MinimalNumberOfCellsConstraint(1);
+ constraint.install(this, scilabGraph);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/OneSelectionDependantAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/OneSelectionDependantAction.java
new file mode 100755
index 000000000..4c1fec61a
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/OneSelectionDependantAction.java
@@ -0,0 +1,38 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+/**
+ * Common class for multi-selection dependent actions.
+ *
+ * Children of this class will be activated when there something selected. If
+ * not, the action will be disabled.
+ */
+public abstract class OneSelectionDependantAction extends DefaultAction {
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * the associated graph
+ */
+ public OneSelectionDependantAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ if (scilabGraph != null) {
+ SelectedNumberOfCellsConstraint constraint = new SelectedNumberOfCellsConstraint(1);
+ constraint.install(this, scilabGraph);
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/SelectedNumberOfCellsConstraint.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/SelectedNumberOfCellsConstraint.java
new file mode 100755
index 000000000..af47f99db
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/SelectedNumberOfCellsConstraint.java
@@ -0,0 +1,64 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.view.mxGraphSelectionModel;
+
+/**
+ * Constraint which specify how many blocks must be selected on the block to
+ * enable the action.
+ */
+public class SelectedNumberOfCellsConstraint extends ActionConstraint {
+ private final int numberOfSelectedCells;
+
+ /**
+ * Default constructor
+ *
+ * @param numberOfSelectedCells
+ * The number of selected block needed to enable the action.
+ */
+ public SelectedNumberOfCellsConstraint(int numberOfSelectedCells) {
+ this.numberOfSelectedCells = numberOfSelectedCells;
+ }
+
+ /**
+ * Install
+ * @param action the action
+ * @param scilabGraph the graph
+ * @see org.scilab.modules.graph.actions.base.ActionConstraint#install(org.scilab.modules.graph.actions.base.DefaultAction,
+ * org.scilab.modules.graph.ScilabGraph)
+ */
+ @Override
+ public void install(DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+
+ scilabGraph.getSelectionModel().addListener(mxEvent.UNDO, this);
+ }
+
+ /**
+ * Update the enable state
+ * @param sender The sender of the event
+ * @param evt the event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object, com.mxgraph.util.mxEventObject)
+ */
+ public void invoke(Object sender, mxEventObject evt) {
+ mxGraphSelectionModel selection = (mxGraphSelectionModel) sender;
+ Object[] cells = selection.getCells();
+ setEnabled((cells != null) && (cells.length >= numberOfSelectedCells));
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/SpecificCellSelectedConstraint.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/SpecificCellSelectedConstraint.java
new file mode 100755
index 000000000..fb892e3dd
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/SpecificCellSelectedConstraint.java
@@ -0,0 +1,72 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+import com.mxgraph.model.mxCell;
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.view.mxGraphSelectionModel;
+
+/**
+ * Update a menu when a specific kind of cell is selected.
+ */
+public class SpecificCellSelectedConstraint extends ActionConstraint {
+ private final Class < ? extends mxCell > kind;
+
+ /**
+ * Default constructor
+ * @param kind The kind of cell which enable/disbale the action.
+ */
+ public SpecificCellSelectedConstraint(Class < ? extends mxCell > kind) {
+ this.kind = kind;
+ }
+
+ /**
+ * Install
+ *
+ * @param action
+ * the current action
+ * @param scilabGraph
+ * tthe scilab graph
+ * @see org.scilab.modules.graph.actions.base.ActionConstraint#install(org.scilab.modules.graph.actions.base.DefaultAction,
+ * org.scilab.modules.graph.ScilabGraph)
+ */
+ @Override
+ public void install(DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+
+ scilabGraph.getSelectionModel().addListener(mxEvent.UNDO, this);
+ }
+
+ /**
+ * @param sender the sender object
+ * @param evt the event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object, com.mxgraph.util.mxEventObject)
+ */
+ public void invoke(Object sender, mxEventObject evt) {
+ mxGraphSelectionModel selection = (mxGraphSelectionModel) sender;
+ Object[] cells = selection.getCells();
+
+ for (Object object : cells) {
+ if (kind.isInstance(object)) {
+ setEnabled(true);
+ return;
+ }
+ }
+
+ setEnabled(false);
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/actions/base/VertexSelectionDependantAction.java b/modules/graph/src/java/org/scilab/modules/graph/actions/base/VertexSelectionDependantAction.java
new file mode 100755
index 000000000..33b4b1c4a
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/actions/base/VertexSelectionDependantAction.java
@@ -0,0 +1,97 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.actions.base;
+
+import org.scilab.modules.graph.ScilabGraph;
+
+import com.mxgraph.model.mxCell;
+import com.mxgraph.util.mxEvent;
+import com.mxgraph.util.mxEventObject;
+import com.mxgraph.view.mxGraphSelectionModel;
+
+/**
+ * Common class for selection dependent actions.
+ *
+ * Children of this class will be activated when there something selected. If
+ * not, the action will be disabled.
+ */
+public abstract class VertexSelectionDependantAction extends DefaultAction {
+
+ /**
+ * Enable the selection if there is at least a vertex in the selection.
+ */
+ private final class VertexSelectionDependantConstraint extends ActionConstraint {
+
+ /**
+ * Default constructor
+ */
+ public VertexSelectionDependantConstraint() {
+ super();
+ }
+
+ /**
+ * @param action the action
+ * @param scilabGraph the current graph
+ * @see org.scilab.modules.graph.actions.base.ActionConstraint#install(org.scilab.modules.graph.actions.base.DefaultAction,
+ * org.scilab.modules.graph.ScilabGraph)
+ */
+ @Override
+ public void install(DefaultAction action, ScilabGraph scilabGraph) {
+ super.install(action, scilabGraph);
+
+ scilabGraph.getSelectionModel().addListener(mxEvent.UNDO, this);
+ }
+
+ /**
+ * @param sender the sender
+ * @param evt the event
+ * @see com.mxgraph.util.mxEventSource.mxIEventListener#invoke(java.lang.Object, com.mxgraph.util.mxEventObject)
+ */
+ public void invoke(Object sender, mxEventObject evt) {
+ mxGraphSelectionModel selection = (mxGraphSelectionModel) sender;
+ Object[] cells = selection.getCells();
+
+ boolean vertexFound = false;
+ if (cells != null) {
+ for (Object object : cells) {
+ if (object instanceof mxCell) {
+ mxCell cell = (mxCell) object;
+ vertexFound = cell.isVertex();
+ }
+
+ if (vertexFound) {
+ break;
+ }
+ }
+
+ setEnabled(vertexFound);
+ }
+ }
+
+ }
+
+ /**
+ * Default constructor
+ *
+ * @param scilabGraph
+ * The associated graph
+ */
+ public VertexSelectionDependantAction(ScilabGraph scilabGraph) {
+ super(scilabGraph);
+
+ if (scilabGraph != null) {
+ VertexSelectionDependantConstraint c = new VertexSelectionDependantConstraint();
+ c.install(this, scilabGraph);
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/event/ArrowKeyListener.java b/modules/graph/src/java/org/scilab/modules/graph/event/ArrowKeyListener.java
new file mode 100755
index 000000000..bbda53699
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/event/ArrowKeyListener.java
@@ -0,0 +1,212 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Clement DAVID
+ * Copyright (C) 2012 - Scilab Enterprises - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.event;
+
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.util.List;
+
+import javax.swing.Timer;
+
+import com.mxgraph.model.mxGeometry;
+import com.mxgraph.model.mxIGraphModel;
+import com.mxgraph.swing.mxGraphComponent;
+import com.mxgraph.util.mxPoint;
+import com.mxgraph.view.mxGraph;
+
+/**
+ * Move cells with the arrow keys.
+ */
+public final class ArrowKeyListener implements KeyListener {
+
+ private static final int DEFAULT_PIXEL_MOVE = 1;
+ private static final int MODIFIER_FACTOR = 5;
+ private static final int DEFAULT_DELAY = 800; // milliseconds
+
+ /* Configuration variables */
+ private final int pixelMove = DEFAULT_PIXEL_MOVE;
+ private int delay = DEFAULT_DELAY;
+
+ /* Runtime variables */
+ private double xIncrement;
+ private double yIncrement;
+ private mxGraph graph;
+
+ private final Timer repetitionTimer;
+ private final ActionListener doMove = new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent arg0) {
+ if (graph != null) {
+
+ final mxIGraphModel model = graph.getModel();
+ model.beginUpdate();
+ try {
+ for (Object cell : graph.getSelectionCells()) {
+ // first increment
+ graph.translateCell(cell, xIncrement, yIncrement);
+
+ // then align
+ final mxGeometry geom = model.getGeometry(cell);
+ model.setGeometry(cell, snap(graph, geom));
+ }
+ } finally {
+ model.endUpdate();
+ }
+
+ }
+ }
+ };
+
+ private static final mxGeometry snap(final mxGraph graph, final mxGeometry rect) {
+ final double x = graph.snap(rect.getX());
+ final double y = graph.snap(rect.getY());
+
+ final double width = graph.snap(rect.getWidth() - x + rect.getX());
+ final double height = graph.snap(rect.getHeight() - y + rect.getY());
+
+ final List<mxPoint> points = rect.getPoints();
+ if (points != null) {
+ for (final mxPoint p : points) {
+ p.setX(graph.snap(p.getX()));
+ p.setY(graph.snap(p.getY()));
+ }
+ }
+
+ final mxGeometry snappedGeom = new mxGeometry(x, y, width, height);
+ snappedGeom.setPoints(points);
+
+ return snappedGeom;
+ }
+
+ /**
+ * Constructor
+ */
+ public ArrowKeyListener() {
+ repetitionTimer = new Timer(delay, doMove);
+ repetitionTimer.setInitialDelay(0);
+ }
+
+ /**
+ * @param delay
+ * the delay to set
+ */
+ public void setDelay(int delay) {
+ this.delay = delay;
+ repetitionTimer.setDelay(delay);
+ }
+
+ /**
+ * @return the delay
+ */
+ public int getDelay() {
+ return delay;
+ }
+
+ /**
+ * Get the action parameters and start the action timer.
+ *
+ * @param e
+ * key event
+ */
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.isConsumed()) {
+ return;
+ }
+
+ int realMove;
+ boolean mustMove = true;
+
+ mxGraphComponent sourceDiagram = (mxGraphComponent) e.getSource();
+ graph = sourceDiagram.getGraph();
+
+ if (graph.isGridEnabled()) {
+ realMove = graph.getGridSize();
+ } else {
+ realMove = pixelMove;
+ }
+
+ if (e.getModifiers() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) {
+ realMove *= MODIFIER_FACTOR;
+ }
+
+ switch (e.getKeyCode()) {
+ case KeyEvent.VK_UP:
+ yIncrement = -realMove;
+ break;
+
+ case KeyEvent.VK_DOWN:
+ yIncrement = realMove;
+ break;
+
+ case KeyEvent.VK_RIGHT:
+ xIncrement = realMove;
+ break;
+
+ case KeyEvent.VK_LEFT:
+ xIncrement = -realMove;
+ break;
+
+ default:
+ mustMove = false;
+ break;
+ }
+
+ if (!mustMove) {
+ return;
+ }
+
+ if (!graph.isGridEnabled()) {
+ xIncrement *= sourceDiagram.getZoomFactor();
+ yIncrement *= sourceDiagram.getZoomFactor();
+ }
+
+ repetitionTimer.start();
+
+ e.consume();
+ }
+
+ /**
+ * Stop the action timer and clear parameters
+ *
+ * @param e
+ * key event
+ */
+ @Override
+ public void keyReleased(KeyEvent e) {
+ if (e.isConsumed()) {
+ return;
+ }
+
+ repetitionTimer.stop();
+ yIncrement = 0;
+ xIncrement = 0;
+ graph = null;
+
+ e.consume();
+ }
+
+ /**
+ * Not used there
+ *
+ * @param e
+ * Not used
+ */
+ @Override
+ public void keyTyped(KeyEvent e) {
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabBooleanCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabBooleanCodec.java
new file mode 100755
index 000000000..50163f4a6
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabBooleanCodec.java
@@ -0,0 +1,178 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.scilab.modules.types.ScilabBoolean;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodec;
+import com.mxgraph.io.mxCodecRegistry;
+
+/**
+ * Define serialization for a {@link ScilabBoolean} instance.
+ */
+public class ScilabBooleanCodec extends ScilabObjectCodec {
+
+ private static final String VALUE = "value";
+
+ /**
+ * Default constructor
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabBooleanCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+
+ }
+
+ /**
+ * Encodes the specified object and returns a node representing then given
+ * object. Calls beforeEncode after creating the node and afterEncode with
+ * the resulting node after processing.
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @return Returns the resulting XML node that represents the given object.
+ */
+ @Override
+ public Node encode(mxCodec enc, Object obj) {
+ String name = mxCodecRegistry.getName(obj);
+ Node node = enc.getDocument().createElement(name);
+
+ ScilabBoolean scilabBoolean = (ScilabBoolean) obj;
+
+ if (binary) {
+ int pos = binaryObjects.size();
+ binaryObjects.add(scilabBoolean);
+ mxCodec.setAttribute(node, BINARY, "true");
+ mxCodec.setAttribute(node, POSITION, pos);
+
+ return node;
+ }
+
+ mxCodec.setAttribute(node, WIDTH, scilabBoolean.getWidth());
+ mxCodec.setAttribute(node, HEIGHT, scilabBoolean.getHeight());
+
+ for (int i = 0; i < scilabBoolean.getHeight(); ++i) {
+ for (int j = 0; j < scilabBoolean.getWidth(); ++j) {
+ Node data = enc.getDocument().createElement(DATA);
+ mxCodec.setAttribute(data, LINE, i);
+ mxCodec.setAttribute(data, COLUMN, j);
+ mxCodec.setAttribute(data, VALUE, scilabBoolean.getData()[i][j]);
+ node.appendChild(data);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Parses the given node into the object or returns a new object
+ * representing the given node.
+ *
+ * @param dec
+ * Codec that controls the encoding process.
+ * @param node
+ * XML node to be decoded.
+ * @param into
+ * Optional object to encode the node into.
+ * @return Returns the resulting object that represents the given XML node
+ * or the object given to the method as the into parameter.
+ */
+ @Override
+ public Object decode(mxCodec dec, Node node, Object into) {
+ ScilabBoolean obj = null;
+
+ try {
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ throw new UnrecognizeFormatException();
+ }
+
+ // attrs = {"as", "height", "width", "binary", "position"}
+ final NamedNodeMap attrs = node.getAttributes();
+ if (attrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ if (getBooleanAttribute(attrs, BINARY)) {
+ return binaryObjects.get(getIntegerAttribute(attrs, POSITION));
+ }
+
+ obj = (ScilabBoolean) cloneTemplate(node);
+
+ final int height = getHeight(attrs);
+ final int width = getWidth(attrs);
+
+ if (height * width == 0) {
+ return obj;
+ }
+
+ final boolean[][] data = new boolean[height][width];
+ fillData(node, data);
+
+ obj.setData(data);
+
+ } catch (UnrecognizeFormatException e) {
+ Logger.getLogger(ScilabStringCodec.class.getName()).severe(e.toString());
+ } catch (NumberFormatException e) {
+ Logger.getLogger(ScilabStringCodec.class.getName()).severe(e.toString());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabBoolean node
+ * @param data
+ * the allocated data
+ * @throws UnrecognizeFormatException
+ * when we are unable to decode the node.
+ */
+ private void fillData(Node node, final boolean[][] data) throws UnrecognizeFormatException {
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node v = dataAttrs.getNamedItem(VALUE);
+ if (v == null) {
+ throw new UnrecognizeFormatException();
+ }
+ data[line][column] = Boolean.parseBoolean(v.getNodeValue());
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabDoubleCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabDoubleCodec.java
new file mode 100755
index 000000000..6811b4f67
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabDoubleCodec.java
@@ -0,0 +1,202 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.scilab.modules.types.ScilabDouble;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodec;
+import com.mxgraph.io.mxCodecRegistry;
+
+/**
+ * Define serialization for a {@link ScilabDouble} instance.
+ */
+public class ScilabDoubleCodec extends ScilabObjectCodec {
+
+ private static final String REALPART = "realPart";
+ private static final String IMGPART = "imaginaryPart";
+
+ /**
+ * Default constructor
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabDoubleCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+
+ }
+
+ /**
+ * Encodes the specified object and returns a node representing then given
+ * object. Calls beforeEncode after creating the node and afterEncode with
+ * the resulting node after processing.
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @return Returns the resulting XML node that represents the given object.
+ */
+ @Override
+ public Node encode(mxCodec enc, Object obj) {
+ String name = mxCodecRegistry.getName(obj);
+ Node node = enc.getDocument().createElement(name);
+
+ ScilabDouble scilabDouble = (ScilabDouble) obj;
+
+ if (binary) {
+ int pos = binaryObjects.size();
+ binaryObjects.add(scilabDouble);
+ mxCodec.setAttribute(node, BINARY, "true");
+ mxCodec.setAttribute(node, POSITION, pos);
+
+ return node;
+ }
+
+ mxCodec.setAttribute(node, WIDTH, scilabDouble.getWidth());
+ mxCodec.setAttribute(node, HEIGHT, scilabDouble.getHeight());
+
+ for (int i = 0; i < scilabDouble.getHeight(); ++i) {
+ for (int j = 0; j < scilabDouble.getWidth(); ++j) {
+ Node data = enc.getDocument().createElement(DATA);
+ mxCodec.setAttribute(data, LINE, i);
+ mxCodec.setAttribute(data, COLUMN, j);
+ if (scilabDouble.getRealPart() != null) {
+ mxCodec.setAttribute(data, REALPART, scilabDouble.getRealPart()[i][j]);
+ }
+ if (scilabDouble.getImaginaryPart() != null) {
+ final double[][] imag = scilabDouble.getImaginaryPart();
+ if (imag.length > i && imag[i].length > j) {
+ mxCodec.setAttribute(data, IMGPART, imag[i][j]);
+ }
+ }
+ node.appendChild(data);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Parses the given node into the object or returns a new object
+ * representing the given node.
+ *
+ * @param dec
+ * Codec that controls the encoding process.
+ * @param node
+ * XML node to be decoded.
+ * @param into
+ * Optional object to encode the node into.
+ * @return Returns the resulting object that represents the given XML node
+ * or the object given to the method as the into parameter.
+ */
+ @Override
+ public Object decode(mxCodec dec, Node node, Object into) {
+ ScilabDouble obj = null;
+
+ try {
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ throw new UnrecognizeFormatException();
+ }
+
+ // attrs = {"as", "height", "width", "binary", "position"}
+ final NamedNodeMap attrs = node.getAttributes();
+ if (attrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ if (getBooleanAttribute(attrs, BINARY)) {
+ return binaryObjects.get(getIntegerAttribute(attrs, POSITION));
+ }
+
+ obj = (ScilabDouble) cloneTemplate(node);
+
+ final int height = getHeight(attrs);
+ final int width = getWidth(attrs);
+
+ if (height * width == 0) {
+ return obj;
+ }
+
+ final double[][] realData = new double[height][width];
+ final double[][] imgData = new double[height][width];
+ final boolean isRealOnly = fillData(node, realData, imgData);
+
+ obj.setRealPart(realData);
+ if (!isRealOnly) {
+ obj.setImaginaryPart(imgData);
+ }
+
+ } catch (UnrecognizeFormatException e) {
+ Logger.getLogger(ScilabDoubleCodec.class.getName()).severe(e.toString());
+ } catch (NumberFormatException e) {
+ Logger.getLogger(ScilabDoubleCodec.class.getName()).severe(e.toString());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabDouble node
+ * @param realData
+ * the real data
+ * @param imgData
+ * the optional imaginary data
+ * @return true if the imaginary data is empty, false otherwise.
+ * @throws UnrecognizeFormatException
+ * on decoding error
+ */
+ private boolean fillData(Node node, double[][] realData, double[][] imgData) throws UnrecognizeFormatException {
+ boolean isRealOnly = true;
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node real = dataAttrs.getNamedItem(REALPART);
+ if (real == null) {
+ throw new UnrecognizeFormatException();
+ }
+ realData[line][column] = Double.parseDouble(real.getNodeValue());
+
+ final Node img = dataAttrs.getNamedItem(IMGPART);
+ if (img != null) {
+ isRealOnly = false;
+ imgData[line][column] = Double.parseDouble(img.getNodeValue());
+ }
+ }
+ return isRealOnly;
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabGraphCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabGraphCodec.java
new file mode 100755
index 000000000..c8ca88cbc
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabGraphCodec.java
@@ -0,0 +1,120 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2009 - DIGITEO - Allan SIMON
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.awt.Color;
+import java.util.Map;
+
+import org.scilab.modules.graph.ScilabGraph;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodec;
+import com.mxgraph.io.mxObjectCodec;
+
+/**
+ * Default codec for the graph component
+ */
+public class ScilabGraphCodec extends mxObjectCodec {
+ private static final String BACKGROUND = "background";
+
+ /**
+ * Default constructor
+ *
+ * @param template
+ * the object template
+ */
+ public ScilabGraphCodec(Object template) {
+ super(template);
+ }
+
+ /**
+ * The constructor used on for configuration
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabGraphCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+ }
+
+ /**
+ * Trace any msg to the xml document.
+ *
+ * @param enc
+ * the current encoder
+ * @param node
+ * the current node
+ * @param msg
+ * the message
+ * @param format
+ * the format
+ */
+ protected void trace(mxCodec enc, Node node, String msg, Object... format) {
+ node.appendChild(enc.getDocument().createComment(String.format(msg, format)));
+ }
+
+ /**
+ * Things to do before encoding
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @param node
+ * XML node to encode the object into.
+ * @return Returns the object to be encoded by the default encoding.
+ * @see com.mxgraph.io.mxObjectCodec#beforeEncode(com.mxgraph.io.mxCodec,
+ * java.lang.Object, org.w3c.dom.Node)
+ */
+ @Override
+ public Object beforeEncode(mxCodec enc, Object obj, Node node) {
+ final ScilabGraph graph = (ScilabGraph) obj;
+ if (graph.getAsComponent() != null) {
+ ((Element) node).setAttribute(BACKGROUND, String.valueOf(graph.getAsComponent().getBackground().getRGB()));
+ }
+ return super.beforeEncode(enc, obj, node);
+ }
+
+ /**
+ * Apply compatibility pattern to the decoded object
+ *
+ * @param dec
+ * Codec that controls the decoding process.
+ * @param node
+ * XML node to decode the object from.
+ * @param obj
+ * Object decoded.
+ * @return The Object transformed
+ * @see org.scilab.modules.xcos.io.codec.XcosObjectCodec#afterDecode(com.mxgraph.io.mxCodec,
+ * org.w3c.dom.Node, java.lang.Object)
+ */
+ @Override
+ public Object afterDecode(mxCodec dec, Node node, Object obj) {
+ final ScilabGraph graph = (ScilabGraph) obj;
+ final Element elem = (Element) node;
+ if (graph.getAsComponent() != null && !elem.getAttribute(BACKGROUND).isEmpty()) {
+ graph.getAsComponent().setBackground((new Color(Integer.parseInt((((Element) node).getAttribute(BACKGROUND))))));
+ }
+
+ return super.afterDecode(dec, node, obj);
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabIntegerCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabIntegerCodec.java
new file mode 100755
index 000000000..270afc6eb
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabIntegerCodec.java
@@ -0,0 +1,332 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.scilab.modules.types.ScilabInteger;
+import org.scilab.modules.types.ScilabIntegerTypeEnum;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodec;
+import com.mxgraph.io.mxCodecRegistry;
+
+/**
+ * Define serialization for a {@link ScilabInteger} instance.
+ */
+public class ScilabIntegerCodec extends ScilabObjectCodec {
+
+ private static final String BUNSIGNED = "bUnsigned"; /* With old IntegerType */
+ private static final String VALUE = "value";
+ private static final String PREC = "precision"; /* With old IntegerType */
+ private static final String PRECISION = "intPrecision"; /*
+ * with
+ * ScilabIntegerTypeEnum
+ */
+
+ /**
+ * Default constructor
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabIntegerCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+
+ }
+
+ /**
+ * Encodes the specified object and returns a node representing then given
+ * object. Calls beforeEncode after creating the node and afterEncode with
+ * the resulting node after processing.
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @return Returns the resulting XML node that represents the given object.
+ */
+ @Override
+ public Node encode(mxCodec enc, Object obj) {
+ String name = mxCodecRegistry.getName(obj);
+ Node node = enc.getDocument().createElement(name);
+
+ ScilabInteger scilabInteger = (ScilabInteger) obj;
+
+ if (binary) {
+ int pos = binaryObjects.size();
+ binaryObjects.add(scilabInteger);
+ mxCodec.setAttribute(node, BINARY, "true");
+ mxCodec.setAttribute(node, POSITION, pos);
+
+ return node;
+ }
+
+ mxCodec.setAttribute(node, WIDTH, scilabInteger.getWidth());
+ mxCodec.setAttribute(node, HEIGHT, scilabInteger.getHeight());
+ mxCodec.setAttribute(node, PRECISION, scilabInteger.getPrec().name());
+
+ for (int i = 0; i < scilabInteger.getHeight(); ++i) {
+ for (int j = 0; j < scilabInteger.getWidth(); ++j) {
+ Node data = enc.getDocument().createElement(DATA);
+ mxCodec.setAttribute(data, LINE, i);
+ mxCodec.setAttribute(data, COLUMN, j);
+ mxCodec.setAttribute(data, VALUE, scilabInteger.getData()[i][j]);
+ node.appendChild(data);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Parses the given node into the object or returns a new object
+ * representing the given node.
+ *
+ * @param dec
+ * Codec that controls the encoding process.
+ * @param node
+ * XML node to be decoded.
+ * @param into
+ * Optional object to encode the node into.
+ * @return Returns the resulting object that represents the given XML node
+ * or the object given to the method as the into parameter.
+ */
+ @Override
+ public Object decode(mxCodec dec, Node node, Object into) {
+ ScilabInteger obj = null;
+
+ try {
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ throw new UnrecognizeFormatException();
+ }
+
+ // attrs = {"as", "height", "width", "binary", "position"}
+ final NamedNodeMap attrs = node.getAttributes();
+ if (attrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ if (getBooleanAttribute(attrs, BINARY)) {
+ return binaryObjects.get(getIntegerAttribute(attrs, POSITION));
+ }
+
+ obj = (ScilabInteger) cloneTemplate(node);
+
+ final int height = getHeight(attrs);
+ final int width = getWidth(attrs);
+
+ if (height * width == 0) {
+ return obj;
+ }
+
+ /* Default values */
+ final Node precNode = attrs.getNamedItem(PRECISION);
+ ScilabIntegerTypeEnum precision;
+ if (precNode != null) {
+ precision = ScilabIntegerTypeEnum.valueOf(precNode.getNodeValue());
+ } else {
+ precision = ScilabIntegerTypeEnum.sci_uint8;
+ }
+
+ /* Compatibility for pre-5.2.2 version */
+ final Node prec = attrs.getNamedItem(PREC);
+ if (prec != null) {
+ /* Old version, we have to convert to the new one */
+ final Node u = attrs.getNamedItem(BUNSIGNED);
+ final boolean unsigned;
+ /*
+ * the default boolean value is false, this value is not
+ * serialized by jgraphx this if we doesn't have attribute the
+ * value is "false".
+ */
+ unsigned = u != null;
+
+ precision = ScilabInteger.convertOldType(prec.getNodeValue(), unsigned);
+
+ }
+
+ switch (precision) {
+ case sci_int8:
+ case sci_uint8:
+ final byte[][] data8 = new byte[height][width];
+ fillData(node, data8);
+ obj.setData(data8, precision == ScilabIntegerTypeEnum.sci_uint8);
+ break;
+ case sci_int16:
+ case sci_uint16:
+ final short[][] data16 = new short[height][width];
+ fillData(node, data16);
+ obj.setData(data16, precision == ScilabIntegerTypeEnum.sci_uint16);
+ break;
+ case sci_int32:
+ case sci_uint32:
+ final int[][] data32 = new int[height][width];
+ fillData(node, data32);
+ obj.setData(data32, precision == ScilabIntegerTypeEnum.sci_uint32);
+ break;
+ default:
+ final long[][] data64 = new long[height][width];
+ fillData(node, data64);
+ obj.setData(data64, precision == ScilabIntegerTypeEnum.sci_uint64);
+ break;
+ }
+
+ } catch (UnrecognizeFormatException e) {
+ Logger.getLogger(ScilabIntegerCodec.class.getName()).severe(e.toString());
+ } catch (NumberFormatException e) {
+ Logger.getLogger(ScilabIntegerCodec.class.getName()).severe(e.toString());
+ }
+ return obj;
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabInteger node
+ * @param data
+ * the allocated data
+ * @throws UnrecognizeFormatException
+ * when we are unable to decode the node.
+ */
+ private void fillData(Node node, byte[][] data) throws UnrecognizeFormatException {
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node v = dataAttrs.getNamedItem(VALUE);
+ if (v == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ data[line][column] = Byte.parseByte(v.getNodeValue());
+ }
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabInteger node
+ * @param data
+ * the allocated data
+ * @throws UnrecognizeFormatException
+ * when we are unable to decode the node.
+ */
+ private void fillData(Node node, short[][] data) throws UnrecognizeFormatException {
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node v = dataAttrs.getNamedItem(VALUE);
+ if (v == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ data[line][column] = Short.parseShort(v.getNodeValue());
+ }
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabInteger node
+ * @param data
+ * the allocated data
+ * @throws UnrecognizeFormatException
+ * when we are unable to decode the node.
+ */
+ private void fillData(Node node, int[][] data) throws UnrecognizeFormatException {
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node v = dataAttrs.getNamedItem(VALUE);
+ if (v == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ data[line][column] = Integer.parseInt(v.getNodeValue());
+ }
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabInteger node
+ * @param data
+ * the allocated data
+ * @throws UnrecognizeFormatException
+ * when we are unable to decode the node.
+ */
+ private void fillData(Node node, long[][] data) throws UnrecognizeFormatException {
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node v = dataAttrs.getNamedItem(VALUE);
+ if (v == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ data[line][column] = Long.parseLong(v.getNodeValue());
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabListCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabListCodec.java
new file mode 100755
index 000000000..e4b429f65
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabListCodec.java
@@ -0,0 +1,178 @@
+/*
+ * Scilab (http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2009 - DIGITEO - Allan SIMON
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.scilab.modules.types.ScilabList;
+import org.scilab.modules.types.ScilabMList;
+import org.scilab.modules.types.ScilabTList;
+import org.scilab.modules.types.ScilabType;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodec;
+import com.mxgraph.io.mxCodecRegistry;
+
+/**
+ * Define serialization for a {@link ScilabList} instance.
+ */
+public class ScilabListCodec extends ScilabObjectCodec {
+
+ private static final String SCILAB_CLASS = "scilabClass";
+
+ /**
+ * Default constructor
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabListCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+
+ }
+
+ /**
+ * Add the class name as an attribute.
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @param node
+ * XML node that represents the default encoding.
+ * @return Returns the resulting node of the encoding.
+ * @see com.mxgraph.io.mxObjectCodec#beforeEncode(com.mxgraph.io.mxCodec,
+ * java.lang.Object, org.w3c.dom.Node)
+ */
+ public Object beforeEncode(mxCodec enc, Object obj, Node node) {
+ if (!binary) {
+ String type = "";
+ for (Class <? extends Object > klass = obj.getClass(); klass != Object.class; klass = klass.getSuperclass()) {
+ if (klass == ScilabMList.class || klass == ScilabTList.class || klass == ScilabList.class || klass.isArray()) {
+ type = klass.getSimpleName();
+ break;
+ }
+ }
+
+ assert !type.equals("");
+ mxCodec.setAttribute(node, SCILAB_CLASS, type);
+ }
+
+ return obj;
+ }
+
+ /**
+ * Instantiate defined class for the attribute
+ *
+ * @param node
+ * the node we are working on
+ * @return the instance of the node.
+ * @see com.mxgraph.io.mxObjectCodec#cloneTemplate(org.w3c.dom.Node)
+ */
+ public Object cloneTemplate(Node node) {
+ Object obj = null;
+ if (node.getAttributes().getNamedItem(SCILAB_CLASS) != null) {
+ String scilabClass = node.getAttributes().getNamedItem(SCILAB_CLASS).getNodeValue();
+ if (scilabClass.equalsIgnoreCase("ScilabMList")) {
+ obj = new ScilabMList();
+ } else if (scilabClass.equalsIgnoreCase("ScilabTList")) {
+ obj = new ScilabTList();
+ } else if (scilabClass.equalsIgnoreCase("ScilabList")) {
+ obj = new ScilabList();
+ } else {
+
+ obj = super.cloneTemplate(node);
+ }
+
+ } else {
+ obj = super.cloneTemplate(node);
+ }
+
+ return obj;
+ }
+
+ /**
+ * Encodes the specified object and returns a node representing then given
+ * object. Calls beforeEncode after creating the node and afterEncode with
+ * the resulting node after processing.
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @return Returns the resulting XML node that represents the given object.
+ */
+ @Override
+ public Node encode(mxCodec enc, Object obj) {
+ String name = mxCodecRegistry.getName(obj);
+ Node node = enc.getDocument().createElement(name);
+
+ if (binary && (obj instanceof ScilabType)) {
+ int pos = binaryObjects.size();
+ binaryObjects.add((ScilabType) obj);
+ mxCodec.setAttribute(node, BINARY, "true");
+ mxCodec.setAttribute(node, POSITION, pos);
+
+ return node;
+ }
+
+ return super.encode(enc, obj);
+ }
+
+ /**
+ * Workaround for a jgraphx bug on deserialization with a possible abstract
+ * array and default value.
+ *
+ * @param dec
+ * the current decoder instance
+ * @param node
+ * the current node
+ * @param into
+ * the object decode into (may be a wrongly typed instance)
+ * @return a valid (right typed) instance
+ * @see com.mxgraph.io.mxObjectCodec#decode(com.mxgraph.io.mxCodec,
+ * org.w3c.dom.Node, java.lang.Object)
+ * @see http://www.jgraph.org/bugzilla/show_bug.cgi?id=55
+ * @see http://bugzilla.scilab.org/show_bug.cgi?id=8141
+ */
+ @Override
+ public Object decode(mxCodec dec, Node node, Object into) {
+ try {
+ final NamedNodeMap attrs = node.getAttributes();
+ if (attrs != null && getBooleanAttribute(attrs, BINARY)) {
+ return binaryObjects.get(getIntegerAttribute(attrs, POSITION));
+ }
+ } catch (UnrecognizeFormatException e) {
+ Logger.getLogger(ScilabDoubleCodec.class.getName()).severe(e.toString());
+ }
+
+ // Workaround case selection :
+ // - node is an "Array"
+ // - into (the default template) is not.
+ if (node.getNodeName().equals("Array") && into != null && !into.getClass().isArray()) {
+ return super.decode(dec, node, null);
+ } else {
+ return super.decode(dec, node, into);
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabObjectCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabObjectCodec.java
new file mode 100755
index 000000000..9ddb8397a
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabObjectCodec.java
@@ -0,0 +1,237 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.util.HashSet;
+import java.util.Map;
+
+import org.scilab.modules.types.ScilabBoolean;
+import org.scilab.modules.types.ScilabDouble;
+import org.scilab.modules.types.ScilabInteger;
+import org.scilab.modules.types.ScilabList;
+import org.scilab.modules.types.ScilabString;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodecRegistry;
+import com.mxgraph.io.mxObjectCodec;
+
+/**
+ * Codec for any Scilab object
+ */
+public abstract class ScilabObjectCodec extends mxObjectCodec {
+ /** Height of the data */
+ protected static final String HEIGHT = "height";
+ /** Width of the data */
+ protected static final String WIDTH = "width";
+ /** columns index of the data */
+ protected static final String COLUMN = "column";
+ /** line index of the data */
+ protected static final String LINE = "line";
+ /** Data field */
+ protected static final String DATA = "data";
+
+ protected static final String POSITION = "position";
+ protected static final String BINARY = "binary";
+
+ protected static boolean binary;
+ protected static ScilabList binaryObjects;
+ protected static final Object LOCK = new Object();;
+
+ /**
+ * Throw when we cannot load the XML.
+ */
+ @SuppressWarnings(value = { "serial" })
+ public class UnrecognizeFormatException extends Exception {
+ /**
+ * Default constructor
+ */
+ public UnrecognizeFormatException() {
+ super();
+ }
+
+ /**
+ * Constructor from another exception
+ *
+ * @param cause
+ * the source exception.
+ */
+ public UnrecognizeFormatException(Exception cause) {
+ super(cause);
+ }
+ }
+
+ /**
+ * The constructor used on the configuration
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabObjectCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+
+ final HashSet<String> newExclude = new HashSet<String>(this.exclude);
+ newExclude.add("type");
+ this.exclude = newExclude;
+
+ }
+
+ public static Object enableBinarySerialization(ScilabList list) {
+ synchronized (LOCK) {
+ binary = true;
+ if (list == null) {
+ binaryObjects = new ScilabList();
+ } else {
+ binaryObjects = list;
+ }
+
+ return LOCK;
+ }
+ }
+
+ public static ScilabList disableBinarySerialization() {
+ synchronized (LOCK) {
+ binary = false;
+ ScilabList ret = binaryObjects;
+ binaryObjects = null;
+
+ return ret;
+ }
+ }
+
+ public static ScilabList getBinaryObjects() {
+ return binaryObjects;
+ }
+
+ /**
+ * Register all known codecs on the {@link mxCodecRegistry}.
+ */
+ public static void register() {
+ ScilabObjectCodec scilabStringCodec = new ScilabStringCodec(new ScilabString(), null, null, null);
+ mxCodecRegistry.register(scilabStringCodec);
+ ScilabObjectCodec scilabBooleanCodec = new ScilabBooleanCodec(new ScilabBoolean(), null, null, null);
+ mxCodecRegistry.register(scilabBooleanCodec);
+ ScilabObjectCodec scilabDoubleCodec = new ScilabDoubleCodec(new ScilabDouble(), null, null, null);
+ mxCodecRegistry.register(scilabDoubleCodec);
+ ScilabObjectCodec scilabIntegerCodec = new ScilabIntegerCodec(new ScilabInteger(), null, null, null);
+ mxCodecRegistry.register(scilabIntegerCodec);
+
+ ScilabObjectCodec scilabListCodec = new ScilabListCodec(new ScilabList(), new String[] { "scilabClass" }, null, null);
+ mxCodecRegistry.register(scilabListCodec);
+ }
+
+ /**
+ * get an integer value from a attributes.
+ *
+ * @param dataAttrs
+ * the attributes
+ * @param attribute
+ * the key to search
+ * @return the value
+ * @throws UnrecognizeFormatException
+ * when the key is not valid.
+ */
+ protected int getIntegerAttribute(final NamedNodeMap dataAttrs, final String attribute) throws UnrecognizeFormatException {
+ final Node node = dataAttrs.getNamedItem(attribute);
+ if (node == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int value;
+ try {
+ value = Integer.parseInt(node.getNodeValue());
+ } catch (NumberFormatException e) {
+ throw new UnrecognizeFormatException(e);
+ }
+ return value;
+ }
+
+ /**
+ * get an integer value from a attributes.
+ *
+ * @param dataAttrs
+ * the attributes
+ * @param attribute
+ * the key to search
+ * @return the value
+ * @throws UnrecognizeFormatException
+ * when the key is not valid.
+ */
+ protected boolean getBooleanAttribute(final NamedNodeMap dataAttrs, final String attribute) {
+ final Node node = dataAttrs.getNamedItem(attribute);
+ if (node == null) {
+ return false;
+ }
+
+ return Boolean.parseBoolean(node.getNodeValue());
+ }
+
+ /**
+ * Get the height of the data attributes.
+ *
+ * @param attrs
+ * the data attributes
+ * @return the height
+ * @throws UnrecognizeFormatException
+ * when the height hasn't been found.
+ */
+ protected int getHeight(final NamedNodeMap attrs) throws UnrecognizeFormatException {
+ return getIntegerAttribute(attrs, HEIGHT);
+ }
+
+ /**
+ * Get the width of the data attributes.
+ *
+ * @param attrs
+ * the data attributes
+ * @return the width
+ * @throws UnrecognizeFormatException
+ * when the width hasn't been found.
+ */
+ protected int getWidth(final NamedNodeMap attrs) throws UnrecognizeFormatException {
+ return getIntegerAttribute(attrs, WIDTH);
+ }
+
+ /**
+ * Get the column index of the data attributes.
+ *
+ * @param dataAttrs
+ * the data attributes
+ * @return the column index
+ * @throws UnrecognizeFormatException
+ * when the column index hasn't been found.
+ */
+ protected int getColumnIndex(final NamedNodeMap dataAttrs) throws UnrecognizeFormatException {
+ return getIntegerAttribute(dataAttrs, COLUMN);
+ }
+
+ /**
+ * Get the line index of the data attributes.
+ *
+ * @param dataAttrs
+ * the data attributes
+ * @return the column index
+ * @throws UnrecognizeFormatException
+ * when the column index hasn't been found.
+ */
+ protected int getLineIndex(final NamedNodeMap dataAttrs) throws UnrecognizeFormatException {
+ return getIntegerAttribute(dataAttrs, LINE);
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/io/ScilabStringCodec.java b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabStringCodec.java
new file mode 100755
index 000000000..90f666d7d
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/io/ScilabStringCodec.java
@@ -0,0 +1,178 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009-2009 - DIGITEO - Bruno JOFRET
+ * Copyright (C) 2010-2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.io;
+
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.scilab.modules.types.ScilabString;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.mxgraph.io.mxCodec;
+import com.mxgraph.io.mxCodecRegistry;
+
+/**
+ * Define serialization for a {@link ScilabString} instance.
+ */
+public class ScilabStringCodec extends ScilabObjectCodec {
+
+ private static final String VALUE = "value";
+
+ /**
+ * Default constructor
+ *
+ * @param template
+ * Prototypical instance of the object to be encoded/decoded.
+ * @param exclude
+ * Optional array of fieldnames to be ignored.
+ * @param idrefs
+ * Optional array of fieldnames to be converted to/from
+ * references.
+ * @param mapping
+ * Optional mapping from field- to attributenames.
+ */
+ public ScilabStringCodec(Object template, String[] exclude, String[] idrefs, Map<String, String> mapping) {
+ super(template, exclude, idrefs, mapping);
+ }
+
+ /**
+ * Encodes the specified object and returns a node representing then given
+ * object. Calls beforeEncode after creating the node and afterEncode with
+ * the resulting node after processing.
+ *
+ * @param enc
+ * Codec that controls the encoding process.
+ * @param obj
+ * Object to be encoded.
+ * @return Returns the resulting XML node that represents the given object.
+ */
+ @Override
+ public Node encode(mxCodec enc, Object obj) {
+ String name = mxCodecRegistry.getName(obj);
+ Node node = enc.getDocument().createElement(name);
+
+ ScilabString scilabString = (ScilabString) obj;
+
+ if (binary) {
+ int pos = binaryObjects.size();
+ binaryObjects.add(scilabString);
+ mxCodec.setAttribute(node, BINARY, "true");
+ mxCodec.setAttribute(node, POSITION, pos);
+
+ return node;
+ }
+
+ mxCodec.setAttribute(node, WIDTH, scilabString.getWidth());
+ mxCodec.setAttribute(node, HEIGHT, scilabString.getHeight());
+
+ for (int i = 0; i < scilabString.getHeight(); ++i) {
+ for (int j = 0; j < scilabString.getWidth(); ++j) {
+ Node data = enc.getDocument().createElement(DATA);
+ mxCodec.setAttribute(data, LINE, i);
+ mxCodec.setAttribute(data, COLUMN, j);
+ mxCodec.setAttribute(data, VALUE, scilabString.getData()[i][j]);
+ node.appendChild(data);
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Parses the given node into the object or returns a new object
+ * representing the given node.
+ *
+ * @param dec
+ * Codec that controls the encoding process.
+ * @param node
+ * XML node to be decoded.
+ * @param into
+ * Optional object to encode the node into.
+ * @return Returns the resulting object that represents the given XML node
+ * or the object given to the method as the into parameter.
+ */
+ @Override
+ public Object decode(mxCodec dec, Node node, Object into) {
+ ScilabString obj = null;
+
+ try {
+ if (node.getNodeType() != Node.ELEMENT_NODE) {
+ throw new UnrecognizeFormatException();
+ }
+
+ // attrs = {"as", "height", "width", "binary", "position"}
+ final NamedNodeMap attrs = node.getAttributes();
+ if (attrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ if (getBooleanAttribute(attrs, BINARY)) {
+ return binaryObjects.get(getIntegerAttribute(attrs, POSITION));
+ }
+
+ obj = (ScilabString) cloneTemplate(node);
+
+ final int height = getHeight(attrs);
+ final int width = getWidth(attrs);
+
+ if (height * width == 0) {
+ return obj;
+ }
+
+ final String[][] data = new String[height][width];
+ fillData(node, data);
+
+ obj.setData(data);
+
+ } catch (UnrecognizeFormatException e) {
+ Logger.getLogger(ScilabStringCodec.class.getName()).severe(e.toString());
+ } catch (NumberFormatException e) {
+ Logger.getLogger(ScilabStringCodec.class.getName()).severe(e.toString());
+ }
+
+ return obj;
+ }
+
+ /**
+ * Fill the data from the node.
+ *
+ * @param node
+ * the ScilabString node
+ * @param data
+ * the allocated data
+ * @throws UnrecognizeFormatException
+ * when we are unable to decode the node.
+ */
+ private void fillData(Node node, final String[][] data) throws UnrecognizeFormatException {
+ for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) {
+ if (n.getNodeType() != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ final NamedNodeMap dataAttrs = n.getAttributes();
+ if (dataAttrs == null) {
+ throw new UnrecognizeFormatException();
+ }
+
+ final int column = getColumnIndex(dataAttrs);
+ final int line = getLineIndex(dataAttrs);
+
+ final Node v = dataAttrs.getNamedItem(VALUE);
+ if (v == null) {
+ throw new UnrecognizeFormatException();
+ }
+ data[line][column] = v.getNodeValue();
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/shape/LatexTextShape.java b/modules/graph/src/java/org/scilab/modules/graph/shape/LatexTextShape.java
new file mode 100755
index 000000000..a4c495cd4
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/shape/LatexTextShape.java
@@ -0,0 +1,115 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.shape;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.util.Map;
+
+import javax.swing.CellRendererPane;
+import javax.swing.Icon;
+
+import org.scilab.modules.graph.utils.ScilabGraphUtils;
+
+import com.mxgraph.canvas.mxGraphics2DCanvas;
+import com.mxgraph.shape.mxITextShape;
+import com.mxgraph.util.mxConstants;
+import com.mxgraph.util.mxRectangle;
+import com.mxgraph.util.mxUtils;
+import com.mxgraph.view.mxCellState;
+
+/**
+ * Implement a text shape that can draw LaTEX text.
+ */
+public class LatexTextShape implements mxITextShape {
+
+ /**
+ * Painter
+ *
+ * @param canvas
+ * the current canvas
+ * @param text
+ * the text to render
+ * @param state
+ * the current state
+ * @param style
+ * the current style
+ * @see com.mxgraph.shape.mxITextShape#paintShape(com.mxgraph.canvas.mxGraphics2DCanvas,
+ * java.lang.String, com.mxgraph.util.mxRectangle, java.util.Map)
+ */
+ @Override
+ public void paintShape(mxGraphics2DCanvas canvas, String text, mxCellState state, Map<String, Object> style) {
+
+ CellRendererPane rendererPane = canvas.getRendererPane();
+ mxRectangle rect = state.getLabelBounds();
+ Graphics2D g = canvas.getGraphics();
+
+ if (rendererPane != null && (g.getClipBounds() == null || g.getClipBounds().intersects(rect.getRectangle()))) {
+ final double scale = canvas.getScale();
+ final double x = rect.getX();
+ final double y = rect.getY();
+ final double w = rect.getWidth();
+ final double h = rect.getHeight();
+
+ AffineTransform at = g.getTransform();
+
+ // handle text color
+ Color textColor = mxUtils.getColor(style, mxConstants.STYLE_FONTCOLOR, Color.BLACK);
+ rendererPane.setForeground(textColor);
+
+ // TODO: handle horizontal align
+ final Object align = mxUtils.getString(style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
+ final double horizAlignProportion;
+ if (align.equals(mxConstants.ALIGN_LEFT)) {
+ horizAlignProportion = 0;
+ } else if (align.equals(mxConstants.ALIGN_RIGHT)) {
+ horizAlignProportion = 1.0;
+ } else {
+ horizAlignProportion = 0.5;
+ }
+
+ // TODO: handle vertical align
+ final Object vertAlign = mxUtils.getString(style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
+ final double vertAlignProportion;
+ if (vertAlign.equals(mxConstants.ALIGN_TOP)) {
+ vertAlignProportion = 0;
+ } else if (vertAlign.equals(mxConstants.ALIGN_BOTTOM)) {
+ vertAlignProportion = 1.0;
+ } else {
+ vertAlignProportion = 0.5;
+ }
+
+ // parse the text and cache it if valid. Will throw an exception
+ // if the text is not valid but the text must have been already
+ // checked on ScilabCanvas#getTextShape(...).
+ float fontSize = (float) (mxUtils.getInt(style, mxConstants.STYLE_FONTSIZE, 16) * scale);
+ final Icon icon = ScilabGraphUtils.getTexIcon(text, fontSize);
+ // the icon is generated scaled so width and height are already scaled
+ final double ih = icon.getIconHeight();
+ final double iw = icon.getIconWidth();
+
+
+ double dx = (iw - w) / 2;
+ double dy = (ih - h) / 2;
+
+ icon.paintIcon(rendererPane, g,
+ (int) (x + dx) + mxConstants.LABEL_INSET ,
+ (int) (y + dy) + mxConstants.LABEL_INSET);
+
+ // Restores the previous transformation
+ g.setTransform(at);
+ }
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/shape/MathMLTextShape.java b/modules/graph/src/java/org/scilab/modules/graph/shape/MathMLTextShape.java
new file mode 100755
index 000000000..8608da2b7
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/shape/MathMLTextShape.java
@@ -0,0 +1,89 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.shape;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import javax.swing.CellRendererPane;
+
+import org.scilab.modules.graph.utils.MathMLRenderUtils;
+import org.xml.sax.SAXException;
+
+import com.mxgraph.canvas.mxGraphics2DCanvas;
+import com.mxgraph.shape.mxITextShape;
+import com.mxgraph.util.mxConstants;
+import com.mxgraph.util.mxUtils;
+import com.mxgraph.view.mxCellState;
+
+/**
+ * Implement a text shape that can draw MathML text.
+ *
+ */
+public class MathMLTextShape implements mxITextShape {
+
+ /**
+ * Painter
+ *
+ * @param canvas
+ * the current canvas
+ * @param text
+ * the text to render
+ * @param state
+ * the current state
+ * @param style
+ * the current style
+ * @see com.mxgraph.shape.mxITextShape#paintShape(com.mxgraph.canvas.mxGraphics2DCanvas,
+ * java.lang.String, com.mxgraph.util.mxRectangle, java.util.Map)
+ */
+ @Override
+ public void paintShape(mxGraphics2DCanvas canvas, String text, mxCellState state, Map<String, Object> style) {
+
+ CellRendererPane rendererPane = canvas.getRendererPane();
+ Rectangle rect = state.getRectangle();
+ Graphics2D g = canvas.getGraphics();
+
+ if (rendererPane != null && (g.getClipBounds() == null || g.getClipBounds().intersects(rect))) {
+ double scale = canvas.getScale();
+ int x = rect.x;
+ int y = rect.y;
+ int w = rect.width;
+ int h = rect.height;
+
+ if (g.hitClip(x, y, w, h)) {
+ AffineTransform at = g.getTransform();
+
+ g.scale(scale, scale);
+ Color textColor = mxUtils.getColor(style, mxConstants.STYLE_FONTCOLOR, Color.BLACK);
+ rendererPane.setForeground(textColor);
+
+ try {
+ Component comp = MathMLRenderUtils.getMathMLComponent(text);
+ rendererPane.paintComponent(g, comp, rendererPane, (int) (x / scale) + mxConstants.LABEL_INSET,
+ (int) (y / scale) + mxConstants.LABEL_INSET, (int) (w / scale), (int) (h / scale), true);
+
+ // Restores the previous transformation
+ g.setTransform(at);
+ } catch (SAXException e) {
+ Logger.getLogger(MathMLTextShape.class.getName()).severe(e.toString());
+ }
+ }
+ }
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/shape/SvgShape.java b/modules/graph/src/java/org/scilab/modules/graph/shape/SvgShape.java
new file mode 100755
index 000000000..0365f1219
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/shape/SvgShape.java
@@ -0,0 +1,85 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010-2010 - DIGITEO - Clement DAVID <clement.david@scilab.org>
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.shape;
+
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+
+import org.apache.batik.ext.awt.RenderingHintsKeyExt;
+import org.scilab.modules.graph.ScilabCanvas;
+
+import com.mxgraph.canvas.mxGraphics2DCanvas;
+import com.mxgraph.shape.mxLabelShape;
+import com.mxgraph.util.mxConstants;
+import com.mxgraph.util.mxUtils;
+import com.mxgraph.view.mxCellState;
+
+/**
+ * Add the SVG capability to the standard Image shape
+ */
+public class SvgShape extends mxLabelShape {
+ /**
+ * Paint the shape
+ *
+ * @param canvas the current canvas
+ * @param state the current state
+ * @see com.mxgraph.shape.mxImageShape#paintShape(com.mxgraph.canvas.mxGraphics2DCanvas, com.mxgraph.view.mxCellState)
+ */
+ @Override
+ public void paintShape(mxGraphics2DCanvas canvas, mxCellState state) {
+ // paint previously set background
+ super.paintShape(canvas, state);
+
+ final String image = getImageForStyle(canvas, state);
+ if (image != null && image.endsWith(".svg")) {
+ // Remove the "Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint"
+ // message and tweak Batik rendering options to increase performance.
+ canvas.getGraphics().setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ canvas.getGraphics().setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+ canvas.getGraphics().setRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING, RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING);
+
+ final Rectangle rect = getImageBounds(canvas, state);
+ canvas.getGraphics().translate(rect.x, rect.y);
+
+ ((ScilabCanvas) canvas).paintSvgForegroundImage(rect.width, rect.height, image);
+
+ if (mxUtils.isTrue(state.getStyle(), mxConstants.STYLE_GLASS, false)) {
+ drawGlassEffect(canvas, state);
+ }
+ } else {
+ super.paintShape(canvas, state);
+ }
+ }
+
+ /**
+ * Get the image bounds for an SVG image
+ *
+ * @param canvas the current canvas
+ * @param state the current state
+ * @return the bounds of the image
+ * @see com.mxgraph.shape.mxImageShape#getImageBounds(com.mxgraph.canvas.mxGraphics2DCanvas, com.mxgraph.view.mxCellState)
+ */
+ @Override
+ public Rectangle getImageBounds(mxGraphics2DCanvas canvas, mxCellState state) {
+ final double rotation = mxUtils.getDouble(state.getStyle(),
+ mxConstants.STYLE_ROTATION, 0);
+ final AffineTransform transform = new AffineTransform();
+ transform.rotate(Math.toRadians(rotation), state.getCenterX(),
+ state.getCenterY());
+ final Shape shape = transform.createTransformedShape(state
+ .getRectangle());
+ return shape.getBounds();
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/Font.java b/modules/graph/src/java/org/scilab/modules/graph/utils/Font.java
new file mode 100755
index 000000000..27719f978
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/Font.java
@@ -0,0 +1,181 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) DIGITEO - 2010-2010 - Clement DAVID <clement.david@scilab.org>
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import java.awt.Color;
+
+import com.mxgraph.util.mxConstants;
+
+/**
+ * Font list from Scilab xlfont().
+ */
+public enum Font {
+ /** xlfont(0) */
+ COURIER(java.awt.Font.MONOSPACED),
+ /** xlfont(1) */
+ SYMBOL(java.awt.Font.DIALOG),
+ /** xlfont(2) */
+ SERIF(java.awt.Font.SERIF),
+ /** xlfont(3) */
+ SERIF_ITALIC(java.awt.Font.SERIF, mxConstants.FONT_ITALIC),
+ /** xlfont(4) */
+ SERIF_BOLD(java.awt.Font.SERIF, mxConstants.FONT_BOLD),
+ /** xlfont(5) */
+ SERIF_BOLD_ITALIC(java.awt.Font.SERIF, mxConstants.FONT_BOLD
+ + mxConstants.FONT_ITALIC),
+ /** xlfont(6) */
+ SANS_SERIF(java.awt.Font.SANS_SERIF),
+ /** xlfont(7) */
+ SANS_SERIF_ITALIC(java.awt.Font.SANS_SERIF, mxConstants.FONT_ITALIC),
+ /** xlfont(8) */
+ SANS_SERIF_BOLD(java.awt.Font.SANS_SERIF, mxConstants.FONT_BOLD),
+ /** xlfont(9) */
+ SANS_SERIF_BOLD_ITALIC(java.awt.Font.SANS_SERIF, mxConstants.FONT_BOLD
+ + mxConstants.FONT_ITALIC);
+
+ private static final Color[] COLORMAP = new Color[] {
+ Color.BLACK,
+ Color.BLUE, Color.GREEN, Color.CYAN, Color.RED, Color.MAGENTA,
+ Color.YELLOW, Color.WHITE, new Color(0, 0, 144),
+ new Color(0, 0, 176), new Color(0, 0, 208),
+ new Color(135, 206, 255), new Color(0, 144, 0),
+ new Color(0, 176, 0), new Color(0, 208, 0), new Color(0, 144, 0),
+ new Color(0, 144, 144), new Color(0, 176, 176),
+ new Color(0, 208, 208), new Color(144, 0, 0), new Color(176, 0, 0),
+ new Color(208, 0, 0), new Color(144, 0, 144),
+ new Color(176, 0, 176), new Color(208, 0, 208),
+ new Color(128, 48, 0), new Color(160, 64, 0),
+ new Color(192, 96, 0), new Color(255, 128, 128),
+ new Color(255, 160, 160), new Color(255, 192, 192),
+ new Color(255, 224, 224), new Color(255, 215, 0)
+ };
+
+ private final String name;
+ private final int modifiers;
+
+ /**
+ * Default constructor.
+ *
+ * @param name
+ * the name of the font
+ */
+ private Font(String name) {
+ this(name, 0);
+ }
+
+ /**
+ * Cstr
+ *
+ * @param name
+ * the name of the font
+ * @param modifiers
+ * the modifiers value
+ */
+ private Font(String name, int modifiers) {
+ this.name = name;
+ this.modifiers = modifiers;
+ }
+
+ /*
+ * Static methods
+ */
+
+ /**
+ * Return the Font for a given Scilab index
+ *
+ * @param index
+ * the index
+ * @return the associated font
+ */
+ public static Font getFont(int index) {
+ return Font.values()[index % Font.values().length];
+ }
+
+ /**
+ * Map a Scilab size to a Java font size.
+ *
+ * @param scilabSize
+ * the size of the font (using getfont)
+ * @return the corresponding java size
+ */
+ // CSOFF: MagicNumber
+ public static int getSize(int scilabSize) {
+ final int ret;
+ if (scilabSize <= 0) {
+ ret = 0;
+ } else if (scilabSize < 1) {
+ ret = (13 * scilabSize);
+ } else if (scilabSize > 4) {
+ ret = (7 * (scilabSize - 4) + 17);
+ } else {
+ ret = (int) (13 + 1.2 * (scilabSize - 1));
+ }
+ return ret;
+ }
+
+ // CSON: MagicNumber
+
+ /**
+ * Map a Scilab color to a Java color.
+ *
+ * @param scilabColor
+ * the color of the font (using getcolor)
+ * @return the corresponding java color
+ */
+ // CSOFF: MagicNumber
+ public static Color getColor(int scilabColor) {
+ return COLORMAP[scilabColor % COLORMAP.length];
+ }
+
+ // CSON: MagicNumber
+
+ /**
+ * Map a Scilab size to a Java font size.
+ *
+ * @param scilabSize
+ * the size of the font (using getfont)
+ * @return the corresponding java size
+ */
+ public static int getSize(String scilabSize) {
+ return getSize(Integer.parseInt(scilabSize));
+ }
+
+ /**
+ * Map a Scilab color to a Java color.
+ *
+ * @param scilabColor
+ * the color of the font (using getcolor)
+ * @return the corresponding java color
+ */
+ public static Color getColor(String scilabColor) {
+ return getColor(Integer.parseInt(scilabColor));
+ }
+
+ /*
+ * Accessors
+ */
+
+ /**
+ * @return the name of the font
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return the modifiers
+ */
+ public int getModifiers() {
+ return modifiers;
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/MathMLRenderUtils.java b/modules/graph/src/java/org/scilab/modules/graph/utils/MathMLRenderUtils.java
new file mode 100755
index 000000000..2a3d7c491
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/MathMLRenderUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import net.sourceforge.jeuclid.swing.JMathComponent;
+
+import org.scilab.modules.graph.view.SupportedLabelType;
+import org.w3c.dom.Document;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Contains useful method for rendering a MathML formula.
+ *
+ * Before accessing this class you must load the jeuclid.jar file on the
+ * classpath.
+ */
+public final class MathMLRenderUtils {
+ /**
+ * Cache for the generated MathML components
+ */
+ private static Map<String, JMathComponent> generatedMathMLComponents = new WeakHashMap<String, JMathComponent>();
+
+ /**
+ * Return a cached or a new instance of a JMathComponent generated from
+ * text.
+ * @param text the MathML formula
+ * @return the {@link JMathComponent} instance
+ * @throws SAXException when the text is not a valid XML file
+ */
+ public static Component getMathMLComponent(String text) throws SAXException {
+ String escapedText = SupportedLabelType.MathML.escape(text);
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder;
+ Document doc;
+ JMathComponent comp;
+
+ comp = generatedMathMLComponents.get(text);
+ if (comp == null) {
+ try {
+ builder = factory.newDocumentBuilder();
+ doc = builder.parse(new InputSource(new StringReader(escapedText)));
+ comp = new JMathComponent();
+ comp.setDocument(doc.getFirstChild());
+ generatedMathMLComponents.put(text, comp);
+ } catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return comp;
+ }
+
+ /**
+ * This class is a static singleton
+ */
+ private MathMLRenderUtils() { }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabExported.java b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabExported.java
new file mode 100755
index 000000000..45eea06e9
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabExported.java
@@ -0,0 +1,34 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to specify that this method is exported to JNI via giws.
+ */
+@Target( { ElementType.METHOD, ElementType.CONSTRUCTOR })
+public @interface ScilabExported {
+ /**
+ * The module where the giws file and generated implementations are
+ * presents, eg "xcos" for SCI/modules/xcos/src/jni/Xcos.giws.xml .
+ */
+ String module();
+
+ /**
+ * Giws file name, eg "Xcos.giws.xml" for
+ * SCI/modules/xcos/src/jni/Xcos.giws.xml .
+ */
+ String filename();
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphConstants.java b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphConstants.java
new file mode 100755
index 000000000..7c48b9eab
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphConstants.java
@@ -0,0 +1,78 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import com.mxgraph.util.mxConstants;
+
+/**
+ * Define all the constants used on a Scilab graph
+ */
+public class ScilabGraphConstants extends mxConstants {
+
+ /**
+ * Defines the size of the arcs for rounded edges. Default is 10.
+ */
+ public static final double LINE_ARCSIZE = 200;
+
+ /**
+ * Defines the key for the centerArrow style.
+ */
+ public static final String STYLE_CENTERARROW = "centerArrow";
+
+ /**
+ * Defines the key for the centerSize style. The type of this value is
+ * <code>float</code> and the value represents the size of the center
+ * marker in pixels.
+ */
+ public static final String STYLE_CENTERSIZE = "centerSize";
+
+ /**
+ * Defines the value for spline edge shape
+ */
+ public static final String SHAPE_SPLINE = "spline";
+ /**
+ * Defines the value if we want the arrow to be centered
+ */
+ public static final String ARROW_POSITION_CENTER = "center";
+
+ /**
+ * Defines the key for flip image .
+ */
+ public static final String STYLE_FLIP = "flip";
+
+ /**
+ * Defines the key for mirror image .
+ */
+ public static final String STYLE_MIRROR = "mirror";
+
+ /* HTML */
+ /**
+ * The html begin symbol
+ */
+ public static final String HTML_BEGIN = "<html>";
+ /**
+ * The html end symbol
+ */
+ public static final String HTML_END = "</html>";
+ /**
+ * The html new line symbol
+ */
+ public static final String HTML_NEWLINE = "<br>";
+
+ /* Events */
+ /** Name of the edit event */
+ public static final String EVENT_CHANGE_EDIT = "edit";
+
+ /** This class is a static singleton, thus it must not be instantiated */
+ protected ScilabGraphConstants() { }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphMessages.java b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphMessages.java
new file mode 100755
index 000000000..c21f94ca1
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphMessages.java
@@ -0,0 +1,40 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+package org.scilab.modules.graph.utils;
+
+import org.scilab.modules.localization.Messages;
+
+/**
+ * Internationalized messages for this graph
+ */
+public final class ScilabGraphMessages {
+
+ public static final String COPY = Messages.gettext("Copy");
+ public static final String CUT = Messages.gettext("Cut");
+ public static final String GROUP = Messages.gettext("Group");
+ public static final String UNGROUP = Messages.gettext("UnGroup");
+ public static final String PASTE = Messages.gettext("Paste");
+ public static final String REDO = Messages.gettext("Redo");
+ public static final String UNDO = Messages.gettext("Undo");
+ public static final String ZOOM_IN = Messages.gettext("Zoom In");
+ public static final String ZOOM_OUT = Messages.gettext("Zoom Out");
+ public static final String DELETE = Messages.gettext("Delete");
+ public static final String SELECT_ALL = Messages.gettext("Select all");
+ public static final String INVERT_SELECTION = Messages.gettext("Invert selection");
+ public static final String UNTITLED = Messages.gettext("Untitled - %s");
+
+ /** This class is a static singleton, thus it must not be instantiated */
+ private ScilabGraphMessages() {
+ }
+
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphRenderer.java b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphRenderer.java
new file mode 100755
index 000000000..40bedccc3
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphRenderer.java
@@ -0,0 +1,131 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import java.awt.Color;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import org.apache.batik.dom.GenericDOMImplementation;
+import org.apache.batik.svggen.CachedImageHandlerBase64Encoder;
+import org.apache.batik.svggen.GenericImageHandler;
+import org.apache.batik.svggen.SVGGeneratorContext;
+import org.apache.batik.svggen.SVGGraphics2D;
+import org.apache.batik.svggen.SVGGraphics2DIOException;
+import org.scilab.modules.graph.ScilabCanvas;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+
+import com.mxgraph.canvas.mxGraphics2DCanvas;
+import com.mxgraph.canvas.mxICanvas;
+import com.mxgraph.util.mxCellRenderer;
+import com.mxgraph.util.mxRectangle;
+import com.mxgraph.util.mxCellRenderer.CanvasFactory;
+import com.mxgraph.view.mxGraph;
+
+/**
+ * This class implement Export operation by rendering graphs.
+ *
+ * Implement custom rendering as {@link mxCellRenderer} does.
+ */
+public class ScilabGraphRenderer {
+
+ /**
+ * This class is a static singleton
+ */
+ private ScilabGraphRenderer() {
+ }
+
+ /**
+ * Create an SVG Document containing a rendered graph.
+ *
+ * Use the Batik svg-generator engine to perform rendering.
+ *
+ * @param graph
+ * The graph to render
+ * @param cells
+ * the cells to render
+ * @param scale
+ * the scale
+ * @param background
+ * the current background
+ * @param clip
+ * the current clip
+ * @param filename
+ * the file where to stream.
+ */
+ public static void createSvgDocument(mxGraph graph, Object[] cells,
+ double scale, Color background, mxRectangle clip, String filename) {
+
+ // Get a DOMImplementation.
+ DOMImplementation domImpl = GenericDOMImplementation
+ .getDOMImplementation();
+
+ // Create an instance of org.w3c.dom.Document.
+ String svgNS = "http://www.w3.org/2000/svg";
+ Document doc = domImpl.createDocument(svgNS, "svg", null);
+
+ // Adding comments and customs
+ SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(doc);
+ ctx.setComment("Generated with Batik SVG Generator");
+ ctx.setEmbeddedFontsOn(true);
+ GenericImageHandler ihandler = new CachedImageHandlerBase64Encoder();
+ ctx.setGenericImageHandler(ihandler);
+
+ // Create an instance of the SVG Generator.
+ final SVGGraphics2D svgGenerator = new SVGGraphics2D(ctx, true);
+
+ // Render the graph using the SVGGraphics2D object
+ mxCellRenderer.drawCells(graph, cells, scale, clip,
+ new CanvasFactory() {
+ private mxGraphics2DCanvas canvas;
+
+ /**
+ * Create a new canvas for drawing
+ *
+ * @param width
+ * the canvas width
+ * @param height
+ * the canvas height
+ * @return a new canvas used for drawing
+ */
+ @Override
+ public mxICanvas createCanvas(int width, int height) {
+ if (canvas == null) {
+ canvas = new ScilabCanvas();
+ canvas.setGraphics(svgGenerator);
+ }
+
+ return canvas;
+ }
+ });
+
+ // Finally, stream out SVG to the standard output using
+ // UTF-8 encoding.
+ boolean useCSS = true; // we want to use CSS style attributes
+ Writer out;
+ try {
+ out = new OutputStreamWriter(new FileOutputStream(filename), "UTF-8");
+ svgGenerator.stream(out, useCSS);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ } catch (SVGGraphics2DIOException e) {
+ e.printStackTrace();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphUtils.java b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphUtils.java
new file mode 100755
index 000000000..ddf6d1bce
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/ScilabGraphUtils.java
@@ -0,0 +1,230 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import java.awt.geom.Dimension2D;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.logging.Logger;
+
+import javax.swing.Icon;
+
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.DocumentLoader;
+import org.apache.batik.bridge.GVTBuilder;
+import org.apache.batik.bridge.UserAgent;
+import org.apache.batik.bridge.UserAgentAdapter;
+import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.util.XMLResourceDescriptor;
+import org.scilab.forge.jlatexmath.ParseException;
+import org.scilab.forge.jlatexmath.TeXConstants;
+import org.scilab.forge.jlatexmath.TeXFormula;
+import org.scilab.forge.jlatexmath.TeXIcon;
+import org.scilab.modules.graph.view.SupportedLabelType;
+import org.w3c.dom.Document;
+
+import com.mxgraph.util.mxUtils;
+
+/**
+ * Utilities functions for ScilabGraph
+ */
+public final class ScilabGraphUtils extends mxUtils {
+ /**
+ * Cache for the generated SVG components
+ */
+ private static Map<URL, WeakReference<GraphicsNode>> generatedSVGComponents = new HashMap<URL, WeakReference<GraphicsNode>>();
+ /**
+ * Cache for the generated SVG document sizes
+ */
+ private static Map<URL, Dimension2D> generatedSVGSizes = new HashMap<URL, Dimension2D>();
+
+ /**
+ * Cache for the generated latex icons
+ */
+ private static Map<Float, Map<String, TeXIcon>> generatedLatexIcons = new WeakHashMap<Float, Map<String, TeXIcon>>();
+
+ /**
+ * Table conversion between escaped/unescaped HTML symbols
+ */
+ private static final String[][] HTML_ESCAPE_TABLE = { { "&lt;", "<" }, { "&gt;", ">" }, { "&amp;", "&" }, { "&quot;", "\"" }, { "&agrave;", "\u00e0" },
+ { "&Agrave;", "\u00c0" }, { "&acirc;", "\u00e2" }, { "&auml;", "\u00e4" }, { "&Auml;", "\u00c4" }, { "&Acirc;", "\u00c2" },
+ { "&aring;", "\u00e5" }, { "&Aring;", "\u00c5" }, { "&aelig;", "\u00e6" }, { "&AElig;", "\u00c6" }, { "&ccedil;", "\u00e7" },
+ { "&Ccedil;", "\u00c7" }, { "&eacute;", "\u00e9" }, { "&Eacute;", "\u00c9" }, { "&egrave;", "\u00e8" }, { "&Egrave;", "\u00c8" },
+ { "&ecirc;", "\u00ea" }, { "&Ecirc;", "\u00ca" }, { "&euml;", "\u00eb" }, { "&Euml;", "\u00cb" }, { "&iuml;", "\u00ef" }, { "&Iuml;", "\u00cf" },
+ { "&ocirc;", "\u00f4" }, { "&Ocirc;", "\u00d4" }, { "&ouml;", "\u00f6" }, { "&Ouml;", "\u00d6" }, { "&oslash;", "\u00f8" },
+ { "&Oslash;", "\u00d8" }, { "&szlig;", "\u00df" }, { "&ugrave;", "\u00f9" }, { "&Ugrave;", "\u00d9" }, { "&ucirc;", "\u00fb" },
+ { "&Ucirc;", "\u00db" }, { "&uuml;", "\u00fc" }, { "&Uuml;", "\u00dc" }, { "&nbsp;", " " }, { "&reg;", "\u00a9" }, { "&copy;", "\u00ae" },
+ { "&euro;", "\u20a0" }
+ };
+
+ /**
+ * Return a cached or a new instance of a {@link GraphicsNode} generated
+ * from the SVG file.
+ *
+ * @param filename
+ * the file to parse
+ * @return the corresponding graphic node
+ */
+ public static GraphicsNode getSVGComponent(URL filename) {
+ WeakReference<GraphicsNode> nodeRef;
+ GraphicsNode node;
+
+ nodeRef = generatedSVGComponents.get(filename);
+ if (nodeRef != null) {
+ node = nodeRef.get();
+ } else {
+ node = null;
+ }
+
+ if (node == null) {
+ try {
+ String xmlParser = XMLResourceDescriptor.getXMLParserClassName();
+ SAXSVGDocumentFactory df = new SAXSVGDocumentFactory(xmlParser);
+ Document doc = df.createDocument(filename.toString());
+ UserAgent userAgent = new UserAgentAdapter();
+ DocumentLoader loader = new DocumentLoader(userAgent);
+ BridgeContext ctx = new BridgeContext(userAgent, loader);
+ ctx.setDynamicState(BridgeContext.STATIC);
+ GVTBuilder builder = new GVTBuilder();
+
+ node = builder.build(ctx, doc);
+
+ generatedSVGComponents.put(filename, node.getWeakReference());
+ generatedSVGSizes.put(filename, ctx.getDocumentSize());
+ } catch (IOException e) {
+ Logger.getLogger(ScilabGraphUtils.class.getName()).severe(e.toString());
+ }
+ }
+ return node;
+ }
+
+ /**
+ * Get the document size for a given URL.
+ *
+ * This method use the Document size cache to get the svg element dimension
+ * and not the real size of the graphical tree.
+ *
+ * @param filename
+ * the file
+ * @return the dimension of the file
+ */
+ public static Dimension2D getSVGDocumentSizes(URL filename) {
+ Dimension2D ret = generatedSVGSizes.get(filename);
+
+ // Generate the GraphicsNode if not available
+ if (ret == null) {
+ getSVGComponent(filename);
+ ret = generatedSVGSizes.get(filename);
+ }
+ return ret;
+ }
+
+ /**
+ * Return a cached or a new instance of a TexIcon generated from the text.
+ *
+ * @param text
+ * the latex formula
+ * @return the TeXIcon
+ * @throws ParseException
+ * when the text is not a valid formula
+ */
+ public static Icon getTexIcon(String text, float size) throws ParseException {
+ TeXIcon icon;
+ String escapedText = SupportedLabelType.Latex.escape(text);
+
+ Map<String, TeXIcon> iconMap = generatedLatexIcons.get(size);
+ if (iconMap == null) {
+ iconMap = new WeakHashMap<String, TeXIcon>();
+ generatedLatexIcons.put(size, iconMap);
+ }
+
+ icon = iconMap.get(escapedText);
+ if (icon == null) {
+ TeXFormula tex = new TeXFormula(escapedText);
+ icon = tex.createTeXIcon(TeXConstants.STYLE_DISPLAY, size);
+ iconMap.put(escapedText, icon);
+ }
+ return icon;
+ }
+
+ /**
+ * Remove the blank char on the beginning of the sequence. This method
+ * modify the {@link StringBuilder} in place.
+ *
+ * @param seq
+ * the sequence
+ */
+ public static void removeBlanks(StringBuilder seq) {
+ int i;
+ for (i = 0; i < seq.length(); i++) {
+ char car = seq.charAt(i);
+ if (car != ' ' && car != '\n') {
+ break;
+ }
+ }
+
+ seq.delete(0, i);
+ }
+
+ /**
+ * Unescape html
+ *
+ * This method modify the {@link StringBuilder} in place.
+ *
+ * @param escapedText
+ * the working text
+ * @param index
+ * the beginning index
+ */
+ public static void unescape(StringBuilder escapedText, int index) {
+ int start, end, table_index;
+
+ start = escapedText.indexOf("&", index);
+ if (start > -1) {
+ end = escapedText.indexOf(";", start);
+ // we don't start from the beginning
+ // the next time, to handle the case of
+ // the &
+ index = start + 1;
+
+ if (end > start) {
+ String temp = escapedText.substring(start, end + 1);
+ // search in HTML_ESCAPE_TABLE[][] if temp is there
+ table_index = 0;
+ while (table_index < HTML_ESCAPE_TABLE.length) {
+ if (HTML_ESCAPE_TABLE[table_index][0].equals(temp)) {
+ break;
+ } else {
+ table_index++;
+ }
+ }
+ if (table_index < HTML_ESCAPE_TABLE.length) {
+ escapedText.replace(start, end + 1, HTML_ESCAPE_TABLE[table_index][1]);
+ unescape(escapedText, index); // recursive call
+ }
+ }
+ }
+ return;
+ }
+
+ /**
+ * This class is a static singleton thus it must not be instantiated
+ */
+ private ScilabGraphUtils() {
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/utils/StyleMap.java b/modules/graph/src/java/org/scilab/modules/graph/utils/StyleMap.java
new file mode 100755
index 000000000..11ee643b7
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/utils/StyleMap.java
@@ -0,0 +1,85 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2009 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.utils;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map.Entry;
+
+/**
+ * Perform useful conversions between a style string and key/value based map.
+ */
+@SuppressWarnings(value = { "serial" })
+public final class StyleMap extends LinkedHashMap<String, String> {
+
+ /**
+ * Create a Map from a style string
+ * @param style The string which contains key=value list
+ */
+ public StyleMap(String style) {
+ super();
+ putAll(style);
+ }
+
+ /**
+ * Put all the style attributes to the current map
+ * @param style The string which contains key=value list
+ * @return the current map
+ */
+ public StyleMap putAll(String style) {
+ if (style != null && style.length() > 0) {
+ final String[] pairs = style.split(";");
+
+ for (String keyValue : pairs) {
+ final int sep = keyValue.indexOf('=');
+
+ if (sep >= 0) {
+ put(keyValue.substring(0, sep), keyValue.substring(sep + 1));
+ } else {
+ put(keyValue, null);
+ }
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Export to a key=value; string
+ * @return formatted string
+ */
+ @Override
+ public String toString() {
+ StringBuilder str = new StringBuilder();
+ String valueRef = null;
+
+ for (Iterator<Entry<String, String>> iterator = entrySet().iterator();
+ iterator.hasNext();) {
+ Entry<String, String> entry = iterator.next();
+
+ str.append(entry.getKey());
+
+ valueRef = entry.getValue();
+ if (valueRef != null && valueRef.length() > 0) {
+ str.append("=");
+ str.append(valueRef);
+ }
+
+ if (iterator.hasNext()) {
+ str.append(";");
+ }
+
+ }
+
+ return str.toString();
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/view/ScilabGraphView.java b/modules/graph/src/java/org/scilab/modules/graph/view/ScilabGraphView.java
new file mode 100755
index 000000000..6972ba790
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/view/ScilabGraphView.java
@@ -0,0 +1,169 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.view;
+
+import java.awt.Component;
+import java.util.Map;
+
+import javax.swing.Icon;
+
+import org.scilab.modules.graph.utils.MathMLRenderUtils;
+import org.scilab.modules.graph.utils.ScilabGraphUtils;
+import org.scilab.modules.gui.messagebox.ScilabModalDialog;
+import org.xml.sax.SAXException;
+
+import com.mxgraph.model.mxCell;
+import com.mxgraph.util.mxConstants;
+import com.mxgraph.util.mxPoint;
+import com.mxgraph.util.mxRectangle;
+import com.mxgraph.util.mxUtils;
+import com.mxgraph.view.mxCellState;
+import com.mxgraph.view.mxGraph;
+import com.mxgraph.view.mxGraphView;
+
+/**
+ * Implement specific method to render a graph
+ */
+public class ScilabGraphView extends mxGraphView {
+
+ /**
+ * Default constructor
+ * @param graph the associated graph
+ */
+ public ScilabGraphView(mxGraph graph) {
+ super(graph);
+ }
+
+ /**
+ * Updates the label bounds in the given state.
+ * @param state the cell visible state
+ */
+ @Override
+ public void updateLabelBounds(mxCellState state) {
+ Object cell = state.getCell();
+ Map<String, Object> style = state.getStyle();
+ String label = graph.getLabel(cell);
+
+ SupportedLabelType type = SupportedLabelType.getFromHTML(label);
+ mxRectangle labelBounds;
+ double w;
+ double h;
+
+ switch (type) {
+ case Latex:
+ /*
+ * As we render text as an image, the label bounds are set to the
+ * scaled generated image values.
+ */
+ try {
+ float fontSize = (float) (mxUtils.getInt(style, mxConstants.STYLE_FONTSIZE, 16) * scale);
+
+ final Icon icon = ScilabGraphUtils.getTexIcon(label, fontSize);
+ // the icon is generated scaled so width and height are already scaled
+ w = icon.getIconWidth();
+ h = icon.getIconHeight();
+
+ final mxPoint offset = state.getAbsoluteOffset();
+ double x = offset.getX();
+ double y = offset.getY();
+
+ final mxRectangle vertexBounds;
+ if (!graph.getModel().isEdge(cell)) {
+ vertexBounds = state;
+
+ x += vertexBounds.getX();
+ y += vertexBounds.getY();;
+
+ // the label is always centered
+ x -= (w - vertexBounds.getWidth()) / 2 ;
+ y -= (h - vertexBounds.getHeight()) / 2 ;
+ }
+
+ labelBounds = new mxRectangle(x, y, w, h);
+ } catch (Exception e) {
+ // popup an error
+ // FIXME: use a ScilabGraphTab instead of null there
+ ScilabModalDialog.show(null, e.getLocalizedMessage());
+
+ // Set a non-rendering label on the model
+ // label will be printed (state contains the value)
+ mxCell c = (mxCell) cell;
+ c.setValue(((String) c.getValue()).substring(1));
+ labelBounds = getDefaultBounds(state, cell, style, label);
+ }
+ break;
+
+ case MathML:
+ /*
+ * As we render text as an image, the label bounds are set to the
+ * scaled generated image values.
+ */
+ try {
+ Component comp = MathMLRenderUtils.getMathMLComponent(label);
+ w = comp.getWidth();
+ h = comp.getHeight();
+
+ final mxPoint offset = state.getOrigin();
+ final mxRectangle size = new mxRectangle();
+ size.setWidth(w);
+ size.setHeight(h);
+
+ labelBounds = mxUtils.getScaledLabelBounds(offset.getX(),
+ offset.getY(), size, state.getWidth(),
+ state.getHeight(), style, scale);
+ } catch (SAXException e) {
+ // popup an error
+ // FIXME: use a ScilabGraphTab instead of null there
+ ScilabModalDialog.show(null, e.getLocalizedMessage());
+
+ // Set a non-rendering label on the model
+ // label will be printed (state contains the value)
+ mxCell c = (mxCell) cell;
+ c.setValue(((String) c.getValue()).substring(1));
+ labelBounds = getDefaultBounds(state, cell, style, label);
+ }
+ break;
+
+ default:
+ labelBounds = getDefaultBounds(state, cell, style, label);
+ break;
+ }
+
+ state.setLabelBounds(labelBounds);
+ }
+
+ /**
+ * Return the default bounds calculated as if the label were text.
+ * @param state the cell state
+ * @param cell the current cell
+ * @param style the cell style
+ * @param label the current text
+ * @return the calculated bounds
+ */
+ private mxRectangle getDefaultBounds(mxCellState state, Object cell,
+ Map<String, Object> style, String label) {
+ mxRectangle labelBounds;
+ mxRectangle vertexBounds;
+
+ if (!graph.getModel().isEdge(cell)) {
+ vertexBounds = state;
+ } else {
+ vertexBounds = null;
+ }
+
+ labelBounds = mxUtils.getLabelPaintBounds(label, style, graph
+ .isHtmlLabel(cell), state.getAbsoluteOffset(), vertexBounds,
+ scale);
+ return labelBounds;
+ }
+}
diff --git a/modules/graph/src/java/org/scilab/modules/graph/view/SupportedLabelType.java b/modules/graph/src/java/org/scilab/modules/graph/view/SupportedLabelType.java
new file mode 100755
index 000000000..cccd7a318
--- /dev/null
+++ b/modules/graph/src/java/org/scilab/modules/graph/view/SupportedLabelType.java
@@ -0,0 +1,155 @@
+/*
+ * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
+ * Copyright (C) 2010 - DIGITEO - Clement DAVID
+ *
+ * This file must be used under the terms of the CeCILL.
+ * This source file is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at
+ * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
+ *
+ */
+
+package org.scilab.modules.graph.view;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.scilab.modules.graph.utils.ScilabGraphUtils;
+import org.scilab.modules.jvm.LoadClassPath;
+
+import com.mxgraph.util.mxUtils;
+
+/**
+ * Specify the supported label type
+ */
+public enum SupportedLabelType {
+ /** The label is HTML formatted. This is the default */
+ HTML,
+ /** The label is Latex formatted */
+ Latex,
+ /** The label is MathML formatted */
+ MathML;
+
+ /**
+ * Pattern to match the &lt;br&gt; HTML tag
+ */
+ private static final Pattern BR_PATTERN = Pattern.compile("<br>\\p{Blank}*");
+
+ /** The '$' symbol is used to tag a LaTeX expression */
+ private static final char LATEX_TAG = '$';
+ /** The '^' symbol is used to tag a LaTeX expression */
+ private static final char MATHML_TAG = '^';
+ /** The id used on classpath.xml to load MathML JARs */
+ private static final String CLASSPATH_MATHML_NAME = "xcos_mathml_rendering";
+
+ /**
+ * Get the {@link SupportedLabelType} for the label.
+ *
+ * The type of the label is found with a specific first character.
+ * <ul>
+ * <li>'$' : for {@value SupportedLabelType#Latex} markup</li>
+ * <li>'^' : for {@value SupportedLabelType#MathML} markup</li>
+ * </ul>
+ *
+ * The {@value SupportedLabelType#HTML} is used as default.
+ *
+ * @param text The label to parse
+ * @return the type of the label
+ */
+ public static SupportedLabelType getFromText(String text) {
+ if (text.length() > 0) {
+ if ((text.charAt(0) == LATEX_TAG) && (
+ text.charAt(text.length() - 1) == LATEX_TAG)) {
+ return Latex;
+ } else if ((text.charAt(0) == MATHML_TAG) && (
+ text.charAt(text.length() - 1) == MATHML_TAG)) {
+ LoadClassPath.loadOnUse(CLASSPATH_MATHML_NAME);
+ return MathML;
+ }
+ }
+ return HTML;
+ }
+
+ /**
+ * Get the {@link SupportedLabelType} for the HTML formatted string.
+ *
+ * The type of the label is found with a specific first character of the
+ * content. The HTML markup is escaped automatically.
+ * <ul>
+ * <li>'$' : for {@value SupportedLabelType#Latex} markup</li>
+ * <li>'^' : for {@value SupportedLabelType#MathML} markup</li>
+ * </ul>
+ *
+ * The {@value SupportedLabelType#HTML} is used as default.
+ *
+ * @param html The HTML string to parse
+ * @return the type of the label
+ */
+ public static SupportedLabelType getFromHTML(String html) {
+ if (html.length() > 0 && html.charAt(0) == '<') {
+
+ final StringBuilder content = new StringBuilder(mxUtils
+ .getBodyMarkup(html, false));
+
+ ScilabGraphUtils.removeBlanks(content);
+
+ if ((content.length() > 0) && (content.charAt(0) == LATEX_TAG)
+ && (content.charAt(content.length() - 1) == LATEX_TAG)) {
+ return Latex;
+ } else if ((content.length() > 0)
+ && (content.charAt(0) == MATHML_TAG)
+ && (content.charAt(content.length() - 1) == MATHML_TAG)) {
+ LoadClassPath.loadOnUse(CLASSPATH_MATHML_NAME);
+ return MathML;
+ }
+ } else {
+ return getFromText(html);
+ }
+
+ return HTML;
+ }
+
+ /**
+ * Escape the text for the current type.
+ * @param text the text to escape
+ * @return the escaped text
+ */
+ public String escape(String text) {
+ StringBuilder escapedText;
+
+ if (text.startsWith("<html")) {
+ escapedText = new StringBuilder(ScilabGraphUtils.getBodyMarkup(text, true));
+ } else {
+ escapedText = new StringBuilder(text);
+ }
+
+ switch (this) {
+ case MathML:
+ case Latex:
+ // Unescape content
+ ScilabGraphUtils.unescape(escapedText, 0);
+
+ // Removing <br>
+ Matcher m = BR_PATTERN.matcher(escapedText);
+ while (m.find()) {
+ escapedText.replace(m.start(), m.end(), "");
+ m.reset();
+ }
+
+ // Removing blank
+ ScilabGraphUtils.removeBlanks(escapedText);
+
+ // Removing the first and last char (tag)
+ escapedText.delete(0, 1);
+ int length = escapedText.length();
+ escapedText.delete(length - 1, length);
+ break;
+
+ default:
+ break;
+ }
+
+ return escapedText.toString();
+ }
+}