#FEATURE by cg
authorClaus Gittinger <cg@exept.de>
Wed, 28 Mar 2018 14:43:32 +0200
changeset 4079 294c4b32e0d0
parent 4078 27d0bc272f2e
child 4080 90b625be9e29
#FEATURE by cg class: Model mechanism to suppress updates added: #isLocked #withUpdatesLockedDo: #withoutSendingUpdatesDo: changed: #withoutUpdatingDo: class: Model::ModelUpdateLockedQuery class definition added: #defaultResumeValue class: Model::ModelUpdateLockedQuery class added: #answer:for:do: #documentation #example #isLocked:
Model.st
--- a/Model.st	Tue Mar 27 20:11:44 2018 +0200
+++ b/Model.st	Wed Mar 28 14:43:32 2018 +0200
@@ -20,6 +20,13 @@
 	category:'Interface-Support-Models'
 !
 
+Query subclass:#ModelUpdateLockedQuery
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:Model
+!
+
 !Model class methodsFor:'documentation'!
 
 copyright
@@ -289,6 +296,128 @@
     "Created: 19.4.1996 / 12:19:40 / cg"
 ! !
 
+!Model methodsFor:'suppressing updates'!
+
+isLocked
+    "ask the updateLocked query."
+
+    ^ ModelUpdateLockedQuery isLocked:self
+!
+
+withUpdatesLockedDo:aBlock
+    "execute aBlock with updates to myself temporarily suppressed,
+     (i.e. by answering true to the updateLocked query)
+     This is a cooperative interface - i.e. possible updaters MUST
+     check me via isLocked, before sending #value"
+
+    ModelUpdateLockedQuery answer:true for:self do:aBlock
+!
+
+withoutSendingUpdatesDo:aBlock
+    "execute aBlock with updates to dependents temporarily suppressed
+     (i.e. I will not notify the dependents during aBlock)
+     Warning: 
+        do not change any dependencies inside the block,
+        as the original dependencies from before will be restored and such changes
+        are lost then."
+
+    |previousDependents|
+
+    [
+        previousDependents := dependents.
+        dependents := nil.
+        aBlock value
+    ] ensure:[
+        dependents := previousDependents
+    ].
+! !
+
+!Model::ModelUpdateLockedQuery class methodsFor:'documentation'!
+
+documentation
+"
+    this query can answer true (ie. ''isLocked'') for a particular model,
+    while inside a updating block.
+
+    This is used for temporal blocking models to be changed
+    (eg. to prevent cyclic updates).
+
+    A particular application of this is found in input-field + tree selection
+    combinations, where entering a new value into the field changes the treeselection,
+    and also tree selection changes the input field's value.
+    Concrete: take a look at the XMLInspector's xpath field, which triggers a tree
+    selection change, but the selection change should not backfire on the field in this
+    case, whereas a regular tree-selection will change the field.
+
+    Notice:
+        do NOT place the query into the general value: method of Model.
+        This is too expensive to be done every time.
+        Thus, the related models need to know about the interlocking and
+        must do this individually.
+
+    see example
+
+    [author:]
+        cg
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+!
+
+example
+"
+    |vh1 vh2|
+
+    vh1 := ValueHolder new.
+    vh1 onChangeEvaluate:[
+        (vh2 isLocked) ifFalse:[
+            vh2 value: #newValue 
+        ].
+    ].
+
+    vh2 := ValueHolder new.
+    vh2 value:#oldValue.
+
+    vh2 withUpdatesLockedDo:[
+        vh1 value:123.
+    ].
+
+    because of the lock, the old value should still be there'.
+    self assert:(vh2 value == #oldValue)
+"
+! !
+
+!Model::ModelUpdateLockedQuery class methodsFor:'handling'!
+
+answer:aBoolean for:aModel do:aBlock
+    "evaluate aBlock, answering aBoolean if asked for the locking status of aModel"
+
+    aBlock
+        on:self 
+        do:[:ex |
+            ex proceedWith:(ex parameter == aModel)
+        ]
+! !
+
+!Model::ModelUpdateLockedQuery class methodsFor:'queries'!
+
+isLocked:aModel
+    "asking for the locking status of aModel"
+
+    ^ self raiseRequestWith:aModel
+! !
+
+!Model::ModelUpdateLockedQuery methodsFor:'defaults'!
+
+defaultResumeValue
+    ^ false
+! !
+
 !Model class methodsFor:'documentation'!
 
 version