I have commands that I would like to make undoable. Is it possible to wrap the commands within an "undoable" environment as suggested in http://www.ceteva.com/forum/viewtopic.php?t=17
I imagine something like this (but wouldn't know where to start):
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
A>>setBar: aBar Undoable newOn: [ bar := aBar ]
a := A new foo: 0; bar: 0; yourself. a setFoo: 5. a setBar: 10. Undoable undo. "a bar == 0" Undoable undo. "a foo == 0" Undoable redo. "a foo == 10"
Thanks - Sophie
Have a look at the Command and CommandHistory clasees. Worked well for our Report Builder...
Gary.
-----Original Message----- From: squeak-dev-bounces@lists.squeakfoundation.org [mailto:squeak-dev-bounces@lists.squeakfoundation.org]On Behalf Of itsme213 Sent: 29 April 2008 6:37 PM To: squeak-dev@lists.squeakfoundation.org Subject: [squeak-dev] Undoable environment ?
I have commands that I would like to make undoable. Is it possible to wrap the commands within an "undoable" environment as suggested in http://www.ceteva.com/forum/viewtopic.php?t=17
I imagine something like this (but wouldn't know where to start):
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
A>>setBar: aBar Undoable newOn: [ bar := aBar ]
a := A new foo: 0; bar: 0; yourself. a setFoo: 5. a setBar: 10. Undoable undo. "a bar == 0" Undoable undo. "a foo == 0" Undoable redo. "a foo == 10"
Thanks - Sophie
"Gary Chambers" gazzaguru2@btinternet.com wrote in message
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
Have a look at the Command and CommandHistory clasees. Worked well for our Report Builder...
I am hoping to find a way for Undoable to dynamically extend a few primitives (e.g. assiging to an instVar or indexedVar, probably adding or removing indexedVars, others??).
========== e.g. currently:
Object>> instVarAt: anInteger put: anObject <primitive: 74> ^self basicAt: anInteger - self class instSize put: anObject
========== Dynamically change to:
Object>> instVarAt: anInteger put: anObject self recordIVarChange: anInteger oldVal: self instVarAt: anInteger. self primInstVarAt: anInteger put: anObject
Object>> primInstVarAt: anInteger put: anObject <primitive: 74> ^self basicAt: anInteger - self class instSize put: anObject
=========== Then #recordIVarChange can put undoable/redoable records on the stack.
Does this sound feasible? Scary to dynamically re-define primitive methods, don't know where to start :-(
Sophie
On 30.04.2008, at 16:22, itsme213 wrote:
"Gary Chambers" gazzaguru2@btinternet.com wrote in message
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
Have a look at the Command and CommandHistory clasees. Worked well for our Report Builder...
I am hoping to find a way for Undoable to dynamically extend a few primitives (e.g. assiging to an instVar or indexedVar, probably adding or removing indexedVars, others??).
========== e.g. currently:
Object>> instVarAt: anInteger put: anObject <primitive: 74> ^self basicAt: anInteger - self class instSize put: anObject
========== Dynamically change to:
Object>> instVarAt: anInteger put: anObject self recordIVarChange: anInteger oldVal: self instVarAt: anInteger. self primInstVarAt: anInteger put: anObject
Object>> primInstVarAt: anInteger put: anObject <primitive: 74> ^self basicAt: anInteger - self class instSize put: anObject
=========== Then #recordIVarChange can put undoable/redoable records on the stack.
Does this sound feasible? Scary to dynamically re-define primitive methods, don't know where to start :-(
This will not work. #instVarAt:put: is not called for regular inst var assignments.
Besides, you certainly only want to do that for your domain objects. One way to achieve that is to extend the compiler for your class hierarchy and make it insert the #recordIVarChange:oldVal:instVarAt: send right before or after the assignment bytecode.
This is how Tweak objects work - it has "fields" that can be used exactly like instance variables in code, but actually generate change events when assigned. It compiles any inst var assignment (and usage) as message send of an accessor named like the variable. The setter then generates the change events. The getter can be used to implement "virtual fields" with a computed value.
- Bert -
You'd need to be very careful... and probably need to redefine instVarAt:put: in the object that handles the command/undo to do the normal thing (to avoid recursion).
Of course, assignments to ivars in methods won't actually call instVarAt:put: (done in the bytecode I believe).
Can you explain the general functionality you are hoping to obtain?
Gary.
-----Original Message----- From: squeak-dev-bounces@lists.squeakfoundation.org [mailto:squeak-dev-bounces@lists.squeakfoundation.org]On Behalf Of itsme213 Sent: 30 April 2008 3:22 PM To: squeak-dev@lists.squeakfoundation.org Subject: [squeak-dev] Re: Undoable environment ?
"Gary Chambers" gazzaguru2@btinternet.com wrote in message
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
Have a look at the Command and CommandHistory clasees. Worked
well for our
Report Builder...
I am hoping to find a way for Undoable to dynamically extend a few primitives (e.g. assiging to an instVar or indexedVar, probably adding or removing indexedVars, others??).
========== e.g. currently:
Object>> instVarAt: anInteger put: anObject <primitive: 74> ^self basicAt: anInteger - self class instSize put: anObject
========== Dynamically change to:
Object>> instVarAt: anInteger put: anObject self recordIVarChange: anInteger oldVal: self instVarAt: anInteger. self primInstVarAt: anInteger put: anObject
Object>> primInstVarAt: anInteger put: anObject <primitive: 74> ^self basicAt: anInteger - self class instSize put: anObject
=========== Then #recordIVarChange can put undoable/redoable records on the stack.
Does this sound feasible? Scary to dynamically re-define primitive methods, don't know where to start :-(
Sophie
"Gary Chambers" gazzaguru2@btinternet.com wrote in message
Can you explain the general functionality you are hoping to obtain?
Generic undo of arbitrary domain-object actions with no extra effort.
AnyObject>> anyMethod Undoable on: [ any side effect block, recursively ]
or, Undoable on: [ anyObject anyMethod ]
- Sophie
Generic undo of arbitrary domain-object actions with no extra effort.
AnyObject>> anyMethod Undoable on: [ any side effect block, recursively ]
or, Undoable on: [ anyObject anyMethod ]
Get GemStone and use transactions.
Or if you are extremely adventurous use the transactional memory I implemented in Squeak: http://source.lukas-renggli.ch/transactional.html.
Other than that you probably can't avoid wrapping #anyMethod into a Command object, as described by the "Design Patterns Smalltalk Companion" book.
Lukas
Other than that you probably can't avoid wrapping #anyMethod into a Command object, as described by the "Design Patterns Smalltalk Companion" book.
Ahh, there is one more thing ...
If you know (or are able to calculate) a list of objects that are changed during #anyMethod, then you can use Seaside's object backtracking mechanism.
Lukas
On 30-Apr-08, at 1:18 PM, itsme213 wrote:
"Gary Chambers" gazzaguru2@btinternet.com wrote in message
Can you explain the general functionality you are hoping to obtain?
Generic undo of arbitrary domain-object actions with no extra effort.
Unless you propose to make a practical completely reversible computational system I suspect you are heading for some disappointment.
Not all actions have trivially derivable inverse actions. Consider a real example from Sophie that occupied me for several days; inserting a character into a paragraph. Sound pathetically simple, doesn't it?
Until you realise that the character might be carrying a style that is not the same as the text where it is being inserted. Or that the insertion point is in between two adjacent pagebreaks. If the character's style matches the style of where it is being inserted, you can simply stick the Character into the relevant String. The undo record would record the insertion index; simple. If the character style doesn't match, then you have to split the string, make a new string for the character, insert that into the paragraph. Of course, the insertion point might be at the very beginning or end of the string and that adds some extra twists. The undo record needs to record that a new string was added instead of merely a Character being put into a String. The undo action has to remove that string and remerge the split halves if needed. Oh, and all cases have to make sure that any annotations like highlighting get updated to account for the splitting, inserting, merging etc.
tim -- tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim Strange OpCodes: ESBD: Erase System and Burn Documentation
Quoting tim Rowledge tim@rowledge.org:
On 30-Apr-08, at 1:18 PM, itsme213 wrote:
"Gary Chambers" gazzaguru2@btinternet.com wrote in message
Can you explain the general functionality you are hoping to obtain?
Generic undo of arbitrary domain-object actions with no extra effort.
Unless you propose to make a practical completely reversible computational system I suspect you are heading for some disappointment.
Not all actions have trivially derivable inverse actions. Consider a real example from Sophie that occupied me for several days; inserting a character into a paragraph. Sound pathetically simple, doesn't it?
Until you realise that the character might be carrying a style that is not the same as the text where it is being inserted. Or that the insertion point is in between two adjacent pagebreaks. If the character's style matches the style of where it is being inserted, you can simply stick the Character into the relevant String. The undo record would record the insertion index; simple. If the character style doesn't match, then you have to split the string, make a new string for the character, insert that into the paragraph. Of course, the insertion point might be at the very beginning or end of the string and that adds some extra twists. The undo record needs to record that a new string was added instead of merely a Character being put into a String. The undo action has to remove that string and remerge the split halves if needed. Oh, and all cases have to make sure that any annotations like highlighting get updated to account for the splitting, inserting, merging etc.
tim
tim Rowledge; tim@rowledge.org; http://www.rowledge.org/tim Strange OpCodes: ESBD: Erase System and Burn Documentation
But surely all that logic is built into the application, so the inverse operation is 'delete character at insertion index' - since you obviously need this functionality. Nobody said it was easy or trivial.
David
There is an undo system that impara wrote for Sophie. You should consider it, we used it extensively to make *most* actions (some VERY complex ones) undoable/redoable, this also included the ability to transparently nest actions, such as having one action be a consolidation of multiple sub actions, then treat the one container action as an atomic do/undo/redo item.
Say for example do most any textual editing, frame layout, page manipulation for 20 mintues, then hold the undo-key down and watch it rollback everything.
On Apr 29, 2008, at 10:36 AM, itsme213 wrote:
I have commands that I would like to make undoable. Is it possible to wrap the commands within an "undoable" environment as suggested in http://www.ceteva.com/forum/viewtopic.php?t=17
I imagine something like this (but wouldn't know where to start):
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
A>>setBar: aBar Undoable newOn: [ bar := aBar ]
a := A new foo: 0; bar: 0; yourself. a setFoo: 5. a setBar: 10. Undoable undo. "a bar == 0" Undoable undo. "a foo == 0" Undoable redo. "a foo == 10"
Thanks - Sophie
-- = = = ======================================================================== John M. McIntosh johnmci@smalltalkconsulting.com Corporate Smalltalk Consulting Ltd. http://www.smalltalkconsulting.com = = = ========================================================================
"John M McIntosh" johnmci@smalltalkconsulting.com wrote
There is an undo system that impara wrote for Sophie. You should consider it,
Where will I find this? I downloaded Sophie and don't see image + sources.
Thanks.
You can also have a look at the Iterator DP in the Smalltalk companion they have an hisotrystream to manipulate commands and do undo. On Apr 29, 2008, at 7:36 PM, itsme213 wrote:
I have commands that I would like to make undoable. Is it possible to wrap the commands within an "undoable" environment as suggested in http://www.ceteva.com/forum/viewtopic.php?t=17
I imagine something like this (but wouldn't know where to start):
A>>setFoo: aFoo Undoable newOn: [ foo := aFoo ]
A>>setBar: aBar Undoable newOn: [ bar := aBar ]
a := A new foo: 0; bar: 0; yourself. a setFoo: 5. a setBar: 10. Undoable undo. "a bar == 0" Undoable undo. "a foo == 0" Undoable redo. "a foo == 10"
Thanks - Sophie
squeak-dev@lists.squeakfoundation.org