[Pharo-project] Preference refactoring again
Hi all, joined Zoo package is a attempt to translate in code what we discussed here before about preference refactoring. The framework is made of 3 classes: PreferenceCollector, PreferenceDefinition and PreferenceValue. In Zoo there are also 2 classes for testing: PrefProvider and PrefChangeListener. PrefProvider class declares some preferences and PrefChangeListener is here to test preference change notification. PrefChangeListener>>initialize super initialize. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientLook: PrefChangeListener class>>test "self test" PrefChangeListener new inspect. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. From PreferenceCollector comment: -------------------------------------- A PreferenceCollector automatically collects all preferences. A preference is represented by a PreferenceDefinition. All PreferenceDefinition are stored in the preferences instance variable. Instance Variables preferences: OrderedCollection of PreferenceDefinition preferences - contains all PreferenceDefinition which are automatically built from pragma found in preference getters ADDING A PREFERENCE PreferenceCollector makes use of the SystemChangeNotifier in order to automate the adding, the removing and the updating of preferences. See #PreferenceCollector>>event: to see how preferences update is implemented. Editing a new method with a preference pragma or inserting a preference pragma in an existing method are the two ways for preference definition adding. The only way to remove a preference definition is to remove the corresponding method. Example of a "blackAndWhite" preference. Methods below are defined by the preference provider APreferencePrivider class. Note that the value stored in BlackAndWhite class variable is an instance of PreferenceValue. In this example, the default value is directly given with the pragma: ------------- APreferencePrivider class>>blackAndWhite <preference: 'Use black and white' type: #Boolean set: #blackAndWhite: defaultValue: false description: 'Use black and white'> ^ BlackAndWhite ifNil: [BlackAndWhite := PreferenceValue value: false location: self selector: #blackAndWhite] APreferencePrivider class>>blackAndWhite: aBoolean self blackAndWhite value: aBoolean ------------- If a default value can't be specified in the pragma, another way consists in using a selector which represents the message to send to the class in order to get the default value: ------------- APreferencePrivider class>>standardFont <preference: 'The default system font' type: #LogicalFont set: #standardFont: default: #defaultStandardFont description: 'The default system font'> ^ StandardFont ifNil: [StandardFont := PreferenceValue value: self defaultStandardFont location: self selector: #standardFont] APreferencePrivider class>>standardFont: aFont self standardFont value: aFont APreferencePrivider class>>defaultStandardFont ^ LogicalFont familyName: 'Arial' fallbackFamilyNames: nil pointSize: 12 stretchValue: 5 weightValue: 400 slantValue: 0 ------------- LISTENING TO A PREFERENCE VALUE CHANGE Any object can register itself as a preference value change listener. See #PreferenceCollector class>>whenChanged: inClass:notify:using:. Each time a preference value is changed, #preference: inClass:changedWith: is sent to the PreferenceCollector class. Example of code a listener can implement in order to be notified each time a gradientButtonLook preference defined by a PrefProvider class is changed. In this example, the listener ask to be notified by a send of #gradientButtonLookIsNow: message. The argument given to gradientButtonLookIsNow: is the new preference value. ------------- .... PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow:. .... ------------- What do you think ? cheers Alain
sounds cool. For me the most important aspect is that preferenceCollector (our current preference class should be a removable layer on top of the system that are declaring preference. Is is correct that PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . means that PrefProvider will receive the message gradientButtonLookIsNow: This way we can push preference to the tools and thety do not have to query the information in the Collector at run-time (hence we could remove Preference and have a more OO design). Sorry not to reply earlier (I was breaking yet another wall in our "kitchen") Stef On Mar 1, 2009, at 10:05 AM, Alain Plantec wrote:
Hi all,
joined Zoo package is a attempt to translate in code what we discussed here before about preference refactoring.
The framework is made of 3 classes: PreferenceCollector, PreferenceDefinition and PreferenceValue. In Zoo there are also 2 classes for testing: PrefProvider and PrefChangeListener. PrefProvider class declares some preferences and PrefChangeListener is here to test preference change notification.
PrefChangeListener>>initialize super initialize. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientLook:
PrefChangeListener class>>test "self test" PrefChangeListener new inspect. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not.
From PreferenceCollector comment: -------------------------------------- A PreferenceCollector automatically collects all preferences. A preference is represented by a PreferenceDefinition. All PreferenceDefinition are stored in the preferences instance variable.
Instance Variables preferences: OrderedCollection of PreferenceDefinition
preferences - contains all PreferenceDefinition which are automatically built from pragma found in preference getters
ADDING A PREFERENCE PreferenceCollector makes use of the SystemChangeNotifier in order to automate the adding, the removing and the updating of preferences. See #PreferenceCollector>>event: to see how preferences update is implemented.
Editing a new method with a preference pragma or inserting a preference pragma in an existing method are the two ways for preference definition adding. The only way to remove a preference definition is to remove the corresponding method.
Example of a "blackAndWhite" preference. Methods below are defined by the preference provider APreferencePrivider class. Note that the value stored in BlackAndWhite class variable is an instance of PreferenceValue. In this example, the default value is directly given with the pragma: ------------- APreferencePrivider class>>blackAndWhite <preference: 'Use black and white' type: #Boolean set: #blackAndWhite: defaultValue: false description: 'Use black and white'> ^ BlackAndWhite ifNil: [BlackAndWhite := PreferenceValue value: false location: self selector: #blackAndWhite]
APreferencePrivider class>>blackAndWhite: aBoolean self blackAndWhite value: aBoolean -------------
If a default value can't be specified in the pragma, another way consists in using a selector which represents the message to send to the class in order to get the default value:
------------- APreferencePrivider class>>standardFont <preference: 'The default system font' type: #LogicalFont set: #standardFont: default: #defaultStandardFont description: 'The default system font'> ^ StandardFont ifNil: [StandardFont := PreferenceValue value: self defaultStandardFont location: self selector: #standardFont]
APreferencePrivider class>>standardFont: aFont self standardFont value: aFont APreferencePrivider class>>defaultStandardFont ^ LogicalFont familyName: 'Arial' fallbackFamilyNames: nil pointSize: 12 stretchValue: 5 weightValue: 400 slantValue: 0 -------------
LISTENING TO A PREFERENCE VALUE CHANGE Any object can register itself as a preference value change listener. See #PreferenceCollector class>>whenChanged: inClass:notify:using:.
Each time a preference value is changed, #preference: inClass:changedWith: is sent to the PreferenceCollector class.
Example of code a listener can implement in order to be notified each time a gradientButtonLook preference defined by a PrefProvider class is changed. In this example, the listener ask to be notified by a send of #gradientButtonLookIsNow: message. The argument given to gradientButtonLookIsNow: is the new preference value. ------------- .... PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow:. .... -------------
What do you think ?
cheers Alain
<Zoo-alain_plantec. 10.mcz>_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Stéphane Ducasse a écrit :
sounds cool. For me the most important aspect is that preferenceCollector (our current preference class should be a removable layer on top of the system that are declaring preference.
Is is correct that
PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: .
means that PrefProvider will receive the message gradientButtonLookIsNow: no, but see the code below:
PrefListener>>initialize super initialize. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . ----------- it means that a PrefListener instance will receive the #gradientButtonLookIsNow: message each time the preference #gradientButtonLook defined in class PrefProvider is changed. PrefListener and PrefProvider represent can be any class in the system. So, in order to read a preference value an object get it from the provider class by message sending, the provider is a class in a package which defines preferences (no need for PreferenceCollector to get the preference value).
This way we can push preference to the tools
yes
and thety do not have to query the information in the Collector at run-time yes, Each package have its own preference set in it represented by a set of methods with pragma. When such a package is loaded, its preferences are automatically stored by PreferenceCollector. When a package is removed, its preferences are automatically removed from PreferenceCollector. PreferenceCollector is only here for supporting tools (cool UI ...) and for change notifications.
(hence we could remove Preference and have a more OO design). I guess yes.
Sorry not to reply earlier (I was breaking yet another wall in our "kitchen") bon courage :)
alain
Stef
On Mar 1, 2009, at 10:05 AM, Alain Plantec wrote:
Hi all,
joined Zoo package is a attempt to translate in code what we discussed here before about preference refactoring.
The framework is made of 3 classes: PreferenceCollector, PreferenceDefinition and PreferenceValue. In Zoo there are also 2 classes for testing: PrefProvider and PrefChangeListener. PrefProvider class declares some preferences and PrefChangeListener is here to test preference change notification.
PrefChangeListener>>initialize super initialize. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientLook:
PrefChangeListener class>>test "self test" PrefChangeListener new inspect. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not.
From PreferenceCollector comment: -------------------------------------- A PreferenceCollector automatically collects all preferences. A preference is represented by a PreferenceDefinition. All PreferenceDefinition are stored in the preferences instance variable.
Instance Variables preferences: OrderedCollection of PreferenceDefinition
preferences - contains all PreferenceDefinition which are automatically built from pragma found in preference getters
ADDING A PREFERENCE PreferenceCollector makes use of the SystemChangeNotifier in order to automate the adding, the removing and the updating of preferences. See #PreferenceCollector>>event: to see how preferences update is implemented.
Editing a new method with a preference pragma or inserting a preference pragma in an existing method are the two ways for preference definition adding. The only way to remove a preference definition is to remove the corresponding method.
Example of a "blackAndWhite" preference. Methods below are defined by the preference provider APreferencePrivider class. Note that the value stored in BlackAndWhite class variable is an instance of PreferenceValue. In this example, the default value is directly given with the pragma: ------------- APreferencePrivider class>>blackAndWhite <preference: 'Use black and white' type: #Boolean set: #blackAndWhite: defaultValue: false description: 'Use black and white'> ^ BlackAndWhite ifNil: [BlackAndWhite := PreferenceValue value: false location: self selector: #blackAndWhite]
APreferencePrivider class>>blackAndWhite: aBoolean self blackAndWhite value: aBoolean -------------
If a default value can't be specified in the pragma, another way consists in using a selector which represents the message to send to the class in order to get the default value:
------------- APreferencePrivider class>>standardFont <preference: 'The default system font' type: #LogicalFont set: #standardFont: default: #defaultStandardFont description: 'The default system font'> ^ StandardFont ifNil: [StandardFont := PreferenceValue value: self defaultStandardFont location: self selector: #standardFont]
APreferencePrivider class>>standardFont: aFont self standardFont value: aFont APreferencePrivider class>>defaultStandardFont ^ LogicalFont familyName: 'Arial' fallbackFamilyNames: nil pointSize: 12 stretchValue: 5 weightValue: 400 slantValue: 0 -------------
LISTENING TO A PREFERENCE VALUE CHANGE Any object can register itself as a preference value change listener. See #PreferenceCollector class>>whenChanged: inClass:notify:using:.
Each time a preference value is changed, #preference: inClass:changedWith: is sent to the PreferenceCollector class.
Example of code a listener can implement in order to be notified each time a gradientButtonLook preference defined by a PrefProvider class is changed. In this example, the listener ask to be notified by a send of #gradientButtonLookIsNow: message. The argument given to gradientButtonLookIsNow: is the new preference value. ------------- .... PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow:. .... -------------
What do you think ?
cheers Alain
<Zoo-alain_plantec.10.mcz>_______________________________________________
Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Stéphane your previous question makes me think of a better solution with requires only one mandatory class and which makes use of standard event notification (without PreferenceCollector). I've joined 4 packages : - PrefCore contains PreferenceValue which is now the only mandatory class. 2 packages for testing: - PrefProvider contains PrefProvider class which declares some preferences - PrefUser contains PrefChangeListener (try PrefChangeListener test). 1 package for UI: - PrefTool contains PreferenceCollector and PreferenceDefinition. They are optional. Code below do not makes use of PreferenceCollector anymore: PrefChangeListener>>initialize super initialize. gradientLook := PrefProvider gradientButtonLook value. "reading of the preference value" "Using of standard event notification engine" PrefProvider when: #gradientButtonLook send: #gradientButtonLookIsNow: to: self. PrefProvider when: #gradientButtonLook send: #gradientLook: to: self. Now, the preference system only need PreferenceValue. PreferenceCollector and PreferenceDefinition are optional and can be brought by a preference supporting tool (UI). Previous version implied a dependency from PrefChangeListener to PreferenceCollector which was bad. PrefChangeListener>>initialize super initialize. gradientLook := PrefProvider gradientButtonLook value. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientLook: alain Stéphane Ducasse a écrit :
sounds cool. For me the most important aspect is that preferenceCollector (our current preference class should be a removable layer on top of the system that are declaring preference.
Is is correct that
PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: .
means that PrefProvider will receive the message gradientButtonLookIsNow:
no, but see the code below: ----------- PrefListener>>initialize super initialize. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . ----------- it means that a PrefListener instance will receive the #gradientButtonLookIsNow: message each time the preference #gradientButtonLook defined in class PrefProvider is changed. PrefListener and PrefProvider represent can be any class in the system. So, in order to read a preference value an object get it from the provider class by message sending, the provider is a class in a package which defines preferences (no need for PreferenceCollector to get the preference value).
This way we can push preference to the tools
yes
and thety do not have to query the information in the Collector at run-time
yes, Each package have its own preference set in it represented by a set of methods with pragma. When such a package is loaded, its preferences are automatically stored by PreferenceCollector. When a package is removed, its preferences are automatically removed from PreferenceCollector. PreferenceCollector is only here for supporting tools (cool UI ...) and for change notifications.
(hence we could remove Preference and have a more OO design).
I guess yes.
Sorry not to reply earlier (I was breaking yet another wall in our "kitchen")
bon courage :) alain
Stef
On Mar 1, 2009, at 10:05 AM, Alain Plantec wrote:
Hi all,
joined Zoo package is a attempt to translate in code what we discussed here before about preference refactoring.
The framework is made of 3 classes: PreferenceCollector, PreferenceDefinition and PreferenceValue. In Zoo there are also 2 classes for testing: PrefProvider and PrefChangeListener. PrefProvider class declares some preferences and PrefChangeListener is here to test preference change notification.
PrefChangeListener>>initialize super initialize. PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow: . PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientLook:
PrefChangeListener class>>test "self test" PrefChangeListener new inspect. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not. PrefProvider gradientButtonLook: PrefProvider gradientButtonLook value not.
From PreferenceCollector comment: -------------------------------------- A PreferenceCollector automatically collects all preferences. A preference is represented by a PreferenceDefinition. All PreferenceDefinition are stored in the preferences instance variable.
Instance Variables preferences: OrderedCollection of PreferenceDefinition
preferences - contains all PreferenceDefinition which are automatically built from pragma found in preference getters
ADDING A PREFERENCE PreferenceCollector makes use of the SystemChangeNotifier in order to automate the adding, the removing and the updating of preferences. See #PreferenceCollector>>event: to see how preferences update is implemented.
Editing a new method with a preference pragma or inserting a preference pragma in an existing method are the two ways for preference definition adding. The only way to remove a preference definition is to remove the corresponding method.
Example of a "blackAndWhite" preference. Methods below are defined by the preference provider APreferencePrivider class. Note that the value stored in BlackAndWhite class variable is an instance of PreferenceValue. In this example, the default value is directly given with the pragma: ------------- APreferencePrivider class>>blackAndWhite <preference: 'Use black and white' type: #Boolean set: #blackAndWhite: defaultValue: false description: 'Use black and white'> ^ BlackAndWhite ifNil: [BlackAndWhite := PreferenceValue value: false location: self selector: #blackAndWhite]
APreferencePrivider class>>blackAndWhite: aBoolean self blackAndWhite value: aBoolean -------------
If a default value can't be specified in the pragma, another way consists in using a selector which represents the message to send to the class in order to get the default value:
------------- APreferencePrivider class>>standardFont <preference: 'The default system font' type: #LogicalFont set: #standardFont: default: #defaultStandardFont description: 'The default system font'> ^ StandardFont ifNil: [StandardFont := PreferenceValue value: self defaultStandardFont location: self selector: #standardFont]
APreferencePrivider class>>standardFont: aFont self standardFont value: aFont APreferencePrivider class>>defaultStandardFont ^ LogicalFont familyName: 'Arial' fallbackFamilyNames: nil pointSize: 12 stretchValue: 5 weightValue: 400 slantValue: 0 -------------
LISTENING TO A PREFERENCE VALUE CHANGE Any object can register itself as a preference value change listener. See #PreferenceCollector class>>whenChanged: inClass:notify:using:.
Each time a preference value is changed, #preference: inClass:changedWith: is sent to the PreferenceCollector class.
Example of code a listener can implement in order to be notified each time a gradientButtonLook preference defined by a PrefProvider class is changed. In this example, the listener ask to be notified by a send of #gradientButtonLookIsNow: message. The argument given to gradientButtonLookIsNow: is the new preference value. ------------- .... PreferenceCollector whenChanged: #gradientButtonLook inClass: PrefProvider notify: self using: #gradientButtonLookIsNow:. .... -------------
What do you think ?
cheers Alain
<Zoo-alain_plantec.10.mcz>_______________________________________________
Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project alain
Hi Alain, this sounds very interesting. I have never been a big fan of the current "Preference Browser". I am now trying to grasp (still learning here) how this new "Pharo Preference Mechanism" works. It would be great if the mechanism could be explained in detail in something like the new Pharo By Example manual :) Alain Plantec wrote:
I've joined 4 packages : - PrefCore contains PreferenceValue which is now the only mandatory class.
2 packages for testing: - PrefProvider contains PrefProvider class which declares some preferences - PrefUser contains PrefChangeListener (try PrefChangeListener test).
1 package for UI: - PrefTool contains PreferenceCollector and PreferenceDefinition. They are optional.
-- View this message in context: http://n2.nabble.com/Preference-refactoring-again-tp2403814p2407403.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
On Mar 2, 2009, at 4:44 AM, Geert wrote:
Hi Alain, this sounds very interesting. I have never been a big fan of the current "Preference Browser". I am now trying to grasp (still learning here) how this new "Pharo Preference Mechanism" works. It would be great if the mechanism could be explained in detail in something like the new Pharo By Example manual :)
this is a great idea. if it is adopted I will write it.
Alain Plantec wrote:
I've joined 4 packages : - PrefCore contains PreferenceValue which is now the only mandatory class.
2 packages for testing: - PrefProvider contains PrefProvider class which declares some preferences - PrefUser contains PrefChangeListener (try PrefChangeListener test).
1 package for UI: - PrefTool contains PreferenceCollector and PreferenceDefinition. They are optional.
-- View this message in context: http://n2.nabble.com/Preference-refactoring-again-tp2403814p2407403.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Geert a écrit :
Hi Alain, this sounds very interesting. thanks I have never been a big fan of the current "Preference Browser". The main problem with current preference system is that it makes uses of globals (declared in the class side of Preferences) and that a lot of packages depend on it. The main goal of the refactoring is to make preferences local to the packages in which they are declared. Current preference browser is not that bad and could be reused. I am now trying to grasp (still learning here) how this new "Pharo Preference Mechanism" works.It would be great if the mechanism could be explained in detail in something like the new Pharo By Example manual :)
Each preference is stored by a PreferenceValue instance and each time a PreferenceValue is updated (with a #value: message sent) an event is sent to the class which defines the preference. The event sending is standard: PreferenceValue>>value: anObject realValue ~= anObject ifTrue: [realValue := anObject. location triggerEvent: selector with: anObject] realValue is the instance variable wich stores current preference value. location is the class which declares the preference selector is the selector of the preference (i.e. #gradientButtonLook) So my proposition is to declare a preference locally. Let's take the example of freetype monitorTypeLCD preference. If we implement it the way it is now, as a boolean, it could be: --------------- FreeTypeSettings class>>monitorTypeLCD <preference: 'LCD monitor type' type: #Boolean set: #monitorTypeLCD: defaultValue: false description: 'Use of a LCD...'> ^ MonitorTypeLCD ifNil: [MonitorTypeLCD := PreferenceValue value: false location: self selector: #monitorTypeLCD] FreeTypeSettings class>>monitorTypeLCD: aBoolean self monitorTypeLCD value: hintingFull FreeTypeSettings class>>initialize FreeTypeSettings when: #monitorTypeLCD send: #monitorTypeLCDPreferenceChanged: to: self. FreeTypeSettings class>>monitorTypeLCDPreferenceChanged: aBoolean self current monitorTypeLCDPreferenceChanged: aBoolean ------------- The pragma you see in FreeTypeSettings class>>monitorTypeLCD in only here for UI tools such as PreferenceBrowser. If a client object needs monitorTypeLCD value, it asks directly to its provider which is FreeTypeSettings class: ... useLCD := FreeTypeSettings monitorTypeLCD value. ... but note that such a preference should be set as a choice between two values #LCD or #CRT... hope things are a little bit clearer now. alain
Alain Plantec wrote:
I've joined 4 packages : - PrefCore contains PreferenceValue which is now the only mandatory class.
2 packages for testing: - PrefProvider contains PrefProvider class which declares some preferences - PrefUser contains PrefChangeListener (try PrefChangeListener test).
1 package for UI: - PrefTool contains PreferenceCollector and PreferenceDefinition. They are optional.
Looks good. Is there really a need for a PreferenceValue class though? I'm concerned that the getter returns a different kind of object to that expected by the setter... For any preference tool the presence of the pragma is sufficient to get/set the native value and, assuming always class-side, support event triggering for changes. Regards, Gary ----- Original Message ----- From: "Alain Plantec" <alain.plantec@free.fr> To: <Pharo-project@lists.gforge.inria.fr> Sent: Monday, March 02, 2009 8:41 AM Subject: Re: [Pharo-project] Preference refactoring again Geert a écrit :
Hi Alain, this sounds very interesting. thanks I have never been a big fan of the current "Preference Browser". The main problem with current preference system is that it makes uses of globals (declared in the class side of Preferences) and that a lot of packages depend on it. The main goal of the refactoring is to make preferences local to the packages in which they are declared. Current preference browser is not that bad and could be reused. I am now trying to grasp (still learning here) how this new "Pharo Preference Mechanism" works.It would be great if the mechanism could be explained in detail in something like the new Pharo By Example manual :)
Each preference is stored by a PreferenceValue instance and each time a PreferenceValue is updated (with a #value: message sent) an event is sent to the class which defines the preference. The event sending is standard: PreferenceValue>>value: anObject realValue ~= anObject ifTrue: [realValue := anObject. location triggerEvent: selector with: anObject] realValue is the instance variable wich stores current preference value. location is the class which declares the preference selector is the selector of the preference (i.e. #gradientButtonLook) So my proposition is to declare a preference locally. Let's take the example of freetype monitorTypeLCD preference. If we implement it the way it is now, as a boolean, it could be: --------------- FreeTypeSettings class>>monitorTypeLCD <preference: 'LCD monitor type' type: #Boolean set: #monitorTypeLCD: defaultValue: false description: 'Use of a LCD...'> ^ MonitorTypeLCD ifNil: [MonitorTypeLCD := PreferenceValue value: false location: self selector: #monitorTypeLCD] FreeTypeSettings class>>monitorTypeLCD: aBoolean self monitorTypeLCD value: hintingFull FreeTypeSettings class>>initialize FreeTypeSettings when: #monitorTypeLCD send: #monitorTypeLCDPreferenceChanged: to: self. FreeTypeSettings class>>monitorTypeLCDPreferenceChanged: aBoolean self current monitorTypeLCDPreferenceChanged: aBoolean ------------- The pragma you see in FreeTypeSettings class>>monitorTypeLCD in only here for UI tools such as PreferenceBrowser. If a client object needs monitorTypeLCD value, it asks directly to its provider which is FreeTypeSettings class: ... useLCD := FreeTypeSettings monitorTypeLCD value. ... but note that such a preference should be set as a choice between two values #LCD or #CRT... hope things are a little bit clearer now. alain
Alain Plantec wrote:
I've joined 4 packages : - PrefCore contains PreferenceValue which is now the only mandatory class.
2 packages for testing: - PrefProvider contains PrefProvider class which declares some preferences - PrefUser contains PrefChangeListener (try PrefChangeListener test).
1 package for UI: - PrefTool contains PreferenceCollector and PreferenceDefinition. They are optional.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Gary Chambers a écrit : Hi Gary,
Looks good. Is there really a need for a PreferenceValue class though?
I'm concerned that the getter returns a different kind of object to that expected by the setter... yes, ok
FreeTypeSettings class>>monitorTypeLCD <preference: 'LCD monitor type' type: #Boolean set: #monitorTypeLCD: defaultValue: false description: 'Use of a LCD...'> ^ (MonitorTypeLCD ifNil: [MonitorTypeLCD := PreferenceValue value: false location: self selector: #monitorTypeLCD]) value
For any preference tool the presence of the pragma is sufficient to get/set the native value and, assuming always class-side, support event triggering for changes. I'm not sure to understand. you suggest a solution like this ? : FreeTypeSettings class>>monitorTypeLCD: aBoolean monitorTypeLCD := aBoolean. self triggerEvent: #monitorTypeLCD with: aBoolean
Of course, then you do not need PreferenceValue. But I prefer PreferenceValue solution because it encapsulates the triggerEvent, the developper do not have to deal with it and it is more evolutive (it is easy to change the way events are triggered or to change the notification framework). regarding the pragma use, I see it as only useful from supporting tools (PreferencesBrowser...). but maybe I'm wrong, let me know. Cheers Alain
Regards, Gary
----- Original Message ----- From: "Alain Plantec" <alain.plantec@free.fr> To: <Pharo-project@lists.gforge.inria.fr> Sent: Monday, March 02, 2009 8:41 AM Subject: Re: [Pharo-project] Preference refactoring again
Geert a écrit :
Hi Alain, this sounds very interesting. thanks I have never been a big fan of the current "Preference Browser". The main problem with current preference system is that it makes uses of globals (declared in the class side of Preferences) and that a lot of packages depend on it. The main goal of the refactoring is to make preferences local to the packages in which they are declared. Current preference browser is not that bad and could be reused. I am now trying to grasp (still learning here) how this new "Pharo Preference Mechanism" works.It would be great if the mechanism could be explained in detail in something like the new Pharo By Example manual :)
Each preference is stored by a PreferenceValue instance and each time a PreferenceValue is updated (with a #value: message sent) an event is sent to the class which defines the preference. The event sending is standard: PreferenceValue>>value: anObject realValue ~= anObject ifTrue: [realValue := anObject. location triggerEvent: selector with: anObject]
realValue is the instance variable wich stores current preference value. location is the class which declares the preference selector is the selector of the preference (i.e. #gradientButtonLook)
So my proposition is to declare a preference locally. Let's take the example of freetype monitorTypeLCD preference. If we implement it the way it is now, as a boolean, it could be: --------------- FreeTypeSettings class>>monitorTypeLCD <preference: 'LCD monitor type' type: #Boolean set: #monitorTypeLCD: defaultValue: false description: 'Use of a LCD...'> ^ MonitorTypeLCD ifNil: [MonitorTypeLCD := PreferenceValue value: false location: self selector: #monitorTypeLCD]
FreeTypeSettings class>>monitorTypeLCD: aBoolean self monitorTypeLCD value: hintingFull
FreeTypeSettings class>>initialize FreeTypeSettings when: #monitorTypeLCD send: #monitorTypeLCDPreferenceChanged: to: self.
FreeTypeSettings class>>monitorTypeLCDPreferenceChanged: aBoolean self current monitorTypeLCDPreferenceChanged: aBoolean ------------- The pragma you see in FreeTypeSettings class>>monitorTypeLCD in only here for UI tools such as PreferenceBrowser.
If a client object needs monitorTypeLCD value, it asks directly to its provider which is FreeTypeSettings class: ... useLCD := FreeTypeSettings monitorTypeLCD value. ...
but note that such a preference should be set as a choice between two values #LCD or #CRT...
hope things are a little bit clearer now. alain
Alain Plantec wrote:
I've joined 4 packages : - PrefCore contains PreferenceValue which is now the only mandatory class.
2 packages for testing: - PrefProvider contains PrefProvider class which declares some preferences - PrefUser contains PrefChangeListener (try PrefChangeListener test).
1 package for UI: - PrefTool contains PreferenceCollector and PreferenceDefinition. They are optional.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Alain Plantec wrote:
The pragma you see in ...
I can't seem to find a lot of info on the "pragmas" people are referring to, what are they exactly, when or what should they be used for, how do they work ...? Maybe another one for the book Stef :) -- View this message in context: http://n2.nabble.com/Preference-refactoring-again-tp2403814p2408738.html Sent from the Pharo Smalltalk mailing list archive at Nabble.com.
participants (4)
-
Alain Plantec -
Gary Chambers -
Geert -
Stéphane Ducasse