001: package net.refractions.udig.catalog.ui.workflow;
002:
003: import java.lang.reflect.InvocationTargetException;
004: import java.util.Map;
005:
006: import net.refractions.udig.catalog.ui.CatalogUIPlugin;
007: import net.refractions.udig.catalog.ui.internal.Messages;
008: import net.refractions.udig.catalog.ui.workflow.Workflow.State;
009: import net.refractions.udig.ui.PlatformGIS;
010:
011: import org.eclipse.core.runtime.IProgressMonitor;
012: import org.eclipse.core.runtime.NullProgressMonitor;
013: import org.eclipse.jface.operation.IRunnableWithProgress;
014: import org.eclipse.jface.wizard.IWizardContainer;
015: import org.eclipse.jface.wizard.IWizardPage;
016: import org.eclipse.jface.wizard.Wizard;
017: import org.eclipse.swt.widgets.Display;
018:
019: public class WorkflowWizard extends Wizard {
020:
021: /** the workflow * */
022: private Workflow workflow;
023:
024: /** the state to page map * */
025: private Map<Class<? extends Workflow.State>, WorkflowWizardPage> map;
026:
027: /**
028: * Creates a new workflow wizard. The workflow passed in must have a valid set of states.
029: *
030: * @param workflow The workflow to be run.
031: * @param map A map of workflow states to wizard pages.
032: */
033: public WorkflowWizard(Workflow workflow,
034: Map<Class<? extends Workflow.State>, WorkflowWizardPage> map) {
035: this .workflow = workflow;
036: this .map = map;
037:
038: // do the wizard initialization stuff
039: setNeedsProgressMonitor(true);
040: }
041:
042: public Workflow getWorkflow() {
043: return workflow;
044: }
045:
046: protected Map<Class<? extends Workflow.State>, WorkflowWizardPage> getStateMap() {
047: return map;
048: }
049:
050: @Override
051: public void addPages() {
052:
053: // initialize all the pages
054: for (IWizardPage page : map.values()) {
055: init(page);
056: }
057:
058: // add the primary pages, make sure to set the state before they
059: // are actually created
060: Workflow.State[] states = workflow.getStates();
061: if (states == null || states.length == 0)
062: throw new IllegalStateException(
063: Messages.WorkflowWizard_noStates);
064:
065: for (int i = 0; i < states.length; i++) {
066: Workflow.State state = states[i];
067: WorkflowWizardPage page = map.get(state.getClass());
068:
069: if (page == null) {
070: String msg = Messages.WorkflowWizard_noPage;
071: throw new IllegalStateException(msg);
072: }
073: page.setState(state);
074:
075: addPage(page);
076: }
077: }
078:
079: /**
080: * Returns the next primary page in the page sequence. This method is called by the
081: *
082: * @see org.eclipse.jface.wizard.IWizardContainer when a page does not contribute a secondary
083: * page.
084: * @see org.eclipse.jface.wizard.IWizard#getNextPage(org.eclipse.jface.wizard.IWizardPage)
085: */
086: @Override
087: public IWizardPage getNextPage(IWizardPage page) {
088: // get the current state from the workflow
089: Workflow.State state = workflow.getCurrentState();
090: if (state == null)
091: return null;
092:
093: WorkflowWizardPage next = map.get(state.getClass());
094:
095: if (next == null) {
096: String msg = Messages.WorkflowWizard_noPage;
097: throw new IllegalStateException(msg);
098: }
099:
100: next.setState(workflow.getCurrentState());
101: return next;
102: }
103:
104: /**
105: * Returns the wizard page which corresponds to a particular workflow state.
106: *
107: * @param state The state in question.
108: * @return The wizard page registered for the state or null if no such page exists.
109: */
110: @SuppressWarnings("unchecked")
111: public IWizardPage getPage(State state) {
112: if (state == null)
113: return null;
114:
115: return getPage((Class<State>) state.getClass());
116: }
117:
118: /**
119: * Returns the wizard page which corresponds to a particular workflow state.
120: *
121: * @param state The class of state in question.
122: * @return The wizard page registered for the state or null if no such page exists.
123: */
124: public IWizardPage getPage(Class<? extends State> theClass) {
125: if (theClass == null)
126: return null;
127:
128: return map.get(theClass);
129: }
130:
131: void init(IWizardPage page) {
132: page.setWizard(this );
133: }
134:
135: private boolean isPageComplete() {
136: Workflow.State state = workflow.getCurrentState();
137: if (state == null)
138: return false;
139:
140: WorkflowWizardPage current = map.get(state.getClass());
141: return current.isPageComplete();
142: }
143:
144: @Override
145: public boolean canFinish() {
146: return !workflow.hasMoreStates() && isPageComplete();
147: }
148:
149: @Override
150: public final boolean performFinish() {
151: final boolean[] finished = new boolean[1];
152:
153: IRunnableWithProgress runnable = new IRunnableWithProgress() {
154:
155: public void run(IProgressMonitor monitor)
156: throws InvocationTargetException,
157: InterruptedException {
158: finished[0] = performFinish(monitor);
159: }
160:
161: };
162: try {
163: run(runnable);
164: } catch (Exception e) {
165: CatalogUIPlugin.log("", e); //$NON-NLS-1$
166: return false;
167: }
168: return finished[0];
169: }
170:
171: private void run(final IRunnableWithProgress runnable)
172: throws InvocationTargetException, InterruptedException {
173: IWizardContainer container2 = getContainer();
174: if (container2 != null && Display.getCurrent() != null) {
175: container2.run(true, true, new IRunnableWithProgress() {
176:
177: public void run(IProgressMonitor monitor)
178: throws InvocationTargetException,
179: InterruptedException {
180: PlatformGIS.runBlockingOperation(runnable, monitor);
181: }
182:
183: });
184: } else {
185: runnable.run(new NullProgressMonitor());
186: }
187: }
188:
189: /**
190: * This method is ran in a <b>non-UI</b> thread. It uses {@link PlatformGIS#runBlockingOperation(IRunnableWithProgress, IProgressMonitor)} to ensure
191: * that blocking operations in this method will not block the UI. It is recommended that all long operation are done in this thread and only
192: * quick UI updates should be done in the UI thread.
193: *
194: * @param monitor the dialog progress monitor.
195: * @return if the wizard finished correctly.
196: *
197: * @see Display#syncExec(Runnable)
198: * @see Display#asyncExec(Runnable)
199: */
200: protected boolean performFinish(IProgressMonitor monitor) {
201: return true;
202: }
203:
204: @Override
205: public boolean needsPreviousAndNextButtons() {
206: return true;
207: }
208:
209: }
|