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