1 /*
2  * gnote
3  *
4  * Copyright (C) 2011-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 
24 #ifndef __NOTE_BUFFER_HPP_
25 #define __NOTE_BUFFER_HPP_
26 
27 #include <queue>
28 
29 #include <gtkmm/textbuffer.h>
30 #include <gtkmm/textiter.h>
31 #include <gtkmm/texttag.h>
32 #include <gtkmm/widget.h>
33 
34 #include "notetag.hpp"
35 
36 namespace sharp {
37   class XmlReader;
38   class XmlWriter;
39 }
40 
41 namespace gnote {
42 
43   class Preferences;
44   class Note;
45   class UndoManager;
46 
47 
48 class NoteBuffer
49   : public Gtk::TextBuffer
50 {
51 public:
52   typedef Glib::RefPtr<NoteBuffer> Ptr;
53   typedef sigc::signal<void, int, int> NewBulletHandler;
54   typedef sigc::signal<void, int, bool> ChangeDepthHandler;
55 
56   bool get_enable_auto_bulleted_lists() const;
create(const NoteTagTable::Ptr & table,Note & note,Preferences & preferences)57   static Ptr create(const NoteTagTable::Ptr & table, Note & note, Preferences & preferences)
58     {
59       return Ptr(new NoteBuffer(table, note, preferences));
60     }
61   ~NoteBuffer();
62 
note() const63   Note & note() const
64     {
65       return m_note;
66     }
67 
68   // Signal that text has been inserted, and any active tags have
69   // been applied to the text.  This allows undo to pull any
70   // active tags from the inserted text.
71   sigc::signal<void, const Gtk::TextIter &, const Glib::ustring &, int> signal_insert_text_with_tags;
72   ChangeDepthHandler                               signal_change_text_depth;
73   NewBulletHandler                                 signal_new_bullet_inserted;
74 
75   void toggle_active_tag(const Glib::ustring &);
76   void set_active_tag(const Glib::ustring &);
77   void remove_active_tag(const Glib::ustring &);
78   DynamicNoteTag::ConstPtr get_dynamic_tag(const Glib::ustring & tag_name, const Gtk::TextIter & iter);
79   void on_tag_applied(const Glib::RefPtr<Gtk::TextTag> &,
80                       const Gtk::TextIter &,const Gtk::TextIter &);
81   bool is_active_tag(const Glib::ustring & );
82   bool is_active_tag(const Glib::RefPtr<Gtk::TextTag> & tag);
83   bool is_bulleted_list_active();
84   bool is_bulleted_list_active(Gtk::TextIter iter);
85   bool can_make_bulleted_list();
86   bool add_tab();
87   bool remove_tab();
88   bool add_new_line(bool soft_break);
89   bool delete_key_handler();
90   bool backspace_key_handler();
91   void check_selection();
92   bool run_widget_queue();
93   void on_tag_changed(const Glib::RefPtr<Gtk::TextTag> &, bool);
undoer()94   UndoManager & undoer()
95     {
96       return *m_undomanager;
97     }
98   Glib::ustring get_selection() const;
99   static void get_block_extents(Gtk::TextIter &, Gtk::TextIter &,
100                            int threshold, const Glib::RefPtr<Gtk::TextTag> & avoid_tag);
101   void toggle_selection_bullets();
increase_cursor_depth()102   void increase_cursor_depth()
103     {
104       change_cursor_depth(true);
105     }
decrease_cursor_depth()106   void decrease_cursor_depth()
107     {
108       change_cursor_depth(false);
109     }
110   void change_cursor_depth_directional(bool right);
111   void insert_bullet(Gtk::TextIter & iter, int depth);
112   void remove_bullet(Gtk::TextIter & iter);
113   void increase_depth(Gtk::TextIter & start);
114   void decrease_depth(Gtk::TextIter & start);
115   DepthNoteTag::Ptr find_depth_tag(Gtk::TextIter &);
116   static bool is_bullet(gunichar c);
117   void select_note_body();
118 protected:
119   NoteBuffer(const NoteTagTable::Ptr &, Note &, Preferences &);
120 
121   virtual void on_apply_tag(const Glib::RefPtr<Gtk::TextTag> & tag,
122                        const Gtk::TextIter &,  const Gtk::TextIter &) override;
123   virtual void on_remove_tag(const Glib::RefPtr<Gtk::TextTag> & tag,
124                        const Gtk::TextIter &,  const Gtk::TextIter &) override;
125 private:
126   void text_insert_event(const Gtk::TextIter & pos, const Glib::ustring & text, int);
127   bool line_needs_bullet(Gtk::TextIter iter);
128   void augment_selection(Gtk::TextIter &, Gtk::TextIter &);
129   void mark_set_event(const Gtk::TextIter &,const Glib::RefPtr<Gtk::TextBuffer::Mark> &);
130   void widget_swap (const NoteTag::Ptr & tag, const Gtk::TextIter & start,
131                     const Gtk::TextIter & end_iter, bool adding);
132   void change_cursor_depth(bool increase);
133   typedef void (NoteBuffer::*DepthAction)(Gtk::TextIter & iter);
134   bool handle_tab(DepthAction depth_action);
135 
136   UndoManager           *m_undomanager;
137   static const gunichar s_indent_bullets[];
138 
139   // GODDAMN Gtk::TextBuffer. I hate you. Hate Hate Hate.
140   struct WidgetInsertData
141   {
142     bool adding;
143     Glib::RefPtr<Gtk::TextBuffer> buffer;
144     Glib::RefPtr<Gtk::TextMark>   position;
145     Gtk::Widget                  *widget;
146     NoteTag::Ptr                  tag;
147   };
148   std::queue<WidgetInsertData> m_widget_queue;
149   sigc::connection             m_widget_queue_timeout;
150   // HATE.
151 
152   // list of Glib::RefPtr<Gtk::TextTag>s to apply on insert
153   std::vector<Glib::RefPtr<Gtk::TextTag> >      m_active_tags;
154 
155   // The note that owns this buffer
156   Note &                       m_note;
157   Preferences &                m_preferences;
158 };
159 
160 class NoteBufferArchiver
161 {
162 public:
163   static Glib::ustring serialize(const Glib::RefPtr<Gtk::TextBuffer> & );
164   static Glib::ustring serialize(const Glib::RefPtr<Gtk::TextBuffer> & buffer, const Gtk::TextIter &,
165                                const Gtk::TextIter &);
166   static void serialize(const Glib::RefPtr<Gtk::TextBuffer> & buffer, const Gtk::TextIter &,
167                         const Gtk::TextIter &, sharp::XmlWriter & xml);
deserialize(const Glib::RefPtr<Gtk::TextBuffer> & buffer,const Glib::ustring & content)168   static void deserialize(const Glib::RefPtr<Gtk::TextBuffer> &buffer,
169                           const Glib::ustring & content)
170     {
171       deserialize(buffer, buffer->begin(), content);
172     }
173   static void deserialize(const Glib::RefPtr<Gtk::TextBuffer> &, const Gtk::TextIter & ,
174                           const Glib::ustring & );
175   static void deserialize(const Glib::RefPtr<Gtk::TextBuffer> & buffer,
176                           const Gtk::TextIter & iter, sharp::XmlReader & xml);
177 private:
178 
179   static void write_tag(const Glib::RefPtr<const Gtk::TextTag> & tag, sharp::XmlWriter & xml,
180                         bool start);
181   static bool tag_ends_here (const Glib::RefPtr<const Gtk::TextTag> & tag,
182                              const Gtk::TextIter & iter,
183                              const Gtk::TextIter & next_iter);
184 
185 //
186 };
187 
188 
189 }
190 
191 #endif
192 
193