AspectAdaptor.st
author Claus Gittinger <cg@exept.de>
Sat, 27 Apr 1996 19:59:26 +0200
changeset 231 2fec6188bd28
parent 223 b65dc250db8d
child 238 a179b5d6152e
permissions -rw-r--r--
examples

"
 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.
"

ProtocolAdaptor subclass:#AspectAdaptor
	instanceVariableNames:'myAspect getMsg putMsg'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Support-Models'
!

!AspectAdaptor 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.
"
!

documentation
"
    an AspectAdaptor forwards updates and change messages
    from/to a complex model.

    Consider the case where editFields are required for the
    elements (instance variables) of a more complex model.
    Without an aspect adaptor, you needed to copy the individual
    values out-of and into multiple valueHolders.
    An aspectAdaptor makes this easier, by playing model with
    value/value: symbols towards the editField, and forwarding changes and
    updates to/from the complex model using different aspect symbols.

    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 
        describing the incompatibility verbal (i.e. no code) to the ST/X team.

    [author:]
        Claus Gittinger

    [see also:]
        ValueHolder Model
"
!

examples
"
    a dialog on a points x/y coordinates:
                                                                        [exBegin]
        |dialog data f|

        data := 0@0.

        dialog := DialogBox new.
        dialog addTextLabel:'x:'.
        f := dialog addInputFieldOn:(AspectAdaptor new
                                        subject:data; 
                                        accessWith:#x 
                                        assignWith:#x:).
        f converter:(PrintConverter new initForNumber).

        dialog addTextLabel:'y:'.
        f := dialog addInputFieldOn:(AspectAdaptor new
                                        subject:data; 
                                        forAspect:#y).
        f converter:(PrintConverter new initForNumber).

        dialog addOkButton.
        data inspect.
        dialog open.

        dialog accepted ifTrue:[
            Transcript showCr:'data now: ' , data printString
        ]
                                                                        [exEnd]


    a dialog on a four-field complex model:
                                                                        [exBegin]
        |dialog data dataModel|

        data := #('hello' 'one' 'two' 'three').
        dataModel := Plug new.
        dataModel respondTo:#field1 with:[data at:1].
        dataModel respondTo:#field2 with:[data at:2].
        dataModel respondTo:#field3 with:[data at:3].
        dataModel respondTo:#field4 with:[data at:4].
        dataModel respondTo:#field1: with:[:arg | data at:1 put:arg].
        dataModel respondTo:#field2: with:[:arg | data at:2 put:arg].
        dataModel respondTo:#field3: with:[:arg | data at:3 put:arg].
        dataModel respondTo:#field4: with:[:arg | data at:4 put:arg].

        dialog := DialogBox new.
        dialog addTextLabel:'1:'.
        dialog addInputFieldOn:(AspectAdaptor new
                                        subject:dataModel; 
                                        accessWith:#field1
                                        assignWith:#field1:). 
        dialog addTextLabel:'2:'.
        dialog addInputFieldOn:(AspectAdaptor new
                                        subject:dataModel; 
                                        forAspect:#field2).
        dialog addTextLabel:'3:'.
        dialog addInputFieldOn:(AspectAdaptor new
                                        subject:dataModel; 
                                        accessWith:#field3
                                        assignWith:#field3:
                                        aspect:#field3). 
        dialog addTextLabel:'4:'.
        dialog addInputFieldOn:(AspectAdaptor new
                                        subject:dataModel; 
                                        forAspect:#field4).
        dialog addOkButton.
        dataModel inspect.
        dialog open.
        dialog accepted ifTrue:[
            Transcript showCr:'data now: ' , data printString
        ]
                                                                        [exEnd]
"
! !

!AspectAdaptor class methodsFor:'instance creation'!

accessWith:getSelector assignWith:putSelector 
    "create and return an adaptor which uses getSelector to fetch a value
     and setSelector to change it."

    ^ (self new) accessWith:getSelector assignWith:putSelector
!

subject:anObject sendsUpdates:aBoolean accessWith:getSel assignWith:putSel aspect:aspect
    ^ (self subject:anObject sendsUpdates:aBoolean) 
		accessWith:getSel assignWith:putSel aspect:aspect
! !

!AspectAdaptor methodsFor:'accessing-spec'!

accessWith:getSelector assignWith:putSelector
    "setup the recevier to use getSelector to fetch a value
     and setSelector to change it."

    getMsg := getSelector.
    putMsg := putSelector
!

accessWith:getSelector assignWith:putSelector aspect:aspectSymbol
    "setup the recevier to use getSelector to fetch a value
     and setSelector to change it."

    getMsg := getSelector.
    putMsg := putSelector.
    myAspect := aspectSymbol
!

forAspect
    myAspect isNil ifTrue:[
	^ getMsg
    ].
    ^ myAspect
!

forAspect:aSelector
    getMsg := myAspect := aSelector.
    putMsg := (aSelector , ':') asSymbol.
! !

!AspectAdaptor methodsFor:'accessing-value'!

setValue:newValue
    |target oldValue|

    target := super value.
    oldValue := target perform:getMsg.
    oldValue ~~ newValue ifTrue:[
	target perform:putMsg with:newValue.
    ]
!

value
    "translate a query for my value from my user
     into an aspect access towards my subject"

    |target|

    target := super value.
    ^ target perform:getMsg
!

value:newValue
    |target oldValue|

    target := super value.
    oldValue := target perform:getMsg.
    oldValue ~~ newValue ifTrue:[
	target perform:putMsg with:newValue.
	subjectSendsUpdates ifFalse:[
	    self changed:#value
	]
    ]
! !

!AspectAdaptor methodsFor:'change & update'!

update:something with:aParameter from:changedObject
    "translate an update from the model into a #value-change
     via my depenedents ..."

    ((changedObject == subject)
    or:[changedObject == subjectChannel]) ifTrue:[
	something == self forAspect ifTrue:[
	    self changed:#value
	].
	^ self
    ].
! !

!AspectAdaptor class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libview2/AspectAdaptor.st,v 1.12 1996-04-27 17:58:52 cg Exp $'
! !