UndoStack.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <LibGUI/Command.h>
  8. #include <LibGUI/UndoStack.h>
  9. namespace GUI {
  10. bool UndoStack::can_undo() const
  11. {
  12. return m_stack_index > 0;
  13. }
  14. bool UndoStack::can_redo() const
  15. {
  16. if (m_stack.is_empty())
  17. return false;
  18. return m_stack_index != m_stack.size();
  19. }
  20. void UndoStack::undo()
  21. {
  22. if (!can_undo())
  23. return;
  24. auto& command = m_stack[--m_stack_index];
  25. command->undo();
  26. if (on_state_change)
  27. on_state_change();
  28. }
  29. void UndoStack::redo()
  30. {
  31. if (!can_redo())
  32. return;
  33. auto& command = m_stack[m_stack_index++];
  34. command->redo();
  35. if (on_state_change)
  36. on_state_change();
  37. }
  38. ErrorOr<void> UndoStack::try_push(NonnullOwnPtr<Command> command)
  39. {
  40. // If the stack cursor is behind the top of the stack, nuke everything from here to the top.
  41. while (m_stack.size() != m_stack_index)
  42. (void)m_stack.take_last();
  43. if (m_clean_index.has_value() && m_clean_index.value() > m_stack.size())
  44. m_clean_index = {};
  45. if (!m_stack.is_empty() && is_current_modified()) {
  46. if (m_stack.last()->merge_with(*command))
  47. return {};
  48. }
  49. TRY(m_stack.try_append(move(command)));
  50. m_stack_index = m_stack.size();
  51. if (on_state_change)
  52. on_state_change();
  53. return {};
  54. }
  55. void UndoStack::push(NonnullOwnPtr<Command> command)
  56. {
  57. MUST(try_push(move(command)));
  58. }
  59. void UndoStack::set_current_unmodified()
  60. {
  61. if (m_clean_index.has_value() && m_clean_index.value() == m_stack_index)
  62. return;
  63. m_clean_index = m_stack_index;
  64. m_last_unmodified_timestamp = Time::now_monotonic();
  65. if (on_state_change)
  66. on_state_change();
  67. }
  68. bool UndoStack::is_current_modified() const
  69. {
  70. if (m_stack.is_empty())
  71. return false;
  72. if (!m_clean_index.has_value())
  73. return true;
  74. if (m_stack_index != m_clean_index.value())
  75. return true;
  76. return false;
  77. }
  78. void UndoStack::clear()
  79. {
  80. if (m_stack.is_empty() && m_stack_index == 0 && !m_clean_index.has_value())
  81. return;
  82. m_stack.clear();
  83. m_stack_index = 0;
  84. m_clean_index.clear();
  85. if (on_state_change)
  86. on_state_change();
  87. }
  88. Optional<DeprecatedString> UndoStack::undo_action_text() const
  89. {
  90. if (!can_undo())
  91. return {};
  92. return m_stack[m_stack_index - 1]->action_text();
  93. }
  94. Optional<DeprecatedString> UndoStack::redo_action_text() const
  95. {
  96. if (!can_redo())
  97. return {};
  98. return m_stack[m_stack_index]->action_text();
  99. }
  100. }