Serenity Operating System
at master 128 lines 2.7 kB view raw
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 8#include <AK/NonnullOwnPtr.h> 9#include <LibGUI/Command.h> 10#include <LibGUI/UndoStack.h> 11 12namespace GUI { 13 14bool UndoStack::can_undo() const 15{ 16 return m_stack_index > 0; 17} 18 19bool UndoStack::can_redo() const 20{ 21 if (m_stack.is_empty()) 22 return false; 23 return m_stack_index != m_stack.size(); 24} 25 26void UndoStack::undo() 27{ 28 if (!can_undo()) 29 return; 30 31 auto& command = m_stack[--m_stack_index]; 32 command->undo(); 33 34 if (on_state_change) 35 on_state_change(); 36} 37 38void UndoStack::redo() 39{ 40 if (!can_redo()) 41 return; 42 43 auto& command = m_stack[m_stack_index++]; 44 command->redo(); 45 46 if (on_state_change) 47 on_state_change(); 48} 49 50ErrorOr<void> UndoStack::try_push(NonnullOwnPtr<Command> command) 51{ 52 // If the stack cursor is behind the top of the stack, nuke everything from here to the top. 53 while (m_stack.size() != m_stack_index) 54 (void)m_stack.take_last(); 55 56 if (m_clean_index.has_value() && m_clean_index.value() > m_stack.size()) 57 m_clean_index = {}; 58 59 if (!m_stack.is_empty() && is_current_modified()) { 60 if (m_stack.last()->merge_with(*command)) 61 return {}; 62 } 63 64 TRY(m_stack.try_append(move(command))); 65 m_stack_index = m_stack.size(); 66 67 if (on_state_change) 68 on_state_change(); 69 70 return {}; 71} 72 73void UndoStack::push(NonnullOwnPtr<Command> command) 74{ 75 MUST(try_push(move(command))); 76} 77 78void UndoStack::set_current_unmodified() 79{ 80 if (m_clean_index.has_value() && m_clean_index.value() == m_stack_index) 81 return; 82 83 m_clean_index = m_stack_index; 84 m_last_unmodified_timestamp = Time::now_monotonic(); 85 86 if (on_state_change) 87 on_state_change(); 88} 89 90bool UndoStack::is_current_modified() const 91{ 92 if (m_stack.is_empty()) 93 return false; 94 if (!m_clean_index.has_value()) 95 return true; 96 if (m_stack_index != m_clean_index.value()) 97 return true; 98 return false; 99} 100 101void UndoStack::clear() 102{ 103 if (m_stack.is_empty() && m_stack_index == 0 && !m_clean_index.has_value()) 104 return; 105 106 m_stack.clear(); 107 m_stack_index = 0; 108 m_clean_index.clear(); 109 110 if (on_state_change) 111 on_state_change(); 112} 113 114Optional<DeprecatedString> UndoStack::undo_action_text() const 115{ 116 if (!can_undo()) 117 return {}; 118 return m_stack[m_stack_index - 1]->action_text(); 119} 120 121Optional<DeprecatedString> UndoStack::redo_action_text() const 122{ 123 if (!can_redo()) 124 return {}; 125 return m_stack[m_stack_index]->action_text(); 126} 127 128}