* Bug #11964 fixed - uicontrol coordinates system did not take figure resizing into...
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / tab / SwingScilabCommonPanel.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2014 - Scilab Enterprises - 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.1-en.txt
10  *
11  */
12 package org.scilab.modules.gui.bridge.tab;
13
14 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AUTORESIZE__;
15 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_AXES_SIZE__;
16 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_BACKGROUND__;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_BORDER_OPT_PADDING__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_CALLBACK__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_CHILDREN__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_COLORMAP__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_EVENTHANDLER_ENABLE__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_EVENTHANDLER_NAME__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_GRID_OPT_GRID__;
24 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_GRID_OPT_PADDING__;
25 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_ID__;
26 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_INFOBAR_VISIBLE__;
27 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_INFO_MESSAGE__;
28 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_LAYOUT__;
29 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_MENUBAR_VISIBLE__;
30 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_NAME__;
31 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_POSITION__;
32 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_RESIZE__;
33 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_SIZE__;
34 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_TOOLBAR_VISIBLE__;
35 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_TYPE__;
36 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UICHECKEDMENU__;
37 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UICHILDMENU__;
38 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UIMENU__;
39 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UIPARENTMENU__;
40 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_ICON__;
41 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_VISIBLE__;
42
43 import java.awt.BorderLayout;
44 import java.awt.Component;
45 import java.awt.Dimension;
46 import java.awt.GridBagConstraints;
47 import java.awt.GridBagLayout;
48 import java.awt.GridLayout;
49 import java.awt.Insets;
50 import java.awt.image.BufferedImage;
51 import java.io.File;
52 import java.io.IOException;
53
54 import javax.imageio.ImageIO;
55 import javax.swing.ImageIcon;
56 import javax.swing.JLayeredPane;
57
58 import org.scilab.modules.commons.gui.FindIconHelper;
59 import org.scilab.modules.graphic_objects.figure.Figure;
60 import org.scilab.modules.graphic_objects.figure.Figure.BarType;
61 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
62 import org.scilab.modules.graphic_objects.graphicModel.GraphicModel;
63 import org.scilab.modules.graphic_objects.uicontrol.Uicontrol;
64 import org.scilab.modules.graphic_objects.utils.LayoutType;
65 import org.scilab.modules.gui.SwingView;
66 import org.scilab.modules.gui.SwingViewObject;
67 import org.scilab.modules.gui.bridge.frame.SwingScilabFrame;
68 import org.scilab.modules.gui.bridge.frame.SwingScilabScrollableFrame;
69 import org.scilab.modules.gui.bridge.window.SwingScilabWindow;
70 import org.scilab.modules.gui.events.callback.ScilabCloseCallBack;
71 import org.scilab.modules.gui.toolbar.ToolBar;
72 import org.scilab.modules.gui.utils.Position;
73 import org.scilab.modules.gui.utils.Size;
74 import org.scilab.modules.gui.utils.ToolBarBuilder;
75 import org.scilab.modules.renderer.JoGLView.util.ColorFactory;
76
77 public class SwingScilabCommonPanel {
78
79     public static final String GRAPHICS_TOOLBAR_DESCRIPTOR = System.getenv("SCI") + "/modules/gui/etc/graphics_toolbar.xml";
80
81     /**
82      * Update the tab after a modification of its properties
83      * @param property the property name
84      * @param value the property value
85      * @see org.scilab.modules.gui.SwingViewObject#update(java.lang.String,
86      * java.lang.Object)
87      */
88     protected static void update(SwingScilabPanel component, int property, Object value) {
89         String name;
90         Integer figureId;
91         switch (property) {
92             case __GO_NAME__:
93                 name = ((String) value);
94                 figureId = (Integer) GraphicController.getController().getProperty(component.getId(), __GO_ID__);
95                 updateTitle(component, name, figureId);
96                 break;
97             case __GO_ID__:
98                 /* Update title */
99                 figureId = ((Integer) value);
100                 Figure localFigure = (Figure) GraphicController.getController().getObjectFromId(component.getId());
101                 name = localFigure.getName();
102                 updateTitle(component, name, figureId);
103
104                 /** Update tool bar */
105                 if (localFigure.getToolbarAsEnum() == BarType.FIGURE) {
106                     SwingScilabWindow parentWindow = SwingScilabWindow.allScilabWindows.get(component.getParentWindowId());
107
108                     //keep current delta between figure size and axes size
109                     component.storeSizeDelta();
110
111                     ToolBar toolbar = ToolBarBuilder.buildToolBar(GRAPHICS_TOOLBAR_DESCRIPTOR, figureId);
112                     toolbar.setVisible(localFigure.getToolbarVisible());
113                     component.setToolBar(toolbar);
114                     parentWindow.addToolBar(toolbar);
115                     //force redraw to get good value on contentpane.getHeight
116                     parentWindow.validate();
117
118                     //apply stored delta to new axes size
119                     component.applyDeltaSize();
120                 }
121
122                 /* Update callback */
123                 String closingCommand =
124                     "if (get_figure_handle(" + figureId + ") <> []) then"
125                     + "  if (get(get_figure_handle(" + figureId + "), 'event_handler_enable') == 'on') then"
126                     + "    execstr(get(get_figure_handle(" + figureId + "), 'event_handler')+'(" + figureId + ", -1, -1, -1000)', 'errcatch', 'm');"
127                     + "  end;"
128                     + "  delete(get_figure_handle(" + figureId + "));"
129                     + "end;";
130                 component.setCallback(null);
131                 component.setCallback(ScilabCloseCallBack.create(component.getId(), closingCommand));
132                 /* Update menus callback */
133                 Integer[] children = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_CHILDREN__);
134                 updateChildrenCallbacks(children, figureId);
135                 break;
136             case __GO_SIZE__: {
137                 Integer[] size = (Integer[]) value;
138                 SwingScilabWindow figure = SwingScilabWindow.allScilabWindows.get(component.getParentWindowId());
139                 Size oldFigureSize = figure.getDims();
140                 if (oldFigureSize.getWidth() != 0 && oldFigureSize.getHeight() != 0 && ((oldFigureSize.getWidth() != size[0]) || (oldFigureSize.getHeight() != size[1]))
141                         && ((Boolean) GraphicController.getController().getProperty(component.getId(), __GO_AUTORESIZE__))) {
142                     figure.setDims(new Size(size[0], size[1]));
143                 }
144                 break;
145             }
146             case __GO_POSITION__:
147                 Integer[] position = (Integer[]) value;
148                 SwingScilabWindow.allScilabWindows.get(component.getParentWindowId()).setPosition(new Position(position[0], position[1]));
149                 break;
150             case __GO_AXES_SIZE__:
151                 Integer[] axesSize = (Integer[]) value;
152                 Dimension oldAxesSize = component.getContentPane().getSize();
153                 if (oldAxesSize.getWidth() != 0 && oldAxesSize.getHeight() != 0 && ((oldAxesSize.getWidth() != axesSize[0]) || (oldAxesSize.getHeight() != axesSize[1]))
154                         && ((Boolean) GraphicController.getController().getProperty(component.getId(), __GO_AUTORESIZE__))) {
155                     // TODO manage tabs when there are docked (do not change the window size if more than one tab docked)
156                     int deltaX = axesSize[0] - (int) oldAxesSize.getWidth();
157                     int deltaY = axesSize[1] - (int) oldAxesSize.getHeight();
158                     Size parentWindowSize = SwingScilabWindow.allScilabWindows.get(component.getParentWindowId()).getDims();
159                     SwingScilabWindow.allScilabWindows.get(component.getParentWindowId()).setDims(new Size(parentWindowSize.getWidth() + deltaX, parentWindowSize.getHeight() + deltaY));
160                 }
161                 break;
162             case __GO_INFO_MESSAGE__:
163                 if (component.getInfoBar() != null) {
164                     component.getInfoBar().setText((String) value);
165                 }
166                 break;
167             case __GO_EVENTHANDLER_ENABLE__:
168                 Boolean enabled = (Boolean) GraphicController.getController().getProperty(component.getId(), __GO_EVENTHANDLER_ENABLE__);
169                 component.setEventHandlerEnabled(enabled);
170                 break;
171             case __GO_EVENTHANDLER_NAME__:
172                 String eventHandlerName = (String) GraphicController.getController().getProperty(component.getId(), __GO_EVENTHANDLER_NAME__);
173                 component.setEventHandler(eventHandlerName);
174                 break;
175             case __GO_VISIBLE__:
176                 component.getContentPane().setVisible((Boolean) value);
177                 if (component.getParentWindow().getNbDockedObjects() == 1) {
178                     component.getParentWindow().setVisible((Boolean) value);
179                 }
180                 break;
181             case __GO_INFOBAR_VISIBLE__: {
182                 Integer[] oldSize = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_AXES_SIZE__);
183                 component.getInfoBar().setVisible((Boolean) value);
184                 SwingScilabWindow parentWindow = SwingScilabWindow.allScilabWindows.get(component.getParentWindowId());
185                 parentWindow.validate();
186                 GraphicController.getController().setProperty(component.getId(), __GO_AXES_SIZE__, oldSize);
187                 break;
188             }
189             case __GO_TOOLBAR_VISIBLE__: {
190                 Integer[] oldSize = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_AXES_SIZE__);
191                 component.getToolBar().setVisible((Boolean) value);
192                 SwingScilabWindow parentWindow = SwingScilabWindow.allScilabWindows.get(component.getParentWindowId());
193                 parentWindow.validate();
194                 GraphicController.getController().setProperty(component.getId(), __GO_AXES_SIZE__, oldSize);
195                 break;
196             }
197             case __GO_MENUBAR_VISIBLE__: {
198                 Integer[] oldSize = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_AXES_SIZE__);
199                 component.getMenuBar().setVisible((Boolean) value);
200                 SwingScilabWindow parentWindow = SwingScilabWindow.allScilabWindows.get(component.getParentWindowId());
201                 parentWindow.validate();
202                 GraphicController.getController().setProperty(component.getId(), __GO_AXES_SIZE__, oldSize);
203                 break;
204             }
205             case __GO_RESIZE__:
206                 component.getParentWindow().setResizable((Boolean) value);
207                 break;
208             case __GO_LAYOUT__:
209                 LayoutType newLayout = LayoutType.intToEnum((Integer) value);
210                 switch (newLayout) {
211                     case BORDER: {
212                         Integer[] padding = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_BORDER_OPT_PADDING__);
213                         component.getWidgetPane().setLayout(new BorderLayout(padding[0], padding[1]));
214                         component.getWidgetPane().setLayout(new BorderLayout());
215                         component.setHasLayout(true);
216                         break;
217                     }
218                     case GRIDBAG: {
219                         component.getWidgetPane().setLayout(new GridBagLayout());
220                         component.setHasLayout(true);
221                         break;
222                     }
223                     case GRID: {
224                         Integer[] padding = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_GRID_OPT_PADDING__);
225                         Integer[] grid = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_GRID_OPT_GRID__);
226                         Integer[] localGrid = new Integer[] { 0, 0 };
227                         localGrid[0] = grid[0];
228                         localGrid[1] = grid[1];
229
230                         if (localGrid[0] == 0 && localGrid[1] == 0) {
231                             localGrid[0] = 1;
232                         }
233
234                         component.getWidgetPane().setLayout(new GridLayout(localGrid[0], localGrid[1], padding[0], padding[1]));
235                         component.setHasLayout(true);
236                         break;
237                     }
238                     case NONE:
239                     default:
240                         component.getWidgetPane().setLayout(null);
241                         component.setHasLayout(false);
242                         break;
243                 }
244                 break;
245             case __GO_GRID_OPT_PADDING__:
246             case __GO_GRID_OPT_GRID__: {
247                 Integer layout = (Integer) GraphicController.getController().getProperty(component.getId(), __GO_LAYOUT__);
248                 LayoutType layoutType = LayoutType.intToEnum(layout);
249
250                 if (layoutType != LayoutType.GRID) {
251                     break;
252                 }
253
254                 Integer[] padding = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_GRID_OPT_PADDING__);
255
256                 Integer[] grid = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_GRID_OPT_GRID__);
257                 Integer[] localGrid = new Integer[] { 0, 0 };
258                 localGrid[0] = grid[0];
259                 localGrid[1] = grid[1];
260
261                 if (localGrid[0] == 0 && localGrid[1] == 0) {
262                     localGrid[0] = 1;
263                 }
264
265                 component.getWidgetPane().setLayout(new GridLayout(localGrid[0], localGrid[1], padding[0], padding[1]));
266                 break;
267             }
268             case __GO_BORDER_OPT_PADDING__: {
269                 Integer layout = (Integer) GraphicController.getController().getProperty(component.getId(), __GO_LAYOUT__);
270                 LayoutType layoutType = LayoutType.intToEnum(layout);
271
272                 if (layoutType != LayoutType.BORDER) {
273                     break;
274                 }
275
276                 Integer[] padding = (Integer[]) GraphicController.getController().getProperty(component.getId(), __GO_BORDER_OPT_PADDING__);
277                 component.getWidgetPane().setLayout(new BorderLayout(padding[0], padding[1]));
278                 component.getWidgetPane().setLayout(new BorderLayout());
279                 break;
280             }
281             case __GO_UI_ICON__: {
282                 File file = new File((String) value);
283                 if (file.exists() == false) {
284                     String filename = FindIconHelper.findImage((String) value);
285                     file = new File(filename);
286                 }
287
288                 try {
289                     BufferedImage icon = ImageIO.read(file);
290                     component.getParentWindow().setIconImage(new ImageIcon(icon).getImage());
291                 } catch (IOException e) {
292                 }
293                 break;
294             }
295             case __GO_COLORMAP__: {
296                 // Force background
297                 Figure figure = (Figure) GraphicController.getController().getObjectFromId(component.getId());
298                 component.setFigureBackground(ColorFactory.createColor(figure.getColorMap(), figure.getBackground()));
299                 break;
300             }
301             case __GO_BACKGROUND__: {
302                 Figure figure = (Figure) GraphicController.getController().getObjectFromId(component.getId());
303                 component.setFigureBackground(ColorFactory.createColor(figure.getColorMap(), (Integer) value));
304                 break;
305             }
306         }
307     }
308
309     /**
310      * Update the title of the Tab
311      * @param figureName figure_name property
312      * @param figureId figure_id property
313      */
314     private static void updateTitle(SwingScilabPanel component, String figureName, Integer figureId) {
315         if ((figureName != null) && (figureId != null)) {
316             String figureTitle = figureName.replaceFirst("%d", figureId.toString());
317             component.setName(figureTitle);
318         }
319     }
320
321     /**
322      * Update the menus callbacks when they are linked to the figure ID
323      * @param children the children UID
324      * @param parentFigureId the figure ID
325      */
326     private static void updateChildrenCallbacks(Integer[] children, int parentFigureId) {
327         for (int kChild = 0; kChild < children.length; kChild++) {
328             Integer childType = (Integer) GraphicController.getController().getProperty(children[kChild], __GO_TYPE__);
329             if (childType != null && (childType == __GO_UIMENU__ || childType == __GO_UIPARENTMENU__ || childType == __GO_UICHILDMENU__ || childType == __GO_UICHECKEDMENU__)) {
330                 String cb = (String) GraphicController.getController().getProperty(children[kChild], __GO_CALLBACK__);
331                 SwingView.getFromId(children[kChild]).update(__GO_CALLBACK__, replaceFigureID(cb, parentFigureId));
332                 Integer[] menuChildren = (Integer[]) GraphicController.getController().getProperty(children[kChild], __GO_CHILDREN__);
333                 updateChildrenCallbacks(menuChildren, parentFigureId);
334             }
335         }
336     }
337
338     /**
339      * Replace pattern [SCILAB_FIGURE_ID] by the figure index
340      * @param initialString string read in XML file
341      * @param parentFigureId the figure ID
342      * @return callback string
343      */
344     private static String replaceFigureID(String initialString, Integer parentFigureId) {
345         return initialString.replaceAll("\\[SCILAB_FIGURE_ID\\]", Integer.toString(parentFigureId));
346     }
347
348     /**
349      * Add a SwingViewObject (from SwingView.java) to container and returns its
350      * index
351      * @param member the member to add
352      */
353     protected static void addMember(SwingScilabPanel component, SwingViewObject member) {
354         //member.get
355         Uicontrol uicontrol = (Uicontrol) GraphicModel.getModel().getObjectFromId(member.getId());
356         if (component.getWidgetPane().getLayout() instanceof BorderLayout) {
357             switch (uicontrol.getBorderPositionAsEnum()) {
358                 case BOTTOM:
359                     component.getWidgetPane().add((Component) member, BorderLayout.SOUTH);
360                     break;
361                 case TOP:
362                     component.getWidgetPane().add((Component) member, BorderLayout.NORTH);
363                     break;
364                 case LEFT:
365                     component.getWidgetPane().add((Component) member, BorderLayout.WEST);
366                     break;
367                 case RIGHT:
368                     component.getWidgetPane().add((Component) member, BorderLayout.EAST);
369                     break;
370                 case CENTER:
371                     component.getWidgetPane().add((Component) member, BorderLayout.CENTER);
372                     break;
373                 default:
374                     break;
375             }
376
377             Integer[] preferredSize = uicontrol.getBorderPreferredSize();
378             if (preferredSize[0].equals(-1) == false && preferredSize[1].equals(-1) == false) {
379                 ((Component) member).setPreferredSize(new Dimension(preferredSize[0], preferredSize[1]));
380             }
381         } else if (component.getWidgetPane().getLayout() instanceof GridBagLayout) {
382             GridBagConstraints constraints = new GridBagConstraints();
383
384             // Grid
385             Integer[] grid = uicontrol.getGridBagGrid();
386             constraints.gridx = grid[0];
387             constraints.gridy = grid[1];
388             constraints.gridwidth = grid[2];
389             constraints.gridheight = grid[3];
390
391             // Weight
392             Double[] weight = uicontrol.getGridBagWeight();
393             constraints.weightx = weight[0];
394             constraints.weighty = weight[1];
395
396             // Anchor
397             switch (uicontrol.getGridBagAnchorAsEnum()) {
398                 case LEFT:
399                     constraints.anchor = GridBagConstraints.EAST;
400                     break;
401                 case UPPER:
402                     constraints.anchor = GridBagConstraints.NORTH;
403                     break;
404                 case LOWER:
405                     constraints.anchor = GridBagConstraints.SOUTH;
406                     break;
407                 case LOWER_LEFT:
408                     constraints.anchor = GridBagConstraints.SOUTHEAST;
409                     break;
410                 case LOWER_RIGHT:
411                     constraints.anchor = GridBagConstraints.SOUTHWEST;
412                     break;
413                 case RIGHT:
414                     constraints.anchor = GridBagConstraints.WEST;
415                     break;
416                 case UPPER_LEFT:
417                     constraints.anchor = GridBagConstraints.NORTHEAST;
418                     break;
419                 case UPPER_RIGHT:
420                     constraints.anchor = GridBagConstraints.NORTHWEST;
421                     break;
422                 case CENTER:
423                 default:
424                     constraints.anchor = GridBagConstraints.CENTER;
425                     break;
426             }
427
428             // Fill
429             switch (uicontrol.getGridBagFillAsEnum()) {
430                 case BOTH:
431                     constraints.fill = GridBagConstraints.BOTH;
432                     break;
433                 case HORIZONTAL:
434                     constraints.fill = GridBagConstraints.HORIZONTAL;
435                     break;
436                 case VERTICAL:
437                     constraints.fill = GridBagConstraints.VERTICAL;
438                     break;
439                 case NONE:
440                 default:
441                     constraints.fill = GridBagConstraints.NONE;
442                     break;
443             }
444
445             // Insets
446             Double[] margins = uicontrol.getMargins();
447             constraints.insets = new Insets(margins[0].intValue(), margins[1].intValue(), margins[2].intValue(), margins[3].intValue());
448
449             // Padding
450             Integer[] padding = uicontrol.getGridBagPadding();
451             constraints.ipadx = padding[0];
452             constraints.ipady = padding[1];
453
454             Integer[] preferredSize = uicontrol.getGridBagPreferredSize();
455             if (preferredSize[0].equals(-1) == false && preferredSize[1].equals(-1) == false) {
456                 ((Component) member).setPreferredSize(new Dimension(preferredSize[0], preferredSize[1]));
457             }
458
459             component.getWidgetPane().add((Component) member, constraints);
460             component.getWidgetPane().revalidate();
461         } else {
462             if (member instanceof SwingScilabScrollableFrame || member instanceof SwingScilabFrame) {
463                 component.getWidgetPane().add((Component) member, JLayeredPane.FRAME_CONTENT_LAYER);
464             } else {
465                 component.getWidgetPane().add((Component) member, JLayeredPane.DEFAULT_LAYER + 1);
466             }
467         }
468     }
469
470     protected static void removeMember(SwingScilabPanel component, SwingViewObject member) {
471         component.getWidgetPane().remove((Component) member);
472     }
473 }