Keeping Track of Workflow States

It is very common to keep in a singleton various extra state information associated with windows and layers created by a workflow. For example, you might want to keep track in a singleton in which step each layer was created. You need to make sure that this singleton and the current environment are in sync.

Listening to layer events

As each layer can be removed independently of the workflow tasks, your singleton must listen to layer removal events. Here is a template for a singleton class listening to such events:

WORKFLOWSINGLETON.JAVA

package com.mycompany.myviewer.mydemoworkflow;
import com.interactive.intviewerapi.IObservable;
import com.interactive.intviewerapi.Listeners;
import com.interactive.intviewerapi.events.EventBroadcaster;
import com.interactive.intviewerapi.events.IEventListener;
import com.interactive.intviewerapi.events.IEventSubscriber;
import com.interactive.intviewerapi.events.ViewerWindowEvent;
import java.util.EventObject;
public class WorkflowSingleton implements IObservable, IEventSubscriber {
    // defines workflow listeners
    class WorkflowListeners extends Listeners {
        public void fireWorkflowEvent(EventObject evt) {
            super.fire(evt);
        }
    }
    private WorkflowListeners _listeners = new WorkflowListeners();
    private static WorkflowSingleton _instance = null;
    /**
     * Returns an instance of this class
     */
    public static WorkflowSingleton getInstance() {
        if (_instance == null) {
            _instance = new WorkflowSingleton();
        }
        return _instance;
    }
    /**
     * Constructs a new workflow singleton.
     */
    private WorkflowSingleton() {
        EventBroadcaster.getInstance().subscribe(ViewerWindowEvent.class, this, true);
    }
    /**
     * Acts upon a layer removal.
     */
    @Override
    public void onEvent(Object event) {
        if (event instanceof ViewerWindowEvent) {
            ViewerWindowEvent layeredWindowEvent = (ViewerWindowEvent) event;
            if (layeredWindowEvent.getEventType().equals(ViewerWindowEvent.VISUALS_REMOVED_EVENT_TYPE)) {
                // act upon the removal of the layer
                //...
                // ask the tasks to update themselves
                this.fireWorkflowEvent();
            }
        }
    }
    /**
     * Adds a new listener to the listeners list.
     * @param lst the event listener to add
     */
    @Override
    public boolean addEventListener(IEventListener lst) {
        if (!_listeners.equals(lst)) {
            return _listeners.addEventListener(lst);
        }
        return true;
    }
    /**
     * Removes a listener from the listeners list.
     * @param lst the event listener to remove
     */
    @Override
    public boolean removeEventListener(IEventListener lst) {
        return _listeners.removeEventListener(lst);
    }
    /**
     * Notifies all registered tasks of a change to this singleton.
     */
    public void fireWorkflowEvent() {
        _listeners.fireWorkflowEvent(new EventObject(this));
    }
    /**
     * Cleans up the state of this singleton.
     */
    public void dispose() {
        //...
    }
}

Each task should be notified and update its status when this singleton is modified. Here is a template for a task class listening to changes in a singleton:

MYDEMOTASK.JAVA

public class MyDemoTask extends AbstractTask implements IEventListener {
    public MyDemoTask () {
        super();
        WorkflowSingleton.getInstance().addEventListener(this);
    }
    @Override
    public void receive(EventObject e) {
        if (e.getSource() instanceof WorkflowSingleton) {
            Status currentStatus = getStatus();
            Status newStatus = ...;
            if (newStatus != currentStatus) {
                setStatus(newStatus);
                fireListener(this);
            }
        }
    }
}

Disposing Workflows

When the user elects to press the "Clear All" button, and when a new session is opened, you want to make sure all variables in your singleton are reset to their initial value.

INTViewer has a mechanism that facilitates this automatic reset. In your workflow.xml file, add a "manager" element with the name of the class that will implement the disposal:

DEMOWORKFLOWTASKS.XML

<workflow>
    <manager class="com.mycompany.myviewer.mydemoworkflow.DemoWorkflowManager" />
    <tasklist name="Load">
        <task factory="DemoWorkflowTaskFactoryId" tooltip="Do first load task."></task>
        <task factory="DemoWorkflowTaskFactoryId" tooltip="Do second load task."></task>
    </tasklist>
    <tasklist name="Process">
        <task factory="DemoWorkflowTaskFactoryId" tooltip="Do first process task."></task>
    </tasklist>
    <tasklist name="Save">
        <task factory="DemoWorkflowTaskFactoryId" tooltip="Do first save task."></task>
    </tasklist>
</workflow>

Here is a template for a manager class performing the disposal of all elements in a singleton:

DEMOWORKFLOWMANAGER.JAVA

package com.mycompany.myviewer.mydemoworkflow;
import com.interactive.intviewerapi.plugins.workflow.AbstractWorkflowManager;
public class DemoWorkflowManager extends AbstractWorkflowManager {
    @Override
    public void dispose() {
        WorkflowSingleton.getDefault().dispose();
    }
}

To associate a Help button with a workflow, add the <help id="xxx"> tag to your workflow task file, xxx being the id of the help page in your module, as registered in your map.xml helpset file.