167f8a89070b055efc00e1050b086583ec01eeae
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / graph / ScilabGraph.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Bruno JOFRET
4  * Copyright (C) 2010 - DIGITEO - ClĂ©ment DAVID
5  *
6  * This file must be used under the terms of the CeCILL.
7  * This source file is licensed as described in the file COPYING, which
8  * you should have received as part of this distribution.  The terms
9  * are also available at
10  * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 package org.scilab.modules.graph;
15
16 import java.awt.Color;
17 import java.util.List;
18
19 import org.scilab.modules.graph.utils.ScilabGraphMessages;
20 import org.scilab.modules.gui.tab.Tab;
21 import org.scilab.modules.gui.utils.UIElementMapper;
22 import org.scilab.modules.gui.window.ScilabWindow;
23 import org.scilab.modules.xcos.utils.XcosComponent;
24
25 import com.mxgraph.swing.mxGraphComponent;
26 import com.mxgraph.swing.handler.mxRubberband;
27 import com.mxgraph.swing.util.mxGraphActions;
28 import com.mxgraph.util.mxEvent;
29 import com.mxgraph.util.mxEventObject;
30 import com.mxgraph.util.mxUndoManager;
31 import com.mxgraph.util.mxUndoableEdit;
32 import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
33 import com.mxgraph.view.mxGraph;
34
35 /**
36  * Represent the base diagram of Xcos.
37  * 
38  * It performs generic operations like undo/redo management, action clean-up,
39  * modification state management, Tab association, etc...
40  */
41 public class ScilabGraph extends mxGraph {
42
43         private static final int DEFAULTCOLOR = 240;
44
45         private final mxUndoManager undoManager = new mxUndoManager();
46         private final XcosComponent component;
47
48         private String title = ScilabGraphMessages.UNTITLED;
49         private String savedFile;
50         private boolean modified;
51         private Tab parentTab;
52         private boolean opened;
53         private boolean redoInAction;
54         private int undoCounter;
55         private boolean readOnly;
56         private Color originalColor;
57
58         private transient mxRubberband rubberBand;
59
60         /**
61          * Manage the modification state on change
62          */
63         private mxIEventListener changeTracker = new mxIEventListener() {
64                 public void invoke(Object source, mxEventObject evt) {
65                         setModified(true);
66                 }
67         };
68
69         /**
70          * Manage the undo/redo on change
71          */
72         private mxIEventListener undoHandler = new mxIEventListener() {
73                 public void invoke(Object source, mxEventObject evt) {
74
75                         if (!redoInAction) {
76                                 undoManager.undoableEditHappened((mxUndoableEdit) evt
77                                                 .getProperty("edit"));
78                                 incrementUndoCounter();
79                         }
80                 }
81         };
82
83         /**
84          * Manage the selection on change
85          */
86         private mxIEventListener selectionHandler = new mxIEventListener() {
87                 public void invoke(Object source, mxEventObject evt) {
88                         List<mxUndoableChange> changes = ((mxUndoableEdit) evt.getProperty("edit")).getChanges();
89                         setSelectionCells(getSelectionCellsForChanges(changes));
90                 }
91         };
92
93         /**
94          * Default constructor: - disable unused actions - install listeners -
95          * Replace JGraphX components by specialized components if needed.
96          */
97         public ScilabGraph() {
98                 super();
99
100                 // Disabling the default connected action and event listeners.
101                 mxGraphActions.getSelectNextAction().setEnabled(false);
102                 mxGraphActions.getSelectPreviousAction().setEnabled(false);
103                 mxGraphActions.getSelectChildAction().setEnabled(false);
104                 mxGraphActions.getSelectParentAction().setEnabled(false);
105
106                 // Undo / Redo capabilities
107                 getModel().addListener(mxEvent.UNDO, undoHandler);
108                 getView().addListener(mxEvent.UNDO, undoHandler);
109
110                 // Keeps the selection in sync with the command history
111                 undoManager.addListener(mxEvent.UNDO, selectionHandler);
112                 undoManager.addListener(mxEvent.REDO, selectionHandler);
113
114                 component = new XcosComponent(this);
115
116                 // Adds rubberband selection
117                 rubberBand = new mxRubberband(component);
118
119                 // Modified property change
120                 getModel().addListener(mxEvent.CHANGE, changeTracker);
121         }
122
123         /**
124          * @return The previously saved file or null.
125          */
126         public String getSavedFile() {
127                 return savedFile;
128         }
129
130         /**
131          * @param savedFile
132          *            The new saved file
133          */
134         public void setSavedFile(String savedFile) {
135                 this.savedFile = savedFile;
136         }
137
138         /**
139          * @return true, if the graph has been modified ; false otherwise.
140          */
141         public boolean isModified() {
142                 return modified;
143         }
144
145         /**
146          * Modify the state of the diagram.
147          * 
148          * @param modified
149          *            The new modified state.
150          * @category UseEvent
151          */
152         public void setModified(boolean modified) {
153                 boolean oldValue = this.modified;
154                 this.modified = modified;
155
156                 getAsComponent().firePropertyChange("modified", oldValue, modified);
157         }
158
159         /**
160          * @param title
161          *            The new title of the tab
162          */
163         public void setTitle(String title) {
164                 this.title = title;
165         }
166
167         /**
168          * @return The current Tab title
169          */
170         public String getTitle() {
171                 return title;
172         }
173
174         /**
175          * @return The component associated with the current graph.
176          */
177         public mxGraphComponent getAsComponent() {
178                 return component;
179         }
180
181         /**
182          * Undo the last action
183          * 
184          * @see com.mxgraph.util.mxUndoManager
185          */
186         public void undo() {
187                 decrementUndoCounter();
188                 redoInAction = true;
189                 undoManager.undo();
190                 redoInAction = false;
191         }
192
193         /**
194          * Redo the last action com.mxgraph.util.mxUndoManager
195          */
196         public void redo() {
197             if (!redoInAction) {
198
199                 incrementUndoCounter();
200                 redoInAction = true;
201                 undoManager.redo();
202                 redoInAction = false;
203             }
204         }
205
206         /**
207          * Used internally to manage the modified state on undo/redo
208          */
209         private void incrementUndoCounter() {
210                 if (undoCounter < Integer.MAX_VALUE) {
211                         undoCounter++;
212                 }
213         }
214
215         /**
216          * Used internally to manage the modified state on undo/redo
217          */
218         private void decrementUndoCounter() {
219                 if (undoCounter > Integer.MIN_VALUE) {
220                         undoCounter--;
221                 }
222         }
223
224         /**
225          * Used internally to manage the modified state on undo/redo
226          * 
227          * @return true if the document is in a previous saved state, false
228          *         otherwise
229          */
230         protected boolean isZeroUndoCounter() {
231                 return (undoCounter == 0);
232         }
233
234         /**
235          * Used internally to manage the modified state on undo/redo
236          */
237         protected void resetUndoCounter() {
238                 undoCounter = 0;
239         }
240
241         /**
242          * @return The associated Tab
243          */
244         public Tab getParentTab() {
245                 return parentTab;
246         }
247
248         /**
249          * @param parentTab
250          *            The new associated Tab
251          */
252         public void setParentTab(Tab parentTab) {
253                 this.parentTab = parentTab;
254         }
255
256         /**
257          * The instance can be not visible but used (when using SuperBlock). The
258          * openned flag is true in this case and also when the Window/Tab is
259          * visible.
260          * 
261          * @param opened
262          *            Openned state
263          */
264         public void setOpened(boolean opened) {
265                 this.opened = opened;
266         }
267
268         /**
269          * @return Openned state
270          */
271         public boolean isOpened() {
272                 return opened;
273         }
274
275         /**
276          * Set the associated Window/Tab visible or not.
277          * 
278          * @param visible
279          *            State of visibility
280          */
281         public void setVisible(boolean visible) {
282                 if (parentTab != null) {
283                         ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper
284                                         .getCorrespondingUIElement(parentTab.getParentWindowId());
285                         xcosWindow.setVisible(visible);
286                 }
287         }
288
289         /**
290          * Check if the associated Window/Tab is visible
291          * 
292          * @return State of visibility
293          */
294         public boolean isVisible() {
295                 if (parentTab != null) {
296                         ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper
297                                         .getCorrespondingUIElement(parentTab.getParentWindowId());
298                         return xcosWindow.isVisible();
299                 }
300
301                 return false;
302         }
303
304         /**
305          * A read-only state will disable all actions in the graph.
306          * 
307          * @param readOnly
308          *            Read-only state
309          */
310         public void setReadOnly(boolean readOnly) {
311                 this.readOnly = readOnly;
312
313                 setCellsLocked(readOnly);
314                 if (isReadonly()) {
315                         setOriginalColor(getAsComponent().getBackground());
316                         getAsComponent().setBackground(
317                                         new Color(DEFAULTCOLOR, DEFAULTCOLOR, DEFAULTCOLOR));
318                 } else {
319                         getAsComponent().setBackground(getOriginalColor());
320                 }
321         }
322
323         /**
324          * @return True if actions are not allowed, false otherwise.
325          */
326         public boolean isReadonly() {
327                 return readOnly;
328         }
329
330         /**
331          * Useful function for the read-only property
332          * 
333          * @param originalColor
334          *            The default color to apply
335          */
336         private void setOriginalColor(Color originalColor) {
337                 this.originalColor = originalColor;
338         }
339
340         /**
341          * Useful function for the read-only property
342          * 
343          * @return The default color
344          */
345         private Color getOriginalColor() {
346                 if (originalColor != null) {
347                         return originalColor;
348                 }
349                 return Color.WHITE;
350         }
351
352         /**
353          * @return The associated RubberBand
354          * @see com.mxgraph.swing.handler.mxRubberband
355          */
356         public mxRubberband getRubberBand() {
357                 return rubberBand;
358         }
359
360         /**
361          * @return The undo manager associated with this graph
362          */
363         protected final mxUndoManager getUndoManager() {
364                 return undoManager;
365         }
366 }