001: package org.osbl.agent.gui;
002:
003: import java.util.ArrayList;
004: import java.util.List;
005:
006: import org.wings.SComponent;
007:
008: /**
009: * An OperationController provides the UI components to manipulate Conditions or Actions.
010: *
011: * It also knows if another given OperationController can pose as a replacement
012: * to itself.
013: *
014: * This class provides a factory method to instantiate the corresponding
015: * Condition or Action for a given Condition- or ActionController.
016: *
017: * @author Sebastian Nozzi.
018: */
019: public abstract class OperationController {
020:
021: /**
022: * For a given Condition or Action instance, it instantiates the corresponding
023: * Condition- or ActionController.
024: *
025: * @param conditionOrAction a Condition or Action instance.
026: * @param packagePrefix the prefix of the package where the correspoding OperationController can be found.
027: *
028: * @return the corresponding OperationController instance.
029: *
030: * @throws InstantiationException the instantiation exception
031: * @throws IllegalAccessException the illegal access exception
032: * @throws ClassNotFoundException the class not found exception
033: */
034:
035: static protected OperationController newInstance(
036: Object conditionOrAction, String packagePrefix)
037: throws InstantiationException, IllegalAccessException,
038: ClassNotFoundException {
039:
040: // Just take the simple name (e.g. just "NumberCondition" instead of
041: // "org.osbl.agent.model.condition.NumberCondition")
042: String operationName = conditionOrAction.getClass()
043: .getSimpleName();
044:
045: // Wrap it around the package prefix and "Controller" at the end.
046: // (in our example: "org.osbl.agent.gui.condition.NumberConditionController")
047: String controllerClassName = packagePrefix + "."
048: + operationName + "Controller";
049:
050: // Note that for this to work you should only call this method for
051: // Conditions/Actions for which a Controller exists and has the
052: // exact class name + "Controller".
053:
054: // Create an instance of the class...
055: OperationController result = (OperationController) Class
056: .forName(controllerClassName).newInstance();
057:
058: // ...and return it.
059: return result;
060:
061: }
062:
063: /**
064: * Convenience method to retrieve localized Strings.
065: *
066: * @param code the String-code.
067: * @param args optional additional arguments.
068: *
069: * @return the localized String
070: */
071: protected String msg(String code, Object... args) {
072: return DesignContext.getMsg(code, args);
073: }
074:
075: /**
076: * Returns the UI components that represent the corresponding model class.
077: * They let the user manipulate the Condition- or ActionController in a visual way.
078: *
079: * Note that subclasses should not override this method but {@link #populateComponentList(List)}.
080: *
081: * @return a list of UI components.
082: */
083: public final List<SComponent> getComponents() {
084:
085: // Create an empty list of SComponents...
086: List<SComponent> result = new ArrayList<SComponent>();
087:
088: // ...let the subclass populate it...
089: populateComponentList(result);
090:
091: // ...and return it.
092: return result;
093: }
094:
095: /**
096: * Populates the component list with the components corresponding to the current
097: * Condition or ActionController.
098: *
099: * @param componentList the component list to be populated.
100: */
101: protected abstract void populateComponentList(
102: List<SComponent> componentList);
103:
104: /**
105: * Returns true if the candidateController can replace this
106: * controller.
107: *
108: * OperationController can replace one another if they perform the same function
109: * regardless of its internal state.
110: *
111: * @param candidateController the candidate controller that might, or not, serve as a
112: * replacement for this one.
113: *
114: * @return true, if can be replaced by the candidate controller.
115: */
116: abstract public boolean canBeReplacedBy(
117: OperationController candidateController);
118:
119: /**
120: * Tries to retrieve an instance of the model class that corresponds to this
121: * OperationController. So, for example, if called on a ConditionController
122: * it tries to instantiate the corresponding Condition. It performs the opposite
123: * operation that {@link #newInstance(Object, String)} does.
124: *
125: * @return the corresponding Condition or Action instance, or null if not successfull.
126: */
127: protected Object newOperationInstance() {
128:
129: // Get complete name of our class (which is not OperationController but
130: // a non abstract subclass of this one).
131: String operationName = this .getClass().getCanonicalName();
132:
133: // Remove the trailing "Controller" from the class name.
134: operationName = operationName.substring(0, operationName
135: .lastIndexOf("Controller"));
136:
137: // Replace ".gui." for ".model", so for example
138: // "org.osbl.agent.gui.condition.NumberConditionController" becomes
139: // "org.osbl.agent.model.condition.NumberCondition".
140: operationName = operationName.replaceFirst("\\.gui\\.",
141: ".model.");
142:
143: try {
144: // Instantiate the class and return it.
145: return Class.forName(operationName).newInstance();
146: } catch (InstantiationException e) {
147: // TODO Auto-generated catch block
148: e.printStackTrace();
149: } catch (IllegalAccessException e) {
150: // TODO Auto-generated catch block
151: e.printStackTrace();
152: } catch (ClassNotFoundException e) {
153: // TODO Auto-generated catch block
154: e.printStackTrace();
155: }
156:
157: return null;
158: }
159:
160: }
|