View Javadoc

1   /*
2    *  XNap Commons
3    *
4    *  Copyright (C) 2005  Steffen Pingel
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or (at your option) any later version.
10   *
11   *  This library 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 GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   */
20  package org.xnap.commons.gui.wizard;
21  
22  import java.awt.BorderLayout;
23  import java.awt.CardLayout;
24  import java.awt.Color;
25  import java.awt.Component;
26  import java.awt.Dialog;
27  import java.awt.Dimension;
28  import java.awt.Font;
29  import java.awt.Frame;
30  import java.awt.event.ActionEvent;
31  import java.util.ArrayList;
32  import java.util.LinkedList;
33  import java.util.List;
34  import javax.swing.AbstractButton;
35  import javax.swing.Action;
36  import javax.swing.BorderFactory;
37  import javax.swing.JLabel;
38  import javax.swing.JPanel;
39  import javax.swing.SwingConstants;
40  import javax.swing.border.EmptyBorder;
41  import org.xnap.commons.gui.Builder;
42  import org.xnap.commons.gui.DefaultDialog;
43  import org.xnap.commons.gui.action.AbstractXNapAction;
44  import org.xnap.commons.i18n.I18n;
45  import org.xnap.commons.i18n.I18nFactory;
46  
47  
48  /***
49   * 
50   * @author Steffen Pingel
51   */
52  public class WizardDialog extends DefaultDialog
53  {
54  
55  	private static final I18n i18n = I18nFactory.getI18n(WizardDialog.class);
56  	
57  	private JLabel titleLabel;
58  	private JLabel iconLabel;
59  	private JLabel descriptionLabel;
60      
61      private JPanel pagePanel;
62      private CardLayout pageCardLayout;
63  
64      private List<WizardPage> pages = new LinkedList<WizardPage>();
65      private int selectedIndex = -1;
66  
67      private AbstractButton nextButton;
68      private AbstractButton finishButton;
69  
70      private PreviousAction previousAction = new PreviousAction();
71      private NextAction nextAction = new NextAction();
72      private FinishAction finishAction = new FinishAction();
73  
74  	private List<WizardDialogListener> listeners 
75  		= new ArrayList<WizardDialogListener>();
76  
77      public WizardDialog(int buttons)
78      {
79  		super(buttons);
80  
81  		initialize();
82      }
83  
84      public WizardDialog(Dialog owner, int buttons)
85      {
86  		super(owner, buttons);
87  		
88  		initialize();
89      }
90  
91      public WizardDialog(Frame owner, int buttons)
92      {
93  		super(owner, buttons);
94  		
95  		initialize();
96      }
97  
98  	public WizardDialog()
99  	{
100 		super(BUTTON_CANCEL);
101 		
102 		initialize();
103 	}
104 
105     public WizardDialog(Dialog owner)
106     {
107 		super(owner, BUTTON_CANCEL);
108 		
109 		initialize();
110     }
111 
112     public WizardDialog(Frame owner)
113     {
114 		super(owner, BUTTON_CANCEL);
115 		
116 		initialize();
117     }
118 
119 	private void initialize()
120 	{
121 		JPanel jpTop = new JPanel(new BorderLayout());
122 		jpTop.setBackground(Color.white);
123 		jpTop.setBorder(BorderFactory.createEtchedBorder());
124 		getContentPane().add(jpTop, BorderLayout.NORTH);
125 
126 		JPanel jpTitle = new JPanel(new BorderLayout());
127 		jpTitle.setBackground(Color.white);
128 		jpTop.add(jpTitle, BorderLayout.CENTER);
129 		
130 		titleLabel = new JLabel(" ");
131 		titleLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
132 		titleLabel.setFont(new Font("Dialog", Font.BOLD, 16));
133 		titleLabel.setForeground(Color.black);
134 		jpTitle.add(titleLabel, BorderLayout.NORTH);
135 
136 		descriptionLabel = new JLabel(" ");
137 		descriptionLabel.setBackground(Color.white);
138 		descriptionLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
139 		descriptionLabel.setForeground(Color.black);
140 		jpTitle.add(descriptionLabel, BorderLayout.CENTER);
141 
142 		iconLabel = new JLabel();
143 		iconLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
144 		jpTop.add(iconLabel, BorderLayout.EAST);
145 
146 		// center
147 		pageCardLayout = new CardLayout();
148 		pagePanel = new JPanel();
149 		pagePanel.setBorder(new EmptyBorder(5, 5, 5, 5));
150 		pagePanel.setLayout(pageCardLayout);
151 
152 		// bottom
153 		JPanel jpButtons = getButtonPanel();
154 
155 		jpButtons.add(Builder.createButton(previousAction), 0);
156 
157 		nextButton = Builder.createButton(nextAction);
158 		nextButton.setHorizontalTextPosition(SwingConstants.LEFT);
159 		jpButtons.add(nextButton, 1);
160 
161 		finishButton = Builder.createButton(finishAction);
162 		jpButtons.add(finishButton, 2);
163 
164 		// set me up
165 		setMainComponent(pagePanel);
166 		setSize(640, 480);
167 	}
168 
169     public void addPage(WizardPage page, String identifier)
170     {
171     	// TODO check if page was already added?
172 		pages.add(page);
173 		pagePanel.add(page.getPanel(), identifier);
174     	if (selectedIndex == -1) {
175     		selectedIndex = 0;
176     	}
177 		updateHeader();
178     }
179 
180     public void addPage(int index, WizardPage page, String identifier)
181     {
182     	// TODO check if page was already added?
183 		pages.add(index, page);
184 		pagePanel.add(page.getPanel(), identifier);
185 		if (selectedIndex == -1) {
186     		selectedIndex = 0;
187     	}
188     	else if (index <= selectedIndex) {
189     		selectedIndex++;
190     	}
191 		updateHeader();
192 	}
193 
194     public void addWizardDialogListener(WizardDialogListener listener)
195     {
196     	listeners.add(listener);
197     }
198     
199 	public void finish()
200 	{
201 		boolean canClose = true;
202 		for (WizardPage page : pages) {
203 			canClose &= page.apply();
204 		}
205 		
206 		if (canClose) {
207 			isOkay = true;
208 			close();
209 		}
210 	}
211 
212 	public Action getFinishAction()
213 	{
214 		return finishAction;
215 	}
216 
217 	public Action getNextAction()
218 	{
219 		return nextAction;
220 	}
221 
222 	public int getSelectedIndex()
223 	{
224 		return selectedIndex;
225 	}
226 
227 	public WizardPage getSelectedPage()
228 	{
229 		return (WizardPage)pages.get(getSelectedIndex());
230 	}
231 
232 	// TODO define what is to happen on add/remove on first/last page
233 	protected void firePageChaned(WizardPage oldPage, WizardPage newPage)
234 	{
235 		WizardDialogListener[] array 
236 			= listeners.toArray(new WizardDialogListener[0]);
237 		for (int i = array.length - 1; i >= 0; i--) {
238 			array[i].pageChanged(oldPage, newPage);
239 		}
240 	}
241 	
242 	/***
243 	 * Removes <code>page</code> from the dialog. Does nothing if page has not
244 	 * been previously added to the dialog.
245 	 * @param page the page to remove
246 	 */
247     public void removePage(WizardPage page)
248     {
249     	int index = pages.indexOf(page);
250     	if (index == -1) {
251     		return;
252     	}
253 		pagePanel.remove(page.getPanel());
254 		pages.remove(index);
255 		if (index <= selectedIndex) {
256 			selectedIndex--;
257 		}
258 		if (selectedIndex == -1) {
259 			clearHeader();
260 		} else {
261 			updateHeader();
262 		}
263 	}
264 
265     public void removeWizardDialogListener(WizardDialogListener listener)
266     {
267     	listeners.remove(listener);
268     }
269 
270     private void updateActions()
271     {
272 		previousAction.setEnabled(selectedIndex > 0);
273 		nextAction.setEnabled(selectedIndex < pages.size() - 1);
274 		if (nextAction.isEnabled()) {
275 			nextButton.requestFocus();
276 		}
277 		else {
278 			finishButton.requestFocus();
279 		}
280     }
281 
282     public void showNextPage()
283     {
284     	if (selectedIndex == pages.size() - 1) {
285     		throw new IllegalStateException("no more pages");
286     	}
287     	
288 		WizardPage oldPage = getSelectedPage();
289 
290 		pageCardLayout.next(pagePanel);
291 		selectedIndex++;
292 		updateHeader();
293 
294 		firePageChaned(oldPage, getSelectedPage());
295     }
296     
297     public void showPreviousPage()
298     {
299     	if (selectedIndex <= 0) {
300     		throw new IllegalStateException("no more pages");
301     	}
302 
303     	WizardPage oldPage = getSelectedPage();
304 
305 		pageCardLayout.previous(pagePanel);
306 		selectedIndex--;
307 		updateHeader();
308 
309 		firePageChaned(oldPage, getSelectedPage());
310     }
311     
312     private void updateHeader() 
313 	{
314 		WizardPage panel = getSelectedPage();
315 		titleLabel.setText(panel.getTitle());
316 		iconLabel.setIcon(panel.getIcon());
317 		descriptionLabel.setText(panel.getDescription());
318 	
319 		updateActions();
320 	}
321 
322     private void clearHeader()
323     {
324 		titleLabel.setText(" ");
325 		iconLabel.setIcon(null);
326 		descriptionLabel.setText(" ");    	
327     }
328     
329     public class PreviousAction extends AbstractXNapAction {
330 	
331 		public PreviousAction()
332 		{
333 			putValue(Action.NAME, i18n.tr("Previous"));
334 			putValue(ICON_FILENAME, "1leftarrow.png");
335         }
336 
337         public void actionPerformed(ActionEvent event) 
338 		{
339 			showPreviousPage();
340         }
341 
342     }
343 
344     public class NextAction extends AbstractXNapAction {
345 	
346 		public NextAction()
347 		{
348 			putValue(Action.NAME, i18n.tr("Next"));
349 			putValue(ICON_FILENAME, "1rightarrow.png");
350         }
351 
352         public void actionPerformed(ActionEvent event) 
353 		{
354         	showNextPage();
355         }
356 
357     }
358 
359     public class FinishAction extends AbstractXNapAction {
360 	
361 		public FinishAction()
362 		{
363 			putValue(Action.NAME, i18n.tr("Finish"));
364         }
365 
366         public void actionPerformed(ActionEvent event) 
367 		{
368 			finish();
369         }
370 
371     }
372 
373     protected class PContainer extends JPanel
374     {
375 		Dimension maxDim = new Dimension(0, 0);
376 
377 		public void add(Component comp, Object constraints) 
378 		{
379 			Dimension d = comp.getPreferredSize();
380 			if (d.height > maxDim.height) {
381 				maxDim.height = d.height;
382 			}
383 			if (d.width > maxDim.width) {
384 				maxDim.width = d.width;
385 			}
386 
387 			super.add(comp, constraints);
388 		}
389 
390 		public Dimension getPreferredSize()
391 		{
392 			// looks like the height is too small
393 			return new Dimension(maxDim.width + 10, maxDim.height + 30);
394 		}
395     }
396 
397 }