View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components;
21  
22  import java.awt.BorderLayout;
23  import java.awt.Component;
24  import java.awt.Container;
25  import java.awt.Dimension;
26  import java.awt.FlowLayout;
27  import java.awt.Graphics;
28  import java.awt.Insets;
29  import java.awt.LayoutManager;
30  import java.awt.Rectangle;
31  import java.awt.event.ActionEvent;
32  import java.awt.event.ActionListener;
33  import java.awt.event.ItemEvent;
34  import java.awt.event.ItemListener;
35  import java.awt.event.KeyAdapter;
36  import java.awt.event.KeyEvent;
37  import java.awt.event.KeyListener;
38  import java.awt.event.WindowAdapter;
39  import java.awt.event.WindowEvent;
40  import java.util.Vector;
41  
42  import javax.swing.CellRendererPane;
43  import javax.swing.ComboBoxModel;
44  import javax.swing.DefaultComboBoxModel;
45  import javax.swing.JComboBox;
46  import javax.swing.JComponent;
47  import javax.swing.JFrame;
48  import javax.swing.JPanel;
49  import javax.swing.ListCellRenderer;
50  import javax.swing.plaf.ComboBoxUI;
51  import javax.swing.plaf.basic.BasicComboBoxRenderer;
52  import javax.swing.plaf.basic.BasicComboBoxUI;
53  import javax.swing.plaf.basic.BasicComboPopup;
54  import javax.swing.plaf.metal.MetalBorders;
55  
56  import com.cosylab.gui.components.util.ColorHelper;
57  
58  
59  /**
60   * A simple implementation of a combo box that provides several display styles
61   * through different javax.swing.plaf.ComboBoxUI implementations. These can be
62   * set through setStyle(int) method and are enumerated as: SIMPLE_STYLE
63   * displays no button in the comboBox. Items are selected from a drop down
64   * list activated on mouseclick. DROP_DOWN_STYLE displays an arrowed button on
65   * the right side of the combo box that activates the drop down list.
66   * SWITCH_STYLE_POPUP_ENABLED positions two buttons on each side of the combo
67   * box that can be used to switch between items of the combo box, while the
68   * complete list of items can still be accesed by mouseclick on the selected
69   * item cell. SWITCH_STYLE_POPUP_DISABLED has the same features as
70   * SWITCH_STYLE_POPUP_ENABLED but the drop-down list is no longer available to
71   * the user. The method setUI(javax.swing.plaf.ComboBoxUI) has been overrriden
72   * to accept only SimpleComboBoxUI instances. In addition SimpleComboBox
73   * accepts custom renderer to be set to rendere only the selected item cell
74   * differently from all the other items in the drop-down list. This renderer
75   * can be set through setSelectedItemRenderer(ListCellRenderer). If null, the
76   * default renderer is used.
77   *
78   * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
79   * @version $id$
80   */
81  public class SimpleComboBox extends JComboBox
82  {
83  
84      private static final long serialVersionUID = -7775055879270581688L;
85  
86  	/** @deprecated 
87  	 *  @use {@link Style#SIMPLE_STYLE} 
88  	 */
89  	public static int SIMPLE_STYLE = 0;
90  
91  	/** @deprecated
92  	 *  @use {@link Style#DROP_DOWN_STYLE} 
93  	 */
94  	public static int DROP_DOWN_STYLE = 3;
95  
96  	/** @deprecated
97  	 *  @use {@link Style#SWITCH_STYLE_POPUP_ENABLED} 
98  	 */
99  	public static int SWITCH_STYLE_POPUP_ENABLED = 1;
100 
101 	/** @deprecated
102 	 *  @use {@link Style#SWITCH_STYLE_POPUP_DISABLED} 
103 	 */
104 	public static int SWITCH_STYLE_POPUP_DISABLED = 2;
105 
106     public enum Style {
107     	SIMPLE_STYLE,
108     	SWITCH_STYLE_POPUP_ENABLED,
109     	SWITCH_STYLE_POPUP_DISABLED,
110     	DROP_DOWN_STYLE
111     };
112 
113 	private ListCellRenderer selectedItemRenderer = null;
114 	private int style = SIMPLE_STYLE;
115 
116     private String HIDE_POPUP_KEY;
117 
118     private Style styleE;
119 
120 	/**
121 	 * Constructor for SimpleComboBox.
122 	 *
123 	 * @param aModel
124 	 *
125 	 * @see javax.swing.JComboBox#JComboBox(ComboBoxModel)
126 	 */
127 	public SimpleComboBox(ComboBoxModel aModel)
128 	{
129 		super(aModel);
130 		init();
131 	}
132 
133 	/**
134 	 * Constructor for SimpleComboBox.
135 	 *
136 	 * @param items
137 	 *
138 	 * @see javax.swing.JComboBox#JComboBox(Object[])
139 	 */
140 	public SimpleComboBox(Object[] items)
141 	{
142 		super(items);
143 		init();
144 	}
145 
146 	/**
147 	 * Constructor for SimpleComboBox.
148 	 *
149 	 * @param items
150 	 *
151 	 * @see javax.swing.JComboBox#JComboBox(Vector)
152 	 */
153 	public SimpleComboBox(Vector items)
154 	{
155 		super(items);
156 		init();
157 	}
158 
159 	/**
160 	 * Constructor for SimpleComboBox.
161 	 *
162 	 * @see javax.swing.JComboBox#JComboBox()
163 	 */
164 	public SimpleComboBox()
165 	{
166 		super();
167 		init();
168 	}
169 
170 	private void init()
171 	{
172 	    //stupid thing needed to get the BasicComboBoxUI.HIDE_POPUP_KEY reference
173         super.setUI(new BasicComboBoxUI());
174         HIDE_POPUP_KEY = String.valueOf(getClientProperty("doNotCancelPopup"));
175         
176 		setUI(new SimpleComboBoxUI());
177 		setBorder(new MetalBorders.Flush3DBorder());
178 	}
179 
180 	/**
181 	 * This method has been overriden to enforce usage of SimpleComboBoxUI.
182 	 *
183 	 * @param ui ComboBoxUI
184 	 *
185 	 * @see javax.swing.JComboBox#setUI(ComboBoxUI)
186 	 */
187 	public void setUI(ComboBoxUI ui)
188 	{
189 	    
190 		if (ui instanceof SimpleComboBoxUI) {
191 			super.setUI(ui);
192 		}
193 	}
194 
195 	/**
196 	 * Returns the selectedItemRenderer.
197 	 *
198 	 * @return ListCellRenderer
199 	 */
200 	public ListCellRenderer getSelectedItemRenderer()
201 	{
202 		return selectedItemRenderer;
203 	}
204 	
205 	@Override
206 	public void setEnabled(boolean b) {
207 		super.setEnabled(b);
208 		ComboBoxUI ui = getUI();
209 		if (ui instanceof SwitchComboBoxUI) {
210 			((SwitchComboBoxUI)ui).leftButton.setEnabled(b);
211 			((SwitchComboBoxUI)ui).rightButton.setEnabled(b);
212 		} else if (ui instanceof DropComboBoxUI) {
213 			((DropComboBoxUI)ui).dropButton.setEnabled(b);
214 		}
215 	}
216 
217 	/**
218 	 * Sets the selectedItemRenderer.
219 	 *
220 	 * @param newSelectedItemRenderer The selectedItemRenderer to set. If null,
221 	 *        the selected item is rendered with the common list cell renderer
222 	 *        of the combo box.
223 	 *
224 	 * @see #setRenderer(ListCellRenderer)
225 	 */
226 	public void setSelectedItemRenderer(
227 	    ListCellRenderer newSelectedItemRenderer)
228 	{
229 		ListCellRenderer oldSelectedItemRenderer = selectedItemRenderer;
230 		selectedItemRenderer = newSelectedItemRenderer;
231 		firePropertyChange("selectedItemRenderer", oldSelectedItemRenderer,
232 		    newSelectedItemRenderer);
233 	}
234 
235 	/**
236 	 * Returns the style.
237 	 *
238 	 * @return int
239 	 */
240 	public int getStyle()
241 	{
242 		return style;
243 	}
244 
245     public void setStyle(Style newStyleE) {
246         if (styleE == newStyleE) {
247             return;
248         }
249 
250         if (newStyleE == Style.SIMPLE_STYLE) {
251             setUI(new SimpleComboBoxUI());
252         } else if (newStyleE == Style.DROP_DOWN_STYLE) {
253             setUI(new DropComboBoxUI());
254         } else if (newStyleE == Style.SWITCH_STYLE_POPUP_ENABLED) {
255             SwitchComboBoxUI ui = new SwitchComboBoxUI();
256             setUI(ui);
257             ui.setPopupEnabled(true);
258         } else if (newStyleE == Style.SWITCH_STYLE_POPUP_DISABLED) {
259             SwitchComboBoxUI ui = new SwitchComboBoxUI();
260             setUI(ui);
261             ui.setPopupEnabled(false);
262         } else {
263             throw (new IllegalArgumentException());
264         }
265 
266         Style oldStyleE = styleE;
267         styleE = newStyleE;
268         firePropertyChange("style", oldStyleE, newStyleE);
269     }
270     
271 	/**
272 	 * Sets the style. SIMPLE_STYLE only displays the selected item. When
273 	 * clicked the drop down list dialog shows up. SWITCH_STYLE_POPUP_DISABLED
274 	 * displays the selected item together with two arrowed buttons on each
275 	 * style to switch between adjacent items in the list. No popup is
276 	 * displayed. SWITCH_STYLE_POPUP_ENABLED is the same as
277 	 * SWITCH_STYLE_POPUP_DISABLED only that at mouse click the drop down list
278 	 * of items is displayed. DROP_DOWN_STYLE displays the SimpleComboBox in
279 	 * conventional way. The selected item is displyed next to a downwards
280 	 * pointing arrow button which brings up the drop down list of all items.
281 	 *
282      * @deprecated use {@link #setStyle(Style)}
283 	 * @param newStyle int the style to be used by this SimpleComboBox
284 	 */
285 	public void setStyle(int newStyle)
286 	{
287         setStyle(Style.values()[newStyle]);
288 	}
289 
290 	/**
291 	 * For testing and demonstration purposes only.
292 	 *
293 	 * @param args String[]
294 	 */
295 	public static void main(String[] args)
296 	{
297 		JFrame frame = new JFrame("SimpleComboBox Demo");
298 		final SimpleComboBox box = new SimpleComboBox();
299 		DefaultComboBoxModel model = new DefaultComboBoxModel();
300 
301 		for (int i = 1; i <= 50; i++) {
302 			model.addElement("item " + i);
303 		}
304 
305 		box.setModel(model);
306 
307 		final JComboBox box1 = new JComboBox();
308 		DefaultComboBoxModel model1 = new DefaultComboBoxModel();
309         for (Style st : Style.values()) {
310             model1.addElement(st);            
311         }
312 		box1.setModel(model1);
313 		box1.addActionListener(new ActionListener() {
314 				public void actionPerformed(ActionEvent e)
315 				{
316 					box.setStyle(((Style)box1.getSelectedItem()));
317 				}
318 			});
319 
320 		frame.getContentPane().setLayout(new FlowLayout());
321 		frame.getContentPane().add(box);
322 		frame.getContentPane().add(box1);
323 		frame.setSize(500, 200);
324 		frame.addWindowListener(new WindowAdapter() {
325 				public void windowClosing(WindowEvent e)
326 				{
327 					System.exit(0);
328 				}
329 			});
330 		frame.setVisible(true);
331 	}
332 
333 	/**
334 	 * The simplest implementation od ComboBoxUI displays no button in the
335 	 * comboBox. Items are selected from a drop down list activated on mouse
336 	 * click.
337 	 *
338 	 * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
339 	 * @version $id$
340 	 */
341 	public static class SimpleComboBoxUI extends ComboBoxUI
342 	{
343 		protected SimpleComboBox comboBox = null;
344 		protected BasicComboPopup popup = null;
345 		protected CellRendererPane cellRenderingPane = null;
346 		protected ItemListener itemListener;
347         
348 		/**
349 		 * Constructor for SimpleComboBoxUI.
350 		 */
351 		public SimpleComboBoxUI()
352 		{
353 			super();
354 		}
355 
356 		/**
357 		 * Delegates to <code>comboBox</code> implementation.
358 		 *
359 		 * @param c JComboBox must be <code>comboBox</code>
360 		 *
361 		 * @return boolean
362 		 *
363 		 * @see javax.swing.plaf.ComboBoxUI#isFocusTraversable(JComboBox)
364 		 */
365 		public boolean isFocusTraversable(JComboBox c)
366 		{
367 			//assert (c == comboBox);
368 
369 			return !comboBox.isEditable();
370 		}
371 
372 		/**
373 		 * Delegates to <code>comboBox</code> implementation.
374 		 *
375 		 * @param c JComboBox must be <code>comboBox</code>
376 		 *
377 		 * @return boolean
378 		 *
379 		 * @see javax.swing.plaf.ComboBoxUI#isPopupVisible(JComboBox)
380 		 */
381 		public boolean isPopupVisible(JComboBox c)
382 		{
383 			//assert (c == comboBox);
384 
385 			if (popup == null) {
386 				return false;
387 			}
388 
389 			return popup.isVisible();
390 		}
391 
392 		/**
393 		 * Delegates to <code>comboBox</code> implementation.
394 		 *
395 		 * @param c JComboBox must be <code>comboBox</code>
396 		 * @param v boolean
397 		 *
398 		 * @see javax.swing.plaf.ComboBoxUI#setPopupVisible(JComboBox, boolean)
399 		 */
400         public void setPopupVisible( JComboBox c, boolean v ) {
401             if ( v ) {
402                 popup.show();
403             } else {
404                 popup.hide();
405             }
406         }
407 
408 		/**
409 		 * Installs this UI to the supplied SimpleComboBox
410 		 *
411 		 * @param c JComponent must be an instance of SimpleComboBox
412 		 *
413 		 * @see javax.swing.plaf.ComponentUI#installUI(JComponent)
414 		 */
415 		public void installUI(JComponent c)
416 		{
417 			//assert (c instanceof SimpleComboBox);
418 
419 			comboBox = (SimpleComboBox)c;
420 			popup = new BasicComboPopup(comboBox) {
421 				private static final long serialVersionUID = -5379054665405013304L;
422 
423 				/* (non-Javadoc)
424 				 * @see javax.swing.plaf.basic.BasicComboPopup#createKeyListener()
425 				 */
426 				protected KeyListener createKeyListener() {
427 					return new KeyAdapter() {
428 					public void keyPressed(KeyEvent e) {
429 						if (e.getKeyCode()==KeyEvent.VK_UP || e.getKeyCode()==KeyEvent.VK_RIGHT) getList().setSelectedIndex(list.getSelectedIndex()-1);
430 						if (e.getKeyCode()==KeyEvent.VK_DOWN || e.getKeyCode()==KeyEvent.VK_LEFT) getList().setSelectedIndex(list.getSelectedIndex()+1);
431 						if (e.getKeyCode()==KeyEvent.VK_ENTER) {
432 							comboBox.setSelectedIndex(getList().getSelectedIndex());
433 							hide();
434 						}
435 						if (e.getKeyCode()==KeyEvent.VK_ESCAPE) hide();
436 						getList().ensureIndexIsVisible(getList().getSelectedIndex());
437 					}
438 				};
439                 
440 				}
441 			};
442 			comboBox.addKeyListener(popup.getKeyListener());
443 			cellRenderingPane = new CellRendererPane();
444 			itemListener = new ItemListener() {
445 						public void itemStateChanged(ItemEvent e)
446 						{
447 							comboBox.revalidate();
448 							comboBox.repaint();
449 						}
450 					};
451 
452 			comboBox.addItemListener(itemListener);
453 			comboBox.addMouseListener(popup.getMouseListener());
454 			comboBox.addMouseMotionListener(popup.getMouseMotionListener());
455 			comboBox.setLayout(new ComboBoxLayoutManager());
456 			comboBox.add(cellRenderingPane, BorderLayout.CENTER);
457 			                                   
458             comboBox.putClientProperty("doNotCancelPopup", comboBox.HIDE_POPUP_KEY);
459 
460         }
461 
462 		/**
463 		 * Uninstalls this UI from the supplied SimpleComboBox
464 		 *
465 		 * @param c JComponent must be <code>comboBox</code>
466 		 *
467 		 * @see javax.swing.plaf.ComponentUI#uninstallUI(JComponent)
468 		 */
469 		public void uninstallUI(JComponent c)
470 		{
471 			//assert (c == comboBox);
472 			super.uninstallUI(c);
473 			comboBox.removeItemListener(itemListener);
474 			comboBox.removeMouseListener(popup.getMouseListener());
475 			comboBox.removeMouseMotionListener(popup.getMouseMotionListener());
476 			comboBox.setLayout(null);
477 			comboBox.remove(cellRenderingPane);
478 			comboBox = null;
479 			popup = null;
480 			cellRenderingPane = null;
481 			itemListener = null;
482 		}
483 
484 		/**
485 		 * Returns the maximum allowed layout size.
486 		 *
487 		 * @param c JComponent must be <code>comboBox</code>
488 		 *
489 		 * @return Dimension layout size.
490 		 *
491 		 * @see javax.swing.plaf.ComponentUI#getMaximumSize(JComponent)
492 		 */
493 		public Dimension getMaximumSize(JComponent c)
494 		{
495 			//assert (c == comboBox);
496 
497 			return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
498 		}
499 
500 		/**
501 		 * Returns the minimum allowed layout size.
502 		 *
503 		 * @param c JComponent must be <code>comboBox</code>
504 		 *
505 		 * @return Dimension layout size.
506 		 *
507 		 * @see javax.swing.plaf.ComponentUI#getMinimumSize(JComponent)
508 		 */
509 		public Dimension getMinimumSize(JComponent c)
510 		{
511 			//assert (c == comboBox);
512 
513 			return getPreferredSize(c);
514 		}
515 
516 		/**
517 		 * Returns the preferred layout size.
518 		 *
519 		 * @param c JComponent must be <code>comboBox</code>
520 		 *
521 		 * @return Dimension layout size.
522 		 *
523 		 * @see javax.swing.plaf.ComponentUI#getPreferredSize(JComponent)
524 		 * @see SimpleComboBoxUI#calculatePreferredSize()
525 		 */
526 		public Dimension getPreferredSize(JComponent c)
527 		{
528 			//assert (c == comboBox);
529 
530 			return calculatePreferredSize();
531 		}
532 
533 		/**
534 		 * This method has been overriden to implement correct combo box
535 		 * painting.
536 		 *
537 		 * @param g Graphics
538 		 * @param jc JComponent must be <code>comboBox</code>
539 		 *
540 		 * @see javax.swing.plaf.ComponentUI#paint(Graphics, JComponent)
541 		 */
542 		public void paint(Graphics g, JComponent jc)
543 		{
544 			//assert (jc == comboBox);
545 
546 			if (comboBox.getRenderer() == null) {
547 				comboBox.setRenderer(new BasicComboBoxRenderer.UIResource());
548 			}
549 
550 			Component c = null;
551 
552 			if (comboBox.getSelectedItemRenderer() == null) {
553 				c = comboBox.getRenderer().getListCellRendererComponent(popup
554 					    .getList(), comboBox.getSelectedItem(),
555 					    comboBox.getSelectedIndex(), true, comboBox.hasFocus());
556 			} else {
557 				c = comboBox.getSelectedItemRenderer()
558 					.getListCellRendererComponent(popup.getList(),
559 					    comboBox.getSelectedItem(),
560 					    comboBox.getSelectedIndex(), true, comboBox.hasFocus());
561 			}
562 
563 			Rectangle bounds = calculateRendererCellRectangle();
564 
565 			// Fix for 4238829: should lay out the JPanel.
566 			boolean shouldValidate = false;
567 
568 			if (c instanceof JPanel) {
569 				shouldValidate = true;
570 			}
571 
572 			cellRenderingPane.paintComponent(g, c, comboBox, bounds.x,
573 			    bounds.y, bounds.width, bounds.height, shouldValidate);
574 		}
575 
576 		/*
577 		 * @return Rectangle
578 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculateRendererCellRectangle(SimpleComboBox)
579 		 */
580 		protected Rectangle calculateRendererCellRectangle()
581 		{
582 			int width = comboBox.getWidth();
583 			int height = comboBox.getHeight();
584 			Insets insets = comboBox.getInsets();
585 
586 			return new Rectangle(insets.left, insets.top,
587 			    width - (insets.left + insets.right),
588 			    height - (insets.top + insets.bottom));
589 		}
590 
591 		/*
592 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#layoutComboBox(SimpleComboBox)
593 		 */
594 		protected void calculateLayout()
595 		{
596 			//cellRenderingPane.setBounds(calculateRendererCellRectangle());
597 		}
598 
599 		/*
600 		 * @return Dimension
601 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculatePreferredSize(SimpleComboBox)
602 		 */
603 		protected Dimension calculatePreferredSize()
604 		{
605 			if (comboBox.getRenderer() == null) {
606 				comboBox.setRenderer(new BasicComboBoxRenderer.UIResource());
607 			}
608 
609 			Component c = null;
610 			int width = 0;
611 			int height = 0;
612 
613 			for (int i = 0; i < popup.getList().getModel().getSize(); i++) {
614 				if (comboBox.getSelectedItemRenderer() == null) {
615 					c = comboBox.getRenderer().getListCellRendererComponent(popup
616 						    .getList(), comboBox.getItemAt(i), i, true,
617 						    comboBox.hasFocus());
618 				} else {
619 					c = comboBox.getSelectedItemRenderer()
620 						.getListCellRendererComponent(popup.getList(),
621 						    comboBox.getItemAt(i), i, true, comboBox.hasFocus());
622 				}
623 
624 				width = Math.max(c.getPreferredSize().width, width);
625 				height = Math.max(c.getPreferredSize().height, height);
626 			}
627 
628 			Insets insets = comboBox.getInsets();
629 
630             int buttonSize = ArrowButton.PREFERRED_SIZE;//height - (insets.top + insets.bottom);
631 
632             Dimension retVal = new Dimension(buttonSize+insets.left + insets.right + width,
633 				    insets.top + insets.bottom + height);
634 
635 			return retVal;
636 		}
637 
638 		/*
639 		 * Layout manager for SimpleComboBox
640 		     * @author Jernej Kamenik
641 		     * @version $id$
642 		     */
643 		protected class ComboBoxLayoutManager implements LayoutManager
644 		{
645 			/**
646 			 * Empty implementation.
647 			 *
648 			 * @param name String
649 			 * @param comp Component
650 			 *
651 			 * @see java.awt.LayoutManager#addLayoutComponent(String,
652 			 *      Component)
653 			 */
654 			public void addLayoutComponent(String name, Component comp)
655 			{
656 			}
657 
658 			/**
659 			 * Empty implementation.
660 			 *
661 			 * @param comp Component
662 			 *
663 			 * @see java.awt.LayoutManager#removeLayoutComponent(Component)
664 			 */
665 			public void removeLayoutComponent(Component comp)
666 			{
667 			}
668 
669 			/**
670 			 * Delegates to <code>parent</code> implementation.
671 			 *
672 			 * @param parent Container
673 			 *
674 			 * @return Dimension
675 			 *
676 			 * @see java.awt.LayoutManager#preferredLayoutSize(Container)
677 			 */
678 			public Dimension preferredLayoutSize(Container parent)
679 			{
680 				return parent.getPreferredSize();
681 			}
682 
683 			/**
684 			 * Delegates to <code>parent</code> implementation.
685 			 *
686 			 * @param parent Container
687 			 *
688 			 * @return Dimension
689 			 *
690 			 * @see java.awt.LayoutManager#minimumLayoutSize(Container)
691 			 */
692 			public Dimension minimumLayoutSize(Container parent)
693 			{
694 				return parent.getMinimumSize();
695 			}
696 
697 			/**
698 			 * Delegates to <code>parent</code> implementation.
699 			 *
700 			 * @param parent Container
701 			 *
702 			 * @see java.awt.LayoutManager#layoutContainer(Container)
703 			 * @see SimpleComboBoxUI#calculateLayout()
704 			 */
705 			public void layoutContainer(Container parent)
706 			{
707 				((SimpleComboBoxUI)((SimpleComboBox)parent).getUI())
708 				.calculateLayout();
709 			}
710 		}
711 	}
712 
713 	/**
714 	 * 
715 	 * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
716 	 * @version $id$ This extension of SimpleComboBoxUI positions two buttons on each side of the combo box to be used for switching between items in the drop-down list.
717 	 */
718 	public static class SwitchComboBoxUI extends SimpleComboBoxUI
719 	{
720 		protected ArrowButton leftButton = null;
721 		protected ArrowButton rightButton = null;
722 		private boolean popupEnabled = true;
723 		private boolean mustSetPopup = false;
724 
725 		/*
726 		 * @return ArrowButton
727 		 */
728 		protected SimpleButton getLeftButton()
729 		{
730 			if (leftButton == null) {
731 				leftButton = new ArrowButton(ArrowButton.LEFT);
732 				leftButton.addActionListener(new ActionListener() {
733 						public void actionPerformed(ActionEvent e)
734 						{
735 							if (comboBox.getSelectedIndex() > 0) {
736 								comboBox.setSelectedIndex(comboBox
737 								    .getSelectedIndex() - 1);
738 							}
739 						}
740 					});
741 				leftButton.setBackground(ColorHelper.getControl());
742 				leftButton.setBorder(null);
743 				leftButton.setPressedBorder(null);
744                 leftButton.putClientProperty("doNotCancelPopup", comboBox.HIDE_POPUP_KEY);
745 			}
746 
747 			return leftButton;
748 		}
749 
750 		/*
751 		 * @return ArrowButton
752 		 */
753 		protected SimpleButton getRightButton()
754 		{
755 			if (rightButton == null) {
756 				rightButton = new ArrowButton(ArrowButton.RIGHT);
757 				rightButton.addActionListener(new ActionListener() {
758 						public void actionPerformed(ActionEvent e)
759 						{
760 							if (comboBox.getSelectedIndex() < (comboBox
761 							    .getItemCount() - 1)) {
762 								comboBox.setSelectedIndex(comboBox
763 								    .getSelectedIndex() + 1);
764 							}
765 						}
766 					});
767 				rightButton.setBackground(ColorHelper.getControl());
768 				rightButton.setBorder(null);
769 				rightButton.setPressedBorder(null);
770                 rightButton.putClientProperty("doNotCancelPopup", comboBox.HIDE_POPUP_KEY);
771 			}
772 
773 			return rightButton;
774 		}
775 
776 		/*
777 		 * @return Dimension
778 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculatePreferredSize()
779 		 */
780 		protected Dimension calculatePreferredSize()
781 		{
782 			Dimension retVal = super.calculatePreferredSize();
783 			retVal.width += ArrowButton.PREFERRED_SIZE;//(getRightButton().getPreferredSize().width + getLeftButton().getPreferredSize().width);
784 
785 			return retVal;
786 		}
787 
788 		/*
789 		 * @return Rectangle
790 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculateRendererCellRectangle()
791 		 */
792 		protected Rectangle calculateRendererCellRectangle()
793 		{
794 			Rectangle retVal = super.calculateRendererCellRectangle();
795 			retVal.x += getRightButton().getBounds().width;
796 			retVal.width -= (getRightButton().getBounds().width
797 			+ getLeftButton().getBounds().width);
798 
799 			return retVal;
800 		}
801 
802 		/*
803 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculateLayout()
804 		 */
805 		protected void calculateLayout()
806 		{
807 			int width = comboBox.getWidth();
808 			int height = comboBox.getHeight();
809 			Insets insets = comboBox.getInsets();
810 
811 			int buttonSize = height - (insets.top + insets.bottom);
812 
813 			getLeftButton().setBounds(insets.left, insets.top, buttonSize,
814 			    buttonSize);
815 			getRightButton().setBounds(width - (insets.right + buttonSize),
816 			    insets.top, buttonSize, buttonSize);
817 		}
818 
819 		/**
820 		 * Returns wether the popup list dialog is enabled.
821 		 *
822 		 * @return boolean
823 		 */
824 		public boolean isPopupEnabled()
825 		{
826 			return popupEnabled;
827 		}
828 
829 		/**
830 		 * Sets the popupEnabled. When true, the user can access the drop-down
831 		 * list by clicking on the selected item cell.
832 		 *
833 		 * @param newPopupEnabled The popupEnabled to set
834 		 */
835 		public void setPopupEnabled(boolean newPopupEnabled)
836 		{
837 			if (popupEnabled == newPopupEnabled) {
838 				return;
839 			}
840 
841 			popupEnabled = newPopupEnabled;
842 
843 			if (comboBox == null) {
844 				mustSetPopup = true;
845 
846 				return;
847 			} else {
848 				mustSetPopup = false;
849 			}
850 
851 			if (popupEnabled) {
852 				comboBox.addMouseListener(popup.getMouseListener());
853 				comboBox.addMouseMotionListener(popup.getMouseMotionListener());
854 			} else {
855 				comboBox.removeMouseListener(popup.getMouseListener());
856 				comboBox.removeMouseMotionListener(popup.getMouseMotionListener());
857 			}
858 		}
859 
860 		/**
861 		 * This method has been overriden to implement uninstallation of the
862 		 * two additional buttons.
863 		 *
864 		 * @param c JComponent
865 		 *
866 		 * @see javax.swing.plaf.ComponentUI#uninstallUI(JComponent)
867 		 */
868 		public void uninstallUI(JComponent c)
869 		{
870 			comboBox.remove(getRightButton());
871 			comboBox.remove(getLeftButton());
872 			rightButton = null;
873 			leftButton = null;
874 			super.uninstallUI(c);
875 		}
876 
877 		/**
878 		 * This method has been overriden to implement installation of the two
879 		 * additional buttons.
880 		 *
881 		 * @param c JComponent
882 		 *
883 		 * @see javax.swing.plaf.ComponentUI#installUI(JComponent)
884 		 */
885 		public void installUI(JComponent c)
886 		{
887 			super.installUI(c);
888 			comboBox.add(getRightButton(), BorderLayout.EAST);
889 			comboBox.add(getLeftButton(), BorderLayout.WEST);
890 
891 			if (mustSetPopup) {
892 				setPopupEnabled(popupEnabled);
893 			}
894 		}
895 	}
896 
897 	/**
898 	 * This extension of SimpleComboBoxUI uses the standard right-side arrow
899 	 * button to activate the drop-down list.
900 	 *
901 	 * @author <a href="mailto:jernej.kamenik@cosylab.com">Jernej Kamenik</a>
902 	 * @version $id$
903 	 */
904 	public static class DropComboBoxUI extends SimpleComboBoxUI
905 	{
906 		protected ArrowButton dropButton = null;
907 
908 		/*
909 		 * @return ArrowButton
910 		 */
911 		protected SimpleButton getDropButton()
912 		{
913 			if (dropButton == null) {
914 				dropButton = new ArrowButton(ArrowButton.DOWN);
915 				dropButton.addMouseListener(popup.getMouseListener());
916 				dropButton.addMouseMotionListener(popup.getMouseMotionListener());
917 				dropButton.setBackground(ColorHelper.getControl());
918 				dropButton.setBorder(null);
919 				dropButton.setPressedBorder(null);
920                 dropButton.putClientProperty("doNotCancelPopup", comboBox.HIDE_POPUP_KEY);
921 			}
922 
923 			return dropButton;
924 		}
925 
926 		/*
927 		 * @return Dimension
928 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculatePreferredSize(SimpleComboBox)
929 		 */
930 		protected Dimension calculatePreferredSize()
931 		{
932 			Dimension retVal = super.calculatePreferredSize();
933 			//retVal.width += getDropButton().getPreferredSize().width;
934 
935 			return retVal;
936 		}
937 
938 		/*
939 		 * @return Rectangle
940 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#calculateRendererCellRectangle(SimpleComboBox)
941 		 */
942 		protected Rectangle calculateRendererCellRectangle()
943 		{
944 			Rectangle retVal = super.calculateRendererCellRectangle();
945 			retVal.width -= getDropButton().getBounds().width;
946 
947 			return retVal;
948 		}
949 
950 		/*
951 		 * @see com.cosylab.gui.components.SimpleComboBox.SimpleComboBoxUI#layoutComboBox(SimpleComboBox)
952 		 */
953 		protected void calculateLayout()
954 		{
955 			int width = comboBox.getWidth();
956 			int height = comboBox.getHeight();
957 			Insets insets = comboBox.getInsets();
958 
959 			int buttonSize = height - (insets.top + insets.bottom);
960 
961 			getDropButton().setBounds(width - (insets.right + buttonSize),
962 			    insets.top, buttonSize, buttonSize);
963 		}
964 
965 		/**
966 		 * This method has been overriden to implement the uninstallation of
967 		 * the additional button.
968 		 *
969 		 * @param c JComponent
970 		 *
971 		 * @see javax.swing.plaf.ComponentUI#uninstallUI(JComponent)
972 		 */
973 		public void uninstallUI(JComponent c)
974 		{
975 			comboBox.remove(getDropButton());
976 			dropButton = null;
977 			super.uninstallUI(c);
978 		}
979 
980 		/**
981 		 * @see javax.swing.plaf.ComponentUI#installUI(JComponent)
982 		 */
983 		public void installUI(JComponent c)
984 		{
985 			super.installUI(c);
986 			comboBox.add(getDropButton(), BorderLayout.EAST);
987 		}
988 	}
989 }
990 
991 /* __oOo__ */