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