#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:
--- 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