View Javadoc

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