* Bug #13772 fixed - Xcos GUI was not locked while setting parameters.
[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.1-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.event.MouseEvent;
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      * @param cells
76      *            the cells to center on
77      */
78     public void zoomAndCenterToCells(final Object[] cells) {
79         final mxRectangle preference = zoomBounds(cells);
80         final Dimension actual = getViewport().getSize();
81
82         final double newScale;
83         final double heightScale = actual.getHeight() / preference.getHeight();
84         final double widthScale = actual.getWidth() / preference.getWidth();
85
86         if (heightScale > 1.0) {
87             if (widthScale > 1.0) {
88                 // We need to zoom in (the max applicable zoom is the lowest)
89                 newScale = Math.min(heightScale, widthScale);
90             } else {
91                 // we need to zoom out (only widthScale is < 1.0)
92                 newScale = widthScale;
93             }
94         } else {
95             if (widthScale > 1.0) {
96                 // we need to zoom out (only heightScale is < 1.0)
97                 newScale = heightScale;
98             } else {
99                 // We need to zoom out (the max applicable zoom is the lowest)
100                 newScale = Math.min(heightScale, widthScale);
101             }
102         }
103
104         // do not apply small zoom values
105         if (Math.abs(1.0 - newScale) < 0.2) {
106             getGraphControl().scrollRectToVisible(zoomBounds(cells).getRectangle(), true);
107             return;
108         }
109
110         zoom(newScale / SCALE_MULTIPLIER);
111         getGraphControl().scrollRectToVisible(zoomBounds(cells).getRectangle(), true);
112     }
113
114     private final mxRectangle zoomBounds(final Object[] cells) {
115         final mxRectangle preference;
116         final Object[] c;
117         if (cells == null || cells.length == 0) {
118             c = graph.getChildCells(graph.getDefaultParent());
119         } else {
120             c = cells;
121         }
122         preference = getChildrenBounds(c);
123
124         return preference;
125     }
126
127     /**
128      * Get the children bound for the cells
129      *
130      * @param cells
131      *            the root of the graph
132      * @return the rectangle or null if not applicable
133      */
134     private mxRectangle getChildrenBounds(final Object[] cells) {
135         mxRectangle result = null;
136
137         if (cells != null && cells.length > 0) {
138             final mxGraphView view = graph.getView();
139             final mxIGraphModel model = graph.getModel();
140
141             for (int i = 0; i < cells.length; i++) {
142                 if (model.isVertex(cells[i]) || model.isEdge(cells[i])) {
143                     final mxICell parent = ((mxICell) cells[i]);
144                     final int childCount = parent.getChildCount();
145
146                     for (int j = 0; j < childCount; j++) {
147                         final mxICell child = parent.getChildAt(j);
148
149                         result = updateRectangle(result, view, child);
150                     }
151
152                     result = updateRectangle(result, view, parent);
153                 }
154             }
155         }
156
157         return result;
158     }
159
160     /**
161      * Update the rectangle parameter with the cell status
162      *
163      * @param result
164      *            the previous result
165      * @param view
166      *            the current view
167      * @param child
168      *            the child we have to work on
169      * @return the updated rectangle
170      */
171     private mxRectangle updateRectangle(mxRectangle result, final mxGraphView view, final mxICell child) {
172         final mxCellState state = view.getState(child);
173         mxRectangle rect = result;
174
175         if (state != null) {
176             if (rect == null) {
177                 rect = new mxRectangle(state);
178             } else {
179                 rect.add(state);
180             }
181         }
182         return rect;
183     }
184
185     /**
186      * Implement a graph control which paint a foreground on top of the view
187      * when the graph is locked.
188      */
189     @SuppressWarnings(value = { "serial" })
190     public class ScilabGraphControl extends mxGraphControl {
191
192         /**
193          * Default constructor
194          */
195         public ScilabGraphControl() {
196             super();
197
198             // Paint the foreground color after the real paint
199             addListener(mxEvent.AFTER_PAINT, new mxEventSource.mxIEventListener() {
200                 @Override
201                 public void invoke(Object sender, mxEventObject evt) {
202
203                     Graphics g = (Graphics) evt.getProperty("g");
204                     if (getGraph().isCellsLocked()) {
205                         g.setColor(MASK_COLOR);
206
207                         Dimension b = getGraphControl().getSize();
208
209                         g.fillRect(0, 0, b.width, b.height);
210                     }
211                 }
212             });
213         }
214
215         /**
216          * @see javax.swing.JComponent#processMouseMotionEvent(java.awt.event.MouseEvent)
217          *
218          * Overloaded to filter out any cursor update if the graph is locked
219          */
220         @Override
221         protected void processMouseMotionEvent(MouseEvent e) {
222             if (!getGraph().isCellsLocked()) {
223                 super.processMouseMotionEvent(e);
224             }
225         }
226     }
227
228     /*
229      * Disable some handlers in case of an headless env.
230      */
231
232     @Override
233     protected void createHandlers() {
234         if (GraphicsEnvironment.isHeadless()) {
235             return;
236         }
237
238         super.createHandlers();
239     }
240 }