001: /*
002: * <copyright>
003: *
004: * Copyright 2000-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.tools.csmart.ui.viewer;
028:
029: import org.cougaar.tools.csmart.experiment.DBExperiment;
030: import org.cougaar.tools.csmart.experiment.Experiment;
031: import org.cougaar.tools.csmart.recipe.RecipeComponent;
032: import org.cougaar.tools.csmart.society.SocietyComponent;
033: import org.cougaar.util.log.Logger;
034:
035: import javax.swing.*;
036: import javax.swing.tree.DefaultMutableTreeNode;
037: import java.util.Enumeration;
038:
039: /**
040: * Set of utilities for determining what tools & actions
041: * should be enabled, based on what items are being currently used.
042: */
043: public class ActionUtil {
044: public static String CONFIGURE_ACTION = "Configure";
045: public static String BUILD_ACTION = "Build";
046: public static String RUN_ACTION = "Run";
047: public static String DUPLICATE_ACTION = "Duplicate";
048: public static String DELETE_ACTION = "Delete";
049: public static String RENAME_ACTION = "Rename";
050: public static String NEW_EXPERIMENT_ACTION = "New Experiment";
051: public static String NEW_EXPERIMENT_FROM_DB_ACTION = "From Database";
052: public static String NEW_EXPERIMENT_FROM_FILE_ACTION = "From File";
053: public static String NEW_EXPERIMENT_FROM_UI_ACTION = "From User";
054: public static String NEW_RECIPE_ACTION = "New Recipe";
055: public static String NEW_FOLDER_ACTION = "New Folder";
056: public static String DELETE_EXPERIMENT_FROM_DATABASE_ACTION = "Delete Experiment From Database";
057: public static String DELETE_RECIPE_FROM_DATABASE_ACTION = "Delete Recipe From Database";
058: public static String SAVE_ACTION = "Save";
059:
060: /**
061: * Enable/disable an action, based on the object selected.
062: * @param action action to enable/disable
063: * @param organizer used to get the selected object and children
064: */
065:
066: public static void setActionAllowed(Action action,
067: Organizer organizer) {
068: Logger log = CSMART
069: .createLogger("org.cougaar.tools.csmart.ui.viewer.ActionUtil");
070: DefaultMutableTreeNode selectedNode = organizer
071: .getSelectedNode();
072:
073: // you can always "run an experiment" using the CSMARTConsole
074: // because you can attach to running nodes
075: if (action.equals(organizer.runExperimentAction)) {
076: action.setEnabled(true);
077: return;
078: }
079:
080: // If nothing is selected, some things are still legitimate
081: if (selectedNode == null) {
082: if (action
083: .equals(organizer.deleteExperimentFromDatabaseAction)
084: || action
085: .equals(organizer.deleteRecipeFromDatabaseAction)) {
086: action.setEnabled(true);
087: return;
088: } else {
089: action.setEnabled(false);
090: return;
091: }
092: }
093:
094: // can't do anything with nodes in an experiment being edited or run
095: if (organizer.isNodeInUse(selectedNode)) {
096: action.setEnabled(false);
097: return;
098: }
099:
100: // handle if selected object is root of workspace
101: if (selectedNode.isRoot()) {
102: if (action.equals(organizer.newExperimentFromDBAction)
103: || action
104: .equals(organizer.newExperimentFromFileAction)
105: || action
106: .equals(organizer.newExperimentFromUIAction)
107: || action.equals(organizer.newFolderAction)
108: || action.equals(organizer.renameAction)
109: || action.equals(organizer.renameWorkspaceAction)
110: || action
111: .equals(organizer.newRecipeFromDatabaseAction)
112: || action.equals(organizer.newRecipeBuiltInAction)
113: || action
114: .equals(organizer.deleteExperimentFromDatabaseAction)
115: || action
116: .equals(organizer.deleteRecipeFromDatabaseAction)) {
117: action.setEnabled(true);
118: return;
119: }
120: action.setEnabled(false);
121: return;
122: } // end handling root
123:
124: Object selectedObject = selectedNode.getUserObject();
125:
126: if (selectedObject instanceof String)
127: action.setEnabled(isActionAllowedOnFolder(action,
128: organizer, organizer.getSelectedNode()));
129: else if (selectedObject instanceof Experiment)
130: action.setEnabled(isActionAllowedOnExperiment(action,
131: organizer, (Experiment) selectedObject));
132: else if (selectedObject instanceof SocietyComponent)
133: action.setEnabled(isActionAllowedOnSociety(action,
134: organizer, (SocietyComponent) selectedObject));
135: else if (selectedObject instanceof RecipeComponent)
136: action.setEnabled(isActionAllowedOnRecipe(action,
137: organizer, (RecipeComponent) selectedObject));
138: else {
139: if (log.isErrorEnabled()) {
140: log.error("ActionUtil: unhandled case: "
141: + (String) action.getValue(Action.NAME));
142: }
143: action.setEnabled(false);
144: }
145: return;
146: }
147:
148: /**
149: * New and rename actions are always allowed.
150: * Delete is allowed on an empty folder.
151: * Other actions are allowed on a folder if and only
152: * they're allowed on at least one of its children.
153: */
154: private static boolean isActionAllowedOnFolder(Action action,
155: Organizer organizer, DefaultMutableTreeNode node) {
156: if (action.equals(organizer.newExperimentFromDBAction)
157: || action.equals(organizer.newExperimentFromFileAction)
158: || action.equals(organizer.newExperimentFromUIAction)
159: || action.equals(organizer.newFolderAction)
160: || action.equals(organizer.newRecipeFromDatabaseAction)
161: || action.equals(organizer.newRecipeBuiltInAction)
162: || action.equals(organizer.renameAction)
163: || action.equals(organizer.renameFolderAction))
164: return true;
165:
166: Enumeration nodes = node.breadthFirstEnumeration();
167: nodes.nextElement(); // advance over first element which is the folder
168: // can delete empty folder, but not root
169: if (!nodes.hasMoreElements() && !node.isRoot())
170: return (action.equals(organizer.deleteAction) || action
171: .equals(organizer.deleteFolderAction));
172: return false;
173: }
174:
175: /**
176: * Don't allow configuring society, or building,
177: * deleting, renaming, or running an experiment,
178: * if you're editing one of its components (i.e. a society or recipe).
179: * Don't allow running an experiment, unless its runnable.
180: * Don't allow deleting, renaming, configuring or building
181: * if you're building or running the experiment.
182: */
183: private static boolean isActionAllowedOnExperiment(Action action,
184: Organizer organizer, Experiment experiment) {
185: if (action.equals(organizer.newExperimentFromDBAction)
186: || action.equals(organizer.newExperimentFromFileAction)
187: || action.equals(organizer.newExperimentFromUIAction)
188: || action.equals(organizer.newFolderAction)
189: || action.equals(organizer.newRecipeFromDatabaseAction)
190: || action.equals(organizer.newRecipeBuiltInAction))
191: return false;
192: if (action.equals(organizer.duplicateAction))
193: return true;
194: if (action.equals(organizer.saveAction)
195: && experiment.isModified())
196: return !experiment.isEditInProgress();
197: SocietyComponent society = experiment.getSocietyComponent();
198: if (society != null && !society.isEditable()) {
199: return false;
200: }
201: RecipeComponent[] recipes = experiment.getRecipeComponents();
202: for (int i = 0; i < recipes.length; i++) {
203: if (!recipes[i].isEditable()) {
204: return false;
205: }
206: }
207: if (society == null) {
208: if (action.equals(organizer.runExperimentAction)
209: || action.equals(organizer.configureAction))
210: return false;
211: }
212: if (action.equals(organizer.runExperimentAction))
213: return experiment.isRunnable();
214: if (action.equals(organizer.deleteAction)
215: || action.equals(organizer.deleteExperimentAction)
216: || action.equals(organizer.renameAction)
217: || action.equals(organizer.renameExperimentAction)
218: || action.equals(organizer.configureAction)
219: || action.equals(organizer.buildExperimentAction))
220: return (!experiment.isEditInProgress() && !experiment
221: .isRunInProgress());
222: return false;
223: }
224:
225: /**
226: * Don't allow duplicating, building an experiment, or deleting
227: * if the user selected a society in an experiment.
228: * Don't allow building, deleting, renaming, or configuring
229: * if the society is being configured.
230: * Don't allow configuring if the society is in an experiment
231: * which is being configured or run.
232: */
233: private static boolean isActionAllowedOnSociety(Action action,
234: Organizer organizer, SocietyComponent society) {
235: if (action.equals(organizer.newExperimentFromDBAction)
236: || action.equals(organizer.newExperimentFromFileAction)
237: || action.equals(organizer.newExperimentFromUIAction)
238: || action.equals(organizer.newFolderAction)
239: || action.equals(organizer.newRecipeFromDatabaseAction)
240: || action.equals(organizer.newRecipeBuiltInAction))
241: return false;
242: if (!society.isEditable())
243: return false;
244: if (isNodeInExperiment(organizer)) {
245: if (action.equals(organizer.duplicateAction)
246: || action.equals(organizer.buildExperimentAction)
247: || action.equals(organizer.deleteAction)
248: || action.equals(organizer.deleteSocietyAction)
249: || action.equals(organizer.runExperimentAction))
250: return false;
251: }
252: if (action.equals(organizer.duplicateAction))
253: return true;
254: if (action.equals(organizer.saveAction) && society.isModified())
255: return (!CSMART.isSocietyInEditor(society));
256: if (action.equals(organizer.deleteAction)
257: || action.equals(organizer.deleteSocietyAction)
258: || action.equals(organizer.renameAction)
259: || action.equals(organizer.renameSocietyAction))
260: return (!CSMART.isSocietyInEditor(society));
261: if (action.equals(organizer.configureAction)
262: || action.equals(organizer.buildExperimentAction)
263: || action.equals(organizer.runExperimentAction))
264: return !organizer.isComponentInUse(society)
265: && !CSMART.isSocietyInEditor(society);
266: return false;
267: }
268:
269: /**
270: * Don't allow duplicating or deleting
271: * if the recipe is in an experiment.
272: * Don't allow deleting, renaming, or configuring
273: * if the recipe is being configured.
274: * Don't allow configuring if the recipe is in an experiment
275: * which is being configured or run.
276: */
277: private static boolean isActionAllowedOnRecipe(Action action,
278: Organizer organizer, RecipeComponent recipe) {
279: if (action.equals(organizer.newExperimentFromDBAction)
280: || action.equals(organizer.newExperimentFromFileAction)
281: || action.equals(organizer.newExperimentFromUIAction)
282: || action.equals(organizer.newFolderAction)
283: || action.equals(organizer.newRecipeFromDatabaseAction)
284: || action.equals(organizer.newRecipeBuiltInAction))
285: return false;
286: if (!recipe.isEditable())
287: return false;
288: if (isNodeInExperiment(organizer)) {
289: if (action.equals(organizer.duplicateAction)
290: || action.equals(organizer.deleteAction)
291: || action.equals(organizer.deleteRecipeAction))
292: return false;
293: }
294: if (action.equals(organizer.saveAction) && recipe.isModified())
295: return (!CSMART.isRecipeInEditor(recipe));
296: if (action.equals(organizer.duplicateAction))
297: return true;
298: if (action.equals(organizer.deleteAction)
299: || action.equals(organizer.deleteRecipeAction)
300: || action.equals(organizer.renameAction)
301: || action.equals(organizer.renameRecipeAction))
302: return (!CSMART.isRecipeInEditor(recipe));
303: if (action.equals(organizer.configureAction))
304: return !organizer.isComponentInUse(recipe)
305: && !CSMART.isRecipeInEditor(recipe);
306: return false;
307: }
308:
309: // return true if the user selected a node within an experiment
310: private static boolean isNodeInExperiment(Organizer organizer) {
311: DefaultMutableTreeNode node = organizer.getSelectedNode();
312: if (node == null)
313: return false;
314: DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) node
315: .getParent();
316: if (parentNode == null)
317: return false;
318: Object o = parentNode.getUserObject();
319: if (o == null)
320: return false;
321: return (o instanceof Experiment);
322: }
323: }
|