blob: 0904bb72d188df944f3508b9463133ae3acc8966 [file] [log] [blame]
/*
* 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()
;