| /* |
| * 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 Context; |
| |
| boolean isBoolean(Context context) : |
| false |
| ; |
| |
| boolean isBoolean(FeatureContext context) : |
| context.selector.eType.name == 'EBoolean' |
| ; |
| |
| boolean hasReferenceBasedCheckBoxes(Section s, Condition c) : |
| bindingsToRefresh(s,c).exists(b | !{b.widget}.typeSelect(CheckBox).isEmpty() && !isBoolean(b.selector)) |
| ; |
| |
| List[Binding] referenceBasedCheckBoxBindings(Section s, Condition c) : |
| bindingsToRefresh(s,c).select(b | !{b.widget}.typeSelect(CheckBox).isEmpty() && !isBoolean(b.selector)) |
| ; |
| |
| List[FeatureContext] getConditionAccessors(Section e) : |
| e.bindings.select(b | b.refreshCondition != null /*&& b.refreshCondition.accessor != null*/).refreshCondition.accessor.purgeDups() |
| ; |
| |
| boolean needsCast(EClass inputType, FeatureContext x) : |
| x.chain == null |
| ? !x.selector.eContainingClass.isSuperTypeOf(inputType) |
| : !x.selector.eContainingClass.isSuperTypeOf(((EReference) ((FeatureContext) x.chain).selector).eReferenceType) |
| ; |
| |
| // look for conditions that share model accessor with the binding of the widget |
| // - assume when binding's widget got changed, there's a need to trigger UI enablement actions |
| List[Action] dependantActions(Section s, Widget w) : |
| triggeredConditions(s, associatedBinding(s,w)).collect(c | triggeredActions(s,c)).flatten() |
| // FIXME replace with smth like: s.actions.select(a | !a.trigger.intersect(triggeredConditions).isEmpty()) |
| ; |
| |
| Binding associatedBinding(Section s, Widget w) : |
| s.bindings.select(b | b.widget == w).first() |
| ; |
| |
| List[Action] triggeredActions(Section s, Condition c) : |
| s.actions.select(a | a.trigger.contains(c)) |
| ; |
| |
| // |
| // XXX replace with EReference [0..*] from Binding to Condition |
| // for now, assume triggered condition share model accessor with binding |
| private List[Condition] triggeredConditions(Section s, Binding b) : |
| s.conditions.select(c | c.accessor == b.selector) |
| ; |
| |
| // |
| // next two are analogous to triggeredCondition |
| // but for radio buttons case, where few conditions may share the same accessor, |
| // so, need to tell actions that became activated from those that became deactivated |
| // NOTE, use of commitCondition is nothing but an attempt to figure out which |
| // condition is associated with the activated binding, perhaps, need to check |
| // refreshCondition also/besides. |
| List[Action] triggeredActions_activated(Section s, Binding b) : |
| //s.conditions.select(c | c.accessor == b.selector && b.commitCondition == c).actions |
| s.actions.select(a | a.trigger.exists(c | c.accessor == b.selector && b.commitCondition == c)) |
| ; |
| |
| List[Action] triggeredActions_deactivated(Section s, Binding b) : |
| //s.conditions.select(c | c.accessor == b.selector && b.commitCondition != c).actions |
| s.actions.select(a | a.trigger.exists(c | c.accessor == b.selector && b.commitCondition != c)) |
| ; |
| |
| List[Binding] triggeredBindingToRefreshBesidesTheOne(Section s, Binding b) : |
| let triggeredAndActivatedConditions = s.conditions.select(c | c.accessor == b.selector && b.commitCondition == c) |
| : s.bindings.select(v | v != b && triggeredAndActivatedConditions.contains(v.refreshCondition)) |
| ; |
| |
| |
| // XXX since we use this extension to perform refresh, do we really need to |
| // take commitCondition into account? |
| List[Binding] dependantBindings(Section s, Widget w) : |
| let activeBinding = associatedBinding(s,w) |
| : (let triggered = triggeredConditions(s, activeBinding) |
| : s.bindings.select(b | b != activeBinding && (triggered.contains(b.refreshCondition) || triggered.contains(b.commitCondition)))) |
| ; |
| |
| List[Binding] bindingsToRefresh(Section s, Condition c) : |
| s.bindings.select(b | b.refreshCondition == c) |
| ; |
| |
| // RadioButton in SWT doesn't deselect another active radiobutton |
| // in the composite on *programmatic* setSelection, hence |
| // need to manually deselect any leftover from previous input |
| boolean needsRadioButtonWorkaround(Section s, Condition c) : |
| bindingsToRefresh(s,c).exists(b | !{b.widget}.typeSelect(RadioButton).isEmpty()) |
| ; |
| |
| List[Binding] radioButtonToWorkaround(Section s, Condition c) : |
| bindingsToRefresh(s,c).select(b | !{b.widget}.typeSelect(RadioButton).isEmpty()) |
| ; |
| |
| |
| // looks for contexts that are being used by bindings and may be null. |
| // NOTE: context directly used by bindings as their accessors are EXCLUDED |
| // from the return list even if they may be null (they are assumed to get created |
| // on appropriate ViewToModel call (which makes success of the view-2-model assignment dependent |
| // on order of binding processing)). Consider the example of radiobutton associated with a EClass: |
| // if (myFlowLayoutRadio.isSelected()) { |
| // /*begin: code that should not get generated*/ |
| // if (getInput().getLayout() == null) {getInput().setLayout(new Layout());} |
| // /*end*/ |
| // getInput().setLayout(new FlowLayout()); |
| // } |
| List[Context] needsCreation(List[Binding] bindings) : |
| // TODO bindings.select(b | needsNullCheck(b.selector)).selector.chain.purgeDups().typeSelect(Context).wholeChain().flatten().toSet().without(bindings.selector).typeSelect(Context).select(x | mayBeNull(x)) |
| bindings.selector.select(x | needsNullCheck(x)).chain.purgeDups().typeSelect(Context).wholeChain().flatten().toSet().without(bindings.selector).typeSelect(Context).select(x | mayBeNull(x)) |
| ; |
| |
| |
| EClass deduceInputType(Section s) : |
| deduceCommon(s.input.typeSelect(FeatureContext).selector.eContainingClass) |
| ; |
| |
| // XXX actually, the code below is not tested and |
| // apparently is not really working as intended, and may |
| // easily get to situations with no answer though common superclass exists |
| // Just didn't get enough time to implement [Head|Tail] logic to implement |
| // pair-by-pair comparison |
| private EClass deduceCommon(List[EClass] classes) : |
| classes.toSet().size() == 1 ? |
| classes.first() : |
| (let supertypesOfTheRest = classes.select(c | classes.forAll(cc | c.isSuperTypeOf(cc))) |
| : supertypesOfTheRest.isEmpty() ? |
| (let supertypesOfNone = classes.select(c | classes.forAll(cc | cc != c && !c.isSuperTypeOf(cc))) |
| : supertypesOfNone.isEmpty() ? |
| deduceCommon(classes.eSuperTypes) : |
| deduceCommon(supertypesOfNone.eSuperTypes.union(classes.without(supertypesOfNone)).typeSelect(EClass)) |
| ) : |
| mostSpecific(supertypesOfTheRest) |
| ) |
| ; |
| |
| private EClass mostSpecific(List[EClass] classes) : |
| classes.size() == 1 |
| ? classes.first() |
| : classes.reject(c | classes.exists(cc | cc != c && c.isSuperTypeOf(cc))).first() |
| ; |