diff options
Diffstat (limited to 'pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/StateMachine.java')
-rw-r--r-- | pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/StateMachine.java | 308 |
1 files changed, 258 insertions, 50 deletions
diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/StateMachine.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/StateMachine.java index 85539eb5..9a71bde2 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/StateMachine.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/StateMachine.java @@ -15,93 +15,301 @@ */ package at.asit.pdfover.gui.workflow; +//Imports +import java.lang.reflect.Constructor; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.asit.pdfover.gui.MainWindow; +import at.asit.pdfover.gui.controls.Dialog.BUTTONS; +import at.asit.pdfover.gui.controls.ErrorDialog; +import at.asit.pdfover.commons.Messages; import at.asit.pdfover.gui.workflow.config.ConfigManipulator; import at.asit.pdfover.gui.workflow.config.ConfigOverlayManipulator; import at.asit.pdfover.gui.workflow.config.ConfigProvider; +import at.asit.pdfover.gui.workflow.config.ConfigProviderImpl; import at.asit.pdfover.gui.workflow.config.PersistentConfigProvider; +import at.asit.pdfover.gui.workflow.states.PrepareConfigurationState; import at.asit.pdfover.gui.workflow.states.State; /** - * + * Workflow holds logical state of signing process and updates the current + * logical state */ -public interface StateMachine { - /** - * Get the ConfigProvider - * @return the ConfigProvider - */ - public ConfigProvider getConfigProvider(); +public class StateMachine implements GUIProvider { - /** - * Get the PersistentConfigProvider - * @return the PersistentConfigProvider - */ - public PersistentConfigProvider getPersistentConfigProvider(); + private static final Logger log = LoggerFactory.getLogger(StateMachine.class); + + private Status status; + + private PDFSignerImpl pdfSigner; + + private ConfigProviderImpl configProvider; /** - * Gets the Config Manipulator - * @return the config manipulator + * Default constructor + * + * @param cmdLineArgs */ - public ConfigManipulator getConfigManipulator(); + public StateMachine(String[] cmdLineArgs) { + this.status = new Status(); + this.status.setCurrentState(new PrepareConfigurationState(this)); + this.pdfSigner = new PDFSignerImpl(); + this.configProvider = new ConfigProviderImpl(); + setCmdLineArgs(cmdLineArgs); + } /** - * Gets the Config Overlay Manipulator - * @return the config overlay manipulator + * Sets the workflow state + * This method should be used to let the user jump + * around between states. This Method also resets certain properties defined + * by later states then state + * + * @param state */ - public ConfigOverlayManipulator getConfigOverlayManipulator(); + public void jumpToState(State state) { + this.status.setCurrentState(state); + this.invokeUpdate(); + } /** - * Get the PDF Signer - * @return the PDF Signer + * Update workflow logic and let state machine do its job... */ - public PDFSigner getPDFSigner(); + public synchronized void update() { + State next = null; + while (this.status.getCurrentState() != null) { + State current = this.status.getCurrentState(); + try { + current.run(); + } catch (Exception e) { + log.error("StateMachine update: ", e); + ErrorDialog errorState = new ErrorDialog(this.getMainShell(), + Messages.getString("error.Unexpected"), BUTTONS.OK); + //errorState.setException(e); + //jumpToState(errorState); + errorState.open(); + this.exit(); + } + + if (this.exit) { + // exit request ignore + next = null; + this.status.setCurrentState(next); + } else { + + if (this.mainWindow != null + && !this.mainWindow.getShell().isDisposed()) { + log.debug("Allowing MainWindow to update its state for " + + current); + current.updateMainWindowBehavior(); + this.mainWindow.applyBehavior(); + this.mainWindow.doLayout(); + } + next = current.nextState(); + if (next == current) { + break; + } + + if (next == null) { + log.info("Next state is null -> exit"); + this.status.setCurrentState(next); + break; + } + + log.debug("Changing state from: " + + current + " to " + + next.toString()); + this.status.setCurrentState(next); + } + } + } /** - * Get the Status - * @return the Status + * Invoke Update in UI (Main) Thread */ - public Status getStatus(); + public void invokeUpdate() { + if (this.display != null) { + this.display.asyncExec(() -> { + this.update(); + }); + } + } - /** - * Gets the GUI provider - * @return the GUI provider + private Display display = null; + + private Shell shell = null; + + private Composite container = null; + + private MainWindow mainWindow = null; + + /* + * (non-Javadoc) + * + * @see + * at.asit.pdfover.gui.workflow.StateMachine#display(org.eclipse.swt.widgets + * .Composite) */ - public GUIProvider getGUIProvider(); + public void display(Composite composite) { + this.mainWindow.setTopControl(composite); + } + + private void createMainWindow() { + try { + + this.display = Display.getDefault(); + + this.mainWindow = new MainWindow(this); + this.mainWindow.open(); + + this.shell = this.mainWindow.getShell(); + + this.container = this.mainWindow.getContainer(); + + this.shell.open(); + this.shell.layout(); + } catch (Exception e) { + log.warn("Main-Window creation FAILED. Reason: " + e.getMessage()); + this.display = null; + this.mainWindow = null; + this.shell = null; + this.container = null; + throw e; + } + } /** - * Jump to specific state - * - * Sets the state machine state this method should be used to let the user jump - * around between states. This Method also resets certain properties defined - * by later states then the target state. - * - * Example: Usually the MainWindow allows the user to jump to the states: - * DataSourceSelectionState, PositioningState and BKUSelectionState + * Gets the Shell for drawing the ui * - * @param state the state to jump to + * @return Composite */ - public void jumpToState(State state); + public synchronized Composite getComposite() { + // Main window will be built on first call + // returns SWT Composite container for states to draw their GUI + + if (this.container == null) { + this.createMainWindow(); + } + + return this.container; + } + + public <T> T createComposite(Class<T> compositeClass, int style, State state) { + T composite = null; + try { + Constructor<T> constructor = compositeClass.getDeclaredConstructor( + Composite.class, int.class, State.class); + composite = constructor.newInstance(getComposite(), style, state); + } catch (Exception e) { + log.error("Could not create Composite for Class " + + compositeClass.getName(), e); + } + return composite; + } /** - * Update state machine - * Calls the next state. + * Only returns a shell if one was already created ... + * + * @return */ - public void update(); + private Shell nonCreatingGetShell() { + return this.shell; + } + + private boolean exit = false; /** - * Update state machine from other thread - * Calls the next state within the main thread + * Exists the Workflow */ - public void invokeUpdate(); + public void exit() { + this.exit = true; + if (this.shell != null) { + this.shell.dispose(); + } + } /** - * Exit state machine execution + * Only returns a shell if one was already created ... + * + * @return */ - public void exit(); + private Display nonCreatingGetDisplay() { + return this.display; + } /** - * Gets the command line arguments - * - * @return the command line arguments + * Workflow main entrance point */ - public String[] getCmdArgs(); + public void start() { + + // Call update to start processing ... + update(); + + // if a user interaction is required we have a shell ... + Shell shell = nonCreatingGetShell(); + Display display = nonCreatingGetDisplay(); + + if (this.status.getCurrentState() == null) { + if (shell != null) { + this.shell.dispose(); + } + } + + if (shell != null && display != null) { + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) { + display.sleep(); + } + } + display.dispose(); + } + } + public ConfigProvider getConfigProvider() { + return this.configProvider; + } + public PersistentConfigProvider getPersistentConfigProvider() { + return this.configProvider; + } + public ConfigManipulator getConfigManipulator() { + return this.configProvider; + } + public ConfigOverlayManipulator getConfigOverlayManipulator() { + return this.configProvider; + } + public Status getStatus() { + return this.status; + } + + public PDFSigner getPDFSigner() { + return this.pdfSigner; + } + + public GUIProvider getGUIProvider() { + return this; + } + + private String[] cmdLineArgs = new String[] {}; + private void setCmdLineArgs(String[] cmdLineArgs) { + this.cmdLineArgs = cmdLineArgs; + } + public String[] getCmdArgs() { + return this.cmdLineArgs; + } + + + public synchronized Shell getMainShell() { + if(this.shell == null) { + this.createMainWindow(); + } + + return this.shell; + } + + public void reloadResources() { + this.mainWindow.reloadLocalization(); + } } |