1 /* 2 * gnote 3 * 4 * Copyright (C) 2013,2016-2017,2019 Aurimas Cernius 5 * Copyright (C) 2009 Hubert Figuiere 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 22 23 #ifndef __UNDO_HPP_ 24 #define __UNDO_HPP_ 25 26 #include <stack> 27 28 #include <sigc++/signal.h> 29 #include <gtkmm/textbuffer.h> 30 #include <gtkmm/texttag.h> 31 #include <gtkmm/textiter.h> 32 33 #include "noncopyable.hpp" 34 #include "notebuffer.hpp" 35 #include "utils.hpp" 36 37 namespace gnote { 38 39 40 class EditAction 41 { 42 public: ~EditAction()43 virtual ~EditAction() {} 44 virtual void undo (Gtk::TextBuffer * buffer) = 0; 45 virtual void redo (Gtk::TextBuffer * buffer) = 0; 46 virtual void merge (EditAction * action) = 0; 47 virtual bool can_merge (const EditAction * action) const = 0; 48 virtual void destroy () = 0; 49 }; 50 51 class EditActionGroup 52 : public EditAction 53 { 54 public: 55 EditActionGroup(bool start); 56 virtual void undo(Gtk::TextBuffer *buffer) override; 57 virtual void redo(Gtk::TextBuffer *buffer) override; 58 virtual void merge(EditAction *action) override; 59 virtual bool can_merge(const EditAction *action) const override; 60 virtual void destroy() override; is_start() const61 bool is_start() const 62 { 63 return m_start; 64 } 65 private: 66 bool m_start; 67 }; 68 69 class ChopBuffer 70 : public Gtk::TextBuffer 71 { 72 public: 73 typedef Glib::RefPtr<ChopBuffer> Ptr; 74 ChopBuffer(const Glib::RefPtr<Gtk::TextTagTable> & table); 75 utils::TextRange add_chop(const Gtk::TextIter & start_iter, const Gtk::TextIter & end_iter); 76 }; 77 78 79 class SplitterAction 80 : public EditAction 81 { 82 public: 83 struct TagData { 84 int start; 85 int end; 86 Glib::RefPtr<Gtk::TextTag> tag; 87 }; 88 get_chop() const89 const utils::TextRange & get_chop() const 90 { 91 return m_chop; 92 } get_split_tags() const93 const std::vector<TagData> & get_split_tags() const 94 { 95 return m_splitTags; 96 } 97 void split(Gtk::TextIter iter, Gtk::TextBuffer *); 98 void add_split_tag(const Gtk::TextIter &, const Gtk::TextIter &, 99 const Glib::RefPtr<Gtk::TextTag> tag); 100 protected: 101 SplitterAction(); 102 int get_split_offset() const; 103 void apply_split_tag(Gtk::TextBuffer *); 104 void remove_split_tags(Gtk::TextBuffer *); 105 std::vector<TagData> m_splitTags; 106 utils::TextRange m_chop; 107 }; 108 109 110 111 class InsertAction 112 : public SplitterAction 113 { 114 public: 115 InsertAction(const Gtk::TextIter & start, const Glib::ustring & text, int length, 116 const ChopBuffer::Ptr & chop_buf); 117 virtual void undo(Gtk::TextBuffer * buffer) override; 118 virtual void redo(Gtk::TextBuffer * buffer) override; 119 virtual void merge(EditAction * action) override; 120 virtual bool can_merge(const EditAction * action) const override; 121 virtual void destroy() override; 122 123 private: 124 int m_index; 125 bool m_is_paste; 126 }; 127 128 129 class EraseAction 130 : public SplitterAction 131 { 132 public: 133 EraseAction(const Gtk::TextIter & start_iter, const Gtk::TextIter & end_iter, 134 const ChopBuffer::Ptr & chop_buf); 135 virtual void undo(Gtk::TextBuffer * buffer) override; 136 virtual void redo(Gtk::TextBuffer * buffer) override; 137 virtual void merge(EditAction * action) override; 138 virtual bool can_merge(const EditAction * action) const override; 139 virtual void destroy() override; 140 141 private: 142 int m_start; 143 int m_end; 144 bool m_is_forward; 145 bool m_is_cut; 146 }; 147 148 149 150 class TagApplyAction 151 : public EditAction 152 { 153 public: 154 TagApplyAction(const Glib::RefPtr<Gtk::TextTag> &, const Gtk::TextIter & start, const Gtk::TextIter & end); 155 virtual void undo(Gtk::TextBuffer * buffer) override; 156 virtual void redo(Gtk::TextBuffer * buffer) override; 157 virtual void merge(EditAction * action) override; 158 virtual bool can_merge(const EditAction * action) const override; 159 virtual void destroy() override; 160 161 private: 162 Glib::RefPtr<Gtk::TextTag> m_tag; 163 int m_start; 164 int m_end; 165 }; 166 167 168 class TagRemoveAction 169 : public EditAction 170 { 171 public: 172 TagRemoveAction(const Glib::RefPtr<Gtk::TextTag> &, const Gtk::TextIter & start, const Gtk::TextIter & end); 173 virtual void undo(Gtk::TextBuffer * buffer) override; 174 virtual void redo(Gtk::TextBuffer * buffer) override; 175 virtual void merge(EditAction * action) override; 176 virtual bool can_merge(const EditAction * action) const override; 177 virtual void destroy() override; 178 private: 179 Glib::RefPtr<Gtk::TextTag> m_tag; 180 int m_start; 181 int m_end; 182 }; 183 184 185 class ChangeDepthAction 186 : public EditAction 187 { 188 public: 189 ChangeDepthAction(int line, bool direction); 190 virtual void undo(Gtk::TextBuffer * buffer) override; 191 virtual void redo(Gtk::TextBuffer * buffer) override; 192 virtual void merge(EditAction * action) override; 193 virtual bool can_merge(const EditAction * action) const override; 194 virtual void destroy() override; 195 private: 196 int m_line; 197 bool m_direction; 198 }; 199 200 201 202 class InsertBulletAction 203 : public EditAction 204 { 205 public: 206 InsertBulletAction(int offset, int depth); 207 virtual void undo(Gtk::TextBuffer * buffer) override; 208 virtual void redo(Gtk::TextBuffer * buffer) override; 209 virtual void merge(EditAction * action) override; 210 virtual bool can_merge(const EditAction * action) const override; 211 virtual void destroy() override; 212 private: 213 int m_offset; 214 int m_depth; 215 }; 216 217 class UndoManager 218 : public gnote::NonCopyable 219 { 220 public: 221 /** the buffer it NOT owned by the UndoManager 222 * it is assume to have a longer life than UndoManager 223 * Actually the UndoManager belong to the buffer. 224 */ 225 UndoManager(NoteBuffer * buffer); 226 ~UndoManager(); get_can_undo()227 bool get_can_undo() 228 { 229 return !m_undo_stack.empty(); 230 } get_can_redo()231 bool get_can_redo() 232 { 233 return !m_redo_stack.empty(); 234 } undo()235 void undo() 236 { 237 undo_redo(m_undo_stack, m_redo_stack, true); 238 } redo()239 void redo() 240 { 241 undo_redo(m_redo_stack, m_undo_stack, false); 242 } freeze_undo()243 void freeze_undo() 244 { 245 ++m_frozen_cnt; 246 } thaw_undo()247 void thaw_undo() 248 { 249 --m_frozen_cnt; 250 } 251 252 void undo_redo(std::stack<EditAction *> &, std::stack<EditAction *> &, bool); 253 void undo_redo_action(EditAction & action, bool); 254 void clear_undo_history(); 255 void add_undo_action(EditAction * action); 256 signal_undo_changed()257 sigc::signal<void> & signal_undo_changed() 258 { return m_undo_changed; } 259 260 private: 261 262 void clear_action_stack(std::stack<EditAction *> &); 263 void on_insert_text(const Gtk::TextIter &, const Glib::ustring &, int); 264 void on_delete_range(const Gtk::TextIter &, const Gtk::TextIter &); 265 void on_tag_applied(const Glib::RefPtr<Gtk::TextTag> &, 266 const Gtk::TextIter &, const Gtk::TextIter &); 267 void on_tag_removed(const Glib::RefPtr<Gtk::TextTag> &, 268 const Gtk::TextIter &, const Gtk::TextIter &); 269 270 void on_change_depth(int, bool); 271 void on_bullet_inserted(int, int); 272 273 guint m_frozen_cnt; 274 bool m_try_merge; 275 NoteBuffer * m_buffer; 276 ChopBuffer::Ptr m_chop_buffer; 277 std::stack<EditAction *> m_undo_stack; 278 std::stack<EditAction *> m_redo_stack; 279 sigc::signal<void> m_undo_changed; 280 }; 281 282 283 } 284 285 #endif 286