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: WizardView.java,v $ 023 Revision 1.16 2004/06/29 07:56:44 markl 024 Keyboard focus fix. 025 026 Revision 1.15 2004/05/12 18:52:03 markl 027 comment block updates 028 029 Revision 1.14 2004/03/16 06:43:39 markl 030 LocaleManager method change 031 032 Revision 1.13 2004/03/15 05:45:31 markl 033 allow subclasses to provide a sequence 034 035 Revision 1.12 2003/01/19 09:50:54 markl 036 Javadoc & comment header updates. 037 038 Revision 1.11 2001/03/20 00:54:53 markl 039 Fixed deprecated calls. 040 041 Revision 1.10 2001/03/12 09:56:54 markl 042 KLabel/KLabelArea changes. 043 044 Revision 1.9 2001/03/12 09:28:02 markl 045 Source code and Javadoc cleanup. 046 047 Revision 1.8 2000/10/11 10:46:17 markl 048 Fixes to better support enabling/disabling navigation. 049 050 Revision 1.7 2000/08/26 09:04:41 markl 051 Changed Wizard*.java APIs to facilitate easier control over forward/ 052 backward navigation. 053 054 Revision 1.6 1999/11/19 06:23:53 markl 055 Added addButton() and removeButton() methods. 056 057 Revision 1.5 1999/04/19 05:59:47 markl 058 I18N changes. 059 060 Revision 1.4 1999/02/28 11:44:08 markl 061 Minor fixes. 062 063 Revision 1.3 1999/02/28 00:27:35 markl 064 Added a updateData() method. This gives subclasses a chance to store their 065 values in the config object. 066 067 Revision 1.2 1999/01/10 03:05:32 markl 068 added GPL header & RCS tag 069 ---------------------------------------------------------------------------- 070*/ 071 072package kiwi.ui; 073 074import java.awt.*; 075import java.awt.event.*; 076import javax.swing.*; 077import javax.swing.border.*; 078import javax.swing.event.*; 079 080import kiwi.event.*; 081import kiwi.util.*; 082 083/** A wizard-style component. <code>WizardView</code> essentially displays a 084 * sequence of panels (or "cards") to the user; each panel typically 085 * contains messages and/or input elements. A <code>WizardPanelSequence</code> 086 * object functions as the source of these panels, and determines the order 087 * in which the panels are presented to the user, and the conditions under 088 * which forward and backward movement is allowed between consecutive panels. 089 * <p> 090 * This component is arranged as follows. The leftmost portion of the 091 * component is used to display an image (which for best results should be 092 * transparent). Animated GIFs are acceptable. The bottom portion of the 093 * component displays the <i>Back</i>, <i>Next</i>, and <i>Cancel</i> 094 * buttons. The remaining space is occupied by the current 095 * <code>WizardPanel</code> provided by the <code>WizardPanelSequence</code> 096 * object. 097 * <p> 098 * The <code>WizardPanelSequence</code> determines when the user may move to 099 * the next or previous panel. Whenever these conditions change, the 100 * <code>WizardPanelSequence</code> fires a <code>ChangeEvent</code> to 101 * notify the <code>WizardView</code>, which responds by dimming or 102 * undimming the <i>Next</i> and <i>Back</i> buttons, as appropriate. When 103 * the final panel in the sequence is reached, the <i>Next</i> button changes 104 * to a <i>Finish</i> button. 105 * <p> 106 * If the <i>Cancel</i> button is pressed, an <code>ActionEvent</code> is 107 * fired with an action command of "cancel". If the <i>Finish</i> button is 108 * pressed, an <code>ActionEvent</code> is fired with an action command of 109 * "finish". 110 * 111 * <p><center> 112 * <img src="snapshot/WizardView.gif"><br> 113 * <i>An example WizardView.</i> 114 * </center> 115 * 116 * @see javax.swing.event.ChangeEvent 117 * @see kiwi.ui.WizardPanelSequence 118 * 119 * @author Mark Lindner 120 */ 121 122public class WizardView extends KPanel 123 { 124 private KButton b_prev, b_next, b_cancel; 125 private KLabel iconLabel; 126 private WizardPanelSequence sequence; 127 private KPanel content; 128 private WizardPanel curPanel = null; 129 private int pos = 0, count = 0; 130 private Icon i_next; 131 private boolean finish = false; 132 private ActionSupport support; 133 private String s_next, s_back, s_finish, s_cancel; 134 private _ActionListener actionListener; 135 private ButtonPanel p_buttons; 136 137 /** Construct a new <code>WizardView</code>. The <code>buildSequence()</code> 138 * method will be called to construct the <code>WizardPanel</code> sequence. 139 * 140 * @since Kiwi 2.0 141 * 142 */ 143 144 public WizardView() 145 { 146 this(null); 147 } 148 149 /** Construct a new <code>WizardView</code>. 150 * 151 * @param sequence The <code>WizardPanelSequence</code> that will provide 152 * <code>WizardPanel</code>s for the wizard. 153 */ 154 155 public WizardView(WizardPanelSequence sequence) 156 { 157 if(sequence == null) 158 sequence = buildSequence(); 159 160 this.sequence = sequence; 161 162 sequence.addChangeListener(new ChangeListener() 163 { 164 public void stateChanged(ChangeEvent evt) 165 { 166 refresh(); 167 } 168 }); 169 170 LocaleData loc = LocaleManager.getDefault().getLocaleData("KiwiDialogs"); 171 172 s_next = loc.getMessage("kiwi.button.next"); 173 s_back = loc.getMessage("kiwi.button.back"); 174 s_finish = loc.getMessage("kiwi.button.finish"); 175 s_cancel = loc.getMessage("kiwi.button.cancel"); 176 177 support = new ActionSupport(this); 178 179 setLayout(new BorderLayout(5, 5)); 180 181 content = new KPanel(); 182 content.setLayout(new GridLayout(1, 0)); 183 184 iconLabel = new KLabel(KiwiUtils.getResourceManager() 185 .getIcon("wizard.gif")); 186 add("West", iconLabel); 187 188 add("Center", content); 189 190 Insets margin = new Insets(1, 5, 1, 5); 191 192 p_buttons = new ButtonPanel(); 193 194 actionListener = new _ActionListener(); 195 196 b_prev = new KButton(s_back, KiwiUtils.getResourceManager() 197 .getIcon("left.gif")); 198 b_prev.setFocusPainted(false); 199 b_prev.addActionListener(actionListener); 200 b_prev.setEnabled(false); 201 b_prev.setMargin(margin); 202 p_buttons.addButton(b_prev); 203 204 i_next = KiwiUtils.getResourceManager().getIcon("right.gif"); 205 206 b_next = new KButton(""); 207 b_next.setHorizontalTextPosition(SwingConstants.LEFT); 208 b_next.setFocusPainted(false); 209 b_next.addActionListener(actionListener); 210 b_next.setMargin(margin); 211 p_buttons.addButton(b_next); 212 213 b_cancel = new KButton(s_cancel); 214 b_cancel.setFocusPainted(false); 215 b_cancel.addActionListener(actionListener); 216 b_cancel.setMargin(margin); 217 p_buttons.addButton(b_cancel); 218 219 KPanel p_bottom = new KPanel(); 220 p_bottom.setLayout(new BorderLayout(5, 5)); 221 222 p_bottom.add("Center", new JSeparator()); 223 p_bottom.add("South", p_buttons); 224 225 add("South", p_bottom); 226 227 reset(); 228 } 229 230 /** A method for constructing the wizard panel sequence. This method may be 231 * overridden by subclasses to provide the sequence for the view instead of 232 * having it supplied via the constructor. The default implementation returns 233 * <b>null</b>. 234 * 235 * @since Kiwi 2.0 236 */ 237 238 protected WizardPanelSequence buildSequence() 239 { 240 return(null); 241 } 242 243 /** Get a reference to the <i>Cancel</i> button. 244 * 245 * @return The <i>Cancel</i> button. 246 */ 247 248 public JButton getCancelButton() 249 { 250 return(b_cancel); 251 } 252 253 /** Get a reference to the <i>Finish</i> button. 254 * 255 * @return The <i>Finish</i> button. 256 */ 257 258 public JButton getFinishButton() 259 { 260 return(b_next); 261 } 262 263 /** Add a button to the <code>WizardView</code> at the specified position. 264 * 265 * @param button The button to add. 266 * @param pos The position at which to add the button. The value 0 denotes 267 * the first position, and -1 denotes the last position. 268 * @exception java.lang.IllegalArgumentException If the value of 269 * <code>pos</code> is invalid. 270 */ 271 272 public void addButton(JButton button, int pos) 273 throws IllegalArgumentException 274 { 275 p_buttons.addButton(button, pos); 276 } 277 278 /** Remove a button from the specified position in the 279 * <code>ButtonPanel</code>. 280 * 281 * @param pos The position of the button to remove, where 0 denotes the 282 * first position. 283 * @exception java.lang.IllegalArgumentException If an attempt is made 284 * to remove one of the predefined wizard buttons. 285 */ 286 287 public void removeButton(int pos) throws IllegalArgumentException 288 { 289 JButton b = (JButton)p_buttons.getButton(pos); 290 if((b == b_cancel) || (b == b_prev) || (b == b_next)) 291 throw(new IllegalArgumentException("Can't remove predefined buttons.")); 292 else 293 p_buttons.removeButton(pos); 294 } 295 296 /** Set the component's icon. Animated and/or transparent GIF images add a 297 * professional touch when used with <code>WizardView</code>s. 298 * 299 * @param icon The new icon to use, or <code>null</code> if no icon is 300 * needed. 301 */ 302 303 public void setIcon(Icon icon) 304 { 305 iconLabel.setIcon(icon); 306 } 307 308 /* show a panel */ 309 310 private void showPanel(WizardPanel panel) 311 { 312 if(curPanel != null) 313 { 314 content.remove(curPanel); 315 curPanel.syncData(); 316 } 317 318 content.add(curPanel = panel); 319 content.validate(); 320 content.repaint(); 321 curPanel.syncUI(); 322 refresh(); 323 curPanel.beginFocus(); 324 } 325 326 /** Reset the <code>WizardView</code>. Resets the component so that the first 327 * panel is displayed. This method also calls the 328 * <code>WizardPanelSequence</code>'s <code>reset()</code> method. 329 * 330 * @see kiwi.ui.WizardPanelSequence#reset 331 */ 332 333 public void reset() 334 { 335 sequence.reset(); 336 b_next.setText(s_next); 337 b_next.setIcon(i_next); 338 showPanel(sequence.getNextPanel()); 339 } 340 341 /* refresh the buttons based on what the sequence tells us */ 342 343 private void refresh() 344 { 345 finish = sequence.isLastPanel(); 346 b_next.setEnabled(sequence.canMoveForward()); 347 b_prev.setEnabled(sequence.canMoveBackward()); 348 349 if(!finish) 350 { 351 b_next.setText(s_next); 352 b_next.setIcon(i_next); 353 } 354 else 355 { 356 b_next.setText(s_finish); 357 b_next.setIcon(null); 358 } 359 } 360 361 /** Add an <code>ActionListener</code> to this component's list of listeners. 362 * 363 * @param listener The listener to add. 364 */ 365 366 public void addActionListener(ActionListener listener) 367 { 368 support.addActionListener(listener); 369 } 370 371 /** Add an <code>ActionListener</code> to this component's list of listeners. 372 * 373 * @param listener The listener to add. 374 */ 375 376 public void removeActionListener(ActionListener listener) 377 { 378 support.removeActionListener(listener); 379 } 380 381 /* Handle events. */ 382 383 private class _ActionListener implements ActionListener 384 { 385 public void actionPerformed(ActionEvent evt) 386 { 387 Object o = evt.getSource(); 388 389 if(o == b_next) 390 { 391 if(finish) 392 { 393 curPanel.syncData(); 394 support.fireActionEvent("finish"); 395 } 396 else 397 showPanel(sequence.getNextPanel()); 398 } 399 400 else if(o == b_prev) 401 showPanel(sequence.getPreviousPanel()); 402 403 else if(o == b_cancel) 404 support.fireActionEvent("cancel"); 405 } 406 } 407 408 } 409 410/* end of source file */