Welcome Dialog

Welcome to the Community!

We have a brand new look! Take a tour with us and explore the latest updates on Adobe Support Community.


ICommandMgr Observer - how to know which command is the one on the undo stack?

Enthusiast ,
May 11, 2021 May 11, 2021

Copy link to clipboard

Copied

I have an observer attached to kDocBoss listening to IID_ICOMMANDMGR. The Update() gets called numerous times for each command. How do I know which command is the one that actually appears on the Undo/Redo menu?

TOPICS
SDK

Views

490

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 12, 2021 May 12, 2021

Copy link to clipboard

Copied

I tried attaching an observer to the ICmdHistory but still no go. I am at a loss here how to get the names of the commands that are on the undo/redo list (Edit>Undo/Edit Redo) in real time as they are added. 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
May 14, 2021 May 14, 2021

Copy link to clipboard

Copied

Hi,

 

I don't think ICmdHistory is the way to go : from the docs

"It hides single commands (ICommand) and command sequences (ICommandSequence)."

As this appears to hide exactly what you are looking for.

 

What is your actual aim? Why do you need to know the specific commnads, commands in indesign are marked via ICommand::Undoability as to how they handle undo/redo.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 14, 2021 May 14, 2021

Copy link to clipboard

Copied

I am trying to keep a cache of the undo/redo list of each document. So I have an AddIn on the kDocBoss for the cache and then I have an observer that is managing that cache.

 

The problem is I can't figure out what to observe. If I observe the ICommandMgr on the kDocBos I get a whole bunch of calls to Update() for every single internal command being called. Many of them are set to ICommand::Undoability kRegularUndo but they don't actually show up on the Undo/Redo stack.

 

So I thought maybe that is because ICmdHistroy is managing which commands actually show up on the stack but that is not working either. I must be missing something obvious but I cna't figure it out.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
May 16, 2021 May 16, 2021

Copy link to clipboard

Copied

As Barlae already suggested this is a complicated topic.

You should start writing an extensive log that covers the various details of ICommand.

 

At the first time the changedBy should be kBeforeDoMessageBoss, followed by kAfterDoMessageBoss of the same command.

Commands can join the previous one for a common undo kAutoUndo, in effect hiding themselves.

Commands can invoke nested commands, multiple levels deep. Creating a document is notorious for that.

There are command sequences that put one name onto multiple commands.

There are commands that are dynamically executed by a mouse tracker performing multiple scale operations until the mouse goes up for the final one.

Dialog managers capture commands during preview mode, in case the user clicks cancel.

Reliably observing undo will also be fun. Watch out for savepoints …

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 16, 2021 May 16, 2021

Copy link to clipboard

Copied

I did notice that I am getting kBeforeDoMessageBoss and kAfterDoMessageBoss for each command. But I am also getting multiple commands with kRegularUndo even though only one is actually being added to the undo stack. I can't figure out how to know which one is being added. For example creating a new text frame gives a Create New Story command  and Create New Text Frame both with kRegularUndo but only Create  New Text Frame shows up on the undo stack. It leads me to believe there is some other way of observing when items get added to the undo history of a document. 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe Community Professional ,
May 17, 2021 May 17, 2021

Copy link to clipboard

Copied

Hi,

 

In the example you give  everything will be tied up in the "Create New Text Frame" command, and it will control the creation of the "Create New Story" command, and these will be combined into the single undo command, as the undo stack is really for the user so it would not make sense to add something that the user can't really see, when this command is run, the user will see a new text frame on the document, they wont see a new story being created, so it wouldn't make sense for that to appear in the menu's for undo, although it would need to be undone at the same time. That is my understanding, hope fully it help.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 19, 2021 May 19, 2021

Copy link to clipboard

Copied

Thank you very much Barlae and Dirk for taking the time to explain this to me. I fully understand that one command is causing other commands. I just can't figure out which one is the "real" one.

When creating a new text frame this is the order of commands I get with the set to ICommand::Undoability kRegularUndo and the ICommand->IsDone() set to kTrue.

I have a PMString which gets the command name using ICommand->GetName(), this is what that PMString holds:

  1. Many Private Create Strands
  2. New Story
  3. Register Strand
  4. TEST
  5. Apply Attributes
  6. TEST
  7. Set Transparency Parameters
  8. Many Apply Attribute(s)
  9. Apply Object Style
  10. Modify Frame Options
  11. Add New Item
  12. Add Path Points
  13. Close Path
  14. Set Item Matrix
  15. Add To Hierarchy
  16. Add New Item
  17. Create Text Frame
  18. Transform Item

 

The only one that actually gets added to the user visible undo stack is number 17 "Create Text Frame". How do I know which one is the one that is calling everything else?

 

 

 

 

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
May 20, 2021 May 20, 2021

Copy link to clipboard

Copied

"When creating a new text frame": There is more than one way to … create a text frame.

 

When I create a new/blank document, use the text tool and drag-create a frame, my first command is an kNewUIDCmdBoss that creates the kFrameListBoss. Ah, your concatening names approach won't even notice it because the command name is blank so I was missing it in your list.

 

New Story (kNewStoryCmdBoss) is definitely before create strands - are you recording the kAfterDoMessageBoss?

Let me repeat the suggestion to produce an exhaustive log file. Anyway, increment a nesting counter on kBefore and decrement it on kAfter, so you can ignore all nested commands. That will give you quite some reduction - you should have done that as soon we were talking about nested commands.

 

At that point several commands will remain top level, and they are kRegularUndo. So I'd assume they are glued together with a command sequence. Revisiting everything with a live plug-in, that is indeed the case. Looking up in this thread, what exactly was wrong with ICmdHistory notifications? kDisableCmdHistoryMessage and alike will be key to your scenario. kAddUndoCmdHistoryItemsMessage is the notification to watch out for a sequence. I just hate wading thru that noise so my tracing code usually hides them away.

 

As I said, it is an interesting but complicated topic. We could go on for days and still end up with something incomplete. In case you are reinventing the wheel of a history panel, there are already two - see 65bit and DTPTools.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
May 23, 2021 May 23, 2021

Copy link to clipboard

Copied

Thank you Dirk your posts are immensely helpful!

 

"When creating a new text frame": There is more than one way to … create a text frame.

 

Yes I meant with dragging the text tool.

 

Let me repeat the suggestion to produce an exhaustive log file. 

 

I have done a bit of that but there are so many commands and so many different ways of executing them in InDesign.  

 

Anyway, increment a nesting counter on kBefore and decrement it on kAfter, so you can ignore all nested commands. That will give you quite some reduction - you should have done that as soon we were talking about nested commands.

 

I am not sure I understand you correctly. I have an fCounter member avriable in my Observer class which I am incrementing and decrementing like this:

 

if(theChange==kAfterDoMessageBoss){
fCounter++;
}
if(theChange==kBeforeDoMessageBoss){
fCounter--;
}


 I am then filtering out a lot of things with this if statement:

 

if(isDone==kTrue&&undoability==1 &&commandName.empty()!=kTrue&&theChange==kAfterDoMessageBoss&&fCreatorID!=creatorID&&fCounter==1){
}


 I am still getting the following when dragging with the text tool to create a text frame:

 

  1. New Story
  2. Create Text Frame
  3. Transform Item

So we are definitely close. When I drag with the rectangle tool I am getting the following:

  1. Add New Item
  2. Add Path Points
  3. Transform Item
  4. Add To Hierarchy
  5. Resize
    In the Undo Stack only the first "Add New Item" is visible. 

 

Looking up in this thread, what exactly was wrong with ICmdHistory notifications? kDisableCmdHistoryMessage and alike will be key to your scenario. kAddUndoCmdHistoryItemsMessage is the notification to watch out for a sequence.

 

Casting the changedBy to an ICommand pointer was not producing a valid pointer. So even though I did get a kDisableCmdHistoryMessage every time a command was executed I was unable to get the name of the command. 


In case you are reinventing the wheel of a history panel, there are already two - see 65bit and DTPTools.

 

Not exactly reinventing the wheel but definitely a similar wheel. I am doing this in house for my company, though. Not looking to sell commercially. Although, their success in the matter definitely lead me to believe I am totally missing the boat. It is encouraging that you are saying I am on the right track. This is what makes InDesign plugin development so difficult. There are so many ways to skin a cat, but not all of them actually work.

 

Would a menu filter get called every time the undo stack changes to update the Edit menu or is that only updated when a user clicks on the Edit menu?

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Enthusiast ,
Aug 24, 2021 Aug 24, 2021

Copy link to clipboard

Copied

LATEST

For all the lurkers out there what ended up working nicely an IdleTask (IIdleTask). I have a private member int32 variable where I save the ICmdHistory->GetUndoStepCount(docRef);. I then test if the amount matches. If it doesn't that means another CmdStackItem was added and I updated the cache. Probably not the most elegant solution but it works.

Likes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines