LCOV - code coverage report
Current view: top level - src/engraving/editing/transaction - undostack.h Coverage Total Hit
Test: filtered_coverage.info Lines: 76.5 % 17 13
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #pragma once
      24              : 
      25              : #include <map>
      26              : 
      27              : #include "global/containers.h"
      28              : #include "global/types/translatablestring.h"
      29              : 
      30              : #include "../../dom/input.h"
      31              : 
      32              : namespace mu::engraving {
      33              : class EngravingObject;
      34              : class Score;
      35              : class Segment;
      36              : class Box;
      37              : 
      38              : class EditData;
      39              : 
      40              : class UndoableCommand;
      41              : enum class UndoableCommandFilter : unsigned char;
      42              : enum class CommandType : signed char;
      43              : 
      44              : class UndoableTransaction
      45              : {
      46              : public:
      47              :     UndoableTransaction(Score* s, const muse::TranslatableString& actionName);
      48              :     ~UndoableTransaction();
      49              : 
      50              :     void undo();
      51              :     void redo();
      52              : 
      53        20940 :     void appendCommand(UndoableCommand* cmd) { m_commands.push_back(cmd); }
      54              :     void append(UndoableTransaction&& other);
      55              : 
      56              :     void unwind(bool cleanUp = true);
      57              :     void cleanup(bool wasDone);
      58              : 
      59         4203 :     const std::vector<UndoableCommand*>& commands() const { return m_commands; }
      60         1266 :     bool empty() const { return m_commands.empty(); }
      61              : 
      62              :     bool hasCommandsMatchingFilter(UndoableCommandFilter, const EngravingItem* target) const;
      63              :     bool hasCommandsNotMatchingFilters(const std::vector<UndoableCommandFilter>& filters, const EngravingItem* target) const;
      64              :     void removeCommandsMatchingFilter(UndoableCommandFilter f, EngravingItem* target);
      65              : 
      66              :     const InputState& undoInputState() const;
      67              :     const InputState& redoInputState() const;
      68              : 
      69              :     struct SelectionInfo {
      70              :         std::vector<EngravingItem*> elements;
      71              :         Fraction tickStart;
      72              :         Fraction tickEnd;
      73              :         staff_idx_t staffStart = muse::nidx;
      74              :         staff_idx_t staffEnd = muse::nidx;
      75              :         Box* startBox = nullptr;
      76              :         Box* endBox = nullptr;
      77              : 
      78          230 :         bool isValid() const { return !elements.empty() || staffStart != muse::nidx; }
      79              :     };
      80              : 
      81              :     const SelectionInfo& undoSelectionInfo() const;
      82              :     const SelectionInfo& redoSelectionInfo() const;
      83              : 
      84              :     void excludeElementFromSelectionInfo(EngravingItem* element);
      85              :     static bool canRecordSelectedElement(const EngravingItem* e);
      86              : 
      87              :     struct ChangesInfo {
      88              :         ElementTypeSet changedObjectTypes;
      89              :         std::map<EngravingObject*, std::unordered_set<CommandType> > changedObjects;
      90              :         StyleIdSet changedStyleIdSet;
      91              :         PropertyIdSet changedPropertyIdSet;
      92              :         bool isTextEditing = false;
      93              :     };
      94              : 
      95              :     ChangesInfo changesInfo(bool undo = false) const;
      96              :     const muse::TranslatableString& actionName() const;
      97              : 
      98              : private:
      99              :     void appendCommands(UndoableTransaction& other);
     100              : 
     101              :     std::vector<UndoableCommand*> m_commands;
     102              : 
     103              :     InputState m_undoInputState;
     104              :     InputState m_redoInputState;
     105              :     SelectionInfo m_undoSelectionInfo;
     106              :     SelectionInfo m_redoSelectionInfo;
     107              :     muse::TranslatableString m_actionName;
     108              : 
     109              :     Score* m_score = nullptr;
     110              : 
     111              :     static void fillSelectionInfo(SelectionInfo&, const Selection&);
     112              :     static void applySelectionInfo(const SelectionInfo&, Selection&);
     113              : };
     114              : 
     115              : class UndoStack
     116              : {
     117              : public:
     118              :     UndoStack();
     119              :     ~UndoStack();
     120              : 
     121              :     bool isLocked() const;
     122              :     void setLocked(bool locked);
     123              : 
     124         3024 :     bool hasActiveTransaction() const { return m_activeTransaction != nullptr; }
     125              : 
     126              :     void beginTransaction(Score*, const muse::TranslatableString& actionName);
     127              :     void endTransaction(bool rollback);
     128              : 
     129          168 :     bool canUndo() const { return m_currentIndex > 0; }
     130           70 :     bool canRedo() const { return m_currentIndex < m_transactions.size(); }
     131         1266 :     bool isClean() const { return m_cleanState == m_states[m_currentIndex]; }
     132              : 
     133            2 :     size_t size() const { return m_transactions.size(); }
     134          364 :     size_t currentIndex() const { return m_currentIndex; }
     135              : 
     136         6331 :     UndoableTransaction* activeTransaction() const { return m_activeTransaction; }
     137              : 
     138          205 :     UndoableTransaction* last() const { return m_currentIndex > 0 ? m_transactions[m_currentIndex - 1] : nullptr; }
     139            0 :     UndoableTransaction* prev() const { return m_currentIndex > 1 ? m_transactions[m_currentIndex - 2] : nullptr; }
     140            0 :     UndoableTransaction* next() const { return canRedo() ? m_transactions[m_currentIndex] : nullptr; }
     141              : 
     142              :     /// Returns the transaction that led to the state with the given `idx`.
     143              :     /// For further discussion of the indices involved in UndoStack, see:
     144              :     /// https://github.com/musescore/MuseScore/pull/25389#discussion_r1825782176
     145            0 :     UndoableTransaction* lastAtIndex(size_t idx) const
     146              :     {
     147            0 :         return idx > 0 && idx - 1 < m_transactions.size() ? m_transactions[idx - 1] : nullptr;
     148              :     }
     149              : 
     150              :     void undo(EditData*);
     151              :     void redo();
     152              :     void reopen();
     153              : 
     154              :     void mergeTransactions(size_t startIdx);
     155            1 :     void cleanRedoStack() { remove(m_currentIndex); }
     156              : 
     157              : private:
     158              :     void remove(size_t idx);
     159              : 
     160              :     UndoableTransaction* m_activeTransaction = nullptr;
     161              :     std::vector<UndoableTransaction*> m_transactions;
     162              :     std::vector<int> m_states;
     163              :     int m_nextState = 0;
     164              :     int m_cleanState = 0;
     165              :     size_t m_currentIndex = 0;
     166              :     bool m_isLocked = false;
     167              : };
     168              : }
        

Generated by: LCOV version 2.0-1