force reset of value after setting string property of lixtbox or popupmenu
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / popupmenu / SwingScilabPopupMenu.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 - Marouane BEN JELLOUL
5  * Copyright (C) 2011 - DIGITEO - Vincent Couvert
6  *
7  * This file must be used under the terms of the CeCILL.
8  * This source file is licensed as described in the file COPYING, which
9  * you should have received as part of this distribution.  The terms
10  * are also available at
11  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
12  *
13  */
14
15 package org.scilab.modules.gui.bridge.popupmenu;
16
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MAX__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_STRING_COLNB__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_STRING__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_VALUE__;
21
22 import java.awt.Color;
23 import java.awt.Component;
24 import java.awt.event.ActionEvent;
25 import java.awt.event.ActionListener;
26 import java.io.IOException;
27 import java.util.Arrays;
28
29 import javax.swing.DefaultComboBoxModel;
30 import javax.swing.Icon;
31 import javax.swing.JComboBox;
32 import javax.swing.JLabel;
33 import javax.swing.JList;
34 import javax.swing.ListCellRenderer;
35 import javax.swing.UIManager;
36 import javax.swing.border.Border;
37
38 import org.scilab.modules.commons.gui.FindIconHelper;
39 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
40 import org.scilab.modules.gui.SwingViewObject;
41 import org.scilab.modules.gui.SwingViewWidget;
42 import org.scilab.modules.gui.events.callback.CommonCallBack;
43 import org.scilab.modules.gui.menubar.MenuBar;
44 import org.scilab.modules.gui.popupmenu.SimplePopupMenu;
45 import org.scilab.modules.gui.textbox.TextBox;
46 import org.scilab.modules.gui.toolbar.ToolBar;
47 import org.scilab.modules.gui.utils.ColorBox;
48 import org.scilab.modules.gui.utils.Position;
49 import org.scilab.modules.gui.utils.PositionConverter;
50 import org.scilab.modules.gui.utils.ScilabRelief;
51 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
52 import org.scilab.modules.gui.utils.Size;
53 import org.scilab.modules.gui.utils.SwingScilabListItem;
54
55 /**
56  * Swing implementation for Scilab PopupMenu in GUIs
57  * @author Vincent COUVERT
58  * @author Marouane BEN JELLOUL
59  */
60 public class SwingScilabPopupMenu extends JComboBox implements SwingViewObject, SimplePopupMenu {
61
62     private static final long serialVersionUID = -4366581303317502544L;
63
64     private Integer uid;
65
66     private CommonCallBack callback;
67
68     private ActionListener defaultActionListener;
69
70     private Border defaultBorder = null;
71
72
73     private ListCellRenderer defaultRenderer = null;
74     private ListCellRenderer listRenderer = null;
75
76     /**
77      * Constructor
78      */
79     public SwingScilabPopupMenu() {
80         super();
81
82         defaultRenderer = getRenderer();
83         listRenderer = new ListCellRenderer() {
84             public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
85                 JLabel label = (JLabel) defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
86
87                 if (value instanceof SwingScilabListItem) {
88                     SwingScilabListItem item = (SwingScilabListItem) value;
89
90                     label.setText(item.toString());
91                     label.setIcon(item.getIcon());
92
93                     //index == -1 is for selected item after click
94                     //so let standard FG and BG
95                     if (index != - 1 && isSelected == false && item.getBackground() != null) {
96                         label.setBackground(item.getBackground());
97                     }
98
99                     if (index != - 1 && isSelected == false && item.getForeground() != null) {
100                         label.setForeground(item.getForeground());
101                     }
102                 }
103                 return label;
104             }
105         };
106
107         setRenderer(listRenderer);
108         /* Bug 3635 fixed: allow arrow keys to browse items */
109         putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
110         defaultActionListener = new ActionListener() {
111             public void actionPerformed(ActionEvent e) {
112                 Double scilabIndices = (double) getUserSelectedIndex();
113                 if (scilabIndices == -1) {
114                     GraphicController.getController().setProperty(uid, __GO_UI_VALUE__, new Double[] {});
115                 } else {
116                     GraphicController.getController().setProperty(uid, __GO_UI_VALUE__, new Double[] {scilabIndices});
117                 }
118
119                 if (callback != null) {
120                     callback.actionPerformed(null);
121                 }
122             }
123         };
124         addActionListener(defaultActionListener);
125     }
126
127     /**
128      * Draws a swing Scilab tab
129      * @see org.scilab.modules.gui.uielement.UIElement#draw()
130      */
131     public void draw() {
132         this.setVisible(true);
133     }
134
135     /**
136      * Gets the dimensions (width and height) of a swing Scilab tab
137      * @return the dimensions of the tab
138      * @see org.scilab.modules.gui.uielement.UIElement#getDims()
139      */
140     public Size getDims() {
141         return new Size(getWidth(), getHeight());
142     }
143
144     /**
145      * Gets the position (X-coordinate and Y-coordinate) of a swing Scilab tab
146      * @return the position of the tab
147      * @see org.scilab.modules.gui.uielement.UIElement#getPosition()
148      */
149     public Position getPosition() {
150         return PositionConverter.javaToScilab(getLocation(), getSize(), getParent());
151     }
152
153     /**
154      * Sets the dimensions (width and height) of a swing Scilab tab
155      * @param newSize the dimensions we want to set to the tab
156      * @see org.scilab.modules.gui.uielement.UIElement#setDims(org.scilab.modules.gui.utils.Size)
157      */
158     public void setDims(Size newSize) {
159         setSize(newSize.getWidth(), newSize.getHeight());
160         doLayout(); /* Needed !! because PopupMenu is badly drawn else */
161     }
162
163     /**
164      * Sets the position (X-coordinate and Y-coordinate) of a swing Scilab tab
165      * @param newPosition the position we want to set to the tab
166      * @see org.scilab.modules.gui.uielement.UIElement#setPosition(org.scilab.modules.gui.utils.Position)
167      */
168     public void setPosition(Position newPosition) {
169         Position javaPosition = PositionConverter.scilabToJava(newPosition, getDims(), getParent());
170         setLocation(javaPosition.getX(), javaPosition.getY());
171     }
172
173     /**
174      * Add a callback to the PopupMenu
175      * @param callback the callback to set.
176      */
177     public void setCallback(CommonCallBack callback) {
178         this.callback = callback;
179     }
180
181     /**
182      * Setter for MenuBar
183      * @param menuBarToAdd the MenuBar associated to the Tab.
184      */
185     public void addMenuBar(MenuBar menuBarToAdd) {
186         /* Unimplemented for PopupMenus */
187         throw new UnsupportedOperationException();
188     }
189
190     /**
191      * Setter for ToolBar
192      * @param toolBarToAdd the ToolBar associated to the Tab.
193      */
194     public void addToolBar(ToolBar toolBarToAdd) {
195         /* Unimplemented for PopupMenus */
196         throw new UnsupportedOperationException();
197     }
198
199     /**
200      * Getter for MenuBar
201      * @return MenuBar: the MenuBar associated to the Tab.
202      */
203     public MenuBar getMenuBar() {
204         /* Unimplemented for PopupMenus */
205         throw new UnsupportedOperationException();
206     }
207
208     /**
209      * Getter for ToolBar
210      * @return ToolBar: the ToolBar associated to the Tab.
211      */
212     public ToolBar getToolBar() {
213         /* Unimplemented for PopupMenus */
214         throw new UnsupportedOperationException();
215     }
216
217     /**
218      * Get the text if the PopupMenu items
219      * @return the items
220      * @see org.scilab.modules.gui.widget.Widget#getText()
221      */
222     public String getText() {
223         /* Unimplemented for PopupMenus */
224         throw new UnsupportedOperationException();
225     }
226
227     /**
228      * Set the text of the PopupMenu items
229      * @param text the text of the items
230      * @see org.scilab.modules.gui.widget.Widget#setText(java.lang.String)
231      */
232     public void setText(String text) {
233         /* Unimplemented for PopupMenus */
234         throw new UnsupportedOperationException();
235     }
236
237     /**
238      * Set the horizontal alignment for the PopupMenu text
239      * @param alignment the value for the alignment (See ScilabAlignment.java)
240      */
241     public void setHorizontalAlignment(String alignment) {
242         // Nothing to do here
243     }
244
245     /**
246      * Set the vertical alignment for the PopupMenu text
247      * @param alignment the value for the alignment (See ScilabAlignment.java)
248      */
249     public void setVerticalAlignment(String alignment) {
250         // Nothing to do here
251     }
252
253     /**
254      * Set the selected index of the PopupMenu
255      * @param index the index of the item to be selected
256      */
257     public void setUserSelectedIndex(int index) {
258         /* Remove the listener to avoid the callback to be executed */
259         removeActionListener(defaultActionListener);
260
261         // Scilab indices in Value begin at 1 and Java indices begin at 0
262         if (index >= 0 && index <= getItemCount()) {
263             setSelectedIndex(index - 1);
264         }
265
266         /* Put back the listener */
267         addActionListener(defaultActionListener);
268     }
269
270     /**
271      * Get the selected index of the PopupMenu
272      * @return the index of the item selected
273      */
274     public int getUserSelectedIndex() {
275         int index = getSelectedIndex();
276         if (index == - 1) {
277             return -1;
278         }
279
280         return index + 1;
281     }
282
283     /**
284      * Get the text of all the PopupMenu items
285      * @return the text items
286      */
287     public String[] getAllItemsText() {
288         String[] retValue = new String[getItemCount()];
289         for (int i = 0; i < getItemCount(); i++) {
290             retValue[i] = getItemAt(i).toString();
291         }
292         return retValue;
293
294     }
295
296     /**
297      * Get the number of items in the PopupMenu
298      * @return the number of items
299      */
300     public int getNumberOfItems() {
301         return getItemCount();
302     }
303
304     /**
305      * Set the text of the PopupMenu items
306      * @param text the text of the items
307      */
308     public void setText(String[] text) {
309         DefaultComboBoxModel model = new DefaultComboBoxModel();
310
311         //get numbers of columns
312         GraphicController controller = GraphicController.getController();
313         Integer nbCol = (Integer) controller.getProperty(getId(), __GO_UI_STRING_COLNB__);
314
315         /* Remove the listener to avoid the callback to be executed */
316         removeActionListener(defaultActionListener);
317
318         boolean tryColorBox = true;
319         boolean tryColor = true;
320         boolean tryIcon = true;
321         int nbRow = text.length / nbCol;
322
323         for (int i = 0; i < nbRow; i++) {
324             Icon icon = null;
325             String str = null;
326             Color background = null;
327             Color foreground = null;
328
329             //4 cols :
330             // - 1st icon or colorBox
331             // - 2nd text
332             // - 3rd BG
333             // - 4th FG
334
335             //3 cols :  2 cases
336             // - 1st icon or colorBox
337             // - 2nd text
338             // - 3rd BG
339             //or
340             // - 1st text
341             // - 2nd BG
342             // - 3rd FG
343
344             //2 cols : 2 cases
345             // - 1st icon or colorBox
346             // - 2nd text
347             //or
348             // - 1st text
349             // - 2nd BG
350
351             if (tryColorBox) { //color
352                 try {
353                     Color color = Color.decode(text[i]);
354                     icon = ColorBox.createColorBox(16, 16, color);
355                 } catch (NumberFormatException e) {
356                     tryColorBox = false;
357                     model.removeAllElements();
358                     //restart loop with icon
359                     i = -1;
360                     continue;
361                 }
362             }
363
364             if (tryIcon) {
365                 try {
366                     icon = FindIconHelper.loadIcon(text[i]);
367                 } catch (IOException e) {
368                     tryIcon = false;
369                     model.removeAllElements();
370                     //restart loop with text only
371                     i = -1;
372                     continue;
373                 }
374             }
375
376             if (tryColor) {
377                 try {
378                     int colIndex = 0;
379                     if (tryColorBox || tryIcon) {
380                         colIndex = 1;
381                     }
382
383                     str = text[(nbRow * colIndex) + i];
384                     if (nbCol > (1 + colIndex)) {
385                         background = Color.decode(text[nbRow * (1 + colIndex) + i]);
386                         if (nbCol > (2 + colIndex)) {
387                             foreground = Color.decode(text[nbRow * (2 + colIndex) + i]);
388                         }
389                     }
390
391                     //add item in list box
392                     model.addElement(new SwingScilabListItem(str, icon, background, foreground));
393                 } catch (NumberFormatException e) {
394                     tryColor = false;
395                     model.removeAllElements();
396                     //restart loop with text only
397                     i = -1;
398                     continue;
399                 }
400             } else { //text only
401                 for (int j = 0; j < nbCol; j++) {
402                     model.addElement(new SwingScilabListItem(text[nbRow * j + i], icon, background, foreground));
403                 }
404             }
405         }
406
407         //reset selected index
408         setSelectedIndex(-1);
409         setModel(model);
410         invalidate();
411         //take care to add listener BEFORE set Property to avoid multiple remove and multiple add
412         addActionListener(defaultActionListener);
413     }
414
415     /**
416      * Set the Relief of the PopupMenu
417      * @param reliefType the type of the relief to set (See ScilabRelief.java)
418      */
419     public void setRelief(String reliefType) {
420         if (defaultBorder == null) {
421             defaultBorder = getBorder();
422         }
423         setBorder(ScilabRelief.getBorderFromRelief(reliefType, defaultBorder));
424     }
425
426     /**
427      * Destroy the PopupMenu
428      */
429     public void destroy() {
430         ScilabSwingUtilities.removeFromParent(this);
431     }
432
433     /**
434      * Setter for InfoBar
435      * @param infoBarToAdd the InfoBar associated to the PopupMenu.
436      */
437     public void addInfoBar(TextBox infoBarToAdd) {
438         /* Unimplemented for PopupMenus */
439         throw new UnsupportedOperationException();
440     }
441
442     /**
443      * Getter for InfoBar
444      * @return the InfoBar associated to the PopupMenu.
445      */
446     public TextBox getInfoBar() {
447         /* Unimplemented for PopupMenus */
448         throw new UnsupportedOperationException();
449     }
450
451
452     /**
453      * Set the UID
454      * @param id the UID
455      */
456     public void setId(Integer id) {
457         uid = id;
458     }
459
460     /**
461      * Get the UID
462      * @return the UID
463      */
464     public Integer getId() {
465         return uid;
466     }
467
468     /**
469      * Generic update method
470      * @param property property name
471      * @param value property value
472      */
473     public void update(int property, Object value) {
474         switch (property) {
475             case __GO_UI_STRING__: {
476                 setText((String[]) value);
477                 break;
478             }
479             case __GO_UI_MAX__: {
480                 Integer val = ((Double)value).intValue();
481                 if (val > 1) {
482                     char[] chars = new char[val];
483                     Arrays.fill(chars, '*');
484                     String proto = new String(chars);
485                     setPrototypeDisplayValue(proto);
486                 }
487                 break;
488             }
489             case __GO_UI_VALUE__: {
490                 Double[] doubleValue = ((Double[]) value);
491
492                 //[] or 0 -> no selection
493                 if (doubleValue.length == 0 || doubleValue[0] == 0) {
494                     setUserSelectedIndex(0);
495                     return;
496                 }
497
498                 int[] intValue = new int[doubleValue.length];
499                 for (int k = 0; k < doubleValue.length; k++) {
500                     intValue[k] = doubleValue[k].intValue();
501                 }
502
503                 // Update selected items in the popupmenu
504                 setUserSelectedIndex(intValue[0]);
505                 break;
506             }
507             default: {
508                 SwingViewWidget.update(this, property, value);
509                 break;
510             }
511         }
512     }
513
514     public void resetBackground() {
515         Color color = (Color) UIManager.getLookAndFeelDefaults().get("ComboBox.background");
516         if (color != null) {
517             setBackground(color);
518         }
519     }
520
521     public void resetForeground() {
522         Color color = (Color)UIManager.getLookAndFeelDefaults().get("ComboBox.foreground");
523         if (color != null) {
524             setForeground(color);
525         }
526     }
527 }