954,536 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Undo/Redo Problem

The scenerio is that I have different type of drawing components on drawing area. In menu I have some combo boxes which apply different properties on these objects. and also add a new UndoableEdit to the UndoManager. Anybody worked with the swing's undo package will get the idea. This way I am successfully performing undo and redo functionality. But the problem is in many cases I need to update the state of these combo boxes for example when a new object is added, appropriate value in the combo boxes has to be selected or when user selects another object, I update the selected index of the combo boxes. On calling the setSelectedIndex() function of these combo boxes the actionPerformed method of the combobox is automatically called which also adds a new undoableEdit into the UndoManager which is not desired since user has not performed any action on the combobox to update the property but I dynamically updated the state of the combobox to match it with the currently selected object. Anybody has solution to this problem?

dasatti
Junior Poster in Training
57 posts since Dec 2008
Reputation Points: 10
Solved Threads: 5
 

I had the same problem and could not find a good approach to handle this (anyone did?).
My workaround to the problem was to filter the setXXX calls caused by focus changes based on a timestamp.
My code customized UndoManager class' code looks like this:

/**
 * Time of last undoable edit<p>
 * We use this as a workaround when undoing in the following case:
 * - table cell was edited and 
 * - undo toolbar-button clicked
 * this causes a stopEdit which in turn causes setValueAt and produces a new edit.
 * If the last edit was created less then MINTIME far (ex. 0.2sec), we undo twice.
 */
private GregorianCalendar editTime;


public synchronized boolean addEdit(UndoableEdit anEdit) {
	this.editTime = new GregorianCalendar();
    editTime.add(Calendar.MILLISECOND, MIN_TIME);	// only after this time, an  xxxxxxxxxx
    boolean success = super.addEdit(anEdit);
    if (success) {
    	adjustMenuState();
    }
	return success;
}

@Override
public synchronized void undo()  {
  try
    {
	  // filter out unwanted edits from focus changes
	  if(editTime.after(GregorianCalendar.getInstance())){
		  	// timeout this one so we can undo it
        	editTime.set(Calendar.YEAR, 1900);	
        	// undo it and kill the unwanted one
        	UndoableEdit e = this.editToBeUndone();
        	undo();	// undo the unwanted
        	if(e instanceof TableCellEdit) {
        		TableCellEdit tce = (TableCellEdit) e;
        		log.warn("Remove edit :" +tce.getPresentationName() + ", " + tce.toString());
        	}
        	e.die();	
        }
	  	// do the undo
        super.undo();
    }
    finally
    {
    	// will call undoTo adjustMenuState();
    }
}


I posted a full description of the Java Undo/Redo mechanism in my blog SNIPPED (without the timestamp mechanism).

designpattern
Newbie Poster
1 post since Sep 2009
Reputation Points: 10
Solved Threads: 0
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You