Add full options management to figure
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / window / SwingScilabWindow.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2007 - INRIA - Vincent Couvert
4  * Copyright (C) 2007 - INRIA - Bruno JOFRET
5  * Copyright (C) 2007 - INRIA - Marouane BEN JELLOUL
6  * Copyright (C) 2009 - DIGITEO - Sylvestre LEDRU (Mac OS X port)
7  * Copyright (C) 2011 - DIGITEO - Vincent Couvert
8  *
9  * This file must be used under the terms of the CeCILL.
10  * This source file is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution.  The terms
12  * are also available at
13  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
14  *
15  */
16
17 package org.scilab.modules.gui.bridge.window;
18
19 import java.awt.Dimension;
20 import java.awt.Frame;
21 import java.awt.Point;
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.awt.event.ComponentAdapter;
25 import java.awt.event.ComponentEvent;
26 import java.awt.event.WindowAdapter;
27 import java.awt.event.WindowEvent;
28 import java.lang.reflect.InvocationTargetException;
29 import java.rmi.server.UID;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.Map;
33 import java.util.UUID;
34
35 import javax.swing.ImageIcon;
36 import javax.swing.JComponent;
37 import javax.swing.JFrame;
38 import javax.swing.SwingUtilities;
39 import javax.swing.WindowConstants;
40
41 import org.flexdock.docking.DockingPort;
42 import org.scilab.modules.action_binding.InterpreterManagement;
43 import org.scilab.modules.commons.gui.ScilabKeyStroke;
44 import org.scilab.modules.gui.bridge.menubar.SwingScilabMenuBar;
45 import org.scilab.modules.gui.bridge.tab.SwingScilabDockablePanel;
46 import org.scilab.modules.gui.bridge.tab.SwingScilabPanel;
47 import org.scilab.modules.gui.bridge.textbox.SwingScilabTextBox;
48 import org.scilab.modules.gui.bridge.toolbar.SwingScilabToolBar;
49 import org.scilab.modules.gui.menubar.MenuBar;
50 import org.scilab.modules.gui.menubar.SimpleMenuBar;
51 import org.scilab.modules.gui.tab.SimpleTab;
52 import org.scilab.modules.gui.textbox.SimpleTextBox;
53 import org.scilab.modules.gui.textbox.TextBox;
54 import org.scilab.modules.gui.toolbar.SimpleToolBar;
55 import org.scilab.modules.gui.toolbar.ToolBar;
56 import org.scilab.modules.gui.utils.ClosingOperationsManager;
57 import org.scilab.modules.gui.utils.Position;
58 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
59 import org.scilab.modules.gui.utils.Size;
60 import org.scilab.modules.gui.window.SimpleWindow;
61
62 /**
63  * Swing implementation for Scilab windows in GUIs
64  * This implementation uses FlexDock package
65  * @author Vincent COUVERT
66  * @author Bruno JOFRET
67  * @author Marouane BEN JELLOUL
68  * @author Sylvestre LEDRU (Mac OS X port)
69
70  */
71 public abstract class SwingScilabWindow extends JFrame implements SimpleWindow {
72
73     private static final long serialVersionUID = -5661926417765805660L;
74
75     private static final int DEFAULTWIDTH = 500;
76     private static final int DEFAULTHEIGHT = 500;
77
78     public static Map<String, SwingScilabWindow> allScilabWindows = Collections.synchronizedMap(new HashMap<String, SwingScilabWindow>());
79
80     protected SimpleMenuBar menuBar;
81     protected SimpleToolBar toolBar;
82     protected SimpleTextBox infoBar;
83     private String uuid;
84     private int elementId; // the id of the Window which contains this SimpleWindow
85     protected String windowUID;
86     private final boolean MAC_OS_X = (System.getProperty("os.name").toLowerCase().startsWith("mac os x"));
87     private Dimension lastDimension;
88     private Point lastPosition;
89     private boolean isRestoring;
90
91     /**
92      * Constructor
93      */
94     public SwingScilabWindow() {
95         super();
96         this.uuid = UUID.randomUUID().toString();
97         setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
98
99         // By default ctrl+w close the window
100         ActionListener listener = new ActionListener() {
101             @Override
102             public void actionPerformed(ActionEvent e) {
103                 processWindowEvent(new WindowEvent(SwingScilabWindow.this, WindowEvent.WINDOW_CLOSING));
104             }
105         };
106         getRootPane().registerKeyboardAction(listener, ScilabKeyStroke.getKeyStroke("OSSCKEY W"), JComponent.WHEN_IN_FOCUSED_WINDOW);
107
108         // TODO : Only for testing : Must be removed
109         this.setDims(new Size(DEFAULTWIDTH, DEFAULTHEIGHT));
110         this.setTitle("Scilab");
111         setIconImage(new ImageIcon(ScilabSwingUtilities.findIcon("scilab", "256x256")).getImage());
112
113         /* defining the Layout */
114         super.setLayout(new java.awt.BorderLayout());
115         windowUID = new UID().toString();
116         allScilabWindows.put(windowUID, this);
117
118         /* there is no menuBar, no toolBar and no infoBar at creation */
119         this.menuBar = null;
120         this.toolBar = null;
121         this.infoBar = null;
122
123         /*
124          * Prevent the background RootPane to catch Focus.
125          * Causes trouble with Scicos use xclick & co.
126          */
127         //this.setFocusable(false);
128
129         // let the OS choose the window position if not specified by user.
130         setLocationByPlatform(true);
131
132         addWindowListener(new WindowAdapter() {
133             @Override
134             public void windowClosing(WindowEvent e) {
135                 ClosingOperationsManager.startClosingOperation(SwingScilabWindow.this);
136             }
137         });
138
139         addComponentListener(new ComponentAdapter() {
140             @Override
141             public void componentResized(ComponentEvent e) {
142                 if (getExtendedState() == NORMAL) {
143                     lastDimension = getSize();
144                 }
145             }
146
147             @Override
148             public void componentMoved(ComponentEvent e) {
149                 if (getExtendedState() == NORMAL) {
150                     lastPosition = getLocation();
151                 }
152             }
153         });
154
155         if (MAC_OS_X) {
156             registerForMacOSXEvents();
157         }
158
159
160
161
162     }
163
164     public void setIsRestoring(boolean b) {
165         isRestoring = b;
166     }
167
168     public boolean isRestoring() {
169         return isRestoring;
170     }
171
172     /**
173      * Get the last dimension of the window before MAXIMIZED or MINIMIZED
174      * @return the last dimension
175      */
176     public Dimension getLastDimension() {
177         if (lastDimension == null) {
178             return getSize();
179         }
180
181         return lastDimension;
182     }
183
184     /**
185      * Get the last position of the window before MAXIMIZED or MINIMIZED
186      * @return the last position
187      */
188     public Point getLastPosition() {
189         if (lastPosition == null) {
190             return getLocation();
191         }
192
193         return lastPosition;
194     }
195
196     /**
197      * This method registers some methods against the specific Mac OS X API
198      * (in order to set the "special" mac os x menus)
199      */
200     private void registerForMacOSXEvents() {
201         try {
202             // Generate and register the OSXAdapter, passing it a hash of all the methods we wish to
203             // use as delegates for various com.apple.eawt.ApplicationListener methods
204             OSXAdapter.setAboutHandler(this, getClass().getMethod("macosxAbout", (Class[]) null));
205             OSXAdapter.setQuitHandler(this, getClass().getMethod("macosxQuit", (Class[]) null));
206             OSXAdapter.setPreferencesHandler(this, getClass().getMethod("macosxPreferences", (Class[]) null));
207             OSXAdapter.setDockIcon(new ImageIcon(ScilabSwingUtilities.findIcon("puffin", "256x256")));
208         } catch (java.lang.NoSuchMethodException e) {
209             System.err.println("OSXAdapter could not find the method: " + e.getLocalizedMessage());
210         }
211     }
212
213     /**
214      * This method is called by the OSXAdapter class when the specific Mac
215      * OS X "About" menu is called. It is the only case where this method
216      * should be used
217      */
218     public void macosxAbout() {
219         InterpreterManagement.requestScilabExec("about();");
220     }
221
222     /**
223      * This method is called by the OSXAdapter class when the specific Mac
224      * OS X "Quit Scilab" menu is called. It is the only case where this method
225      * should be used
226      */
227     public boolean macosxQuit() {
228         InterpreterManagement.requestScilabExec("exit();");
229         return false;
230     }
231
232     /**
233      * This method is called by the OSXAdapter class when the specific Mac
234      * OS X "Preferences" menu is called. It is the only case where this method
235      * should be used
236      */
237     public void macosxPreferences() {
238         InterpreterManagement.requestScilabExec("preferences();");
239     }
240
241     /**
242      * @return the UUID associated with this window
243      */
244     public String getUUID() {
245         return uuid;
246     }
247
248     /**
249      * @param uuid the UUID associated with this window
250      */
251     public void setUUID(String uuid) {
252         this.uuid = uuid;
253     }
254
255     /**
256      * Creates a swing Scilab window
257      * @return the created window
258      */
259     public static SwingScilabWindow createWindow(boolean isDockingPort) {
260         if (isDockingPort) {
261             return new SwingScilabDockingWindow();
262         }
263         return new SwingScilabStaticWindow();
264     }
265
266     /**
267      * Draws a swing Scilab window
268      * @see org.scilab.modules.gui.uielement.UIElement#draw()
269      */
270     @Override
271     public void draw() {
272         this.setVisible(true);
273         this.doLayout();
274     }
275
276     /**
277      * Private method to raise to the front the window
278      */
279     private void raiseToFront() {
280         // force visibility
281         setVisible(true);
282
283         // deiconify the window if needed
284         setState(NORMAL);
285
286         // put it in front of others
287         toFront();
288     }
289
290     /**
291      * Deiconify the window and put it in front of other window
292      */
293     @Override
294     public void raise() {
295         // blocking call. So graphic synchronization must be desactivated here.
296         if (!SwingUtilities.isEventDispatchThread()) {
297             /* javasci bug: See bug 9544 why we are doing this check */
298             try {
299                 SwingUtilities.invokeAndWait(new Runnable() {
300                     @Override
301                     public void run() {
302                         raiseToFront();
303                     }
304                 });
305             } catch (InterruptedException e) {
306                 e.printStackTrace();
307             } catch (InvocationTargetException e) {
308                 e.printStackTrace();
309             }
310         } else {
311             raiseToFront();
312         }
313     }
314
315     /**
316      * Gets the dimensions (width and height) of a swing Scilab window
317      * @return the dimensions of the window
318      * @see org.scilab.modules.gui.uielement.UIElement#getDims()
319      */
320     @Override
321     public Size getDims() {
322         return new Size(getSize().width, getSize().height);
323
324     }
325
326     /**
327      * Sets the dimensions (width and height) of a swing Scilab window
328      * @param newWindowSize the dimensions to set to the window
329      * @see org.scilab.modules.gui.uielement.UIElement#setDims(org.scilab.modules.gui.utils.Size)
330      */
331     @Override
332     public void setDims(Size newWindowSize) {
333         //if (!SwingUtilities.isEventDispatchThread()) {
334         if (getDims().getWidth() != newWindowSize.getWidth() || getDims().getHeight() != newWindowSize.getHeight()) {
335             Dimension finalDim = new Dimension(newWindowSize.getWidth(), newWindowSize.getHeight());
336
337             setSize(finalDim);
338             setPreferredSize(finalDim);
339             // validate so the new values are taken into account immediately
340             validate();
341         }
342         //}
343     }
344
345     /**
346      * Gets the position (X-coordinate and Y-coordinate) of a swing Scilab window
347      * @return the position of the window
348      * @see org.scilab.modules.gui.uielement.UIElement#getPosition()
349      */
350     @Override
351     public Position getPosition() {
352         return new Position(this.getX(), this.getY());
353     }
354
355     /**
356      * Sets the position (X-coordinate and Y-coordinate) of a swing Scilab window
357      * @param newWindowPosition the position to set to the window
358      * @see org.scilab.modules.gui.uielement.UIElement#setPosition(org.scilab.modules.gui.utils.Position)
359      */
360     @Override
361     public void setPosition(Position newWindowPosition) {
362         //if (!SwingUtilities.isEventDispatchThread()) {
363         if (getPosition().getX() != newWindowPosition.getX() || getPosition().getY() != newWindowPosition.getY()) {
364             this.setLocation(newWindowPosition.getX(), newWindowPosition.getY());
365         }
366         //}
367     }
368
369     /**
370      * Gets the title of a swing Scilab window
371      * @return the title of the window
372      * @see javax.swing.JFrame#getTitle()
373      */
374     @Override
375     public String getTitle() {
376         return super.getTitle();
377     }
378
379     /**
380      * Sets the title of a swing Scilab window
381      * @param newWindowTitle the title to set to the window
382      * @see java.awt.Frame#setTitle(java.lang.String)
383      */
384     @Override
385     public void setTitle(String newWindowTitle) {
386         // set only if required
387         if (newWindowTitle != null && !newWindowTitle.equals(getTitle())) {
388             super.setTitle(newWindowTitle);
389         }
390     }
391
392     /**
393      * {@inheritedDoc}
394      */
395     @Override
396     public void setName(String name) {
397         super.setName(name);
398         setTitle(name);
399     }
400
401     /**
402      * Gets the docking port associated to the window (created by default at window creation)
403      * @return the docking port associated to the window
404      */
405     public abstract DockingPort getDockingPort();
406
407     /**
408      * Add a Scilab tab to a Scilab window
409      * @param newTab the Scilab tab to add to the Scilab window
410      * @see org.scilab.modules.gui.window.Window#addTab(org.scilab.modules.gui.tab.Tab)
411      */
412     public abstract void addTab(SwingScilabPanel newTab);
413
414     /**
415      * Remove a Scilab tab from a Scilab window
416      * @param tabs the Scilab tabs to remove from the Scilab window
417      * @see org.scilab.modules.gui.window.Window#removeTab(org.scilab.modules.gui.tab.Tab)
418      */
419     public abstract void removeTabs(SwingScilabPanel[] tabs);
420     /**
421      * Remove a Scilab tab from a Scilab window
422      * @param tab the Scilab tab to remove from the Scilab window
423      * @see org.scilab.modules.gui.window.Window#removeTab(org.scilab.modules.gui.tab.Tab)
424      */
425     public void removeTab(SimpleTab tab) {
426         removeTabs(new SwingScilabDockablePanel[] {(SwingScilabDockablePanel) tab});
427     }
428
429     /**
430      * Sets a Scilab MenuBar to a Scilab window
431      * @param newMenuBar the Scilab MenuBar to add to the Scilab window
432      * @see org.scilab.modules.gui.window.Window#addMenuBar(org.scilab.modules.gui.menubar.MenuBar)
433      */
434     @Override
435     public void addMenuBar(MenuBar newMenuBar) {
436         if (newMenuBar == null) {
437             if (this.menuBar != null) {
438                 this.menuBar = null;
439                 setJMenuBar(null);
440             }
441             // else nothing to do both are null
442         } else {
443             if (this.menuBar != newMenuBar.getAsSimpleMenuBar()) {
444                 this.menuBar = newMenuBar.getAsSimpleMenuBar();
445
446                 setJMenuBar((SwingScilabMenuBar) newMenuBar.getAsSimpleMenuBar());
447             }
448             //  else nothing to do element alredy set
449         }
450     }
451
452     public boolean compareMenuBar(MenuBar mb) {
453         if (mb == null ^ this.menuBar == null) {
454             return false;
455         }
456
457         if (mb == null && this.menuBar == null) {
458             return true;
459         }
460
461         return mb.getAsSimpleMenuBar() == this.menuBar;
462     }
463
464     /**
465      * Sets a Scilab ToolBar to a Scilab window
466      * @param newToolBar the Scilab ToolBar to set to the Scilab window
467      * @see org.scilab.modules.gui.window.Window#addToolBar(org.scilab.modules.gui.toolbar.ToolBar)
468      */
469     @Override
470     public void addToolBar(ToolBar newToolBar) {
471         if (newToolBar == null) {
472             if (this.toolBar != null) {
473                 // Remove old InfoBar if already set
474                 super.remove((SwingScilabToolBar) this.toolBar);
475                 this.toolBar = null;
476             }
477             // else nothing to do both are null
478         } else {
479             if (this.toolBar != newToolBar.getAsSimpleToolBar()) {
480                 if (this.toolBar != null) {
481                     // Remove old InfoBar if already set
482                     super.remove((SwingScilabToolBar) this.toolBar);
483                 }
484                 this.toolBar = newToolBar.getAsSimpleToolBar();
485                 super.add((SwingScilabToolBar) this.toolBar, java.awt.BorderLayout.PAGE_START);
486             }
487             //  else nothing to do element alredy set
488         }
489     }
490
491     public boolean compareToolBar(ToolBar tb) {
492         if (tb == null ^ this.toolBar == null) {
493             return false;
494         }
495
496         if (tb == null && this.toolBar == null) {
497             return true;
498         }
499
500         return tb.getAsSimpleToolBar() == this.toolBar;
501     }
502
503     /**
504      * Sets a Scilab InfoBar to a Scilab window
505      * @param newInfoBar the Scilab InfoBar to set to the Scilab window
506      * @see org.scilab.modules.gui.window.Window#addInfoBar(org.scilab.modules.gui.textbox.TextBox)
507      */
508     @Override
509     public void addInfoBar(TextBox newInfoBar) {
510         if (newInfoBar == null) {
511             if (this.infoBar != null) {
512                 // Remove old InfoBar if already set
513                 super.remove((SwingScilabTextBox) this.infoBar);
514                 this.infoBar = null;
515             }
516             // else nothing to do both are null
517         } else {
518             if (this.infoBar != newInfoBar.getAsSimpleTextBox()) {
519                 if (this.infoBar != null) {
520                     // Remove old InfoBar if already set
521                     super.remove((SwingScilabTextBox) this.infoBar);
522                 }
523                 this.infoBar = newInfoBar.getAsSimpleTextBox();
524                 super.add((SwingScilabTextBox) this.infoBar, java.awt.BorderLayout.PAGE_END);
525             }
526             //  else nothing to do element alredy set
527         }
528     }
529
530     public boolean compareInfoBar(TextBox ib) {
531         if (ib == null ^ this.infoBar == null) {
532             return false;
533         }
534
535         if (ib == null && this.infoBar == null) {
536             return true;
537         }
538
539         return ib.getAsSimpleTextBox() == this.infoBar;
540     }
541
542     /**
543      * Get the element id for this window
544      * @return id the id of the corresponding window object
545      */
546     @Override
547     public int getElementId() {
548         return elementId;
549     }
550
551     /**
552      * Set the element id for this window
553      * @param id the id of the corresponding window object
554      */
555     @Override
556     public void setElementId(int id) {
557         this.elementId = id;
558         //sciDockingListener.setAssociatedWindowId(id);
559     }
560
561     /**
562      * Close the window
563      * @see org.scilab.modules.gui.window.SimpleWindow#close()
564      */
565     @Override
566     public abstract void close();
567
568     /**
569      * @return number of objects (tabs) docked in this window
570      */
571     @Override
572     public abstract int getNbDockedObjects();
573
574     /**
575      * Update the dimension of the window and its component.
576      * Only useful when the window is not yet visible
577      */
578     @Override
579     public void updateDimensions() {
580         pack();
581     }
582
583     /**
584      * DeIconify Window
585      */
586     @Override
587     public void windowDeiconified() {
588         super.setState(Frame.NORMAL);
589     }
590
591     /**
592      * Iconify Window
593      */
594     @Override
595     public void windowIconified() {
596         super.setState(Frame.ICONIFIED);
597     }
598
599     /**
600      * Maximized Window
601      */
602     @Override
603     public void windowMaximized() {
604         super.setExtendedState(Frame.MAXIMIZED_BOTH);
605     }
606
607     /**
608      * Window is in the "normal" state.
609      */
610     @Override
611     public void windowNormal() {
612         super.setState(Frame.NORMAL);
613     }
614
615     /**
616      * Get the window UID
617      * @return the UID
618      */
619     public String getId() {
620         return windowUID;
621     }
622 }