I am writing a custom plugin for TinyMCE. One of the new buttons makes a number of DOM manipulations in the document. The default undo behavior creates a few undo levels in the middle of the changes. If the user hits the undo button after using the plugin, he/she then sees a document with the operation partially reversed and really not in a proper state.
It looks like there used to be a pair of instance commands called mceBeginUndoLevel / mceEndUnoLevel (removed in version 3.3) that let a developer start/end a large undo batch that would be undone in a single operation....but I don't see anything in the docs that replaces that feature.
Some forum postings suggest using editor.undoManager.add() as a replacement, and that works for cases where you want more levels of undo during an operation, but I actually want less.
There is also a undoManager.onBeforeAdd event that you can hook into, but looking at the source for the undoManager, I don't think that hooking there will let you abort an undo snapshot.
So, is there a proper way to batch undo operations that I'm not seeing using the existing API? If not, my only other option seems to be patching the undoManager to allow the onBeforeAdd hook to abort a snapshot.
I suggest overwriting the current UndoManager. It is just a rather small file.
That's what we needed to do in order to suppress the creation of some unwanted undosteps.
Related
I'm trying to use RevertAllInCurrentGroup to undo the last operation but it doesn't seem to work. Actually what I really want to do is just remove the undo from the history; I don't care whether the undo is applied or not.
In some init code I have:
// 'component' is a MonoBehaviour-derived class. Here I create the default editor for the component
m_editor = Editor.CreateEditor(component);
And then in OnGUI in my EditorWindow:
m_editor.OnInspectorGUI();
// ..'hasChanged' is set to true if the user changed some property
if (hasChanged)
{
// ..do some stuff using the new values on the object, which includes sending a message to a server
Undo.RevertAllInCurrentGroup();
}
When I call RevertAllInCurrentGroup I get InvalidOperationException: Operation is not valid due to the current state of the object in some Stack object in GUILayoutUtility.EndLayoutGroup. I figured maybe I shouldn't be doing the revert in OnGUI, so I changed it to set a flag and do the revert in Update but that doesn't make any difference (except I obviously no longer get the exception).
Does anyone know how to use this function, or if there is some other way that I could undo the last operation that was applied by the Editor instance? I've tried using Undo.RegisterCompleteObjectUndo and Undo.ClearUndo but they don't seem to do anything either (the undo operation still appears in the undo stack).
For clarification, I'm dynamically creating GameObjects with components in the editor based on messages I receive from a server (which is a running Unity game, which could be inside or outside the editor - this is a live update system). Then I allow editing of those components, and send the changed components back to the server. I'm rendering my own inspector UI and I wanted to use the built-in Editor instances for components (e.g. so the built-in CameraEditor will be used if there is a Camera component).
The only problem is that using the built-in editors causes undo operations to be added to the stack, but I really don't care about these undo operations because the GameObject they apply to is just a temporary placeholder GameObject which is continually updated every coulpe of seconds, whenever I receive a new message from the server.
if what you want is the same as clicking on the Edit->Undo menu (or as you put, undo the last operation that was applied by the editor), use below code:
Undo.PerformUndo();
Here's the situation that I'm trying to describe, and would like to reflect in the org file:
Suppose you started a task, but while working on it you realized that the description of the task must be amended in a way that it justifies that task to be extended. Still you don't want to lose the original estimate, just for historical purposes, so, roughly, what I would like to have would be:
* STARTED Do something seemingly easy
DEADLINE: <2013-06-09>
This should be a breezy
AMENDED: <2013-06-10>
Looks like this will require more effort
The agenda buffer would use the latest date in the task, but it would be still "interesting" to know the original estimate after the task was finished.
There are many options in org-mode for logging or adding notes whenever a task properties change.
Check for example lognotereschedule, which will ask you for a note when rescheduling a task.
You can choose to store all notes and status changes in a special drawer called LOGBOOK in order to avoid clutter.
I have a fairly good idea of what the Subject class does and when to use it, but I've just been looking through the language reference on msdn and see there are various other ISubject implementations such as:
AsyncSubject
BehaviorSubject
ReplaySubject
As the documentation is pretty thin on the ground, whats the point of each of these types and under what situations would you use them?
These subjects all share a common property - they take some (or all) of what gets posted to them via OnNext and record it and play it back to you - i.e. they take a Hot Observable and make it Cold. This means, that if you Subscribe to any of these more than once (i.e. Subscribe => Unsubscribe => Subscribe again), you'll see at least one of the same value again.
ReplaySubject: Every time you subscribe to the Subject, you get the entire history of what has been posted replayed back to you, as fast as possible (or a subset, like the last n items)
AsyncSubject: Always plays back the last item posted and completes, but only after the source has completed. This Subject is awesome for async functions, since you can write them without worrying about race conditions: even if someone Subscribes after the async method completes, they get the result.
BehaviorSubject: Kind of like ReplaySubject but with a buffer of one, so you always get the last thing that was posted. You also can provide an initial value. Always provides one item instantly on Subscribe.
In light of the latest version (v1.0.2856.0) and to keep this question up to date, there has been a new set of subject classes:
FastSubject, FastBehaviorSubject, FastAsyncSubject and FastReplaySubject
As per the release notes they
are much faster than regular subjects
but:
don’t decouple producer and consumer by an IScheduler
(effectively limiting them to
ImmediateScheduler);
don’t protect against stack overflow;
don’t synchronize input messages.
Fast subjects are used by Publish and
Prune operators if no scheduler is
specified.
In regards to AsyncSubject
This code:
var s = new AsyncSubject<int>();
s.OnNext(1);
s.Subscribe(Console.WriteLine);
s.OnNext(2);
s.OnNext(3);
s.OnCompleted();
prints a single value 3. And it prints same if subscription is moved to after completion. So it plays back not the first, but the last item, plays it after completion (until complete, it does not produce values), and it does not work like Subject before completion.
See this Prune discussion for more info (AsyncSubject is basically the same as Prune)
Paul's answer pretty much nails it. There's a few things worth adding, though:
AsyncSubject works as Paul says, but only after the source completes. Before that, it works like Subject (where "live" values are received by subscribers)
AsyncSubject has changed since I last ran tests against it. It no longer acts as a live subject before completion, but waits for completion before it emits a value. And, as Sergey mentions, it returns the last value, not the first (though I should have caught that as that's always been the case)
AsyncSubject is used by Prune, FromAsyncPattern, ToAsync and probably a few others
BehaviorSubject is used by overloads of Publish that accept an initial value
ReplaySubject is used by Replay
NOTE: All operator references above refer to the publishing set of operators as they were before they were replaced with generalised publish operators in rev 2838 (Christmas '10) as it has been mentioned that the original operators will be re-added
Ok, so I have a quickfix/refactoring that deletes or changes the type of an offending field from a Java class, if the field is not present in an external DSL.
The problem is that the marker that triggered the quickfix is not removed from the GUI the first time my IncrementalProjectBuilder, even though the code that removes it is executed. If I execute the quickfix a second time, the same marker gets deleted again, only that now the marker also disappears in the GUI.
Interesting fact: If I step-debug the code that deletes the marker, the GUI gets updated properly.
I figure, there is something I'm missing here, as telling some component that I'm finished with the refactoring or with removing the markers.
Any hints?
Problems View is not updated in real time (due to performance reasons) The update is run in a separate job. So when you delete the marker, it will not get reflected immediately. So when that code runs second time/stepping thru, there is a lot of chances that the update job has run
I am looking into how to write a paint program that supports undo and seeing that, most likely, a command pattern is what I want. Something still escapes me, though, and I'm hoping someone can provide a simple answer or confirmation.
Basically, if I am to embody the ability to undo a command, for instance stamping a solid circle on the screen, does this mean I need to essentially copy the frame buffer that the circle covers into memory, into this command object? I don't see any other way of being able to undo what might be, for instance, stamping over a bunch of random pixel colors.
I've heard that one approach is just to keep track of the forward actions and when an undo is performed, you simply start from step 1 and draw forwards to the step before the undo, but this seems unfeasible if you are to support a large undo stack.
Perhaps the solution is something in between where you keep a bitmap of every 15-20 actions and start from the last 'save' forwards.
Can someone provide any insight on what is the typical accepted approach in this case, either saving buffer rectangles in the commands, redo-ing every action forwards, or something I've altogether missed?
Update: Plenty of good responses. Thanks, everyone. I'm thinking from what I'm reading that I will approach this by saving out the buffer every N actions and when the user issues an undo command redo all commands from the most recent saved buffer. I can tweak N to as high a value as possible that doesn't noticeably bog down the user experience of needing responsive undo (in order to minimize memory usage), but I suspect without really knowing for sure at this point, that I should be able to get away with performing quite a few actions in one frame such that this isn't too bad. Hopefully this approach will let me quickly determine whether to turn the other direction and instead go with saving bitmap rects for the previous states for actions that require it.
First, beware overdesign: if your app isn't complex and your images small, you may find 'just store everything' to be quick, cheap and feasible. But assuming that's not so:
You are correct that it is not feasible to redraw the entire canvas from step 1 forward for each undo; unless your paint program is very simple some operations simply take too long. Also, an infinite undo buffer is probably not called for (and could be very space-consuming to store).
If your art program is complex, I'd actually start with a hybrid approach, to deal with the variety of operations. Save frame buffer every so often (the every 15-20 commands you suggest seems OK; I might start with 10 and adjust once I had it working) and go forward from last save. But don't make the 'every 15 operations' rigid, because it is likely that a few extra rules of thumb would make it seem much more fluid to the user.
For example, some time-consuming or tricky-to-reverse operations could always create a new save point:
- Any canvas resize (crop etc.)
- Any save. ("I just saved" is a very likely place for the user to undo back to.)
- Any operation which is extremely time-consuming should create a new save point after, not before, the operation; i.e. it should flag the next operation to save the buffer to undo. (Why? If the op takes 30 seconds, you don't want every undo in the stack afterwards to take an extra 30+ seconds.)
- Conversely, any operation which has an easily performed mathematical negative, or is self-inverting (like photonegative) need never bother to save frame buffer, and shouldn't count towards the next save.
All of this leaves out the question of layers; if your program has them it's obviously sufficient to save only those layers that change.
Definitely my highest-priority suggestion though: regardless of what method you use, you should always save frame buffer for the most recent operation performed. "Whoops, didn't mean that" is the most likely reason for undo, so you always want undo-one-step to be responsive. You can discard this buffer after the next command execution if it's not one you're keeping.
You'll also need to consider what constitutes one atomic undo operation. (For example, is a set of strokes with a single brush tool one operation or many? Both have advantages and drawbacks.)
Perhaps the solution is something in between where you keep a bitmap of every 15-20 actions and start from the last 'save' forwards.
I would go with something like this one. You have to bound your command stack at some point anyway, so you'll need a starting point if the user empties it.
You could get clever and save the buffer when you reach the bound and use that as your save point, since you have to drop a command from the stack anyway. Essentially, your save point buffer is the representation of the dropped actions, so as you're dropping actions from your undo stack, you just write them onto that buffer.
I've heard that one approach is just to keep track of the forward actions and when an undo is performed, you simply start from step 1 and draw forwards to the step before the undo
This isn't a very good idea. Users typically undo only a few recent actions and they expect it to be fast, so it's better to be able to revert immediately than redoing everything from the start.
Can someone provide any insight on what is the typical accepted approach in this case, either saving buffer rectangles in the commands, redo-ing every action forwards, or something I've altogether missed?
You don't have to store all commands in the same way. Depending on the type of operation, you can use one or more techniques, for example:
Drawing/painting operations generally can't be reverted directly, so you have no choice but to save the original image contents. You can however save space by storing only parts of the image that have changed instead of the entire image.
Some operations like inverting colours are inherently invertible, so in such cases, you only need to store the type of operation on the undo stack, and you can replay the operation in either direction.
If you probably won't draw gigantic bitmaps, your approach seems totally ok.
To simplify even more, write whole pictures to tmp directory onto disk, and see what it will be like for the users.
Don't overdesign at start-there are other issues that need to be adressed, no doubt.
From my understanding, the command pattern for implementing undo/redo sorts of systems just record the actions in a stack, not the actual results from those actions (since those will be recreated/removed in sequence). I think you alluded to this, but said you considered it unfeasible for a large undo stack. Can you be more specific? I believe it is possible.