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