How can I remove a specific command from a QUndoStack?
This command can be given by its index or pointer.
If you are using Qt 5.9, the QUndoStack::command(int index) and QUndoCommand::setObsolete(bool obsolete) functions are probably what you are looking for. The relevant docs from the QUndoStack::redo() command provide the explanation for how an obsoleted command is handled:
If QUndoCommand::isObsolete() returns true for the current command, then the command will be deleted from the stack. Additionally, if the clean index is greater than or equal to the current command index, then the clean index is reset.
That's the thing about stacks - you only work on top of the stack. You can push and you can pop. You don't remove stuff from the middle of the stack.
In an undo-redo scenario this is even more important, as the order of commands must be diligently preserved for the whole thing to work. Otherwise you will break it.
Which is why it is called an "undo stack" and not "reverse arbitrary action whatchamacallit".
There is QUndoStack::setIndex(int idx) which will undo all commands until the provided index. But you cannot really remove only a specific command. You need to undo all commands until you reach and remove the one you want.
As #dtech has pointed out, it does not make sense to undo a command which is not at the most recently pushed command (i.e., the command at top of the stack).
It does, however, make sense to undo the most recently pushed command.
And QUndoStack provides a very convenient way to do this: QUndoStack::undo().
But, this does not delete the command, as it will still be available through QUndoStack::push(...). To truly delete the command, it must be marked obsolete before undoing it:
auto* cmd = const_cast<QUndoCommand*>(undo_stack.command(undo_stack.count()-1));
cmd->undo(); // must be called explicitly
cmd->setObsolete(true);
undo_stack.undo();
It requires a const_cast, so I'd call it a hack. But for me, it works.
Related
New to Go and building a simple LRU cache in Go to get used to syntax and Go development.
Having an issue with the MoveToFront list method, it fails on the following check in the MoveToFront body
if e.list != l || l.root.next == e
I want to move the element (e) to the front of the list when I retrieve it from cache , like this
if elem, ok := lc.entries[k]; ok {
lc.list.MoveToFront(elem) // needs fixing
return elem
}
return nil
The Code can be seen here on line 32 the issue occurs
https://github.com/hajjboy95/golrucache/blob/master/lru_cache/lrucache.go#L32
There seem to be two problems, to me. First, this isn't how the List data type is meant to be used: lc.list.PushFront() will create a List.Element and return a pointer to it. That's not fatal, but at the least, it is kind of annoying—the caller has to dig through the returned List.Element when using Get, instead of just getting the value.
Meanwhile, presumably the failure you see is because you remove elements in Put when the LRU-list runs out of space, but you don't remove them from the corresponding map. Hence a later Put of the just-removed key will try to re-use the element in place, even though the element was removed from the list. To fix this, you'll need to hold both key and value. (In my simple experiment I did not see any failures here, but the problem became clear enough.)
I restructured the code somewhat and turned it into a working example on the Go Playground. I make no promises as to suitability, etc.
I've been using ManagedActionand and ElevatedManagedAction for sometime and everything has been great; however, I have a need now to execute actions in a particular order, or at least ensure actions are done first/last as may be necessary.
I assumed that actions were executed in the order entered for example:
Project project =
new Project("My Project",
new Property("SOME_PROPERTY", "ABC"),
new Dir(#"%ProgramFiles%\blah blah blah",
new File(...),
...
new ManagedAction(CustomActions.FirstAction, ...) {},
...
new ManagedAction(CustomActions.LastAction, ...) {}
...
I have a number of actions and so then thought, well ... , maybe bottom up, so I put what I wanted to run first at the bottom. That didn't change the order, so then I thought maybe alphabetical and did a couple of tests and sure enough that's what it did.
So, is there another way to specify the order actions are called other than adding a prefix for the name of the action, like A01_FirstAction, A02_LastAction ...?
Thanks,
Rick
Yes there is!
project.Actions = new WixSharp.Action[] {
new ManagedAction(CustomActions.MyFirstCustomAction,Return.check, When.Before, Step.InstallFinalize, Condition.NOT_Installed),
new ManagedAction(CustomActions.MySecondCustomAction,Return.check, When.After, Step.PreviousAction, Condition.NOT_Installed),
new ManagedAction(CustomActions.MyThirdCustomAction,Return.check, When.After, Step.PreviousAction, Condition.NOT_Installed)
}
Just take a look at the 2 parameters When and Step. In this case the first ManagedAction will be executed Before the step InstallFinalize. The second ManagedAction will be executed After the PreviousAction. This means after the previous action defined in the array. Same goes with the last ManagedAction. That's the way I figured out to specify an order.
Hope this helps.
Why is this test causing the following failure and error?
expected 'NO. ONE' to equal 'ITEM TWO'
<unknown> at /swiper-slider/test/basic-test.html:59
Object.Fake.downAt at /polymer-gestures/test/js/fake.js:98
Object.Fake.downOnNode at /polymer-gestures/test/js/fake.js:89
Context.<anonymous> at /swiper-slider/test/basic-test.html:56
polymer-gestures/test/js/fake.js is failing to find the target in this method, called from this method but I can't narrow down the exact culprit.
My hunch is that it has something to do with the div.swiper-button-next element being appended as a child on the fly and use of document.querySelector('swiper-slider /deep/ div.swiper-button-next') in the test.
I have a hunch that one of a few things is happening.
the div.swiper-button-next isn't in the DOM by the time you make the call. Either work a callback into your system to fire when everything is done (then check the value inside that callback), or (just to test if this is actually the problem) put a manual setTimeout to delay the query selector and assertion for a bit.
Polymer's targetAt function uses elementFromPoint() internally. Double check to make sure you don't have any overlays (core-overlay tends to crap all over my window sometimes...) and that the element you really want to tap is actually the element being found. Don't be afraid to put some debugging/console.log statements into the actual polymer source code to see what it is finding there.
I haven't spent too much time looking over the test, but your slideEls[1] could possibly have changed since you queried for it. querySelectorAll returns a "non-live" nodelist, so changes to the DOM don't update your selection.
I'm working on a game engine in C++ using Lua for NPC behaviour. I ran into some problems during the design.
For everything that needs more than one frame for execution I wanted to use a linked list of processes (which are C++ classes). So this:
goto(point_a)
say("Oh dear, this lawn looks really scruffy!")
mowLawn()
would create a GotoProcess object, which would have a pointer to a SayProcess object, which would have a pointer to a MowLawnProcess object. These objects would be created instantly when the NPC is spawned, no further scripting needed.
The first of these objects will be updated each frame. When it's finished, it will be deleted and the next one will be used for updating.
I extended this model by a ParallelProcess which would contain multiple processes that are updated simultaneously.
I found some serious problems. Look at this example: I want a character to walk to point_a and then go berserk and just attack anybody who comes near. The script would look like that:
goto(point_a)
while true do
character = getNearestCharacterId()
attack(character)
end
That wouldn't work at all with my design. First of all, the character variable would be set at the beginning, when the character hasn't even started walking to point_a. Then, then script would continue adding AttackProcesses forever due to the while loop.
I could implement a WhileProcess for the loop and evaluate the script line by line. I doubt this would increase readability of the code though.
Is there another common approach I didn't think of to tackle this problem?
I think the approach you give loses a lot of the advantages of using a scripting language. It will break with conditionals as well as loops.
With coroutines all you really need to do is:
npc_behaviour = coroutine.create(
function()
goto(point_a)
coroutine.yield()
say("Oh dear, this lawn looks really scruffy!")
coroutine.yield()
mowLawn()
coroutine.yield()
end
)
goto, say and mowLawn return immediately but initiate the action in C++. Once C++ completes those actions it calls coroutine.resume(npc_behaviour)
To avoid all the yields you can hide them inside the goto etc. functions, or do what I do which is have a waitFor function like:
function waitFor(id)
while activeEvents[id] ~= nil do
coroutine.yield()
end
end
activeEvents is just a Lua table which keeps track of all the things which are currently in progress - so a goto will add an ID to the table when it starts, and remove it when it finishes, and then every time an action finishes, all coroutines are activated to check if the action they're waiting for is finished.
Have you looked at Finite State Machines ? If I were you I wouldn't use a linked list but a stack. I think the end result is the same.
stack:push(action:new(goto, character, point_a))
stack:push(action:new(say, character, "Oh dear, this lawn was stomped by a mammoth!"))
stack:push(action:new(mowLawn, character))
Executing the actions sequentially would give something like :
while stack.count > 0 do -- do all actions in the stack
action = stack:peek() -- gets the action on top of the stack
while action.over ~= true do -- continue action until it is done
action:execute() -- execute is what the action actually does
end
stack:pop() -- action over, remove it and proceed to next one
end
The goto and other functions would look like this :
function goto(action, character, point)
-- INSTANT MOVE YEAH
character.x = point.x
character.y = point.y
action.over = true -- set the overlying action to be over
end
function attack(action, character, target)
-- INSTANT DEATH WOOHOO
target.hp = 0
action.over = true -- attack is a punctual action
end
function berserk(action, character)
attack(action, character, getNearestCharacterId()) -- Call the underlying attack
action.over = false -- but don't set action as done !
end
So whenever you stack:push(action:new(berserk, character)) it will loop on attacking a different target every time.
I also made you a stack and action implementation in object lua here. Haven't tried it. May be bugged like hell. Good luck with your game !
I don't know the reasons behind you design, and there might be simpler / more idiomatic ways to it.
However, would writing a custom "loop" process that would somehow take a function as it's argument do the trick ?
goto(point_a)
your_loop(function ()
character = getNearestCharacterId()
attack(character)
end)
Since Lua has closures (see here in the manual), the function could be attached to your 'LoopProcess', and you call this same function at each frame. You would probably have to implement your LoopProcess so that that it's never removed from the process list ...
If you want your loop to be able to stop, it's a bit more complicated ; you would have to pass another function containing the test logic (and again, you LoopProcess would have to call this every frame, or something).
Hoping I understood your problem ...
I'd like the user to be able to edit the number of recent files shown in the File menu of my MFC application. I've used two very good references:
http://www.codeproject.com/KB/menus/changemru.aspx
http://www.microsoft.com/msj/0899/c/c0899.aspx
It involves deleting and recreating the CRecentFileList object stored in CWinApp::m_pRecentFileList. Unfortunately, I find that the menu is not updated properly after replacing the CRecentFileList. See code snippet below:
void CMyWinApp::SetMRUListSize( int size )
{
// size guaranteed to be between 1 and 16
delete m_pRecentFileList ;
LoadStdProfileSettings( size ) ;
}
What can I do to ensure that what is drawn into the File menu is synchronized with m_pRecentFileList after I recreate the object?
My CApp derives from CWinApp. In initInstance, you have this line:
LoadStdProfileSettings(10);
At the end of InitInstance, add this code:
m_pmf->m_pRecentFileList = m_pRecentFileList;
Here m_pmf is my MainFrame class and I created a member CMainFrame::m_pRecentFileList of type CRecentFileList which is in the MFC source file filelist.cpp. m_pRecentFileList on the right is protected and CMainFrame doesn't have access to it from outside InitInstance, but you can make a functional copy here.
At the end of CMainFrame::OnClose, force a registry update by:
m_pRecentFileList->WriteList();
// Force registry update on exit. This doesn't work without forcing.
I don't even have to rebuild m_pRecentFileList, the MRU mechanism updates it correctly. Example: 5 MRU items, the first is moved to another directory and can no longer be found. Stepping through the code in the debugger shows that the bad entry is removed from the list. For some reason, the updated list isn't saved correctly unless I force it as explained above. I originally thought the problem might have something to do with privileges (64-bit Win7), but running the app as admin didn't help.
Some of Microsoft's documentation suggest you should call CWinApp::LoadStdProfileSettings from within InitInstance. This suggests to me that it's something done once during initialisation rather than at run time.
Have you tried fully implementing the second of the two links you provided? My guess is you need to add the second part instead of the call to CWinApp::LoadStdProfileSettings:
m_pRecentFileList = new CRecentFileList(0, strSection, strEntryFormat, nCount);
if(m_pRecentFileList)
{
bReturn = TRUE;
// Reload list of MRU files from registry
m_pRecentFileList->ReadList();
}
[Edit] Apparently m_pRecentFileList points to an CRecentFileList Class . Have you tried calling CRecentFileList::UpdateMenu?
There's another CodeProject example which might help too.