Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Failed commands on QUndoStack
Forum Updated to NodeBB v4.3 + New Features

Failed commands on QUndoStack

Scheduled Pinned Locked Moved General and Desktop
3 Posts 2 Posters 1.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    Resurrection
    wrote on last edited by
    #1

    Qt Undo/Redo Framework is pretty neat but I have encountered a rather annoying problem with it. When a command fails to redo there is no way for it to be removed from the stack. Since it is the most recent command I fail to see why there is this limitation.

    Essentially it would mean removing it upon failure or after calling QUndoCommand::undo if failure was indicated (same as going one step back and recording new command). Currently this could be partially implemented for stand-alone commands but not for macros or child commands as one has no control over it once it is finished.

    I have already tried to implement it using the merging mechanism but it is not perfect (for instance if first command fails it cannot be merged with anything or it does not work outside macro's boundaries when macro is recording) and it prevents the merge to be used in a regular way.

    The result is that the stack might contain bunch of invalid commands that do nothing (or undos changes that were not actually done) that causes problems ranging from mere inconvenience to potential corruption of data/state (if undo expects redo to be successful).

    Are there any solutions to this problem?

    Secrets are power.

    1 Reply Last reply
    0
    • R Offline
      R Offline
      Resurrection
      wrote on last edited by
      #2

      This isn't the complete solution but work-around that will work for some cases and does not create too much overhead:

      Have a base class of all your command sub-classes, such as

      Note: Using C++11

      @
      class UndoBase : public QUndoCommand
      {
      public:
      bool isFailed() const { return m_bFailed; }
      void setDisabled(const bool &disabled) { m_bDisabled = disabled; }

      protected:
      bool m_bFailed = false;
      bool m_bDisabled = false;
      };
      @

      and then your commands like this

      @
      class MyUndo : public UndoBase
      {
      public:
      virtual void undo() override
      {
      if(m_bDisabled) return;
      //your undo code
      }
      virtual void redo() override
      {
      if(m_bDisabled) return;
      //your redo code
      m_bFailed = true; //if failed
      }
      };
      @

      and then create a processing function for your commands either in subclass of QUndoStack or wherever like this (example assumes this function is part of QUndoStack subclass):

      @
      bool processCommand(UndoBase *cmd)
      {
      if(!cmd) return false;

      cmd->redo();
      
      if(cmd->isFailed())
      {
          delete cmd;
          return false;
      }
      else
      {
          cmd->setDisabled(true);
          push(cmd);
          cmd->setDisabled(false);
      
          return true; 
      }
      

      }
      @

      This will ensure that any failed command gets discarded. However if you are recording in the macro the macro command will still be placed on the stack...

      Secrets are power.

      1 Reply Last reply
      0
      • Y Offline
        Y Offline
        Yevhenii Dementieiev
        wrote on last edited by
        #3

        Very old topic, but anyway here is the answer, since 5.9.

        QUndoCommand::setObsolete(bool)
        

        Returns whether the command is obsolete.
        The boolean is used for the automatic removal of commands that are not necessary in the
        stack anymore. Will be checked in QUndoStack::push(),
        QUndoStack::undo(), QUndoStack::redo(), and QUndoStack::setIndex().

        Example:

        void YourUndoCommand::redo()
        {
            // Your code that failed for some reason...
            const bool redoFailed = true;
        
            if (redoFailed)
            {
                    // Mark this command as absolute, which means 
                    // it will be removed automatically from the stack just after we leave redo.
                    this->setObsolete(true);
            }
        }
        
        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved