2 /******************************************************************************
3 * MODULE : edit_modify.cpp
4 * DESCRIPTION: base routines for modifying the edit tree + notification
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
12 #include "modification.hpp"
13 #include "edit_modify.hpp"
14 #include "tm_window.hpp"
16 #include "../../Style/Memorizer/clean_copy.hpp"
19 /******************************************************************************
20 * Constructors and destructors
21 ******************************************************************************/
23 edit_modify_rep::edit_modify_rep ():
24 author (new_author ()),
26 edit_modify_rep::~edit_modify_rep () {}
28 /******************************************************************************
29 * Notification of changes in document
30 ******************************************************************************/
33 edit_modify_rep::notify_assign (path p
, tree u
) {
35 if (!(rp
<= p
)) return;
36 cur_pos
= position_new (tp
);
37 ::notify_assign (get_typesetter (), p
/ rp
, u
);
41 edit_modify_rep::notify_insert (path p
, tree u
) {
42 if (!(rp
<= p
)) return;
43 cur_pos
= position_new (tp
);
44 ::notify_insert (get_typesetter (), p
/ rp
, u
);
48 edit_modify_rep::notify_remove (path p
, int nr
) {
49 if (!(rp
<= p
)) return;
50 cur_pos
= position_new (tp
);
51 ::notify_remove (get_typesetter (), p
/ rp
, nr
);
55 edit_modify_rep::notify_split (path p
) {
56 if (!(rp
<= p
)) return;
57 cur_pos
= position_new (tp
);
58 ::notify_split (get_typesetter (), p
/ rp
);
62 edit_modify_rep::notify_join (path p
) {
63 if (!(rp
<= p
)) return;
64 cur_pos
= position_new (tp
);
65 ::notify_join (get_typesetter (), p
/ rp
);
69 edit_modify_rep::notify_assign_node (path p
, tree_label op
) {
70 if (!(rp
<= p
)) return;
71 cur_pos
= position_new (tp
);
72 ::notify_assign_node (get_typesetter (), p
/ rp
, op
);
76 edit_modify_rep::notify_insert_node (path p
, tree t
) {
77 if (!(rp
<= p
)) return;
78 cur_pos
= position_new (tp
);
79 ::notify_insert_node (get_typesetter (), p
/ rp
, t
);
83 edit_modify_rep::notify_remove_node (path p
) {
84 if (!(rp
<= p
)) return;
85 cur_pos
= position_new (tp
);
86 ::notify_remove_node (get_typesetter (), p
/ rp
);
90 edit_modify_rep::post_notify (path p
) {
91 // cout << "Post notify\n";
92 if (!(rp
<= p
)) return;
94 notify_change (THE_TREE
);
95 tp
= position_get (cur_pos
);
96 position_delete (cur_pos
);
97 cur_pos
= nil_observer
;
100 cout << "et= " << et << "\n";
101 cout << "tp= " << tp << "\n\n";
105 /******************************************************************************
106 * Hooks / notify changes to editor
107 ******************************************************************************/
109 // FIXME: the notification might be slow when we have many
110 // open buffers. In the future, we might obtain the relevant editors
111 // from all possible prefixes of p using a hashtable
113 // FIXME: the undo system is not safe when a change is made inside
114 // a buffer which has no editor attached to it
117 edit_assign (editor_rep
* ed
, path pp
, tree u
) {
119 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
120 ed
->notify_assign (p
, u
);
124 edit_insert (editor_rep
* ed
, path pp
, tree u
) {
126 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
127 ed
->notify_insert (p
, u
);
131 edit_remove (editor_rep
* ed
, path pp
, int nr
) {
133 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
135 ed
->notify_remove (p
, nr
);
139 edit_split (editor_rep
* ed
, path pp
) {
141 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
142 ed
->notify_split (p
);
146 edit_join (editor_rep
* ed
, path pp
) {
148 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
149 if (N(p
)<1) FAILED ("path too short in join");
154 edit_assign_node (editor_rep
* ed
, path pp
, tree_label op
) {
156 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
157 ed
->notify_assign_node (p
, op
);
161 edit_insert_node (editor_rep
* ed
, path pp
, tree t
) {
163 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
164 ed
->notify_insert_node (p
, t
);
168 edit_remove_node (editor_rep
* ed
, path pp
) {
170 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
171 ed
->notify_remove_node (p
);
175 edit_announce (editor_rep
* ed
, modification mod
) {
178 edit_assign (ed
, mod
->p
, mod
->t
);
181 edit_insert (ed
, mod
->p
, mod
->t
);
184 edit_remove (ed
, path_up (mod
->p
), last_item (mod
->p
));
187 edit_split (ed
, mod
->p
);
190 edit_join (ed
, mod
->p
);
192 case MOD_ASSIGN_NODE
:
193 edit_assign_node (ed
, mod
->p
, L(mod
));
195 case MOD_INSERT_NODE
:
196 edit_insert_node (ed
, mod
->p
, mod
->t
);
198 case MOD_REMOVE_NODE
:
199 edit_remove_node (ed
, mod
->p
);
201 default: FAILED ("invalid modification type");
206 edit_done (editor_rep
* ed
, modification mod
) {
207 path p
= copy (mod
->p
);
208 ASSERT (ed
->the_buffer_path() <= p
, "invalid modification");
211 copy_announce (subtree (ed
->et
, ed
->rp
), ed
->cct
, mod
/ ed
->rp
);
215 /******************************************************************************
216 * undo and redo handling
217 ******************************************************************************/
220 edit_modify_rep::clear_undo_history () {
221 global_clear_history ();
225 edit_modify_rep::this_author () {
230 edit_modify_rep::start_editing () {
231 set_author (this_author ());
235 edit_modify_rep::end_editing () {
240 edit_modify_rep::start_slave (double a
) {
241 arch
->start_slave (a
);
245 edit_modify_rep::mark_start (double a
) {
246 arch
->mark_start (a
);
250 edit_modify_rep::mark_cancel (double a
) {
251 return arch
->mark_cancel (a
);
255 edit_modify_rep::mark_end (double a
) {
260 edit_modify_rep::add_undo_mark () {
265 edit_modify_rep::remove_undo_mark () {
270 edit_modify_rep::undo_possibilities () {
271 return arch
->undo_possibilities ();
275 edit_modify_rep::undo (bool redoable
) {
276 interrupt_shortcut ();
277 if (inside_graphics () && !as_bool (eval ("graphics-undo-enabled"))) {
278 eval ("(graphics-reset-context 'undo)"); return; }
279 if (arch
->undo_possibilities () == 0) {
280 set_message ("No more undo information available", "undo"); return; }
282 path p
= arch
->undo ();
283 if (!is_nil (p
)) go_to (p
);
285 else arch
->forget ();
286 if (arch
->conform_save ()) {
287 set_message ("Your document is back in its original state", "undo");
289 if (inside_graphics ())
290 eval ("(graphics-reset-context 'undo)");
294 edit_modify_rep::unredoable_undo () {
299 edit_modify_rep::undo (int i
) {
300 ASSERT (i
== 0, "invalid undo");
305 edit_modify_rep::redo_possibilities () {
306 return arch
->redo_possibilities ();
310 edit_modify_rep::redo (int i
) {
311 interrupt_shortcut ();
312 if (arch
->redo_possibilities () == 0) {
313 set_message ("No more redo information available", "redo"); return; }
314 path p
= arch
->redo (i
);
315 if (!is_nil (p
)) go_to (p
);
316 if (arch
->conform_save ()) {
317 set_message ("Your document is back in its original state", "undo");
322 edit_modify_rep::require_save () {
323 arch
->require_autosave ();
324 arch
->require_save ();
328 edit_modify_rep::notify_save (bool real_save
) {
330 arch
->notify_autosave ();
331 if (real_save
) arch
->notify_save ();
335 edit_modify_rep::need_save (bool real_save
) {
336 if (arch
->conform_save ()) return false;
337 if (real_save
) return true;
338 return !arch
->conform_autosave ();
342 edit_modify_rep::show_history () {
346 /******************************************************************************
347 * handling multiple cursor positions
348 ******************************************************************************/
351 edit_modify_rep::position_new (path p
) {
352 tree st
= subtree (et
, path_up (p
));
353 int index
= last_item (p
);
354 observer o
= tree_position (st
, index
);
355 attach_observer (st
, o
);
360 edit_modify_rep::position_delete (observer o
) {
363 if (o
->get_position (st
, index
))
364 detach_observer (st
, o
);
368 edit_modify_rep::position_set (observer o
, path p
) {
369 tree st
= subtree (et
, path_up (p
));
370 int index
= last_item (p
);
371 o
->set_position (st
, index
);
375 edit_modify_rep::position_get (observer o
) {
376 //return super_correct (et, obtain_position (o));
377 return correct_cursor (et
, obtain_position (o
));