| /* |
| * Copyright (c) 2008 Borland Software Corp. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Artem Tikhomirov (Borland) - initial API and implementation |
| */ |
| «IMPORT "http://www.eclipse.org/gmf/2008/Widget"» |
| «IMPORT "http://www.eclipse.org/gmf/2008/Context"» |
| «IMPORT "http://www.eclipse.org/gmf/2008/Binding"» |
| «IMPORT "http://www.eclipse.org/emf/2002/Ecore"» |
| |
| «EXTENSION Forms» |
| «EXTENSION Widgets» |
| «EXTENSION Context» |
| |
| // |
| // |
| // |
| «DEFINE registerListeners FOR Section» |
| «IF hasTextWidgets()-» |
| for (Text t : new Text[] {«FOREACH textWidgets() AS te SEPARATOR ", "»«te.fieldName()»«ENDFOREACH»}) { |
| t.addListener(SWT.Modify, this); |
| t.addListener(SWT.FocusOut, this); |
| t.addListener(SWT.KeyDown, this); |
| } |
| «ENDIF-» |
| «IF hasSpins()-» |
| for (Spinner s : new Spinner[] {«FOREACH spinWidgets() AS s SEPARATOR ", "»«s.fieldName()»«ENDFOREACH»}) { |
| s.addListener(SWT.Modify, this); |
| s.addListener(SWT.FocusOut, this); |
| } |
| «ENDIF-» |
| «IF hasRadioButtons() || hasCheckBoxes() || hasCombos()-» |
| for (Widget w : new Widget[] {«FOREACH (List[Widget])radioWidgets().union(checkboxWidgets()).union(comboWidgets()) AS r SEPARATOR ", "»«r.fieldName()»«ENDFOREACH»}) { |
| w.addListener(SWT.Selection, this); |
| } |
| «ENDIF-» |
| «ENDDEFINE» |
| |
| // |
| // |
| // |
| «DEFINE handleEventMethodBody FOR Section» |
| «IF hasTextWidgets() || hasSpins() /*though, spinners may require more attention*/ -» |
| if (event.type == SWT.Modify) { |
| // XXX also override isDirty to compare values if they |
| // match model's and to clear dirty state in case like aaa^H^H^H |
| markDirty(); |
| } else if (event.type == SWT.FocusOut) { |
| applyChanges(); |
| } else if (event.type == SWT.KeyDown) { |
| if (event.keyCode == SWT.ESC) { |
| discardChanges(); |
| } else if (event.keyCode == SWT.CR) { |
| applyChanges(); |
| } |
| } |
| «ENDIF-» |
| «IF hasRadioButtons() || hasCheckBoxes()-» |
| if (event.type == SWT.Selection) { |
| «LET checkboxWidgets().select(w | isBoolean(associatedBinding(w).selector)) AS booleanCheckBoxes-» |
| «IF !booleanCheckBoxes.isEmpty()-» |
| if «FOREACH booleanCheckBoxes AS r SEPARATOR " else if "»(«r.fieldName()» == event.widget) { |
| «IF !dependantActions(r).isEmpty()-» |
| if («r.fieldName()».getSelection()) { |
| «EXPAND ApplyAction FOREACH dependantActions(r)-» |
| } else { |
| «EXPAND RevertAction FOREACH dependantActions(r)-» |
| } |
| «ENDIF-» |
| applyChanges(); // Commit; View to Model |
| // Optimization? Instead of full refresh, just dependant widgets should get updated |
| «EXPAND RefreshAssociated(r)-» |
| }«ENDFOREACH» |
| «ENDIF-» |
| «ENDLET-» |
| «LET checkboxWidgets().select(w | !isBoolean(associatedBinding(w).selector)) AS referenceBasedCheckBoxes-» |
| «IF hasRadioButtons() || !referenceBasedCheckBoxes.isEmpty()-» |
| if «FOREACH (List[Widget])radioWidgets().union(referenceBasedCheckBoxes) AS r SEPARATOR " else if "»(«r.fieldName()» == event.widget) { |
| «LET associatedBinding(r) AS activeBinding-» |
| if («r.fieldName()».getSelection()) { |
| «EXPAND ApplyAction FOREACH triggeredActions_activated(activeBinding)-» |
| «EXPAND RevertAction FOREACH triggeredActions_deactivated(activeBinding)-» |
| applyChanges(); // Commit; View to Model |
| «EXPAND doRefresh(triggeredBindingToRefreshBesidesTheOne(activeBinding), activeBinding.refreshCondition.accessor)-» |
| }«IF !triggeredActions_activated(activeBinding).isEmpty()» else { |
| «EXPAND RevertAction FOREACH triggeredActions_activated(activeBinding)-» |
| «IF !{activeBinding.widget}.typeSelect(CheckBox).isEmpty()-» |
| applyChanges(); // Commit; View to Model |
| «ENDIF-» |
| }«ENDIF» |
| «ENDLET-» |
| }«ENDFOREACH» |
| «ENDIF-» |
| «ENDLET-» |
| «IF hasCombos()-» |
| if («FOREACH comboWidgets() AS cb SEPARATOR " || "»«cb.fieldName()» == event.widget«ENDFOREACH») { |
| applyChanges();«REM»TODO need to process possible enablements here as well (actions for conditions with accessor equal to the activated)«ENDREM» |
| } |
| «ENDIF» |
| } |
| «ENDIF-» |
| «ENDDEFINE» |
| |
| // |
| // |
| // for all bindings that share the same condition, refresh UI state |
| «DEFINE RefreshAssociated(Widget w) FOR Section-» |
| «EXPAND doRefresh(dependantBindings(w), null)-» |
| «ENDDEFINE» |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| |
| «DEFINE Commit FOR Section-» |
| «REM» |
| FIXME |
| Need to create not only the those elements that would get committed at this time |
| e.g. is wizard/generatePerspective == false, do not create GenPerspective |
| «ENDREM» |
| «EXPAND createMissing(1, this) FOR needsCreation(bindings.select(b | b.commitCondition == null))-» |
| |
| «FOREACH bindings.select(b | b.commitCondition == null) AS b»«EXPAND ViewToModel(b) FOR b.widget»«ENDFOREACH» |
| |
| «FOREACH conditions.select(c | bindings.exists(b | c == b.commitCondition)) AS c-» |
| «IF triggeredActions(c).isEmpty()-» |
| «FOREACH bindings.select(b | b.commitCondition == c) AS b-» |
| if («EXPAND uiConditionGet FOR b.widget») { |
| «EXPAND createMissing(1, this) FOR needsCreation({b})-» |
| «EXPAND ViewToModel(b) FOR b.widget-» |
| } |
| «ENDFOREACH-» |
| «ELSE-» |
| «LET bindings.select(b | b.commitCondition == c) AS bc-» |
| if («EXPAND uiConditionGet FOREACH triggeredActions(c) SEPARATOR " || "») { |
| «LET needsCreation(bc) AS toCreate-» |
| «FOREACH bc.select(b | b.selector.wholeChain().intersect(toCreate).isEmpty()) AS b-» |
| «EXPAND ViewToModel(b) FOR b.widget-» |
| «ENDFOREACH-» |
| «EXPAND createMissing(1, this) FOR toCreate-» |
| «FOREACH bc.select(b | !b.selector.wholeChain().intersect(toCreate).isEmpty()) AS b-» |
| «EXPAND ViewToModel(b) FOR b.widget-» |
| «ENDFOREACH-» |
| «ENDLET-» |
| }«LET bc.select(b | !{b.widget}.typeSelect(CheckBox).isEmpty() && !isBoolean(b.selector)) AS referenceBasedCheckBoxBindings-» |
| «IF !referenceBasedCheckBoxBindings.isEmpty()» else { |
| «FOREACH referenceBasedCheckBoxBindings AS cb-» |
| «EXPAND modelAccessSet(cb.selector)»(null); |
| «ENDFOREACH-» |
| } |
| «ENDIF-» |
| «ENDLET-» |
| «ENDLET-» |
| «ENDIF-» |
| «ENDFOREACH-» |
| «ENDDEFINE» |
| |
| |
| // assume each element of the list is context that mayBeNull |
| «DEFINE createMissing(int level, Section s) FOR List[Context]-» |
| «IF exists(x | wholeChain(x).size() >= level)-» |
| «FOREACH select(x | wholeChain(x).size() == level).typeSelect(FeatureContext) AS x-» |
| if («EXPAND modelAccessGet(x) FOR s» == null) { |
| «EXPAND modelAccessSet(x) FOR s»(«EXPAND MetaModel::factory FOR x.selector.eType»); |
| } |
| «ENDFOREACH-» |
| «EXPAND createMissing(level+1, s)-» |
| «ENDIF-» |
| «ENDDEFINE» |
| |
| |
| «DEFINE Refresh FOR Section» |
| «EXPAND doRefresh(bindings.select(b | b.refreshCondition == null), null)-» |
| |
| «FOREACH conditions.select(c | bindings.exists(b | b.refreshCondition == c)) AS c-» |
| «REM»grouping bindings by condition - to generate only one check and to set dependant bindings/widgets inside the same if()«ENDREM» |
| if («EXPAND modelConditionClause(c)») { |
| «EXPAND doRefresh(bindingsToRefresh(c), c.accessor)-» |
| «EXPAND ApplyAction FOREACH triggeredActions(c)-» |
| }«IF !triggeredActions(c).isEmpty() || needsRadioButtonWorkaround(c) || hasReferenceBasedCheckBoxes(c)» else { |
| «EXPAND deselectWidget FOREACH radioButtonToWorkaround(c)-» |
| «EXPAND deselectWidget FOREACH referenceBasedCheckBoxBindings(c)-» |
| «EXPAND RevertAction FOREACH triggeredActions(c)-» |
| }«ENDIF-» |
| «ENDFOREACH-» |
| |
| «FOREACH conditions.select(c | bindings.exists(b | b.commitCondition == c && b.refreshCondition != c) && !triggeredActions(c).isEmpty()) AS c-» |
| if («IF c.accessor.chain != null && needsNullCheck(c.accessor.chain)»«EXPAND nullModelConditionClause(this) FOR c.accessor.chain» && «ENDIF»«EXPAND modelConditionClause(c)») { |
| «EXPAND ApplyAction FOREACH triggeredActions(c)-» |
| } else {«REM»Shouldn't I add radiobutton workaround here as well?«ENDREM» |
| «EXPAND RevertAction FOREACH triggeredActions(c)-» |
| } |
| «ENDFOREACH-» |
| «ENDDEFINE» |
| |
| |
| «REM» |
| Performs a refresh taking into account possible null Contexts |
| In certain cases, there might be a null/whatever check for specific context, |
| (e.g. when refresh is conditioned) so that we may assume here the context is |
| already known to be non-null. |
| «ENDREM» |
| «DEFINE doRefresh(List[Binding] bnd, Context exclude) FOR Section-» |
| «FOREACH bnd.select(b | needsNullCheck(b.selector) && b.selector != exclude).selector.chain.purgeDups().typeSelect(Context) AS x-» |
| if («EXPAND nullModelConditionClause(this) FOR x») { |
| «FOREACH bnd.select(b | b.selector.chain == x) AS b-» |
| «EXPAND ModelToView(b) FOR b.widget-» |
| «ENDFOREACH-» |
| } |
| «ENDFOREACH-» |
| «FOREACH bnd.select(b | !needsNullCheck(b.selector) || b.selector == exclude) AS b-» |
| «EXPAND ModelToView(b) FOR b.widget-» |
| «ENDFOREACH-» |
| «ENDDEFINE» |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Model to View - Refresh/Update |
| |
| «DEFINE ModelToView(Binding b) FOR Widget»«ERROR "abstract ModelToView(Binding) FOR Widget"»«ENDDEFINE» |
| |
| «DEFINE ModelToView(Binding b) FOR TextEntry-» |
| «fieldName()».setText(«EXPAND modelAccessGet(b.selector) FOR b.section»);/*Bridge.fieldSet(«fieldName()», «EXPAND modelAccessGet(b.selector) FOR b.section»);*/ |
| «ENDDEFINE» |
| |
| // XXX NOTE: actual model value from b.selector is not used for now - not sure |
| // how to tell radiobuttons based on boolean values vs. radiobtns used to switch |
| // UI based on a condition |
| «DEFINE ModelToView(Binding b) FOR RadioButton-» |
| «fieldName()».setSelection(true); |
| «ENDDEFINE» |
| |
| «DEFINE ModelToView(Binding b) FOR CheckBox-» |
| «fieldName()».setSelection(«IF isBoolean(b.selector)»«EXPAND modelAccessGet(b.selector) FOR b.section»«ELSE»true«ENDIF»); |
| «ENDDEFINE» |
| |
| «DEFINE ModelToView(Binding b) FOR Spin-» |
| «fieldName()».setSelection(«EXPAND modelAccessGet(b.selector) FOR b.section»); |
| «ENDDEFINE» |
| |
| «DEFINE ModelToView(Binding b) FOR Combo-» |
| «fieldName()».select(«EXPAND modelAccessGet(b.selector) FOR b.section».getValue()); |
| «ENDDEFINE» |
| |
| «REM» |
| XXX WORKAROUND. May be reasonable to hide that behind RadioGroupController |
| |
| Programmatic radioButton.setSelection(true) doesn't deselect |
| any previously selected radiobutton within the same composite |
| (as it happens with user action/event). Hence, need to deselect |
| radiobuttons manually (leftover selection from previous input) |
| «ENDREM» |
| «DEFINE deselectWidget FOR Binding-» |
| «fieldName(widget)».setSelection(false); |
| «ENDDEFINE» |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // View to Model - Commit |
| |
| «DEFINE ViewToModel(Binding b) FOR Widget»«ERROR "abstract ViewToModel(Condition, Binding) FOR Widget"»«ENDDEFINE» |
| |
| «DEFINE ViewToModel(Binding b) FOR TextEntry-» |
| «EXPAND modelAccessSet(b.selector) FOR b.section»(/*Bridge.fieldGet(«fieldName()»)*/«fieldName()».getText()); |
| «ENDDEFINE» |
| |
| «DEFINE ViewToModel(Binding b) FOR RadioButton-» |
| «EXPAND modelAccessSet(b.selector) FOR b.section»(«EXPAND NewValue FOR b.commitCondition»); |
| «ENDDEFINE» |
| |
| «DEFINE ViewToModel(Binding b) FOR CheckBox-» |
| «EXPAND modelAccessSet(b.selector) FOR b.section»(«IF isBoolean(b.selector)»«fieldName()».getSelection()«ELSE»«EXPAND NewValue FOR b.commitCondition»«ENDIF»); |
| «ENDDEFINE» |
| |
| «DEFINE ViewToModel(Binding b) FOR Spin-» |
| «EXPAND modelAccessSet(b.selector) FOR b.section»(«fieldName()».getSelection()); |
| «ENDDEFINE» |
| |
| «DEFINE ViewToModel(Binding b) FOR Combo-» |
| «EXPAND modelAccessSet(b.selector) FOR b.section»(«EXPAND enumComboModelClass FOR b».get(«fieldName()».getSelectionIndex())); |
| «ENDDEFINE» |
| |
| «DEFINE NewValue FOR Condition»«ERROR "abstract NewValue FOR Condition"»«ENDDEFINE» |
| «DEFINE NewValue FOR InstanceCondition»«EXPAND MetaModel::factory FOR type»«ENDDEFINE» |
| «DEFINE NewValue FOR EqualsCondition»«value»«ENDDEFINE» |
| |
| |
| |
| ///////////////////////////////////////////////////////////////////////////////// |
| // Adapters |
| |
| «DEFINE AdaptersField FOR Section-» |
| private org.eclipse.emf.common.notify.Adapter[] myModelListeners; |
| «ENDDEFINE» |
| |
| «DEFINE AttachAdapters FOR Section-» |
| myModelListeners = new org.eclipse.emf.common.notify.Adapter[] { |
| «EXPAND Adapter::New(getConditionAccessors()) FOR input.typeSelect(FeatureContext)» |
| }; |
| getInput().eAdapters().addAll(java.util.Arrays.asList(myModelListeners)); |
| «ENDDEFINE» |
| |
| «DEFINE DetachAdapters FOR Section-» |
| if (myModelListeners != null) { |
| getInput().eAdapters().removeAll(java.util.Arrays.asList(myModelListeners)); |
| myModelListeners = null; |
| } |
| «ENDDEFINE» |
| |
| «DEFINE modelAccessSet(Context c) FOR Section»«ENDDEFINE» |
| «DEFINE modelAccessGet(Context c) FOR Section»«IF c == null»getInput(/*not sure which modelAccesGet would get invoked when c==null*/)«ENDIF»«ENDDEFINE» |
| |
| «DEFINE modelAccessSet(FeatureContext c) FOR Section-» |
| «IF needsCast(deduceInputType(), c)-» |
| ((«c.selector.eContainingClass.name») «EXPAND modelAccessGet(c.chain)»)«ELSE-» |
| «EXPAND modelAccessGet(c.chain)-» |
| «ENDIF».set«c.selector.name.toFirstUpper()-» |
| «ENDDEFINE» |
| |
| «DEFINE modelAccessGet(FeatureContext c) FOR Section-» |
| «IF c == null»getInput()«ELSE-» |
| «IF needsCast(deduceInputType(), c)-» |
| ((«c.selector.eContainingClass.name») «EXPAND modelAccessGet (c.chain)»)«ELSE-» |
| «EXPAND modelAccessGet(c.chain)-» |
| «ENDIF-» |
| «IF "EBoolean" == c.selector.eType.name».is«ELSE».get«ENDIF»«c.selector.name.toFirstUpper()»()«ENDIF-» |
| «ENDDEFINE» |
| |
| «DEFINE uiConditionGet FOR Action-» |
| «FOREACH widgets AS w SEPARATOR " && "»«IF kind.value == 1 || kind.value == 3»!«ENDIF»«w.fieldName()»«IF kind.value < 2».isVisible()«ELSE».isEnabled()«ENDIF»«ENDFOREACH-» |
| «ENDDEFINE» |
| |
| // Sorta hack for radiobuttons. Unless Action(kind=SELECTION) is introduced |
| «DEFINE uiConditionGet FOR Widget»«ERROR "abstract uiConditionGet FOR Widget"»«ENDDEFINE» |
| «DEFINE uiConditionGet FOR RadioButton»«fieldName()».getSelection()«ENDDEFINE» |
| |
| |
| «DEFINE modelConditionClause(Condition c) FOR Section»«ERROR "abstract modelConditionClause"»«ENDDEFINE» |
| |
| «DEFINE modelConditionClause(InstanceCondition c) FOR Section-» |
| «EXPAND modelAccessGet(c.accessor)» instanceof «c.type.name-» |
| «ENDDEFINE» |
| |
| «DEFINE modelConditionClause(EqualsCondition c) FOR Section-» |
| «EXPAND modelAccessGet(c.accessor)»«IF c.value != null» == «c.value»«ENDIF-» |
| «ENDDEFINE» |
| «DEFINE modelConditionClause(AndCondition c) FOR Section-» |
| «FOREACH c.conjuncts AS cj SEPARATOR " && "»«EXPAND modelConditionClause(cj)»«ENDFOREACH» |
| «ENDDEFINE» |
| |
| //uiConditionSet |
| «DEFINE ApplyAction FOR Action-» |
| «FOREACH widgets AS w»«w.fieldName()».«IF kind.value < 2»setVisible«ELSE»setEnabled«ENDIF»(«kind.value == 0 || kind.value == 2»); |
| «ENDFOREACH-» |
| «ENDDEFINE» |
| |
| «DEFINE RevertAction FOR Action-» |
| «FOREACH widgets AS w»«w.fieldName()».«IF kind.value < 2»setVisible«ELSE»setEnabled«ENDIF»(«kind.value == 1 || kind.value == 3»); |
| «ENDFOREACH-» |
| «ENDDEFINE» |
| |
| // |
| «DEFINE nullModelConditionClause(Section s) FOR Context»«ERROR "abstract nullModelConditionClause"»«ENDDEFINE» |
| «DEFINE nullModelConditionClause(Section s) FOR FeatureContext-» |
| «FOREACH wholeChain().select(x | mayBeNull(x)).typeSelect(FeatureContext) AS x SEPARATOR " && "»«EXPAND modelAccessGet(x) FOR s» != null«ENDFOREACH-» |
| «ENDDEFINE» |
| |
| |
| «DEFINE PopulateWidgets FOR Section-» |
| «FOREACH comboWidgets() AS wc-» |
| // TODO «wc.fieldName()».setItems(VALUES.toString().toArray()); |
| for (org.eclipse.emf.common.util.Enumerator e : «EXPAND enumComboModelClass FOR associatedBinding(wc)».VALUES) { |
| «wc.fieldName()».add(e.getName()); |
| } |
| «ENDFOREACH-» |
| «ENDDEFINE» |
| |
| «REM»FIXME: hack/quickfix - always assume combos are associated with eenum«ENDREM» |
| «DEFINE enumComboModelClass FOR Binding»«((FeatureContext) selector).selector.eType.name»«ENDDEFINE» |