fix bug on icon in listbox and combobox
[scilab.git] / scilab / modules / gui / src / java / org / scilab / modules / gui / bridge / listbox / SwingScilabListBox.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) 2010-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.listbox;
16
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_LISTBOXTOP__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_BACKGROUNDCOLOR__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MAX__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MIN__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_STRING__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_VALUE__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_STRING_COLNB__;
24
25 import java.awt.Color;
26 import java.awt.Component;
27 import java.awt.Font;
28 import java.awt.event.AdjustmentEvent;
29 import java.awt.event.AdjustmentListener;
30 import java.io.File;
31 import java.io.IOException;
32
33 import javax.imageio.ImageIO;
34 import javax.swing.DefaultListCellRenderer;
35 import javax.swing.DefaultListModel;
36 import javax.swing.ImageIcon;
37 import javax.swing.JLabel;
38 import javax.swing.JList;
39 import javax.swing.JScrollPane;
40 import javax.swing.ListCellRenderer;
41 import javax.swing.ListSelectionModel;
42 import javax.swing.UIManager;
43 import javax.swing.border.Border;
44 import javax.swing.event.ListSelectionEvent;
45 import javax.swing.event.ListSelectionListener;
46
47 import org.scilab.modules.commons.gui.FindIconHelper;
48 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
49 import org.scilab.modules.gui.SwingViewObject;
50 import org.scilab.modules.gui.SwingViewWidget;
51 import org.scilab.modules.gui.events.callback.CommonCallBack;
52 import org.scilab.modules.gui.listbox.SimpleListBox;
53 import org.scilab.modules.gui.menubar.MenuBar;
54 import org.scilab.modules.gui.textbox.TextBox;
55 import org.scilab.modules.gui.toolbar.ToolBar;
56 import org.scilab.modules.gui.utils.ColorBox;
57 import org.scilab.modules.gui.utils.Position;
58 import org.scilab.modules.gui.utils.PositionConverter;
59 import org.scilab.modules.gui.utils.ScilabRelief;
60 import org.scilab.modules.gui.utils.ScilabSwingUtilities;
61 import org.scilab.modules.gui.utils.Size;
62 import org.scilab.modules.gui.utils.SwingScilabIconItem;
63 import org.scilab.modules.gui.utils.SwingScilabTextItem;
64 import org.scilab.modules.gui.utils.SwingScilabColorItem;
65
66 /**
67  * Swing implementation for Scilab ListBox in GUIs
68  * @author Vincent COUVERT
69  * @author Marouane BEN JELLOUL
70  */
71 public class SwingScilabListBox extends JScrollPane implements SwingViewObject, SimpleListBox {
72
73     private static final long serialVersionUID = 3507396207331058895L;
74
75     private static final int COLORS_COEFF = 255;
76
77     private Integer uid;
78
79     private Border defaultBorder = null;
80
81     private CommonCallBack callback;
82
83     private ListSelectionListener listListener;
84
85     private AdjustmentListener adjustmentListener;
86
87     /**
88      * the JList we use
89      */
90     private JList list;
91
92     private ListCellRenderer defaultRenderer = null;
93     private ListCellRenderer textRenderer = null;
94     private ListCellRenderer colorRenderer = null;
95     private ListCellRenderer iconRenderer = null;
96
97     private boolean colorBox = false;
98     private boolean iconBox = false;
99
100     /**
101      * Constructor
102      */
103     public SwingScilabListBox() {
104         super();
105         getViewport().add(getList());
106         defaultRenderer = getList().getCellRenderer();
107
108         textRenderer = new DefaultListCellRenderer();
109         getList().setCellRenderer(textRenderer);
110
111         listListener = new ListSelectionListener() {
112             public void valueChanged(ListSelectionEvent e) {
113
114                 //value not ready
115                 if (e.getValueIsAdjusting()) {
116                     return;
117                 }
118
119                 // Scilab indices in Value begin at 1 and Java indices begin at 0
120                 int[] javaIndices = getList().getSelectedIndices().clone();
121                 Double[] scilabIndices = new Double[javaIndices.length];
122                 for (int i = 0; i < getList().getSelectedIndices().length; i++) {
123                     scilabIndices[i] = (double) javaIndices[i] + 1;
124                 }
125
126                 GraphicController.getController().setProperty(uid, __GO_UI_VALUE__, scilabIndices);
127                 if (callback != null) {
128                     callback.actionPerformed(null);
129                 }
130             }
131         };
132         getList().addListSelectionListener(listListener);
133
134         adjustmentListener = new AdjustmentListener() {
135             public void adjustmentValueChanged(AdjustmentEvent arg0) {
136                 int listboxtopValue = getList().getUI().locationToIndex(getList(), getViewport().getViewPosition()) + 1;
137                 GraphicController.getController().setProperty(uid, __GO_UI_LISTBOXTOP__, new Integer[] {listboxtopValue});
138             }
139         };
140         getVerticalScrollBar().addAdjustmentListener(adjustmentListener);
141     }
142
143     /**
144      * To get the Background color of the element.
145      * @return color the Color
146      */
147     public Color getBackground() {
148         return getList().getBackground();
149     }
150
151     /**
152      * To get the Font of the element.
153      * @return font the Font
154      */
155     public Font getFont() {
156         return getList().getFont();
157     }
158
159     /**
160      * To get the Foreground color of the element.
161      * @return color the Color
162      */
163     public Color getForeground() {
164         return getList().getForeground();
165     }
166
167     /**
168      * To set the Background color of the element.
169      * @param color the Color
170      */
171     public void setListBackground(Color color) {
172         getList().setBackground(color);
173     }
174
175     /**
176      * To set the Font of the element.
177      * @param font the Font
178      */
179     public void setFont(Font font) {
180         getList().setFont(font);
181     }
182
183     /**
184      * To set the Foreground color of the element.
185      * @param color the Color
186      */
187     public void setForeground(Color color) {
188         getList().setForeground(color);
189     }
190
191     /**
192      * Draws a swing Scilab tab
193      * @see org.scilab.modules.gui.uielement.UIElement#draw()
194      */
195     public void draw() {
196         this.setVisible(true);
197         this.doLayout();
198     }
199
200     /**
201      * Gets the dimensions (width and height) of a swing Scilab tab
202      * @return the dimensions of the tab
203      * @see org.scilab.modules.gui.uielement.UIElement#getDims()
204      */
205     public Size getDims() {
206         return new Size(getWidth(), getHeight());
207     }
208
209     /**
210      * Gets the position (X-coordinate and Y-coordinate) of a swing Scilab tab
211      * @return the position of the tab
212      * @see org.scilab.modules.gui.uielement.UIElement#getPosition()
213      */
214     public Position getPosition() {
215         return PositionConverter.javaToScilab(getLocation(), getSize(), getParent());
216     }
217
218     /**
219      * Sets the dimensions (width and height) of a swing Scilab tab
220      * @param newSize the dimensions we want to set to the tab
221      * @see org.scilab.modules.gui.uielement.UIElement#setDims(org.scilab.modules.gui.utils.Size)
222      */
223     public void setDims(Size newSize) {
224         setSize(newSize.getWidth(), newSize.getHeight());
225     }
226
227     /**
228      * Sets the position (X-coordinate and Y-coordinate) of a swing Scilab tab
229      * @param newPosition the position we want to set to the tab
230      * @see org.scilab.modules.gui.uielement.UIElement#setPosition(org.scilab.modules.gui.utils.Position)
231      */
232     public void setPosition(Position newPosition) {
233         Position javaPosition = PositionConverter.scilabToJava(newPosition, getDims(), getParent());
234         setLocation(javaPosition.getX(), javaPosition.getY());
235     }
236
237     /**
238      * Sets the visibility status of an UIElement
239      * @param newVisibleState the visibility status we want to set for the UIElement
240      *                      (true if the UIElement is visible, false if not)
241      */
242     public void setVisible(boolean newVisibleState) {
243         super.setVisible(newVisibleState);
244         list.setVisible(newVisibleState);
245     }
246
247     /**
248      * Sets the enable status of an UIElement
249      * @param newEnableState the enable status we want to set for the UIElement
250      *                      (true if the UIElement is enabled, false if not)
251      */
252     public void setEnabled(boolean newEnableState) {
253         if (newEnableState != super.isEnabled()) {
254             super.setEnabled(newEnableState);
255             getList().setEnabled(newEnableState);
256             if (newEnableState) {
257                 if (listListener != null) {
258                     getList().addListSelectionListener(listListener);
259                 }
260             } else {
261                 if (listListener != null) {
262                     getList().removeListSelectionListener(listListener);
263                 }
264             }
265         }
266     }
267
268     /**
269      * Add a callback to the CheckBox
270      * @param cb the callback to set.
271      */
272     public void setCallback(CommonCallBack cb) {
273         this.callback = cb;
274     }
275
276     /**
277      * Setter for MenuBar
278      * @param menuBarToAdd the MenuBar associated to the Tab.
279      */
280     public void addMenuBar(MenuBar menuBarToAdd) {
281         /* Unimplemented for ListBoxes */
282         throw new UnsupportedOperationException();
283     }
284
285     /**
286      * Setter for ToolBar
287      * @param toolBarToAdd the ToolBar associated to the Tab.
288      */
289     public void addToolBar(ToolBar toolBarToAdd) {
290         /* Unimplemented for ListBoxes */
291         throw new UnsupportedOperationException();
292     }
293
294     /**
295      * Getter for MenuBar
296      * @return MenuBar: the MenuBar associated to the Tab.
297      */
298     public MenuBar getMenuBar() {
299         /* Unimplemented for ListBoxes */
300         throw new UnsupportedOperationException();
301     }
302
303     /**
304      * Getter for ToolBar
305      * @return ToolBar: the ToolBar associated to the Tab.
306      */
307     public ToolBar getToolBar() {
308         /* Unimplemented for ListBoxes */
309         throw new UnsupportedOperationException();
310     }
311
312     /**
313      * Get the first item text
314      * @return the items
315      * @see org.scilab.modules.gui.widget.Widget#getText()
316      */
317     public String getText() {
318         /* Unimplemented for ListBoxes */
319         throw new UnsupportedOperationException();
320     }
321
322     /**
323      * Get the text of all the list items
324      * @return the items
325      * @see org.scilab.modules.gui.listbox.ListBox#getAllItemsText()
326      */
327     public String[] getAllItemsText() {
328         String[] retValue = new String[getList().getModel().getSize()];
329         for (int i = 0; i < getList().getModel().getSize(); i++) {
330             retValue[i] = getList().getModel().getElementAt(i).toString();
331         }
332         return retValue;
333     }
334
335     /**
336      * Get the number of items in the list
337      * @return the number of items
338      * @see org.scilab.modules.gui.listbox.ListBox#getNumberOfItems()
339      */
340     public int getNumberOfItems() {
341         return getList().getModel().getSize();
342     }
343
344     /**
345      * Set the text of the list items
346      * @param text the text of the items
347      * @see org.scilab.modules.gui.widget.Widget#setText(java.lang.String)
348      */
349     public void setText(String text) {
350         DefaultListModel model = new DefaultListModel();
351         model.addElement(text);
352         getList().setModel(model);
353         revalidate();
354     }
355
356     /**
357      * Set the text of the list items
358      * @param text the text of the items
359      * @see org.scilab.modules.gui.widget.Widget#setText(java.lang.String)
360      */
361     public void setText(String[] text) {
362         DefaultListModel model = new DefaultListModel();
363
364         // check numbers of columns
365         GraphicController controller = GraphicController.getController();
366         Integer nbCol = (Integer)controller.getProperty(getId(), __GO_UI_STRING_COLNB__);
367
368         /* Remove the listener to avoid the callback to be executed */
369         getList().removeListSelectionListener(listListener);
370
371         getList().removeAll();
372
373         colorBox = false;
374         iconBox = false;
375         if (nbCol == 2) {
376             //combocolor ?
377             colorBox = true;
378
379             //first try to convert 2nd col to color
380             if (colorRenderer == null) {
381                 colorRenderer = new ListCellRenderer() {
382                     public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
383                         JLabel label = (JLabel) defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
384
385                         if (value instanceof SwingScilabColorItem) {
386                             SwingScilabColorItem item = (SwingScilabColorItem)value;
387                             String text = item.toString();
388                             label.setText(text);
389                             label.setIcon(ColorBox.createColorBox(16, 16, item.getColor()));
390                         }
391                         return label;
392                     }
393                 };
394
395             }
396
397             getList().setCellRenderer(colorRenderer);
398
399             int colorOffset = text.length / 2;
400             try {
401                 for (int i = 0 ; i < colorOffset ; i++) {
402                     Color color = Color.decode(text[colorOffset + i]);
403                     //add item in combobox
404                     model.addElement(new SwingScilabColorItem(text[i], color));
405                 }
406
407             } catch (NumberFormatException e) {
408                 model.clear();
409                 colorBox = false;
410                 iconBox = true;
411             }
412
413             //try to convert 2nd col to icon ( only if color convertion failed )
414             if (iconBox) {
415                 if (iconRenderer == null) {
416                     iconRenderer = new ListCellRenderer() {
417                         public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
418                             JLabel label = (JLabel) defaultRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
419
420                             if (value instanceof SwingScilabIconItem) {
421                                 SwingScilabIconItem item = (SwingScilabIconItem)value;
422                                 label.setText(item.toString());
423                                 label.setIcon(item.getIcon());
424                             }
425                             return label;
426                         }
427                     };
428                 }
429
430                 getList().setCellRenderer(iconRenderer);
431
432                 //fill items
433                 int iconOffset = text.length / 2;
434                 try {
435                     for (int i = 0; i < iconOffset; i++) {
436                         String iconFile = FindIconHelper.findIcon((text[iconOffset + i]), false);
437                         if (iconFile == null) {
438                             iconFile = "";
439                         }
440
441                         //add item in listbox
442                         File file = new File(iconFile);
443                         if (file.exists() == false) {
444                             String filename = FindIconHelper.findImage(iconFile, false);
445                             if (filename == null) {
446                                 filename = "";
447                             }
448
449                             file = new File(filename);
450                         }
451
452                         model.addElement(new SwingScilabIconItem(text[i], new ImageIcon(ImageIO.read(file))));
453                     }
454                 } catch (IOException e) {
455                     model.clear();
456                     iconBox = false;
457                     colorBox = false;
458                 }
459             }
460
461         }
462
463         //default case or colorBox failed
464         if (colorBox == false && iconBox == false) {
465             getList().setCellRenderer(textRenderer);
466             for (int i = 0; i < text.length; i++) {
467                 model.addElement(new SwingScilabTextItem(text[i]));
468             }
469         }
470
471         //reset selected index
472         getList().setSelectedIndex(-1);
473         getList().setModel(model);
474         getList().revalidate();
475
476
477         //take care to add listener BEFORE set Property to avoid multiple remove and multiple add
478         getList().addListSelectionListener(listListener);
479
480     }
481
482     /**
483      * Set the horizontal alignment for the ListBox text
484      * @param alignment the value for the alignment (See ScilabAlignment.java)
485      */
486     public void setHorizontalAlignment(String alignment) {
487         // Nothing to do here
488     }
489
490     /**
491      * Set the vertical alignment for the ListBox text
492      * @param alignment the value for the alignment (See ScilabAlignment.java)
493      */
494     public void setVerticalAlignment(String alignment) {
495         // Nothing to do here
496     }
497
498     /**
499      * Set if more than one item can be selected in a ListBox
500      * @param status true if multiple selection is enabled
501      */
502     public void setMultipleSelectionEnabled(boolean status) {
503         if (status) {
504             getList().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
505         } else {
506             getList().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
507         }
508     }
509
510     /**
511      * Set the selected indices of the ListBox
512      * @param indices the indices of the items to be selected
513      */
514     public void setSelectedIndices(int[] indices) {
515         // Scilab indices in Value begin at 1 and Java indices begin at 0
516         int[] javaIndices = indices.clone();
517         for (int i = 0; i < javaIndices.length; i++) {
518             javaIndices[i] = javaIndices[i] - 1;
519         }
520
521         /* Remove the listener to avoid the callback to be executed */
522         if (listListener != null) {
523             getList().removeListSelectionListener(listListener);
524         }
525
526         getList().setSelectedIndices(javaIndices);
527
528         /* Put back the listener */
529         if (listListener != null) {
530             getList().addListSelectionListener(listListener);
531         }
532     }
533
534     /**
535      * Get the selected indices of the ListBox
536      * @return the indices of the items selected
537      */
538     public int[] getSelectedIndices() {
539         // Scilab indices in Value begin at 1 and Java indices begin at 0
540         int[] javaIndices = getList().getSelectedIndices().clone();
541         int[] scilabIndices = javaIndices.clone();
542         for (int i = 0; i < getList().getSelectedIndices().length; i++) {
543             scilabIndices[i] = scilabIndices[i] + 1;
544         }
545         return scilabIndices;
546     }
547
548     /**
549      * Get the number of items selected in the ListBox
550      * @return the number of items selected
551      */
552     public int getSelectionSize() {
553         return getList().getSelectedIndices().length;
554     }
555
556     /**
557      * Get or create the list component
558      * @return the list
559      */
560     private JList getList() {
561         if (list == null) {
562             list = new JList();
563             list.setLayoutOrientation(JList.VERTICAL);
564             list.setModel(new DefaultListModel());
565         }
566         return list;
567     }
568
569     /**
570      * Set the Relief of the ListBox
571      * @param reliefType the type of the relief to set (See ScilabRelief.java)
572      */
573     public void setRelief(String reliefType) {
574         if (defaultBorder == null) {
575             defaultBorder = getBorder();
576         }
577         setBorder(ScilabRelief.getBorderFromRelief(reliefType, defaultBorder));
578     }
579
580     /**
581      * Destroy the ListBox
582      */
583     public void destroy() {
584         ScilabSwingUtilities.removeFromParent(this);
585     }
586
587     /**
588      * Setter for InfoBar
589      * @param infoBarToAdd the InfoBar associated to the ListBox.
590      */
591     public void addInfoBar(TextBox infoBarToAdd) {
592         /* Unimplemented for ListBoxes */
593         throw new UnsupportedOperationException();
594     }
595
596     /**
597      * Getter for InfoBar
598      * @return the InfoBar associated to the ListBox.
599      */
600     public TextBox getInfoBar() {
601         /* Unimplemented for ListBoxes */
602         throw new UnsupportedOperationException();
603     }
604
605     /**
606      * Adjusts the view so that the element given by index is displayed at the top of the ListBox.
607      * @param index the index of the element to be displayed at the top of the ListBox.
608      */
609     public void setListBoxTop(int index) {
610         getVerticalScrollBar().removeAdjustmentListener(adjustmentListener);
611         if (index > 0 & index != getListBoxTop()) {
612             getViewport().setViewPosition(getList().getUI().indexToLocation(getList(), index - 1));
613             doLayout();
614         }
615         getVerticalScrollBar().addAdjustmentListener(adjustmentListener);
616     }
617
618     /**
619      * Gets the index of the element displayed at the top of the ListBox
620      * @return the index of the element displayed at the top of the ListBox
621      */
622     public int getListBoxTop() {
623         return getList().getUI().locationToIndex(getList(), getViewport().getViewPosition()) + 1;
624     }
625
626     /**
627      * Set the UID
628      * @param id the UID
629      */
630     public void setId(Integer id) {
631         uid = id;
632     }
633
634     /**
635      * Get the UID
636      * @return the UID
637      */
638     public Integer getId() {
639         return uid;
640     }
641
642     /**
643      * Generic update method
644      * @param property property name
645      * @param value property value
646      */
647     public void update(int property, Object value) {
648         GraphicController controller = GraphicController.getController();
649         switch (property) {
650             case __GO_UI_VALUE__ : {
651                 Double[] indexes = (Double[])value;
652                 int[] index = new int[indexes.length];
653                 for (int i = 0 ; i < indexes.length ; i++) {
654                     index[i] = indexes[i].intValue();
655                 }
656                 setSelectedIndices(index);
657                 break;
658             }
659             case __GO_UI_BACKGROUNDCOLOR__ : {
660                 Double[] allColors = ((Double[]) value);
661                 if (allColors[0] != -1) {
662                     setListBackground(new Color((int) (allColors[0] * COLORS_COEFF),
663                                                 (int) (allColors[1] * COLORS_COEFF),
664                                                 (int) (allColors[2] * COLORS_COEFF)));
665                 } else {
666                     resetBackground();
667                 }
668                 break;
669             }
670             case __GO_UI_STRING__ : {
671                 // Listboxes manage string vectors
672                 setText((String[]) value);
673                 break;
674             }
675             case __GO_UI_MAX__ : {
676                 Double maxValue = ((Double) value);
677                 // Enable/Disable multiple selection
678                 double minValue = (Double) controller.getProperty(uid, __GO_UI_MIN__);
679                 setMultipleSelectionEnabled(maxValue - minValue > 1);
680                 break;
681             }
682             case __GO_UI_MIN__ : {
683                 Double minValue = ((Double) value);
684                 // Enable/Disable multiple selection
685                 Double maxValue = (Double) controller.getProperty(uid, __GO_UI_MAX__);
686                 setMultipleSelectionEnabled(maxValue - minValue > 1);
687                 break;
688             }
689             case __GO_UI_LISTBOXTOP__: {
690                 Integer[] listboxtopValue = ((Integer[]) value);
691                 if (listboxtopValue.length > 0) {
692                     setListBoxTop(listboxtopValue[0]);
693                 }
694                 break;
695             }
696             default: {
697                 SwingViewWidget.update(this, property, value);
698                 break;
699             }
700         }
701     }
702
703     public void resetBackground() {
704         Color color = (Color)UIManager.getLookAndFeelDefaults().get("List.background");
705         if (color != null) {
706             getList().setBackground(color);
707         }
708     }
709
710     public void resetForeground() {
711         Color color = (Color)UIManager.getLookAndFeelDefaults().get("List.foreground");
712         if (color != null) {
713             getList().setForeground(color);
714         }
715     }
716 }