001: package org.osbl.agent.gui;
002:
003: import java.awt.event.ActionEvent;
004: import java.awt.event.ActionListener;
005: import java.util.ArrayList;
006: import java.util.List;
007:
008: import org.concern.Controller;
009: import org.osbl.agent.logic.RuntimeContext;
010: import org.osbl.agent.model.Rule;
011: import org.osbl.agent.model.RuleContext;
012: import org.osbl.client.wings.XButton;
013: import org.osbl.client.wings.form.GenericObjectEditor;
014: import org.osbl.client.wings.form.GenericObjectList;
015: import org.osbl.client.wings.form.ObjectForm;
016: import org.osbl.client.wings.shell.Client;
017: import org.osbl.client.wings.shell.Window;
018: import org.wings.SButton;
019: import org.wings.SComponent;
020:
021: /**
022: * This class drives the operation of the Preview Mode.
023: *
024: * @author Sebastian Nozzi.
025: */
026: public abstract class PreviewController {
027:
028: /** The runtime context. */
029: private RuntimeContext runtimeContext;
030:
031: /** The index of the target object being shown. */
032: private int targetIndex = 0;
033:
034: /** The list item objects. */
035: private List<Object> listItemTargets;
036:
037: /** The window where the preview mode is shown. */
038: private Window previewWindow;
039:
040: /** Whether the window is visible or not. */
041: private boolean showingWindow = false;
042:
043: /** The previous button. */
044: private SButton previousButton;
045:
046: /** The apply button. */
047: private SButton applyButton;
048:
049: /** The skip button. */
050: private SButton skipButton;
051:
052: /** The finish button. */
053: private SButton finishButton;
054:
055: /** The design context. */
056: protected DesignContext designContext;
057:
058: /** The Rule being run. */
059: protected Rule currentRule;
060:
061: /**
062: * Instantiates a new PreviewController with a given DesignContext.
063: *
064: * @param designContext the design context
065: */
066: public PreviewController(DesignContext designContext) {
067:
068: this .designContext = designContext;
069:
070: }
071:
072: /**
073: * Convenience method to get localized versions of strings/labels.
074: *
075: * @param code the String-code
076: * @param args optional arguments
077: *
078: * @return the localized String
079: */
080: private String msg(String code, Object... args) {
081: return designContext.msg(code, args);
082: }
083:
084: /**
085: * Initiates the Preview Mode using the given Rule.
086: *
087: * @param rule the Rule for which the Preview Mode will be started.
088: */
089: public void runRule(Rule rule) {
090:
091: // Get the object-editor and object-list, used to retrieve and manipulate the objects
092: GenericObjectEditor objectEditor = (GenericObjectEditor) designContext
093: .getObjectEditor();
094: GenericObjectList objectList = (GenericObjectList) objectEditor
095: .getList();
096:
097: listItemTargets = new ArrayList<Object>();
098:
099: // Retrieve all applicable list-items
100: for (int rowIdx = 0; rowIdx < objectList.getRowCount(); rowIdx++) {
101:
102: Object listItemObject = getListObject(rowIdx);
103:
104: if (runtimeContext.ruleIsApplicable(rule, listItemObject)) {
105: listItemTargets.add(listItemObject);
106: }
107: }
108:
109: // If items were found...
110: if (listItemTargets.size() > 0) {
111:
112: targetIndex = 0;
113:
114: // ...setup the window if not already done so
115: if (previewWindow == null)
116: setupWindow();
117:
118: currentRule = rule;
119:
120: // ...and begin showing the items in the UI.
121: showListItemTarget();
122: }
123: }
124:
125: /**
126: * Setups the window.
127: */
128: private void setupWindow() {
129:
130: previewWindow = new Window();
131:
132: List<SComponent> controls = new ArrayList<SComponent>();
133:
134: previousButton = new XButton("Previous");
135: applyButton = new XButton("Apply & Proceed");
136: skipButton = new XButton("Skip");
137: finishButton = new XButton("Finish");
138:
139: controls.add(previousButton);
140: controls.add(applyButton);
141: controls.add(skipButton);
142: controls.add(finishButton);
143:
144: previewWindow.setTitle(msg("previewWindowTitle"));
145:
146: getObjectForm().getEnvironment().setControls(controls);
147:
148: previousButton.addActionListener(new ActionListener() {
149: public void actionPerformed(ActionEvent e) {
150: previous();
151: }
152: });
153:
154: applyButton.addActionListener(new ActionListener() {
155: public void actionPerformed(ActionEvent e) {
156: apply();
157: }
158: });
159:
160: skipButton.addActionListener(new ActionListener() {
161: public void actionPerformed(ActionEvent e) {
162: skip();
163: }
164: });
165:
166: finishButton.addActionListener(new ActionListener() {
167: public void actionPerformed(ActionEvent e) {
168: finish();
169: }
170: });
171:
172: }
173:
174: /**
175: * Runs the Rule and then shows the current list-item in the UI.
176: */
177: private void showListItemTarget() {
178:
179: Object listItemTarget = listItemTargets.get(targetIndex);
180:
181: // This makes use of the persistence functionality of the editor, letting the
182: // editor retrieve the object for us.
183: ((GenericObjectEditor) designContext.getObjectEditor())
184: .revertObject(listItemTarget);
185:
186: // Once retrieved, we show it in the UI.
187: populateForm(listItemTarget);
188:
189: // We create and populate a RuleContext.
190: RuleContext ruleContext = new RuleContext();
191: runtimeContext.populateRuleContext(ruleContext, listItemTarget);
192:
193: // Conditions apply?
194: if (currentRule.evaluateConditions(ruleContext)) {
195:
196: // Then Execute the Actions...
197: currentRule.executeActions(ruleContext);
198:
199: // ...and show the results on screen...
200: getObjectForm().getEnvironment().setDelegate(previewWindow);
201:
202: if (showingWindow == false) {
203: Client.getInstance().pushWindow(
204: designContext.getParentWindow(), previewWindow);
205: showingWindow = true;
206: }
207:
208: // "Previous" not possible if at beginning
209: previousButton.setEnabled(canGoBack());
210: // It's always possible to advance (apply or skip), but when
211: // you reach the end, we close the window automatically.
212:
213: } else {
214: // On to the next target!
215: skip();
216: }
217:
218: }
219:
220: /**
221: * Closes the window.
222: */
223: private void closeWindow() {
224: if (showingWindow) {
225: Client.getInstance().popWindow(previewWindow);
226: showingWindow = false;
227: }
228: }
229:
230: /**
231: * Finish.
232: */
233: private void finish() {
234: designContext.getObjectEditor().getList().refresh();
235: closeWindow();
236: }
237:
238: /**
239: * Skip.
240: */
241: private void skip() {
242: if (canAdvance()) {
243: targetIndex++;
244: showListItemTarget();
245: } else
246: finish();
247: }
248:
249: /**
250: * Previous.
251: */
252: private void previous() {
253: if (canGoBack()) {
254: targetIndex--;
255: showListItemTarget();
256: }
257: }
258:
259: /**
260: * Can advance?
261: *
262: * @return true, if it is possible to advance to the next item.
263: */
264: private boolean canAdvance() {
265: return targetIndex + 1 < listItemTargets.size();
266: }
267:
268: /**
269: * Can go back?
270: *
271: * @return true, if it is possible to go back to the previous item.
272: */
273: private boolean canGoBack() {
274: return targetIndex - 1 >= 0;
275: }
276:
277: /**
278: * Applies the changes done by the Rule and/or user to the target object.
279: */
280: private void apply() {
281:
282: Object targetToPersist = listItemTargets.get(targetIndex);
283:
284: ObjectForm objectForm = getObjectForm();
285:
286: // Use the object-form to check for validation issues (already part of OSBL)
287: if (!objectForm.hasValidationIssues()) {
288: saveObject(targetToPersist);
289: }
290:
291: // Move to next item
292: skip();
293: }
294:
295: /**
296: * Gets the con:cern controller, used to retrieve con:cern related objects.
297: *
298: * @param targetObject the target object for which a con:cern controller will be sought.
299: *
300: * @return the con:cern controller found.
301: */
302: protected abstract Controller getController(Object targetObject);
303:
304: /**
305: * Persists the object.
306: *
307: * @param targetObject the target object to be persisted.
308: */
309: private void saveObject(Object targetObject) {
310: // Makes use of the editor's persistence functionality to store the object.
311: ((GenericObjectEditor) designContext.getObjectEditor())
312: .saveObject(targetObject);
313: // Call possible post-update actions.
314: postUpdateActions(targetObject);
315: }
316:
317: /**
318: * Post update actions.
319: *
320: * @param targetObject the target object for which post-update actions will be done.
321: */
322: protected abstract void postUpdateActions(Object targetObject);
323:
324: /**
325: * Sets the runtime context.
326: *
327: * @param runtimeContext the new RuntimeContext
328: */
329: public void setRuntimeContext(RuntimeContext runtimeContext) {
330: this .runtimeContext = runtimeContext;
331: }
332:
333: /**
334: * Returns the real subject instance from a (possibly) con:cern object (like Work/Subject)
335: *
336: * @param targetObject the target object
337: *
338: * @return the subject instance, in con:cern terms.
339: */
340: protected abstract Object getSubjectInstance(Object targetObject);
341:
342: /**
343: * Gets the object form.
344: *
345: * @return the object form
346: */
347: protected abstract ObjectForm getObjectForm();
348:
349: /**
350: * Populates the on-screen form (which is part of the editor).
351: *
352: * @param targetObject the target object used to populate the form.
353: */
354: protected abstract void populateForm(Object targetObject);
355:
356: /**
357: * Retrieves an item from the list at the given index.
358: *
359: * @param rowIdx the row index.
360: *
361: * @return the list item.
362: */
363: protected abstract Object getListObject(int rowIdx);
364:
365: }
|