Redo observer does not send on modified/on change events


#1

Hi there, I’m making an extension that observes the model’s changes. I’ve noticed that for certain actions, onChangeEntity (from EntityObserver) and onElementModified (fromEntitiesObserver) are not fired when the action is done with a REDO. Recreate the issue with the following:

  1. Create a rectangle.
  2. Select the face only of the rectangle.
  3. Run the following code in the Ruby console.
class MyEntityObserver < Sketchup::EntityObserver
	def onChangeEntity(entity)
		puts "onChangeEntity: #{entity}"
	end
end

class MyModelObserver < Sketchup::ModelObserver
	def onTransactionCommit(model)
		puts "Transaction committed.";
	end
	def onTransactionUndo(model)
		puts "Transaction undone.";
	end
	def onTransactionRedo(model)
		puts "Transaction redone.";
	end
end

model = Sketchup.active_model
entity = model.selection[0]
entity.add_observer(MyEntityObserver.new)
Sketchup.active_model.add_observer(MyModelObserver.new);
  1. Move the rectangle face around several times. Note in the console the onChanged event is fired.
  2. Undo your movements. The event is still fired.
  3. Redo the movements. The event is no longer fired.

Is there a reason for this behaviour, or is it a bug? I’m trying to think of a workaround, but this seems like a pretty tough problem to resolve. Is there any other way to observe when an entity is modified, no matter what? Or pull the undo stack from Sketchup itself?

Thanks for any help,
Erik


#2

I think this is intended. There’s a separate observer being fired on undo and redo.


#3

@ErikRoss, I see what you see when running the example.

Repeated undoing and redoing shows inconsistent observer behavior.

Each time the undo command is used, both the ModelObserver#onTransactionUndo and the EntityObserver#onChangeEntity callbacks fire, …

… but only the ModelObserver#onTransactionRedo callback fires on an redo command.

If you again undo, … both the ModelObserver#onTransactionUndo and the EntityObserver#onChangeEntity callbacks fire even though there was no intervening change event firing off an observer callback (of any kind.)

This is inconsistent and unexpected.

Not correct. (There are separate callback methods being called of the same model observer. But, during an undo, the Entity observer’s #onChangeEntity callback method is called first, before the model observer undo transaction callback.)

This (the lack of signalling a reverting change for the entity) cannot really be intended as it is poor design. This would require coders to keep separate state variables in order to sync observer events. This would not be good API design.

I’ll log it as an issue so Thomas can look into it …

Expectation / Suggestion:

Either an intervening EntityObserver#onChangeEntity callback should fire for Redo, (This would be consistent with Undo behavior,) …

… and posssibly, a new EntityObserver#onRevertEntity callback should be implemented for undo that fires before the ModelObserver#onTransactionUndo event., to signal the reverting and reversal of the original EntityObserver#onChangeEntity call after the pre-undo (the original) change.

(But then this latter #onRevertEntity implementation would possibly break existing plugins unless it also still fired the #onChangeEntity event in the absence of a #onRevertEntity callback.)


#4

Thanks very much for filing the bug report Dan!


#5

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.