5d8023d4f11fdffb31efd1ad7fd329cebb31272a
[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                                                 .getArgAt(0));
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.getArgAt(0))
89                                         .getChanges();
90                         setSelectionCells(getSelectionCellsForChanges(changes));
91                 }
92         };
93
94         /**
95          * Default constructor: - disable unused actions - install listeners -
96          * Replace JGraphX components by specialized components if needed.
97          */
98         public ScilabGraph() {
99                 super();
100
101                 // Disabling the default connected action and event listeners.
102                 mxGraphActions.getSelectNextAction().setEnabled(false);
103                 mxGraphActions.getSelectPreviousAction().setEnabled(false);
104                 mxGraphActions.getSelectChildAction().setEnabled(false);
105                 mxGraphActions.getSelectParentAction().setEnabled(false);
106
107                 // Undo / Redo capabilities
108                 getModel().addListener(mxEvent.UNDO, undoHandler);
109                 getView().addListener(mxEvent.UNDO, undoHandler);
110
111                 // Keeps the selection in sync with the command history
112                 undoManager.addListener(mxEvent.UNDO, selectionHandler);
113                 undoManager.addListener(mxEvent.REDO, selectionHandler);
114
115                 component = new XcosComponent(this);
116
117                 // Adds rubberband selection
118                 rubberBand = new mxRubberband(component);
119
120                 // Modified property change
121                 getModel().addListener(mxEvent.CHANGE, changeTracker);
122         }
123
124         /**
125          * @return The previously saved file or null.
126          */
127         public String getSavedFile() {
128                 return savedFile;
129         }
130
131         /**
132          * @param savedFile
133          *            The new saved file
134          */
135         public void setSavedFile(String savedFile) {
136                 this.savedFile = savedFile;
137         }
138
139         /**
140          * @return true, if the graph has been modified ; false otherwise.
141          */
142         public boolean isModified() {
143                 return modified;
144         }
145
146         /**
147          * Modify the state of the diagram.
148          * 
149          * @param modified
150          *            The new modified state.
151          * @category UseEvent
152          */
153         public void setModified(boolean modified) {
154                 boolean oldValue = this.modified;
155                 this.modified = modified;
156
157                 getAsComponent().firePropertyChange("modified", oldValue, modified);
158         }
159
160         /**
161          * @param title
162          *            The new title of the tab
163          */
164         public void setTitle(String title) {
165                 this.title = title;
166         }
167
168         /**
169          * @return The current Tab title
170          */
171         public String getTitle() {
172                 return title;
173         }
174
175         /**
176          * @return The component associated with the current graph.
177          */
178         public mxGraphComponent getAsComponent() {
179                 return component;
180         }
181
182         /**
183          * Undo the last action
184          * 
185          * @see com.mxgraph.util.mxUndoManager
186          */
187         public void undo() {
188                 decrementUndoCounter();
189                 redoInAction = true;
190                 undoManager.undo();
191                 redoInAction = false;
192         }
193
194         /**
195          * Redo the last action com.mxgraph.util.mxUndoManager
196          */
197         public void redo() {
198                 incrementUndoCounter();
199                 redoInAction = true;
200                 undoManager.redo();
201                 redoInAction = false;
202         }
203
204         /**
205          * Used internally to manage the modified state on undo/redo
206          */
207         private void incrementUndoCounter() {
208                 if (undoCounter < Integer.MAX_VALUE) {
209                         undoCounter++;
210                 }
211         }
212
213         /**
214          * Used internally to manage the modified state on undo/redo
215          */
216         private void decrementUndoCounter() {
217                 if (undoCounter > Integer.MIN_VALUE) {
218                         undoCounter--;
219                 }
220         }
221
222         /**
223          * Used internally to manage the modified state on undo/redo
224          * 
225          * @return true if the document is in a previous saved state, false
226          *         otherwise
227          */
228         protected boolean isZeroUndoCounter() {
229                 return (undoCounter == 0);
230         }
231
232         /**
233          * Used internally to manage the modified state on undo/redo
234          */
235         protected void resetUndoCounter() {
236                 undoCounter = 0;
237         }
238
239         /**
240          * @return The associated Tab
241          */
242         public Tab getParentTab() {
243                 return parentTab;
244         }
245
246         /**
247          * @param parentTab
248          *            The new associated Tab
249          */
250         public void setParentTab(Tab parentTab) {
251                 this.parentTab = parentTab;
252         }
253
254         /**
255          * The instance can be not visible but used (when using SuperBlock). The
256          * openned flag is true in this case and also when the Window/Tab is
257          * visible.
258          * 
259          * @param opened
260          *            Openned state
261          */
262         public void setOpened(boolean opened) {
263                 this.opened = opened;
264         }
265
266         /**
267          * @return Openned state
268          */
269         public boolean isOpened() {
270                 return opened;
271         }
272
273         /**
274          * Set the associated Window/Tab visible or not.
275          * 
276          * @param visible
277          *            State of visibility
278          */
279         public void setVisible(boolean visible) {
280                 if (parentTab != null) {
281                         ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper
282                                         .getCorrespondingUIElement(parentTab.getParentWindowId());
283                         xcosWindow.setVisible(visible);
284                 }
285         }
286
287         /**
288          * Check if the associated Window/Tab is visible
289          * 
290          * @return State of visibility
291          */
292         public boolean isVisible() {
293                 if (parentTab != null) {
294                         ScilabWindow xcosWindow = (ScilabWindow) UIElementMapper
295                                         .getCorrespondingUIElement(parentTab.getParentWindowId());
296                         return xcosWindow.isVisible();
297                 }
298
299                 return false;
300         }
301
302         /**
303          * A read-only state will disable all actions in the graph.
304          * 
305          * @param readOnly
306          *            Read-only state
307          */
308         public void setReadOnly(boolean readOnly) {
309                 this.readOnly = readOnly;
310
311                 setCellsLocked(readOnly);
312                 if (isReadonly()) {
313                         setOriginalColor(getAsComponent().getBackground());
314                         getAsComponent().setBackground(
315                                         new Color(DEFAULTCOLOR, DEFAULTCOLOR, DEFAULTCOLOR));
316                 } else {
317                         getAsComponent().setBackground(getOriginalColor());
318                 }
319         }
320
321         /**
322          * @return True if actions are not allowed, false otherwise.
323          */
324         public boolean isReadonly() {
325                 return readOnly;
326         }
327
328         /**
329          * Useful function for the read-only property
330          * 
331          * @param originalColor
332          *            The default color to apply
333          */
334         private void setOriginalColor(Color originalColor) {
335                 this.originalColor = originalColor;
336         }
337
338         /**
339          * Useful function for the read-only property
340          * 
341          * @return The default color
342          */
343         private Color getOriginalColor() {
344                 if (originalColor != null) {
345                         return originalColor;
346                 }
347                 return Color.WHITE;
348         }
349
350         /**
351          * @return The associated RubberBand
352          * @see com.mxgraph.swing.handler.mxRubberband
353          */
354         public mxRubberband getRubberBand() {
355                 return rubberBand;
356         }
357
358         /**
359          * @return The undo manager associated with this graph
360          */
361         protected final mxUndoManager getUndoManager() {
362                 return undoManager;
363         }
364 }