/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.foundation.wkf.action; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.foundation.FlexoEditor; import org.openflexo.foundation.FlexoModelObject; import org.openflexo.foundation.action.FlexoAction; import org.openflexo.foundation.action.FlexoActionType; import org.openflexo.foundation.ie.widget.IEHyperlinkWidget; import org.openflexo.foundation.rm.DuplicateResourceException; import org.openflexo.foundation.wkf.WKFObject; import org.openflexo.foundation.wkf.edge.FlexoPostCondition; import org.openflexo.foundation.wkf.node.AbstractNode; import org.openflexo.foundation.wkf.node.ActionNode; import org.openflexo.foundation.wkf.node.FlexoPreCondition; import org.openflexo.foundation.wkf.node.OperationNode; import org.openflexo.foundation.wkf.node.SelfExecutableNode; import org.openflexo.foundation.wkf.utils.OperationAssociatedWithComponentSuccessfully; import org.openflexo.toolbox.FlexoBoolean; public class BindButtonsToActionNode extends FlexoAction<BindButtonsToActionNode, OperationNode, WKFObject> { protected static final Logger logger = Logger.getLogger(BindButtonsToActionNode.class.getPackage().getName()); public static FlexoActionType<BindButtonsToActionNode, OperationNode, WKFObject> actionType = new FlexoActionType<BindButtonsToActionNode, OperationNode, WKFObject>( "bind_buttons_to_action_nodes", FlexoActionType.defaultGroup) { /** * Factory method */ @Override public BindButtonsToActionNode makeNewAction(OperationNode focusedObject, Vector<WKFObject> globalSelection, FlexoEditor editor) { return new BindButtonsToActionNode(focusedObject, globalSelection, editor); } @Override public boolean isVisibleForSelection(OperationNode object, Vector<WKFObject> globalSelection) { return !(object instanceof SelfExecutableNode); } @Override public boolean isEnabledForSelection(OperationNode object, Vector<WKFObject> globalSelection) { return object != null && object.getComponentInstance() != null; } }; static { FlexoModelObject.addActionForClass(actionType, OperationNode.class); } protected BindButtonsToActionNode(OperationNode focusedObject, Vector<WKFObject> globalSelection, FlexoEditor editor) { super(actionType, focusedObject, globalSelection, editor); } public static final int OK = 0; public static final int CANCEL = 1; public static final int IGNORE = 2; /** * The operation node for which action nodes will be created */ private OperationNode operationNode; /** * This hashtable keeps a record of the associations made by the end-user. The key list contains all the buttons of the component that * needs to be associated with an action. The values are ActionNode that needs to be associated with the button. If the ActionNode * returns a <code>null</code> value, then it means that the action needs to be created (it was the dummy ActionNode that was selected). */ private Map<IEHyperlinkWidget, ActionNode> associations; /** * This is the vector of actions (including the dummy) that were selectable to be bound to a button */ private List<ActionNode> actions; /** * This boolean indicates wheter previous ActionNodes should be kept or not */ private boolean cleanActions = false; /** * This array of FlexoBoolean indicates wheter the associated ActionNode (the order is the same as the one given by the keys of the * hashtable) should be linked to the Begin and end node or not. */ private FlexoBoolean[] insertActionNode; /** * If an exception was thrown then it needs to be passed also (mainly to handle the CANCEL option, information for going back to the * previous state is contained in that exception) */ private OperationAssociatedWithComponentSuccessfully exception; private Vector<IEHyperlinkWidget> buttons; private int retval = -1; @Override protected void doAction(Object context) throws DuplicateResourceException { switch (retval) { case OK: handleOK(); break; case CANCEL: handleCancel(exception); break; case IGNORE: handleIgnore(); break; } } public OperationNode getOperationNode() { return operationNode; } public void setOperationNode(OperationNode operationNode) { this.operationNode = operationNode; } private void handleOK() { // cleanActions(cleanActions); int i = 0; if (logger.isLoggable(Level.INFO)) { logger.info("Ok pressed"); } for (IEHyperlinkWidget w : buttons) { if (!getInsertActionNode()[i++].getValue()) { continue; } ActionNode node = getAssociations().get(w); if (node.getProcess() == null) { node = OperationNode.createNewActionNodeForButton(w, operationNode); } else { associateNodeWithButton(node, w); } if (node != null) { linkActionToBeginNode(node); } } } private static void linkActionToBeginNode(ActionNode node) { boolean bind = true; Enumeration<FlexoPreCondition> en = node.getPreConditions().elements(); while (en.hasMoreElements() && bind) { FlexoPreCondition pre = en.nextElement(); Enumeration<FlexoPostCondition<AbstractNode, AbstractNode>> en1 = pre.getIncomingPostConditions().elements(); while (en1.hasMoreElements() && bind) { FlexoPostCondition<AbstractNode, AbstractNode> post = en1.nextElement(); if (post.getStartNode() instanceof ActionNode && ((ActionNode) post.getStartNode()).isBeginNode()) { bind = false; } } } if (bind) { OperationNode.linkActionToBeginNode(node); } } private static void handleIgnore() { // Well, for now we do nothing and it should not change in the future // (Look at my Master comment!) } private static void handleCancel(OperationAssociatedWithComponentSuccessfully ex) { if (ex == null) { // instance has not changed. return; } try { if (ex.getPreviousComponentInstance() != null) { ex.getNode().setComponentInstance(ex.getPreviousComponentInstance()); } else { ex.getNode().removeComponentInstance(); } } catch (OperationAssociatedWithComponentSuccessfully e) { // We have nothing to do here since we set the component instance // back to the ways it was // NTH: re-associate action nodes with the butons of the UI. } } private void cleanActions(boolean cleanActions) { if (cleanActions) { for (ActionNode a : actions) { if (a.getAssociatedButtonWidget() == null && a.getProcess() != null) { a.delete(); } } } } private void associateNodeWithButton(ActionNode node, IEHyperlinkWidget w) { node.setAssociatedButtonWidget(w); } public Map<IEHyperlinkWidget, ActionNode> getAssociations() { return associations; } public void setAssociations(Map<IEHyperlinkWidget, ActionNode> map) { this.associations = map; } public List<ActionNode> getActions() { return actions; } public void setActions(List<ActionNode> list) { this.actions = list; } public boolean getCleanActions() { return cleanActions; } public void setCleanActions(boolean cleanActions) { this.cleanActions = cleanActions; } public FlexoBoolean[] getInsertActionNode() { return insertActionNode; } public void setInsertActionNode(FlexoBoolean[] linkToBeginAndEndNode) { this.insertActionNode = linkToBeginAndEndNode; } public int getRetval() { return retval; } public void setRetval(int retval) { this.retval = retval; } public OperationAssociatedWithComponentSuccessfully getException() { return exception; } public void setException(OperationAssociatedWithComponentSuccessfully exception) { this.exception = exception; } /** * @param buttons */ public void setButtons(Vector<IEHyperlinkWidget> buttons) { this.buttons = buttons; } }