001: /*
002: * Copyright 2006 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: *
013: * @created Feb 01, 2006
014: * @author Michael D'Amour
015: */
016: package org.pentaho.jfreereport.wizard.ui;
017:
018: import java.util.LinkedList;
019: import java.util.List;
020: import java.util.Properties;
021: import org.eclipse.swt.SWT;
022: import org.eclipse.swt.events.KeyEvent;
023: import org.eclipse.swt.events.KeyListener;
024: import org.eclipse.swt.events.SelectionEvent;
025: import org.eclipse.swt.events.SelectionListener;
026: import org.eclipse.swt.graphics.Color;
027: import org.eclipse.swt.graphics.Font;
028: import org.eclipse.swt.graphics.FontData;
029: import org.eclipse.swt.graphics.RGB;
030: import org.eclipse.swt.layout.GridData;
031: import org.eclipse.swt.layout.GridLayout;
032: import org.eclipse.swt.widgets.Composite;
033: import org.eclipse.swt.widgets.Label;
034: import org.pentaho.jfreereport.wizard.ReportWizard;
035: import org.pentaho.jfreereport.wizard.WizardManager;
036: import org.pentaho.jfreereport.wizard.messages.Messages;
037: import org.pentaho.jfreereport.wizard.ui.swt.PentahoSWTButton;
038: import org.pentaho.jfreereport.wizard.ui.swt.SWTLine;
039: import org.pentaho.jfreereport.wizard.utility.SWTUtility;
040:
041: /**
042: *
043: * This class is the base class for all wizard panels. WizardPanels are added to a WizardManager's "step" list. A WizardPanel may override several methods to control wizard behavior, for example, isContinueAllowed() is used to determine if
044: * enough information has been filled out by the user to continue to the next step (or finish).
045: *
046: */
047: public class WizardPanel extends Composite implements
048: SelectionListener, IWizardListener, KeyListener {
049: /**
050: * The 'Back' button on the wizard
051: */
052: protected PentahoSWTButton backButton;
053:
054: /**
055: * The 'Next' button on the wizard
056: */
057: protected PentahoSWTButton nextButton;
058:
059: /**
060: * The 'Finish' button on the wizard
061: */
062: protected PentahoSWTButton finishButton;
063:
064: protected PentahoSWTButton publishButton;
065:
066: /**
067: * The 'Ok' button on the wizard
068: */
069: protected PentahoSWTButton okButton;
070:
071: /**
072: * The 'Cancel' button on the wizard
073: */
074: protected PentahoSWTButton cancelButton;
075:
076: /**
077: * The 'Preview' button on the wizard
078: */
079: protected PentahoSWTButton previewButton;
080:
081: /**
082: * A reference to the WizardManager
083: */
084: protected WizardManager wizardManager = null;
085:
086: /**
087: * An SWT Composite which is the main content area for a wizard step.
088: */
089: protected Composite mainPanel = null;
090:
091: /**
092: * There are two flags that mark a wizard step, dirty and stateChanged. Dirty is used to indicate that we are too dirty to continue, it should only be used for special cases.
093: */
094: public boolean dirty = false;
095:
096: /**
097: * stateChanged is the primary flag to indicate that something has changed. The purpose of this flag is to allow us to process or skip changes. When next/finish is fired we can check stateChanged.
098: */
099: public boolean stateChanged = false;
100:
101: /**
102: * This list contains IDirtyListeners who care about being notified when dirtiness happens.
103: */
104: List eventListenerList = new LinkedList();
105:
106: protected Font labelFont;
107:
108: protected Font textFont;
109:
110: Properties properties;
111:
112: /**
113: * Creates a new WizardPanel object.
114: *
115: * @param parent
116: * @param style
117: * @param manager
118: */
119: public WizardPanel(Composite parent, int style,
120: WizardManager manager) {
121: super (parent, style);
122: initialize(manager);
123: }
124:
125: public Properties getProperties() {
126: return properties;
127: }
128:
129: /**
130: *
131: * The initialize method creates the GUI
132: *
133: * @param manager
134: * WizardManager that we will add ourselves to listen on and hold reference to
135: */
136: public void initialize(WizardManager manager) {
137: manager.addWizardListener(this );
138: wizardManager = manager;
139: FontData fd = new FontData();
140: fd.setName(getFont().getFontData()[0].getName());
141: fd.setHeight(10);
142: fd.setLocale(getFont().getFontData()[0].getLocale());
143: fd.setStyle(SWT.BOLD);
144: labelFont = new Font(getDisplay(), fd);
145: FontData fd2 = new FontData();
146: fd2.setName(getFont().getFontData()[0].getName());
147: fd2.setHeight(9);
148: fd2.setLocale(getFont().getFontData()[0].getLocale());
149: fd2.setStyle(SWT.NORMAL);
150: textFont = new Font(getDisplay(), fd2);
151: GridLayout gridLayout = null;
152: if (ReportWizard.applicationMode == ReportWizard.MODE_DIALOG) {
153: gridLayout = new GridLayout(9, false);
154: setLayout(gridLayout);
155: mainPanel = createContentPanel(9);
156: mainPanel.setBackground(ReportWizard.background);
157: SWTLine line = new SWTLine(this , SWT.NONE);
158: line.setEtchedColors(new Color(getDisplay(), new RGB(128,
159: 128, 128)), new Color(getDisplay(), new RGB(255,
160: 255, 255)));
161: GridData gridData = new GridData(SWT.FILL, SWT.TOP, true,
162: false);
163: gridData.heightHint = 5;
164: gridData.horizontalSpan = 9;
165: line.setLayoutData(gridData);
166: line.setHorizontal(true);
167: line.setBackground(ReportWizard.background);
168: } else if (ReportWizard.applicationMode == ReportWizard.MODE_APPLICATION) {
169: gridLayout = new GridLayout(8, false);
170: setLayout(gridLayout);
171: mainPanel = createContentPanel(8);
172: mainPanel.setBackground(ReportWizard.background);
173: SWTLine line = new SWTLine(this , SWT.NONE);
174: line.setEtchedColors(new Color(getDisplay(), new RGB(128,
175: 128, 128)), new Color(getDisplay(), new RGB(255,
176: 255, 255)));
177: GridData gridData = new GridData(SWT.FILL, SWT.TOP, true,
178: false);
179: gridData.heightHint = 5;
180: gridData.horizontalSpan = 8;
181: line.setLayoutData(gridData);
182: line.setHorizontal(true);
183: line.setBackground(ReportWizard.background);
184: } else if (ReportWizard.applicationMode == ReportWizard.MODE_EMBEDDED) {
185: gridLayout = new GridLayout(7, false);
186: setLayout(gridLayout);
187: mainPanel = createContentPanel(7);
188: mainPanel.setBackground(ReportWizard.background);
189: SWTLine line = new SWTLine(this , SWT.NONE);
190: line.setEtchedColors(new Color(getDisplay(), new RGB(128,
191: 128, 128)), new Color(getDisplay(), new RGB(255,
192: 255, 255)));
193: line.setHorizontal(true);
194: line.setBackground(ReportWizard.background);
195: GridData gridData = new GridData(SWT.FILL, SWT.CENTER,
196: true, false);
197: gridData.heightHint = 5;
198: gridData.horizontalSpan = 7;
199: line.setLayoutData(gridData);
200: }
201: GridData gridData = new GridData(SWT.FILL, SWT.BOTTOM, true,
202: false);
203: gridData.widthHint = 40;
204: Label l = new Label(this , SWT.NONE);
205: l.setText(""); //$NON-NLS-1$
206: l.setLayoutData(gridData);
207: l.setBackground(ReportWizard.background);
208: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
209: previewButton = new PentahoSWTButton(this , SWT.NONE, gridData,
210: PentahoSWTButton.NORMAL, Messages
211: .getString("WizardPanel.0")); //$NON-NLS-1$
212: previewButton.setLayoutData(gridData);
213: previewButton.addSelectionListener(this );
214: Label space = new Label(this , SWT.NONE);
215: space.setText(""); //$NON-NLS-1$
216: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
217: gridData.widthHint = 40;
218: space.setLayoutData(gridData);
219: space.setBackground(ReportWizard.background);
220: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
221: backButton = new PentahoSWTButton(this , SWT.NONE, gridData,
222: PentahoSWTButton.BACK, Messages
223: .getString("WizardPanel.1")); //$NON-NLS-1$
224: backButton.setLayoutData(gridData);
225: backButton.addSelectionListener(this );
226: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false, false);
227: nextButton = new PentahoSWTButton(this , SWT.NONE, gridData,
228: PentahoSWTButton.FORWARD, Messages
229: .getString("WizardPanel.2")); //$NON-NLS-1$
230: nextButton.setLayoutData(gridData);
231: nextButton.addSelectionListener(this );
232: if (ReportWizard.applicationMode == ReportWizard.MODE_APPLICATION) {
233: Label spacer = new Label(this , SWT.NONE);
234: spacer.setText(""); //$NON-NLS-1$
235: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false,
236: false);
237: gridData.widthHint = 40;
238: spacer.setLayoutData(gridData);
239: spacer.setBackground(ReportWizard.background);
240: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false,
241: false);
242: publishButton = new PentahoSWTButton(this , SWT.NONE,
243: gridData, PentahoSWTButton.NORMAL, Messages
244: .getString("WizardPanel.3")); //$NON-NLS-1$
245: publishButton.setLayoutData(gridData);
246: publishButton.addSelectionListener(this );
247: }
248: if (ReportWizard.applicationMode == ReportWizard.MODE_DIALOG) {
249: Label spacer = new Label(this , SWT.NONE);
250: spacer.setText(""); //$NON-NLS-1$
251: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false,
252: false);
253: gridData.widthHint = 40;
254: spacer.setLayoutData(gridData);
255: spacer.setBackground(ReportWizard.background);
256: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false,
257: false);
258: okButton = new PentahoSWTButton(this , SWT.NONE, gridData,
259: PentahoSWTButton.NORMAL, Messages
260: .getString("WizardPanel.4")); //$NON-NLS-1$
261: okButton.setLayoutData(gridData);
262: okButton.addSelectionListener(this );
263: gridData = new GridData(SWT.CENTER, SWT.BOTTOM, false,
264: false);
265: cancelButton = new PentahoSWTButton(this , SWT.NONE,
266: gridData, PentahoSWTButton.NORMAL, Messages
267: .getString("WizardPanel.5")); //$NON-NLS-1$
268: cancelButton.setLayoutData(gridData);
269: cancelButton.addSelectionListener(this );
270: }
271: Label r = new Label(this , SWT.NONE);
272: r.setText(""); //$NON-NLS-1$
273: r.setBackground(ReportWizard.background);
274: gridData = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
275: r.setLayoutData(gridData);
276: }
277:
278: /**
279: *
280: * This method creates the main panel composite used by Wizard Panels.
281: *
282: * @return Composite the main panel
283: */
284: public Composite createContentPanel(int hSpan) {
285: mainPanel = new Composite(this , SWT.NONE);
286: GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
287: gridData.horizontalSpan = hSpan;
288: mainPanel.setLayoutData(gridData);
289: return mainPanel;
290: }
291:
292: /**
293: *
294: * This method adds an IDirtyListener to our listener list
295: *
296: * @param l
297: * the IDirtyListener to add
298: */
299: public void addDirtyListener(IDirtyListener l) {
300: eventListenerList.add(l);
301: }
302:
303: /**
304: *
305: * This method removes an IDirtyListener from our listener list
306: *
307: * @param l
308: * the IDirtyListener to remove
309: */
310: public void removeDirtyListener(IDirtyListener l) {
311: eventListenerList.remove(l);
312: }
313:
314: /**
315: * This method removes all IDirtyListeners from the event listener list
316: */
317: public void removeAllDirtyListeners() {
318: eventListenerList.clear();
319: }
320:
321: /**
322: * Fires 'dirtyFired' on all listeners
323: */
324: public void fireDirtyEvent() {
325: for (int i = 0; i < eventListenerList.size(); i++) {
326: IDirtyListener l = (IDirtyListener) eventListenerList
327: .get(i);
328: l.dirtyFired(dirty);
329: }
330: }
331:
332: /**
333: *
334: * When any widget is selected, such as a button, a combobox, a checkbox, etc, we mark dirty/stateChanged unless the event originates from next/back/finish/cancel buttons.
335: *
336: * @param e
337: */
338: public void widgetSelected(SelectionEvent e) {
339: Object source = e.getSource();
340: if (source == nextButton) {
341: wizardManager.next();
342: } else if (source == backButton) {
343: wizardManager.back();
344: } else if (source == publishButton) {
345: wizardManager.publish();
346: } else if (source == finishButton) {
347: wizardManager.finish();
348: } else if (source == cancelButton) {
349: wizardManager.cancel();
350: } else if (source == previewButton) {
351: // does it make sense to have a preview()
352: wizardManager.preview();
353: } else if (source == okButton) {
354: wizardManager.finish();
355: } else {
356: stateChanged = true;
357: dirty = true;
358: fireDirtyEvent();
359: }
360: updateState();
361: }
362:
363: /**
364: * This method updates the button enabled state as well as the overall panel enabled state. The buttons have their state updated based on checking if their action is allowed. If the previous wizard step does not allow continue then this
365: * step should appear to be disabled (if a GUI, like tabs, allows you to select them).
366: */
367: public void updateState() {
368: int myIndex = wizardManager.getSteps().indexOf(this );
369: boolean enable = true;
370: for (int i = 0; enable && (i < myIndex); i++) {
371: WizardPanel previousStep = (WizardPanel) wizardManager
372: .getSteps().get(i);
373: enable = previousStep.isContinueAllowed();
374: }
375: if (!isEnabled() || !enable) {
376: SWTUtility.setEnabled(this , enable);
377: }
378: if (backButton != null) {
379: backButton.setEnabled(wizardManager.isBackAllowed());
380: }
381: if (nextButton != null) {
382: nextButton.setEnabled(wizardManager.isNextAllowed());
383: }
384: if (finishButton != null) {
385: finishButton.setEnabled(wizardManager.isFinishAllowed());
386: }
387: if (previewButton != null) {
388: previewButton.setEnabled(wizardManager.isFinishAllowed());
389: }
390: initWizardPanel();
391: }
392:
393: public void initWizardPanel() {
394: }
395:
396: /**
397: *
398: * This method is necessary to implement when implementing SelectionListener and we do not use it.
399: *
400: * @param e
401: */
402: public void widgetDefaultSelected(SelectionEvent e) {
403: }
404:
405: /**
406: *
407: * This method should be overridden by subclasses to return if we are allowed to move to the next step or finish.
408: *
409: * @return boolean
410: */
411: public boolean isContinueAllowed() {
412: return true;
413: }
414:
415: /**
416: *
417: * This method should be overridden by subclasses to return if we are allowed to move to the next step.
418: *
419: * @return boolean
420: */
421: public boolean isNextAllowed() {
422: return true;
423: }
424:
425: /**
426: *
427: * This method should be overridden by subclasses to return if we are allowed to move back (the default behavior here is to return true, which is likely acceptable most of the time).
428: *
429: * @return boolean
430: */
431: public boolean isBackAllowed() {
432: return true;
433: }
434:
435: /**
436: *
437: * This method is called when the WizardManager is told to move to the next step. This method is called on all listeners, so it may be important and useful for implements of this method in subclasses to filter out everything except
438: * itself.
439: *
440: * @param source
441: * The WizardPanel that the next event originated from
442: */
443: public boolean nextFired(WizardPanel source) {
444: updateState();
445: return true;
446: }
447:
448: /**
449: *
450: * This method is called when the WizardManager is told to move to the previous step. This method is called on all listeners, so it may be important and useful for implements of this method in subclasses to filter out everything except
451: * itself.
452: *
453: * @param source
454: * The WizardPanel that the back event originated from
455: */
456: public void backFired(WizardPanel source) {
457: updateState();
458: }
459:
460: /**
461: *
462: * This method is called when the WizardManager is told to finish. This method is called on all listeners, so it may be important and useful for implements of this method in subclasses to filter out everything except itself.
463: *
464: * @param source
465: * The WizardPanel that the finish event originated from
466: */
467: public void finishFired(WizardPanel source) {
468: updateState();
469: }
470:
471: /**
472: *
473: * This method is called when the WizardManager is informed that the wizard is cancelled. This method is called on all listeners, so it may be important and useful for implements of this method in subclasses to filter out everything
474: * except itself.
475: *
476: * @param source
477: * The WizardPanel that the finish event originated from
478: */
479: public boolean cancelFired(WizardPanel source) {
480: return true;
481: }
482:
483: /**
484: *
485: * This method is called when the WizardManager is informed that the wizard is previewing. This method is called on all listeners, so it may be important and useful for implements of this method in subclasses to filter out everything
486: * except itself.
487: *
488: * @param source
489: * The WizardPanel that the finish event originated from
490: */
491: public boolean previewFired(WizardPanel source) {
492: updateState();
493: return true;
494: }
495:
496: public void publishFired(WizardPanel source) {
497: updateState();
498: }
499:
500: /**
501: * This method gets the WizardManager for this WizardPanel
502: *
503: * @return Returns the wizardManager.
504: */
505: public WizardManager getWizardManager() {
506: return wizardManager;
507: }
508:
509: /**
510: * This method sets the WizardManager for this WizardPanel
511: *
512: * @param wizardManager
513: * The wizardManager to set.
514: */
515: public void setWizardManager(WizardManager wizardManager) {
516: this .wizardManager = wizardManager;
517: }
518:
519: /**
520: * This method gets the main panel (Composite).
521: *
522: * @return Returns the mainPanel.
523: */
524: public Composite getMainPanel() {
525: return mainPanel;
526: }
527:
528: /**
529: * This method sets the main panel (Composite).
530: *
531: * @param mainPanel
532: * The mainPanel to set.
533: */
534: public void setMainPanel(Composite mainPanel) {
535: this .mainPanel = mainPanel;
536: }
537:
538: /**
539: *
540: * This method is fired when a key is pressed on components we have added the WizardPanel as a KeyListener on.
541: *
542: * @param e
543: */
544: public void keyPressed(KeyEvent e) {
545: }
546:
547: /**
548: *
549: * This method is fired when a key is released on components we have added the WizardPanel as a KeyListener on.
550: *
551: * @param e
552: */
553: public void keyReleased(KeyEvent e) {
554: stateChanged = true;
555: dirty = true;
556: fireDirtyEvent();
557: wizardManager.update();
558: }
559:
560: }
|