001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: WizardPanelSequence.java,v $
023   Revision 1.9  2004/05/12 19:16:54  markl
024   comment block updates
025
026   Revision 1.8  2003/01/19 09:50:54  markl
027   Javadoc & comment header updates.
028
029   Revision 1.7  2001/03/12 09:28:02  markl
030   Source code and Javadoc cleanup.
031
032   Revision 1.6  2000/08/26 09:04:41  markl
033   Changed Wizard*.java APIs to facilitate easier control over forward/
034   backward navigation.
035
036   Revision 1.5  1999/08/24 08:30:44  markl
037   Fixed some javadoc comments.
038
039   Revision 1.4  1999/03/11 03:59:01  markl
040   Minor layout fix.
041
042   Revision 1.3  1999/02/28 11:44:08  markl
043   Minor fixes.
044
045   Revision 1.2  1999/01/10 03:05:32  markl
046   added GPL header & RCS tag
047   ----------------------------------------------------------------------------
048*/
049
050package kiwi.ui;
051
052import java.util.*;
053import javax.swing.event.*;
054
055import kiwi.event.*;
056import kiwi.util.*;
057
058/** This class serves as a factory of <code>WizardPanel</code>s for a
059  * <code>WizardView</code>. A <code>WizardPanelSequence</code> maintains a set
060  * of <code>WizardPanel</code>s and a <code>Config</code> object. When a
061  * <code>WizardPanel</code> is added to the sequence, a reference to the
062  * <code>Config</code> object is passed to the panel. The panel may use this
063  * <code>Config</code> object to store results from user input or to look up
064  * the current or default values for its input fields.
065  * <p>
066  * Whenever the value of a property is changed or a property is added to or
067  * removed from  the <code>Config</code> object, the <code>Config</code>
068  * object notifies the <code>WizardPanelSequence</code> via a
069  * <code>ChangeEvent</code>. Subclassers may override the
070  * <code>stateChanged()</code> method to handle these events.
071  *
072  * @see kiwi.ui.WizardView
073  * @see kiwi.ui.WizardPanel
074  * @see kiwi.util.Config
075  * @see javax.swing.event.ChangeEvent
076  *
077  * @author Mark Lindner
078  */
079
080public class WizardPanelSequence implements ChangeListener
081  {
082  /** The list of <code>WizardPanel</code>s. */
083  protected Vector panels;
084  /** The index of the currently-selected <code>WizardPanel</code>. */
085  protected int currentIndex = -1;
086  private ChangeSupport support;
087  /** The configuration object for this sequence. */
088  protected Config config;
089
090  /** Construct a new <code>WizardPanelSequence</code>.
091    */
092  
093  public WizardPanelSequence()
094    {
095    this(new Config());
096    }
097  
098  /** Construct a new <code>WizardPanelSequence</code> with the given
099    * configuration object.
100    * 
101    * @param config The configuration object to use as a datasource.
102    */
103  
104  public WizardPanelSequence(Config config)
105    {
106    panels = new Vector();
107    support = new ChangeSupport(this);
108    this.config = config;
109    config.addChangeListener(this);
110    }
111
112  /** Add a <code>WizardPanel</code> to this sequence. All panels should be
113    * added before the sequence is used to construct a <code>WizardView</code>.
114    *
115    * @param panel The panel to add.
116    * @see #addPanels
117    */
118  
119  public final void addPanel(WizardPanel panel)
120    {
121    panels.addElement(panel);
122    panel.addChangeListener(this);
123    panel.setConfig(config);
124    }
125
126  /** Add an array of <code>WizardPanel</code>s to this sequence. All panels
127    * should be added before the sequence is used to construct a
128    * <code>WizardView</code>.
129    *
130    * @param panels The panels to add.
131    * @see #addPanel
132    */
133  
134  public final void addPanels(WizardPanel panels[])
135    {
136    for(int i = 0; i < panels.length; i++)
137      addPanel(panels[i]);
138    }
139
140  /** Reset the sequence. Resets the sequence so that the first panel in the
141    * sequence becomes the current panel; thus the next call to
142    * <code>getNextPanel()</code> will return the first panel in the sequence.
143    *
144    * @see #getNextPanel
145    */
146  
147  public void reset()
148    {
149    currentIndex = -1;
150    }
151
152  /** Get a reference to this <code>WizardPanelSequence</code>'s
153    * <code>Config</code> object.
154    *
155    * @return The <code>Config</code> object.
156    */
157  
158  public final Config getConfig()
159    {
160    return(config);
161    }
162
163  /** Get the currently displayed panel from this sequence.
164   *
165   * @return The current panel.
166   */
167
168  public WizardPanel getCurrentPanel()
169    {
170    return((currentIndex < 0) ? null
171           : (WizardPanel)panels.elementAt(currentIndex));
172    }
173
174  /** Get the next panel from this sequence. The default implementation
175    * returns the next panel from the <code>panels</code> vector and
176    * increments the <code>currentIndex</code> variable only if the end of
177    * the sequence has not been reached <i>and</i> the next panel is
178    * reachable (e.g., if <code>canMoveForward()</code> returns
179    * <cod>true</code>).
180    *
181    * @return The next panel to be displayed in the <code>WizardView</code>.
182    */
183  
184  public WizardPanel getNextPanel()
185    {
186    if(isLastPanel())
187      return(null);
188
189//    if(!canMoveForward()) return(null);
190
191    return((WizardPanel)panels.elementAt(++currentIndex));
192    }
193
194  /** Get the previous panel from this sequence. The default implementation
195    * returns the previous panel from the <code>panels</code> vector and
196    * decrements the <code>currentIndex</code> variable only if the beginning
197    * of the sequence has not been reached <i>and</i> the previous panel is
198    * reachable (e.g., if <code>canMoveBackward()</code> returns
199    * <code>true</code>).
200    *
201    * @return The previous panel to be displayed in the
202    * <code>WizardView</code>.
203    */
204  
205  public WizardPanel getPreviousPanel()
206    {
207    if(currentIndex == 0)
208      return(null);
209
210//    if(!canMoveBackward()) return(null);
211
212    return((WizardPanel)panels.elementAt(--currentIndex));
213    }
214
215  /** Determine if the current panel is the last panel in the sequence. Once
216    * the last panel in a sequence has been reached, th
217    * <code>WizardView</code> changes its <i>Next</i> button to a
218    * <i>Finish</i> button.
219    *
220    * @return <code>true</code> if the current panel is the last panel, and
221    * <code>false</code> otherwise.
222    */
223  
224  public boolean isLastPanel()
225    {
226    return(currentIndex == (panels.size() - 1));
227    }
228
229  /** Determine if the user is allowed to move to the next panel. The
230    * default implementation returns <code>true</code> if the current panel
231    * is not the last panel in the sequence <i>and</i> the
232    * <code>canMoveForward()</code> method of the current panel
233    * returns <code>true</code>. Subclassers may wish to override this
234    * method to allow movement forward only if certain conditions are
235    * met.
236    *
237    * @return <code>true</code> if the previous panel is reachable, and
238    * <code>false</code> otherwise.
239    */
240  
241  public boolean canMoveForward()
242    {
243    if(currentIndex > panels.size() - 1)
244      return(false);
245
246    WizardPanel p = getCurrentPanel();
247    return((p == null) ? false : p.canMoveForward());
248    }
249
250  /** Determine if the user is allowed to move to the previous
251    * panel. The default implementation returns <code>true</code> if the
252    * current panel is not the first panel in the sequence <i>and</i>
253    * the <code>canMoveBackward()</code> method of the current panel
254    * returns <code>true</code>. Subclassers may wish to override this
255    * method to allow movement backward only if certain conditions are
256    * met.
257    */
258  
259  public boolean canMoveBackward()
260    {
261    if(currentIndex <= 0)
262      return(false);
263
264    WizardPanel p = getCurrentPanel();
265    return((p == null) ? false : p.canMoveBackward());
266    }
267
268  /** Handle <code>ChangeEvent</code>s fired by the <code>WizardPanel</code>s
269    * that belong to this sequence. The default implementation does nothing;
270    * subclassers may wish to add logic to determine (based on the current
271    * values of properties in the <code>Config</code> object) whether movement
272    * to the next or previous panel is allowed, or to determine which panel
273    * will be displayed next, for example.
274    *
275    * @param evt The event. The source of the event is the
276    * <code>WizardPanel</code> that fired it.
277    * @see java.util.EventObject#getSource
278    */
279  
280  public void stateChanged(ChangeEvent evt)
281    {
282    // handle change events here
283
284    fireChangeEvent();
285    }
286
287  /** Add a <code>ChangeListener</code> to this object's list of listeners.
288    *
289    * @param listener The listener to add.
290    */  
291  
292  public void addChangeListener(ChangeListener listener)
293    {
294    support.addChangeListener(listener);
295    }
296
297  /** Remove a <code>ChangeListener</code> from this object's list of
298    * listeners.
299    *
300    * @param listener The listener to remove.
301    */
302  
303  public void removeChangeListener(ChangeListener listener)
304    {
305    support.removeChangeListener(listener);
306    }
307
308  /** Fire a change event. Notify listeners (typically only the
309    * <code>WizardView</code> that owns this sequence) that the state of this
310    * <code>WizardPanelSequence</code> has changed. Subclassers may wish to
311    * call this method from the body of the <code>stateChanged()</code>
312    * method if a change in the <code>Config</code> object has changed the
313    * state of this <code>WizardPanelSequence</code> in a way that will
314    * affect the appearance of the <code>WizardView</code>.
315    */
316  
317  protected void fireChangeEvent()
318    {
319    support.fireChangeEvent();
320    }
321
322  /** Dispose of this object. */
323  
324  public void dispose()
325    {
326    config.removeChangeListener(this);
327    config = null;
328    }
329
330  }
331
332/* end of source file */