001: /*
002: * WizardProcessPanel.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.underworldlabs.swing.wizard;
023:
024: import java.awt.BorderLayout;
025: import java.awt.CardLayout;
026: import java.awt.Color;
027: import java.awt.Dimension;
028: import java.awt.Font;
029: import java.awt.GradientPaint;
030: import java.awt.Graphics;
031: import java.awt.Graphics2D;
032: import java.awt.GridBagConstraints;
033: import java.awt.GridBagLayout;
034: import java.awt.Insets;
035: import java.awt.LayoutManager;
036: import java.awt.Paint;
037: import java.awt.event.ActionEvent;
038: import java.awt.event.ActionListener;
039: import java.util.ArrayList;
040: import java.util.List;
041: import javax.swing.Action;
042: import javax.swing.BorderFactory;
043: import javax.swing.BoxLayout;
044: import javax.swing.JButton;
045: import javax.swing.JLabel;
046: import javax.swing.JPanel;
047: import javax.swing.UIManager;
048: import javax.swing.border.Border;
049: import org.underworldlabs.swing.plaf.UIUtils;
050:
051: /* ----------------------------------------------------------
052: * CVS NOTE: Changes to the CVS repository prior to the
053: * release of version 3.0.0beta1 has meant a
054: * resetting of CVS revision numbers.
055: * ----------------------------------------------------------
056: */
057:
058: /**
059: * Base wizard process panel.
060: *
061: * @author Takis Diakoumis
062: * @version $Revision: 1.6 $
063: * @date $Date: 2006/07/15 12:51:31 $
064: */
065: public abstract class WizardProcessPanel extends JPanel implements
066: ActionListener {
067:
068: /** the selection model */
069: private WizardProcessModel model;
070:
071: /** the left panel */
072: private JPanel leftPanel;
073:
074: /** the right panel */
075: private JPanel rightPanel;
076:
077: /** the base content panel */
078: private JPanel contentPanel;
079:
080: /** the right panel layout */
081: private CardLayout cardLayout;
082:
083: /** the next button */
084: private JButton nextButton;
085:
086: /** the previous button */
087: private JButton backButton;
088:
089: /** the cancel button */
090: private JButton cancelButton;
091:
092: /** the help button */
093: protected JButton helpButton;
094:
095: /** the title label */
096: private JLabel titleLabel;
097:
098: /** the step label list */
099: private List<JLabel> stepLabels;
100:
101: /** the normal label font */
102: private Font labelFont;
103:
104: /** the selected label font */
105: private Font selectedLabelFont;
106:
107: /** whether buttons are enabled */
108: private boolean buttonsEnabled;
109:
110: /** Creates a new instance of WizardProcessPanel */
111: public WizardProcessPanel() {
112: this (null);
113: }
114:
115: /** Creates a new instance of WizardProcessPanel */
116: public WizardProcessPanel(WizardProcessModel model) {
117: super (new BorderLayout());
118: this .model = model;
119: try {
120: init();
121: } catch (Exception e) {
122: e.printStackTrace();
123: }
124: }
125:
126: private void init() throws Exception {
127: buttonsEnabled = true;
128: Border labelBorder = BorderFactory.createMatteBorder(0, 0, 1,
129: 0, Color.BLACK);
130:
131: // setup the title label and right panel
132: cardLayout = new CardLayout();
133: rightPanel = new JPanel(cardLayout);
134:
135: titleLabel = new JLabel("", JLabel.LEFT);
136: titleLabel.setBorder(labelBorder);
137:
138: // store the fonts
139: Font font = titleLabel.getFont();
140: selectedLabelFont = font.deriveFont(Font.BOLD);
141: labelFont = font.deriveFont(Font.PLAIN);
142:
143: titleLabel.setFont(selectedLabelFont);
144:
145: JPanel rightContentPanel = new JPanel(new GridBagLayout());
146: GridBagConstraints gbc = new GridBagConstraints();
147: gbc.gridy++;
148: gbc.gridx = 0;
149: gbc.insets.top = 5;
150: gbc.insets.left = 5;
151: gbc.insets.right = 5;
152: gbc.insets.bottom = 0;
153: gbc.weightx = 1.0;
154: gbc.fill = GridBagConstraints.HORIZONTAL;
155: gbc.anchor = GridBagConstraints.NORTHWEST;
156: rightContentPanel.add(titleLabel, gbc);
157: gbc.gridy++;
158: gbc.weighty = 1.0;
159: gbc.insets.bottom = 5;
160: gbc.fill = GridBagConstraints.BOTH;
161: rightContentPanel.add(rightPanel, gbc);
162:
163: // setup the left panel
164: JLabel stepsLabel = new JLabel("Steps", JLabel.LEFT);
165: stepsLabel.setOpaque(false);
166: stepsLabel.setBorder(labelBorder);
167: stepsLabel.setFont(selectedLabelFont);
168:
169: leftPanel = new JPanel();
170: leftPanel.setOpaque(false);
171: leftPanel.setPreferredSize(new Dimension(170, getHeight()));
172: leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
173:
174: JPanel leftContentPanel = new StepListPanel(new GridBagLayout());
175: gbc.gridy = 0;
176: gbc.weighty = 0;
177: gbc.insets.bottom = 0;
178: gbc.fill = GridBagConstraints.HORIZONTAL;
179: leftContentPanel.add(stepsLabel, gbc);
180: gbc.gridy++;
181: gbc.weighty = 1.0;
182: gbc.insets.bottom = 5;
183: gbc.fill = GridBagConstraints.BOTH;
184: leftContentPanel.add(leftPanel, gbc);
185:
186: // add the panels to the base
187: JPanel base = new JPanel(new BorderLayout());
188: base.add(leftContentPanel, BorderLayout.WEST);
189: base.add(rightContentPanel, BorderLayout.CENTER);
190: add(base, BorderLayout.CENTER);
191:
192: // setup the button panel
193: nextButton = new JButton("Next");
194: nextButton.setMnemonic('N');
195:
196: backButton = new JButton("Back");
197: backButton.setMnemonic('B');
198:
199: cancelButton = new JButton("Cancel");
200: cancelButton.setMnemonic('C');
201:
202: nextButton.addActionListener(this );
203: backButton.addActionListener(this );
204: cancelButton.addActionListener(this );
205:
206: helpButton = new JButton("Help");
207: helpButton.setMnemonic('H');
208:
209: Dimension btnDim = new Dimension(75, 25);
210: nextButton.setPreferredSize(btnDim);
211: backButton.setPreferredSize(btnDim);
212: cancelButton.setPreferredSize(btnDim);
213: helpButton.setPreferredSize(btnDim);
214:
215: Insets buttonInsets = new Insets(2, 2, 2, 2);
216: nextButton.setMargin(buttonInsets);
217: backButton.setMargin(buttonInsets);
218: cancelButton.setMargin(buttonInsets);
219:
220: backButton.setEnabled(false);
221:
222: JPanel buttonPanel = new JPanel(new GridBagLayout());
223: gbc.gridy = 0;
224: gbc.gridx = 0;
225: gbc.insets.left = 5;
226: gbc.insets.top = 7;
227: gbc.insets.bottom = 5;
228: gbc.insets.right = 0;
229: gbc.fill = GridBagConstraints.NONE;
230: gbc.anchor = GridBagConstraints.WEST;
231: gbc.weighty = 0;
232: gbc.weightx = 0.5;
233: buttonPanel.add(helpButton, gbc);
234: gbc.anchor = GridBagConstraints.EAST;
235: gbc.gridx = 1;
236: gbc.weightx = 0;
237: gbc.insets.left = 7;
238: buttonPanel.add(backButton, gbc);
239: gbc.gridx = 2;
240: buttonPanel.add(nextButton, gbc);
241: gbc.gridx = 3;
242: gbc.insets.right = 5;
243: buttonPanel.add(cancelButton, gbc);
244:
245: // add a border to the button panel
246: buttonPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0,
247: 0, UIManager.getColor("controlDkShadow")));
248: add(buttonPanel, BorderLayout.SOUTH);
249:
250: }
251:
252: protected void prepare() {
253:
254: // setup the step labels
255: String[] steps = model.getSteps();
256: stepLabels = new ArrayList<JLabel>(steps.length);
257: for (int i = 0; i < steps.length; i++) {
258: JLabel label = new WizardStepLabel(i + 1, steps[i]);
259: label.setFont(labelFont);
260: leftPanel.add(label);
261: stepLabels.add(label);
262: }
263:
264: // prepare the first panel
265: setTitleLabelText(model.getTitle(0));
266: rightPanel.add(model.getPanelAt(0), String.valueOf(0));
267: cardLayout.first(rightPanel);
268: setSelectedStep(0);
269: }
270:
271: /**
272: * Reformats the label display at the specified index.
273: *
274: * @param index - the label index
275: */
276: protected void setSelectedStep(int index) {
277: for (int i = 0, n = stepLabels.size(); i < n; i++) {
278: JLabel label = stepLabels.get(i);
279: if (i != index) {
280: label.setFont(labelFont);
281: } else {
282: label.setFont(selectedLabelFont);
283: }
284: }
285: }
286:
287: /**
288: * Sets the action for the help button to that specified.
289: *
290: * @param a - the help action to be applied
291: */
292: protected void setHelpAction(Action a) {
293: helpButton.setAction(a);
294: helpButton.setIcon(null);
295: helpButton.setText("Help");
296: }
297:
298: /**
299: * Sets the action for the help button to that specified with
300: * the specified action command string.
301: * This will also set a null icon value and set the button
302: * text to 'Help'.
303: *
304: * @param a - the help action to be applied
305: * @param actionCommand - the action command string
306: */
307: protected void setHelpAction(Action a, String actionCommand) {
308: helpButton.setAction(a);
309: helpButton.setIcon(null);
310: helpButton.setText("Help");
311: helpButton.setActionCommand(actionCommand);
312: }
313:
314: /**
315: * Sets the title label text to that specified.
316: *
317: * @param text - the title text
318: */
319: protected void setTitleLabelText(String text) {
320: titleLabel.setText(text);
321: Dimension dim = titleLabel.getSize();
322: titleLabel.paintImmediately(0, 0, dim.width, dim.height);
323: }
324:
325: /**
326: * Returns whether the buttons are enabled.
327: * If the buttons are not set enabled, any changes
328: * to them using setEnabled(..) is ignored.
329: *
330: * @return true | false
331: */
332: public boolean isButtonsEnabled() {
333: return buttonsEnabled;
334: }
335:
336: /**
337: * Sets the buttons to be enabled.
338: *
339: * @param buttonsEnabled - true | false
340: */
341: public void setButtonsEnabled(boolean buttonsEnabled) {
342: this .buttonsEnabled = buttonsEnabled;
343: }
344:
345: /**
346: * Sets the text label on the next button to that specified.
347: *
348: * @param text - the 'NEXT' button text
349: */
350: public void setNextButtonText(String text) {
351: nextButton.setText(text);
352: }
353:
354: /**
355: * Sets the text label on the back (previous) button to that specified.
356: *
357: * @param text - the 'BACK' button text
358: */
359: public void setBackButtonText(String text) {
360: backButton.setText(text);
361: }
362:
363: /**
364: * Sets the text label on the cancel button to that specified.
365: *
366: * @param text - the 'CANCEL' button text
367: */
368: public void setCancelButtonText(String text) {
369: cancelButton.setText(text);
370: }
371:
372: /**
373: * Enables/disables the next button.
374: *
375: * @param true | false
376: */
377: public void setNextButtonEnabled(boolean enable) {
378: if (buttonsEnabled) {
379: nextButton.setEnabled(enable);
380: }
381: }
382:
383: /**
384: * Enables/disables the next button.
385: *
386: * @param true | false
387: */
388: public void setBackButtonEnabled(boolean enable) {
389: if (buttonsEnabled) {
390: backButton.setEnabled(enable);
391: }
392: }
393:
394: /**
395: * Enables/disables the next button.
396: *
397: * @param true | false
398: */
399: public void setCancelButtonEnabled(boolean enable) {
400: if (buttonsEnabled) {
401: cancelButton.setEnabled(enable);
402: }
403: }
404:
405: /**
406: * Returns the currently selected index.
407: *
408: * @return the current index
409: */
410: public int getSelectedIndex() {
411: return model.getSelectedIndex();
412: }
413:
414: /**
415: * Adds the specified panel to the layout with the specified name.
416: *
417: * The name must be the string value of the index of the specified panel.
418: *
419: * @param panel - the panel
420: * @param title - the layout name
421: */
422: public void addPanel(JPanel panel, String title) {
423: rightPanel.add(panel, title);
424: }
425:
426: /**
427: * Enables/diables buttons based on the current selected index.
428: */
429: protected void resetButtons() {
430: setNextButtonEnabled(model.hasNext());
431: setBackButtonEnabled(model.hasPrevious());
432: }
433:
434: /**
435: * Performs the cancel action.
436: */
437: public abstract void cancel();
438:
439: /**
440: * Performs the action on the selection on next.
441: */
442: protected void next() {
443: if (model.hasNext() && model.next()) {
444: int index = model.getSelectedIndex();
445: String layoutName = String.valueOf(index);
446: rightPanel.add(model.getPanelAt(index), layoutName);
447: setTitleLabelText(model.getTitle(index));
448: cardLayout.show(rightPanel, layoutName);
449: setSelectedStep(index);
450: resetButtons();
451: }
452: }
453:
454: /**
455: * Performs the action on the selection on back.
456: */
457: protected void back() {
458: if (model.hasPrevious() && model.previous()) {
459: int index = model.getSelectedIndex();
460: String layoutName = String.valueOf(index);
461: setTitleLabelText(model.getTitle(index));
462: cardLayout.show(rightPanel, layoutName);
463: setSelectedStep(index);
464: resetButtons();
465: }
466: }
467:
468: /**
469: * Executes the actions associated with the button selctions.
470: *
471: * @param e - the originating event
472: */
473: public void actionPerformed(ActionEvent e) {
474: Object source = e.getSource();
475: if (source == nextButton) {
476: next();
477: } else if (source == backButton) {
478: back();
479: } else if (source == cancelButton) {
480: cancel();
481: }
482: }
483:
484: /**
485: * Returns the wizard model for this instance.
486: *
487: * @return the model
488: */
489: public WizardProcessModel getModel() {
490: return model;
491: }
492:
493: /**
494: * Sets the wizard model to that specified.
495: *
496: * @param model - the model to be used
497: */
498: public void setModel(WizardProcessModel model) {
499: this .model = model;
500: }
501:
502: // the top labels for each panel
503: private class WizardLabel extends JLabel {
504:
505: public WizardLabel(String text, int alignment) {
506: super (text, alignment);
507: }
508:
509: public Dimension getPreferredSize() {
510: return new Dimension(getParent().getWidth(), getHeight());
511: }
512:
513: }
514:
515: // the steps left hand panel
516: private class StepListPanel extends JPanel {
517:
518: private Color darkColor;
519: private Color lightColor;
520:
521: public StepListPanel(LayoutManager layout) {
522: super (layout);
523: darkColor = UIUtils.getDefaultActiveBackgroundColour();
524: lightColor = getBackground();
525: }
526:
527: public void paintComponent(Graphics g) {
528: Graphics2D g2 = (Graphics2D) g;
529: /*
530: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
531: RenderingHints.VALUE_ANTIALIAS_ON);
532: */
533:
534: super .paintComponent(g);
535:
536: int width = getWidth();
537: int height = getHeight();
538:
539: Paint originalPaint = g2.getPaint();
540: GradientPaint fade = new GradientPaint(0, height,
541: darkColor, 0, (int) (height * 0.2), lightColor);
542:
543: g2.setPaint(fade);
544: g2.fillRect(0, 0, width, height);
545:
546: g2.setPaint(originalPaint);
547: }
548:
549: public boolean isOpaque() {
550: return false;
551: }
552:
553: }
554:
555: private class WizardStepLabel extends JLabel {
556:
557: public WizardStepLabel(int index, String text) {
558: StringBuffer sb = new StringBuffer();
559: sb
560: .append("<html><table border=\"0\" cellpadding=\"2\"><tr><td valign=\"top\" nowrap>");
561: sb.append(index);
562: sb.append(".</td><td>");
563: sb.append(text.replaceAll("\n", "<br>"));
564: sb.append("</td></tr></table></html>");
565: setText(sb.toString());
566: }
567:
568: public boolean isOpaque() {
569: return false;
570: }
571:
572: }
573:
574: }
|