ProtocolAdaptor.st
changeset 69 225a9efd50f5
child 71 5b34cd877517
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ProtocolAdaptor.st	Tue May 09 02:23:22 1995 +0200
@@ -0,0 +1,282 @@
+'From Smalltalk/X, Version:2.10.5 on 9-may-1995 at 12:03:43 pm'!
+
+ValueModel subclass:#ProtocolAdaptor
+	 instanceVariableNames:'accessPath subject subjectChannel subjectSendsUpdates'
+	 classVariableNames:''
+	 poolDictionaries:''
+	 category:'Interface-Support'
+!
+
+!ProtocolAdaptor class methodsFor:'documentation'!
+
+copyright
+"
+ COPYRIGHT (c) 1995 by Claus Gittinger
+              All Rights Reserved
+
+ This software is furnished under a license and may be used
+ only in accordance with the terms of that license and with the
+ inclusion of the above copyright notice.   This software may not
+ be provided or otherwise made available to, or used by, any
+ other person.  No title to or ownership of the software is
+ hereby transferred.
+"
+!
+
+version
+"
+$Header: /cvs/stx/stx/libview2/ProtocolAdaptor.st,v 1.1 1995-05-09 00:21:52 claus Exp $
+"
+!
+
+documentation
+"
+    a ProtocolAdaptor allows access to embeded values in a
+    complex model and plays model towards the outside world.
+
+    Consider the case where editFields are required for the
+    elements (instance variables) of a more complex model.
+    Using ValueHolders, you had to copy the individual
+    values out-of and into multiple valueHolders.
+    A protocolAdaptor makes this easier, by playing model towards
+    the editField, returning a value from the complex model, 
+    and forwards changes to the complex model.
+
+    Notice: since you can specify the aspect- and changeSymbols in most ST/X
+    widgets, ProtocolAdapters are not always needed (at  least, if no access-
+    path is required). 
+    However, if you want to apply widgets on objects which where not originally 
+    designed as models (such as Arrays), ProtocolAdapters are very useful.
+
+    Notice: this class was implemented using protocol information
+    from alpha testers - it may not be complete or compatible to
+    the corresponding ST-80 class. If you encounter any incompatibilities,
+    please forward a note to the ST/X team.
+"
+!
+
+examples 
+"
+	|a obj|
+
+	a := ProtocolAdaptor accessPath:#(1 2 3).
+	obj := Array with:#(11 (121 122 123) 13)
+		     with:#(21 (221 222 223) 23)
+		     with:#(33 (321 322 323) 33).
+	a valueUsingSubject:obj  
+
+
+
+	|a obj|
+
+	a := ProtocolAdaptor accessPath:#(1 2 origin).
+	obj := Array with:(Array with:1@1 with:(1@2 corner:100@100))
+		     with:(Array with:2@1 with:2@2)
+		     with:(Array with:3@1 with:3@2).
+	a valueUsingSubject:obj  
+
+
+
+	|a model|
+
+	a := ProtocolAdaptor accessPath:#(1 2 origin).
+	model := (Array with:(Array with:1@1 with:(1@2 corner:100@100))
+		     with:(Array with:2@1 with:2@2)
+		     with:(Array with:3@1 with:3@2)) asValue.
+	a subjectChannel:model.
+	a value   
+"
+! !
+
+!ProtocolAdaptor class methodsFor:'instance creation'!
+
+accessPath:aCollectionOfSelectors
+    ^ (self new) accessPath:aCollectionOfSelectors
+!
+
+subject:anObject
+    ^ (self new) subject:anObject
+!
+
+subject:anObject sendsUpdates:aBoolean
+    ^ (self new) subject:anObject; sendsUpdates:aBoolean
+!
+
+subject:anObject accessPath:aCollectionOfSelectors
+    ^ (self new) subject:anObject; accessPath:aCollectionOfSelectors
+!
+
+subject:anObject sendsUpdates:aBoolean accessPath:aCollectionOfSelectors
+    ^ (self new) subject:anObject; sendsUpdates:aBoolean; accessPath:aCollectionOfSelectors
+!
+
+subjectChannel:aValueHolder
+    ^ (self new) subjectChannel:aValueHolder
+!
+
+subjectChannel:aValueHolder sendsUpdates:aBoolean 
+    ^ (self new) subjectChannel:aValueHolder; sendsUpdates:aBoolean
+!
+
+subjectChannel:aValueHolder accessPath:aCollectionOfSelectors
+    ^ (self new) subjectChannel:aValueHolder; accessPath:aCollectionOfSelectors
+!
+
+subjectChannel:aValueHolder sendsUpdates:aBoolean accessPath:aCollectionOfSelectors
+    ^ (self new) subjectChannel:aValueHolder; sendsUpdates:aBoolean; accessPath:aCollectionOfSelectors
+! !
+
+!ProtocolAdaptor methodsFor:'accessing'!
+
+setValue:newValue usingSubject:anObject
+    "set a value in anObject, using the selectors in accessPath.
+     A helper for setValue:."
+
+    |obj lastIndex|
+
+    obj := anObject.
+    lastIndex := accessPath size.
+    accessPath keysAndValuesDo:[:idx :aSelectorOrIndex |
+	aSelectorOrIndex isInteger ifTrue:[
+	    idx == lastIndex ifTrue:[
+		obj at:aSelectorOrIndex put:newValue
+	    ] ifFalse:[
+		obj := obj at:aSelectorOrIndex
+	    ]
+	] ifFalse:[
+	    idx == lastIndex ifTrue:[
+		obj perform:(aSelectorOrIndex , ':') asSymbol with:newValue
+	    ] ifFalse:[
+		obj := obj perform:aSelectorOrIndex
+	    ]
+	]
+    ].
+    ^ newValue
+!
+
+valueUsingSubject:anObject
+    "return the value from anObject, using the selectors in accessPath.
+     A helper for value."
+
+    |obj|
+
+    obj := anObject.
+    accessPath notNil ifTrue:[
+	accessPath do:[:aSelectorOrIndex |
+	    aSelectorOrIndex isInteger ifTrue:[
+		obj := obj at:aSelectorOrIndex
+	    ] ifFalse:[
+		obj := obj perform:aSelectorOrIndex
+	    ]
+	].
+    ].
+    ^ obj
+!
+
+value
+    "return the value from my subject or subjectChannel."
+
+    |obj|
+
+    subject notNil ifTrue:[
+	obj := subject.
+    ] ifFalse:[
+	obj := subjectChannel value
+    ].
+    ^ self valueUsingSubject:obj
+!
+
+setValue:newValue
+    "set the value in my subject or subjectChannel."
+
+    |obj|
+
+    subject notNil ifTrue:[
+	obj := subject.
+    ] ifFalse:[
+	obj := subjectChannel value
+    ].
+    ^ self setValue:newValue usingSubject:obj
+! !
+
+!ProtocolAdaptor methodsFor:'change notification'!
+
+notifyChange
+    subjectSendsUpdates ifFalse:[
+        super notifyChange:#value
+    ]
+! !
+
+!ProtocolAdaptor methodsFor:'initialization'!
+
+initialize
+    super initialize.
+    subjectSendsUpdates := false. 
+! !
+
+!ProtocolAdaptor methodsFor:'change & update'!
+
+update:something with:aPArameter from:changedObject
+    "translate updates from my subject into value-changes towards
+     my dependents. Since I have no specific aspect, every change is forwarded"
+
+    (changedObject == subject
+    or:[changedObject == subjectChannel]) ifTrue:[
+	self changed:#value.
+	^ self
+    ].
+! !
+
+!ProtocolAdaptor methodsFor:'accessing-spec'!
+
+subjectSendsUpdates
+    "return true, if the subject sends updates itself
+     If true, the receiver will not send updates on changes"
+
+    ^ subjectSendsUpdates
+!
+
+subjectSendsUpdates:aBoolean
+    "set/clear the flag which states if the subject sends updates itself.
+     If true, the receiver will not send updates on changes"
+
+    subjectSendsUpdates := aBoolean.
+!
+
+subjectChannel:aValueHolder
+    |oldChannel|
+
+    oldChannel := subjectChannel.
+    subjectChannel := aValueHolder.
+    oldChannel notNil ifTrue:[
+	self changed:#value.
+    ].
+!
+
+subjectChannel
+    ^ subjectChannel
+!
+
+subject:anObject
+    subject notNil ifTrue:[
+	subject removeDependent:self
+    ].
+    subject := anObject.
+    self changed:#value.
+    subject notNil ifTrue:[
+	subject addDependent:self
+    ].
+!
+
+subject
+    ^ subject
+!
+
+accessPath:aCollectionOfSelectors
+    accessPath := aCollectionOfSelectors
+!
+
+accessPath
+    ^ accessPath
+! !
+