9731e92ce267dcdd672e5c10e8c6098b958d7d40
[scilab.git] / scilab / modules / graph / src / java / org / scilab / modules / graph / ScilabComponent.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2010 - DIGITEO - Clement DAVID
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 package org.scilab.modules.graph;
14
15 import java.awt.Color;
16 import java.awt.Dimension;
17 import java.awt.Graphics;
18 import java.awt.GraphicsEnvironment;
19 import java.awt.Rectangle;
20
21 import com.mxgraph.model.mxICell;
22 import com.mxgraph.model.mxIGraphModel;
23 import com.mxgraph.swing.mxGraphComponent;
24 import com.mxgraph.util.mxEvent;
25 import com.mxgraph.util.mxEventObject;
26 import com.mxgraph.util.mxEventSource;
27 import com.mxgraph.util.mxRectangle;
28 import com.mxgraph.view.mxCellState;
29 import com.mxgraph.view.mxGraphView;
30
31 /**
32  * Implement the default component for the {@link ScilabGraph}.
33  */
34 @SuppressWarnings(value = { "serial" })
35 public class ScilabComponent extends mxGraphComponent {
36     /**
37      * Color use to mask the graph when the graph is locked
38      */
39     private static final Color MASK_COLOR = new Color(240, 240, 240, 100);
40
41     private static final double SCALE_MULTIPLIER = 1.1;
42
43     /**
44      * Construct the component with the associated graph
45      *
46      * @param graph
47      *            The associated graph
48      */
49     public ScilabComponent(ScilabGraph graph) {
50         super(graph);
51     }
52
53     /**
54      * @return the associated graph control
55      * @see com.mxgraph.swing.mxGraphComponent#createGraphControl()
56      */
57     @Override
58     protected mxGraphControl createGraphControl() {
59         return new ScilabGraphControl();
60     }
61
62     /**
63      * Create the associated canvas
64      *
65      * @return the canvas
66      */
67     @Override
68     public ScilabCanvas createCanvas() {
69         return new ScilabCanvas();
70     }
71
72     /**
73      * Zoom the whole graph and center the view on it.
74      */
75     public void zoomAndCenterToCells() {
76
77     }
78
79     /**
80      * Zoom the whole graph and center the view on it.
81      *
82      * @param cells
83      *            the cells to center on
84      */
85     public void zoomAndCenterToCells(final Object[] cells) {
86         final mxGraphView view = graph.getView();
87
88         final Rectangle preference;
89         final Object[] c;
90         if (cells == null || cells.length == 0) {
91             c = graph.getChildCells(graph.getDefaultParent());
92         } else {
93             c = cells;
94         }
95         preference = getChildrenBounds(c).getRectangle();
96
97         Dimension actual = getViewport().getSize();
98
99         double newScale;
100         double heightScale = actual.getHeight() / preference.getHeight();
101         double widthScale = actual.getWidth() / preference.getWidth();
102
103         if (heightScale > 1.0) {
104             if (widthScale > 1.0) {
105                 // We need to zoom in (the max applicable zoom is the lowest)
106                 newScale = Math.min(heightScale, widthScale) * (1.0 - (SCALE_MULTIPLIER - 1.0));
107             } else {
108                 // we need to zoom out (only widthScale is < 1.0)
109                 newScale = widthScale * SCALE_MULTIPLIER;
110             }
111         } else {
112             if (widthScale > 1.0) {
113                 // we need to zoom out (only heightScale is < 1.0)
114                 newScale = heightScale * SCALE_MULTIPLIER;
115             } else {
116                 // We need to zoom out (the max applicable zoom is the lowest)
117                 newScale = Math.min(heightScale, widthScale) * SCALE_MULTIPLIER;
118             }
119         }
120
121         zoom(newScale);
122
123         view.revalidate();
124         Rectangle orig = getChildrenBounds(graph.getChildCells(graph.getDefaultParent())).getRectangle();
125         getGraphControl().scrollRectToVisible(orig);
126     }
127
128     /**
129      * Get the children bound for the cells
130      *
131      * @param cells
132      *            the root of the graph
133      * @return the rectangle or null if not applicable
134      */
135     private mxRectangle getChildrenBounds(final Object[] cells) {
136         mxRectangle result = null;
137
138         if (cells != null && cells.length > 0) {
139             final mxGraphView view = graph.getView();
140             final mxIGraphModel model = graph.getModel();
141
142             for (int i = 0; i < cells.length; i++) {
143                 if (model.isVertex(cells[i]) || model.isEdge(cells[i])) {
144                     final mxICell parent = ((mxICell) cells[i]);
145                     final int childCount = parent.getChildCount();
146
147                     for (int j = 0; j < childCount; j++) {
148                         final mxICell child = parent.getChildAt(j);
149
150                         result = updateRectangle(result, view, child);
151                     }
152
153                     result = updateRectangle(result, view, parent);
154                 }
155             }
156         }
157
158         return result;
159     }
160
161     /**
162      * Update the rectangle parameter with the cell status
163      *
164      * @param result
165      *            the previous result
166      * @param view
167      *            the current view
168      * @param child
169      *            the child we have to work on
170      * @return the updated rectangle
171      */
172     private mxRectangle updateRectangle(mxRectangle result, final mxGraphView view, final mxICell child) {
173         final mxCellState state = view.getState(child);
174         mxRectangle rect = result;
175
176         if (state != null) {
177             if (rect == null) {
178                 rect = new mxRectangle(state);
179             } else {
180                 rect.add(state);
181             }
182         }
183         return rect;
184     }
185
186     /**
187      * Implement a graph control which paint a foreground on top of the view
188      * when the graph is locked.
189      */
190     @SuppressWarnings(value = { "serial" })
191     public class ScilabGraphControl extends mxGraphControl {
192
193         /**
194          * Default constructor
195          */
196         public ScilabGraphControl() {
197             super();
198
199             // Paint the foreground color after the real paint
200             addListener(mxEvent.AFTER_PAINT, new mxEventSource.mxIEventListener() {
201                 @Override
202                 public void invoke(Object sender, mxEventObject evt) {
203
204                     Graphics g = (Graphics) evt.getProperty("g");
205                     if (getGraph().isCellsLocked()) {
206                         g.setColor(MASK_COLOR);
207
208                         Rectangle b = getBounds();
209
210                         g.fillRect(b.x, b.y, b.width, b.height);
211                     }
212                 }
213             });
214         }
215     }
216
217     /*
218      * Disable some handlers in case of an headless env.
219      */
220
221     @Override
222     protected void createHandlers() {
223         if (GraphicsEnvironment.isHeadless()) {
224             return;
225         }
226
227         super.createHandlers();
228     }
229 }