Undo/redo

I developed a network of nodes similar to Flower example. The application has the undo/redo functionality which work for deletion, creation, change of user object, but the redo does not work moving a node. That is if a node is moved to a new location, it can be moved back to the original location by using UNDO, but it can’t be moved back to the new location by using REDO. I thought JGoView/Document/UndoManager will take care of SELECTION_MOVED behaviour and I spent a lot of time on this unsuccessfully. I appreciate your suggestion.
Thong

That is very odd. As you can see in all of the example applications that support undo/redo, all that behavior should come for free. It is only when you add your own state that you need to do any programming, typically overrides of JGoObject.copyNewValueForRedo and changeValue.
If you do have any overrides of those methods, do you remember to call the super method for all cases except those that you have added (i.e. the states that you are implementing)?
Another possibility is that the undo manager is discarding all of the changes after some undos. Are you able to
A: (1) move a node (2) delete a node
B: Undo twice, and have the second node reappear
C: Redo twice, and have the second node disappear again, even though the first node doesn’t move back?

Walter,
Thank you for your quick response.
This is what happened when I tested your suggested scenario
A: move node A from location Xa to Ya, then delete node B at location Xb
B: Undo one, node B reappears at Xb; Undo one more, node A moves back to Xa
C: Redo one, node A does not move to Ya, it moves to Za which is about 10 pixels away from Xa; Redo one more, node B disappears

This is the codes that I changed

public void changeValue(JGoDocumentChangedEdit e, boolean undo) {
switch (e.getFlags()) {
case CiiConstants.CSF_CHANGED:
successFactor = (CiCriticalSuccessFactor) e.getValue(undo);
return;
default:
super.changeValue(e, undo);
return;
}
}

public void copyNewValueForRedo(JGoDocumentChangedEdit e) {
switch (e.getFlags()) {
case CiiConstants.CSF_CHANGED:
CiCriticalSuccessFactor copyCSF = (CiCriticalSuccessFactor) getCSF().clone();
e.setNewValue(copyCSF);
return;
case JGoObject.ChangedGeometry:
//System.out.println("CSFNode " + this.getLocation()); // test if the new location is recognised.
super.copyNewValueForRedo(e);
default:
super.copyNewValueForRedo(e);
return;
}
}

OK, so it’s not the second possibility, where some side-effect is messing up the undo manager’s history.
If I were you, I would step through the code where changeValue is getting the ChangedGeometry subhint, to make sure the new value has the right values for X and Y, and if so, to figure out why the node is moving to the wrong location. I’ll guess that the values are wrong. Maybe somewhere in your code you are inappropriately modifying a Rectangle representing the bounding rectangle.

Walter,
I spent a day on tracing this problem. By overiding some JGoView.doMoveSelection and JGoObject.handleMove and setBoundingRect, I have traced the result of moving a node from loc(510,30) to loc(240,280). A problem is identified as when the mouse is up, the setBoundingRect is called to set the final bounding rectangle but the execution did not lead to callings JGoObject.update, JGoDocument.fireUpdate and the UndoManager and upto the node.copyNewValueForRedo. Note that my code of overiding setBoundingRect always calls super.setBoundingRect.
Do you have any idea?
Ta
Thong

YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
KMEditorView:DoMoveSelection: move offset x 1, offset y 1

CSFNode:HandelMove - old loc (510, 30) and new loc (510 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=510,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 510,30,46,46

CSFNode:HandelMove - old loc (510, 30) and new loc (510 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=510,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 510,30,46,46

KMEditorView:DoMoveSelection: move offset x -6, offset y -1

CSFNode:HandelMove - old loc (510, 30) and new loc (510 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=510,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 510,30,46,46

KMEditorView:DoMoveSelection: move offset x -14, offset y 2

CSFNode:HandelMove - old loc (510, 30) and new loc (510 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=510,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 510,30,46,46

KMEditorView:DoMoveSelection: move offset x -14, offset y 2

CSFNode:HandelMove - old loc (510, 30) and new loc (510 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=510,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 510,30,46,46

KMEditorView:DoMoveSelection: move offset x -23, offset y 6

CSFNode:HandelMove - old loc (510, 30) and new loc (480 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=510,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 480,30,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -8, offset y 15

CSFNode:HandelMove - old loc (480, 30) and new loc (480 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=480,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 480,30,46,46

KMEditorView:DoMoveSelection: move offset x -24, offset y 24

CSFNode:HandelMove - old loc (480, 30) and new loc (450 ,60)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=480,y=30,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 450,60,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -13, offset y 7

CSFNode:HandelMove - old loc (450, 60) and new loc (450 ,60)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=450,y=60,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 450,60,46,46

KMEditorView:DoMoveSelection: move offset x -32, offset y 19

CSFNode:HandelMove - old loc (450, 60) and new loc (420 ,90)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=450,y=60,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 420,90,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -21, offset y 0

CSFNode:HandelMove - old loc (420, 90) and new loc (390 ,90)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=420,y=90,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 390,90,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -10, offset y 14

CSFNode:HandelMove - old loc (390, 90) and new loc (390 ,90)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=390,y=90,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 390,90,46,46

KMEditorView:DoMoveSelection: move offset x -29, offset y 27

CSFNode:HandelMove - old loc (390, 90) and new loc (360 ,120)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=390,y=90,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 360,120,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -26, offset y 14

CSFNode:HandelMove - old loc (360, 120) and new loc (330 ,120)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=360,y=120,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 330,120,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -37, offset y 41

CSFNode:HandelMove - old loc (330, 120) and new loc (300 ,150)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=330,y=120,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 300,150,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -13, offset y 17

CSFNode:HandelMove - old loc (300, 150) and new loc (300 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=300,y=150,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 300,180,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x -19, offset y -8

CSFNode:HandelMove - old loc (300, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=300,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x 5, offset y -3

CSFNode:HandelMove - old loc (270, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

KMEditorView:DoMoveSelection: move offset x 1, offset y 1

CSFNode:HandelMove - old loc (270, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

KMEditorView:DoMoveSelection: move offset x -4, offset y 5

CSFNode:HandelMove - old loc (270, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

KMEditorView:DoMoveSelection: move offset x -8, offset y 7

CSFNode:HandelMove - old loc (270, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

KMEditorView:DoMoveSelection: move offset x -12, offset y 10

CSFNode:HandelMove - old loc (270, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

KMEditorView:DoMoveSelection: move offset x -14, offset y 11

CSFNode:HandelMove - old loc (270, 180) and new loc (270 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 270,180,46,46

KMEditorView:DoMoveSelection: move offset x -15, offset y 11

CSFNode:HandelMove - old loc (270, 180) and new loc (240 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=270,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 240,180,46,46

==========================================

KMEditorView: sub-hint is changedGeometry

The object is csf1

KMEditorView:DoMoveSelection: move offset x 15, offset y 11

CSFNode:HandelMove - old loc (240, 180) and new loc (240 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=240,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 240,180,46,46


KMEditorView:DoMouseUp- Doc point java.awt.Point[x=266,y=222] View point java.awt.Point[x=215,y=222]

KMEditorView:DoMoveSelection: move offset x 15, offset y 11

CSFNode:HandelMove - old loc (240, 180) and new loc (240 ,180)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=240,y=180,width=46,height=46]

CSFNode - to be SET with (L,T,W,H): 240,180,46,46

If CSFNode:HandleMove is being called with a location that hasn’t changed, why is KMEditorView:DoMoveSelection being called with a non-zero offset?

All I do with those methods are to recall super methods + print out statements for tracing purposes. I don’t know why they happen like that as they excute JGO classes’ methods. I also created UndoManager class extended JGoUndoManager and overrode documentChanged for tracing purposes. This UndoManager is used instead of JGoUndoManger.

What had happened to my problem is that after the mouse is up, CSFNode:setBoundingRect is called, leading following methods are called: JGoObject:setBoundingRect, JGoObject:Update, JGoDocument:fireUpdate, JGoDocument:invokeListener which will call JGoView:documentChanged and JGoUndoManager:documentChanged.
In fact, the JGoUndoManager:documentChanged is never got executed for some very strange reasons. As I can’t override the JGoDocument:invokeListener method so I can’t investigate further.

Do you have any suggestions for what goes wrong dynamically? Appreciate it
Thong


KMEditorView:DoMouseUp- Doc point java.awt.Point[x=305,y=51] View point java.awt.Point[x=305,y=51]

KMEditorView:DoMoveSelection: move offset x 8, offset y -1

CSFNode:HandelMove - old loc (240, 30) and new loc (240 ,30)

CSFNode - Current Bounding Rect java.awt.Rectangle[x=240,y=30,width=126,height=46]

CSFNode - to be SET with (L,T,W,H): 240,30,126,46

CSFNode - after calling super.setBoundingRect

KMDocument:FireUpdate the document is NOT suspended its updates

KMDocument:FireUpdate number of listeners 2

KMEditorView:documentChanged - object com.nwoods.jgo.JGoUndoManager$JGoCompoundEdit@172290f hasBeenDone: true alive: true inProgress: false edits: [203: 1 CiCSFNode 0/java.awt.Rectangle[x=77,y=47,width=126,height=46]

KMEditorView:documentChanged - flags: 0

KMEditorView:documentChanged - repaint the view

KMDocument:FireUpdate - finishing super.fireUpdate

Wait – are you saying that JGoDocument.fireUpdate is being called, and then some but not all of the document’s listeners are being called?
And JGoDocument.getUndoManager() is your undo manager? I suppose you could look at JGoDocument.getDocumentListeners() to make sure your undo manager is in that array. Presumably you would have noticed any exceptions that might have occurred in the KMEditorView.documentChanged method.
By the way, what version of JGo are you using?

I pinpoint the cause of the problem related to the question you asked me about “If CSFNode:HandleMove is being called with a location that hasn’t
changed, why is KMEditorView:DoMoveSelection being called with a
non-zero offset?”. This is the cause of the problem I have experience. KMEditorView:DoMoveSelection calls JGoView:doMoveSelection with a
non-zero offset, which susequently calls JGoView:moveSelection with a non-zero offset which is then adjusted by some rules and ends up as a zero offet passed to JGoObject:handleMove which calls JGoObject:setBoundingRect. Because of a zero offset move, the callings of listerners are ignored. Is it a bug in JGo5.15 the version that I used. I am certain about this cause because I modified the offset to a non-zero value, the undo/redo works.
Appreciate your suggestion?
Thong

Do you have JGoView.getSnapMove() set to SnapJump or SnapAfter? Moving to grid spots is the only way for JGoView.moveSelection to result in a zero offset.
But in Demo1 when I turn on SnapJump, undo and redo work fine, including undoing the position of an object to be at an old, non-grid-aligned, position.
What version of JGo are you using?

I use JGo5.15.
Yes, the problem is with JGoView.setSnapMove() sets to SnapJump or SnapAfter as I turn it off undo/redo works fine. Turn SnapMove on it does not work in my application.
Appreciate your suggestion.