View Javadoc

1   /*
2    *  XNap Commons
3    *
4    *  Copyright (C) 2005  Felix Berger
5    *  Copyright (C) 2005  Steffen Pingel
6    *
7    *  This library is free software; you can redistribute it and/or
8    *  modify it under the terms of the GNU Lesser General Public
9    *  License as published by the Free Software Foundation; either
10   *  version 2.1 of the License, or (at your option) any later version.
11   *
12   *  This library is distributed in the hope that it will be useful,
13   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15   *  Lesser General Public License for more details.
16   *
17   *  You should have received a copy of the GNU Lesser General Public
18   *  License along with this library; if not, write to the Free Software
19   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   */
21  package org.xnap.commons.gui;
22  
23  import java.awt.CardLayout;
24  import java.awt.Component;
25  import java.awt.Container;
26  import javax.swing.DefaultListModel;
27  import javax.swing.Icon;
28  import javax.swing.ImageIcon;
29  import javax.swing.JLabel;
30  import javax.swing.JList;
31  import javax.swing.JScrollPane;
32  import javax.swing.JSplitPane;
33  import javax.swing.ListCellRenderer;
34  import javax.swing.ListSelectionModel;
35  import javax.swing.SwingConstants;
36  import javax.swing.border.EmptyBorder;
37  import javax.swing.event.ChangeEvent;
38  import javax.swing.event.ChangeListener;
39  import javax.swing.event.ListSelectionEvent;
40  import javax.swing.event.ListSelectionListener;
41  
42  /***
43   * This class provides a tabbed pane like behaving widget. The 
44   * <code>IconSplitPane</code> is split up in two parts. The left part is a
45   * {@link javax.swing.JList JList} that contains icons and their descriptions.
46   * The right part can be any component. If the user selects on of the icons
47   * from the list the respective panel is show at the right.
48   *
49   * <p>The names of the methods are modelled after the 
50   * {@link javax.swing.JTabbedPane JTabbedPane}.
51   * 
52   * TODO add ComponentOrientation support
53   * TODO show empty icon instead of no icon? to separated list entries
54   */
55  public class IconSplitPane extends JSplitPane
56  {
57  
58      private JList iconList;
59      private DefaultListModel iconListModel;
60      private CardLayout containerLayout;
61      private Container container;
62      private transient ChangeEvent changeEvent = null;
63  
64      public IconSplitPane()
65      {
66  		super(JSplitPane.HORIZONTAL_SPLIT);
67  
68  		initialize();
69      }
70  
71      private void initialize() 
72      {
73  		setOneTouchExpandable(true);
74  
75  		iconList = new JList();
76  		iconListModel = new DefaultListModel();
77  		iconList.setModel(iconListModel);
78  		iconList.addListSelectionListener(new IconListener());
79  		iconList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
80  		iconList.setCellRenderer(new IconRenderer());
81  
82  		JScrollPane jspIcons = new JScrollPane(iconList);
83  		jspIcons.setHorizontalScrollBarPolicy
84  			(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
85  		add(jspIcons, JSplitPane.LEFT);
86  
87  		containerLayout = new CardLayout();
88  		container = new Container();
89  		container.setLayout(containerLayout);
90  		add(container, JSplitPane.RIGHT);
91      }
92  
93      /***
94       * Adds a new tab.
95       */
96      public void addTab(String description, Icon icon, Component c) 
97      {
98  		insertTab(description, icon, c, iconListModel.size());
99      }
100 
101     /***
102      * Inserts a new tab at <code>index</code>.
103      */
104     public void insertTab(String description, Icon icon, Component c, 
105 						  int index) 
106     {
107 		if (icon != null) {
108 			if (icon instanceof ImageIcon) {
109 				((ImageIcon)icon).setDescription(description);
110 			}
111 			iconListModel.insertElementAt(icon, index);
112 		}
113 		else {
114 			iconListModel.insertElementAt(description, index);
115 		}
116 
117 		container.add(c, description, index);
118 		setDividerLocation(iconList.getPreferredSize().width + 30);
119 
120 		if (iconListModel.size() == 1) {
121 			iconList.setSelectedIndex(0);
122 			//setDividerLocation(jlIcons.getPreferredSize().width * 2);
123 		}
124 		else if (iconList.getSelectedIndex() >= index) {
125 			iconList.setSelectedIndex(iconList.getSelectedIndex() + 1);
126 		}
127     }
128 
129     /***
130      * Returns all tabs as an array.
131      */
132     public Component[] getTabs()
133     {
134 		return container.getComponents();
135     }
136 
137     /***
138      * Returns the tab at index <code>i</code>.
139      */
140     public Component getTabAt(int i)
141     {
142 		return container.getComponents()[i];
143     }
144 
145     /***
146      * Returns the number of tabs.
147      */
148     public int getTabCount()
149     {
150 		return container.getComponentCount();
151     }
152 
153     /***
154      * Returns the description at index <code>i</code>.
155      */
156     public String getDescriptionAt(int i)
157     {
158 		Object o = iconListModel.get(i);
159 		if (o != null) {
160 			if (o instanceof ImageIcon) {
161 				return ((ImageIcon)o).getDescription();
162 			}
163 			return o.toString();
164 		}
165 
166 		return null;
167     }
168 
169     /***
170      * Returns the icon at index <code>i</code>.
171      */
172     public Icon getIconAt(int i)
173     {
174 		Object o = iconListModel.get(i);
175 		if (o instanceof Icon) {
176 			return (Icon)o;
177 		}
178 		else {
179 			return null;
180 		}
181     }
182 
183     /***
184      * Returns the title at index <code>i</code>.
185      */
186     public String getTitleAt(int i)
187     {
188 		return iconListModel.get(i).toString();
189     }
190 
191     /***
192      * Sets the icon at index <code>i</code> to <code>icon</code>.
193      */
194     public void setIconAt(int i, Icon icon)
195     {
196 		if (icon != null) {
197 			if (icon instanceof ImageIcon) {
198 				((ImageIcon)icon).setDescription(getDescriptionAt(i));
199 			}
200 
201 			iconListModel.set(i, icon);
202 		}
203     }
204 
205     /***
206      * Returns the <code>index</code> of the currently selected tab.
207      */
208     public int getSelectedIndex()
209     {
210 		return iconList.getSelectedIndex();
211     }
212 
213     /***
214      * Selects <code>c</code>. The corresponding icon will also be selected.
215      */
216     public void setSelectedComponent(Component c)
217     {
218 		int i = indexOfComponent(c);
219 		if (i != -1) {
220 			iconList.setSelectedIndex(i);
221 		}
222     }
223 
224     /***
225      * Returns the index of <code>c</code>.
226      */
227     public int indexOfComponent(Component c)
228     {
229 		int count = container.getComponentCount();
230 		for (int i = 0; i < count; i++) {
231 			if (container.getComponent(i) == c) {
232 				return i;
233 			}
234 		}
235 
236 		return -1;
237     }
238 
239     /***
240      * Removes tab <code>c</code>.
241      */
242     public void remove(Component c)
243     {
244 		if (container == null)
245 			return;
246 
247 		int i = indexOfComponent(c);
248 		if (i != -1) {
249 			removeTabAt(i);
250 		}
251     }
252 
253     /***
254      * Removes tab at index <code>i</code>.
255      */
256     public void removeTabAt(int i)
257     {
258 		if (i == iconList.getSelectedIndex()) {
259 			iconList.setSelectedIndex(0);
260 		}
261 		container.remove(i);
262 		iconListModel.remove(i);
263     }
264 
265     /***
266      * Adds a listener that gets notified when a tab is selected.
267      */
268     public void addChangeListener(ChangeListener l) 
269     {
270         listenerList.add(ChangeListener.class, l);
271     }
272 
273     /***
274      * Removes a <code>ChangeListener</code>.
275      *
276      * @param l the ChangeListener to remove
277      * @see #fireStateChanged
278      * @see #addChangeListener
279      */
280     public void removeChangeListener(ChangeListener l) {
281         listenerList.remove(ChangeListener.class, l);
282     }
283 
284     /***
285      * Send a <code>ChangeEvent</code>, whose source is this tabbedpane, to
286      * each listener.  This method method is called each time
287      * a <code>ChangeEvent</code> is received from the model.
288      *
289      * @see #addChangeListener
290      */
291     protected void fireStateChanged() {
292         // Guaranteed to return a non-null array
293         Object[] listeners = listenerList.getListenerList();
294         // Process the listeners last to first, notifying
295         // those that are interested in this event
296         for (int i = listeners.length-2; i>=0; i-=2) {
297             if (listeners[i]==ChangeListener.class) {
298                 // Lazily create the event:
299                 if (changeEvent == null)
300                     changeEvent = new ChangeEvent(this);
301                 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
302             }
303         }
304     }
305 
306     /***
307      * Returns the currently selected tab.
308      */
309     public Component getSelectedComponent()
310     {
311 		return container.getComponent(iconList.getSelectedIndex());
312     }
313 
314     /***
315      * Listens for icon selection events.
316      */
317     private class IconListener implements ListSelectionListener
318     {
319 
320 		public void valueChanged(ListSelectionEvent e)
321 		{
322 			int index = iconList.getSelectedIndex();
323 			if (index != -1) {
324 				String description = null;
325 				Object o = iconListModel.elementAt(index);
326 				if (o instanceof ImageIcon)
327 					description = ((ImageIcon)o).getDescription();
328 				else if (o instanceof String)
329 					description = (String)o;
330 				containerLayout.show(container, description);
331 				fireStateChanged();
332 			}
333 		}
334 
335     }
336 
337     /***
338      * Renders the icons in the <code>JList</code>.
339      */
340     private class IconRenderer extends JLabel implements ListCellRenderer 
341     {
342 
343 		public IconRenderer() 
344 		{
345 			this.setOpaque(true);
346 			this.setHorizontalAlignment(CENTER);
347 			this.setVerticalAlignment(CENTER);
348 			this.setHorizontalTextPosition(CENTER);
349 			this.setVerticalTextPosition(SwingConstants.BOTTOM);
350 			this.setBorder(new EmptyBorder(5, 5, 5, 5));
351 		}
352 
353 		public Component getListCellRendererComponent(JList list, Object value,
354 													  int index,
355 													  boolean isSelected,
356 													  boolean cellHasFocus)
357 		{
358 			if (isSelected) {
359 				this.setBackground(list.getSelectionBackground());
360 				this.setForeground(list.getSelectionForeground());
361 			} 
362 			else {
363 				this.setBackground(list.getBackground());
364 				this.setForeground(list.getForeground());
365 			}
366 
367 			this.setText(null);
368 			this.setIcon(null);
369 
370 			if (value instanceof ImageIcon) {
371 				ImageIcon icon = (ImageIcon)value;
372 				this.setText(icon.getDescription());
373 				this.setIcon(icon);
374 			}
375 			else if (value instanceof String) {
376 				this.setText((String)value);
377 //				this.setIcon(IconHelper.getEmptyIcon(32));
378 			}
379 
380 			return this;
381 		}
382 
383     }   
384 
385 }