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