Fix dirty conflict between archiver and emulate_keyboard
[texmacs.git] / src / src / Edit / Modify / edit_modify.cpp
blob3b19a00cf2d8e819dc0c69320459ab196127c985
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"
15 #ifdef EXPERIMENTAL
16 #include "../../Style/Memorizer/clean_copy.hpp"
17 #endif
19 /******************************************************************************
20 * Constructors and destructors
21 ******************************************************************************/
23 edit_modify_rep::edit_modify_rep ():
24 author (new_author ()),
25 arch (author, rp) {}
26 edit_modify_rep::~edit_modify_rep () {}
28 /******************************************************************************
29 * Notification of changes in document
30 ******************************************************************************/
32 void
33 edit_modify_rep::notify_assign (path p, tree u) {
34 (void) u;
35 if (!(rp <= p)) return;
36 cur_pos= position_new (tp);
37 ::notify_assign (get_typesetter (), p / rp, u);
40 void
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);
47 void
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);
54 void
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);
61 void
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);
68 void
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);
75 void
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);
82 void
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);
89 void
90 edit_modify_rep::post_notify (path p) {
91 // cout << "Post notify\n";
92 if (!(rp <= p)) return;
93 selection_cancel ();
94 notify_change (THE_TREE);
95 tp= position_get (cur_pos);
96 position_delete (cur_pos);
97 cur_pos= nil_observer;
98 go_to_correct (tp);
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
116 void
117 edit_assign (editor_rep* ed, path pp, tree u) {
118 path p= copy (pp);
119 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
120 ed->notify_assign (p, u);
123 void
124 edit_insert (editor_rep* ed, path pp, tree u) {
125 path p= copy (pp);
126 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
127 ed->notify_insert (p, u);
130 void
131 edit_remove (editor_rep* ed, path pp, int nr) {
132 path p= copy (pp);
133 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
134 if (nr <= 0) return;
135 ed->notify_remove (p, nr);
138 void
139 edit_split (editor_rep* ed, path pp) {
140 path p= copy (pp);
141 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
142 ed->notify_split (p);
145 void
146 edit_join (editor_rep* ed, path pp) {
147 path p= copy (pp);
148 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
149 if (N(p)<1) FAILED ("path too short in join");
150 ed->notify_join (p);
153 void
154 edit_assign_node (editor_rep* ed, path pp, tree_label op) {
155 path p= copy (pp);
156 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
157 ed->notify_assign_node (p, op);
160 void
161 edit_insert_node (editor_rep* ed, path pp, tree t) {
162 path p= copy (pp);
163 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
164 ed->notify_insert_node (p, t);
167 void
168 edit_remove_node (editor_rep* ed, path pp) {
169 path p= copy (pp);
170 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
171 ed->notify_remove_node (p);
174 void
175 edit_announce (editor_rep* ed, modification mod) {
176 switch (mod->k) {
177 case MOD_ASSIGN:
178 edit_assign (ed, mod->p, mod->t);
179 break;
180 case MOD_INSERT:
181 edit_insert (ed, mod->p, mod->t);
182 break;
183 case MOD_REMOVE:
184 edit_remove (ed, path_up (mod->p), last_item (mod->p));
185 break;
186 case MOD_SPLIT:
187 edit_split (ed, mod->p);
188 break;
189 case MOD_JOIN:
190 edit_join (ed, mod->p);
191 break;
192 case MOD_ASSIGN_NODE:
193 edit_assign_node (ed, mod->p, L(mod));
194 break;
195 case MOD_INSERT_NODE:
196 edit_insert_node (ed, mod->p, mod->t);
197 break;
198 case MOD_REMOVE_NODE:
199 edit_remove_node (ed, mod->p);
200 break;
201 default: FAILED ("invalid modification type");
205 void
206 edit_done (editor_rep* ed, modification mod) {
207 path p= copy (mod->p);
208 ASSERT (ed->the_buffer_path() <= p, "invalid modification");
209 ed->post_notify (p);
210 #ifdef EXPERIMENTAL
211 copy_announce (subtree (ed->et, ed->rp), ed->cct, mod / ed->rp);
212 #endif
215 /******************************************************************************
216 * undo and redo handling
217 ******************************************************************************/
219 void
220 edit_modify_rep::clear_undo_history () {
221 global_clear_history ();
224 double
225 edit_modify_rep::this_author () {
226 return author;
229 void
230 edit_modify_rep::start_editing () {
231 set_author (this_author ());
234 void
235 edit_modify_rep::end_editing () {
236 global_confirm ();
239 void
240 edit_modify_rep::start_slave (double a) {
241 arch->start_slave (a);
244 void
245 edit_modify_rep::mark_start (double a) {
246 arch->mark_start (a);
249 bool
250 edit_modify_rep::mark_cancel (double a) {
251 return arch->mark_cancel (a);
254 void
255 edit_modify_rep::mark_end (double a) {
256 arch->mark_end (a);
259 void
260 edit_modify_rep::add_undo_mark () {
261 arch->confirm ();
264 void
265 edit_modify_rep::remove_undo_mark () {
266 arch->retract ();
270 edit_modify_rep::undo_possibilities () {
271 return arch->undo_possibilities ();
274 void
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; }
281 if (redoable) {
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");
288 beep (); }
289 if (inside_graphics ())
290 eval ("(graphics-reset-context 'undo)");
293 void
294 edit_modify_rep::unredoable_undo () {
295 undo (false);
298 void
299 edit_modify_rep::undo (int i) {
300 ASSERT (i == 0, "invalid undo");
301 undo (true);
305 edit_modify_rep::redo_possibilities () {
306 return arch->redo_possibilities ();
309 void
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");
318 beep (); }
321 void
322 edit_modify_rep::require_save () {
323 arch->require_autosave ();
324 arch->require_save ();
327 void
328 edit_modify_rep::notify_save (bool real_save) {
329 arch->confirm ();
330 arch->notify_autosave ();
331 if (real_save) arch->notify_save ();
334 bool
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 ();
341 void
342 edit_modify_rep::show_history () {
343 arch->show_all ();
346 /******************************************************************************
347 * handling multiple cursor positions
348 ******************************************************************************/
350 observer
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);
356 return o;
359 void
360 edit_modify_rep::position_delete (observer o) {
361 tree st;
362 int index;
363 if (o->get_position (st, index))
364 detach_observer (st, o);
367 void
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);
374 path
375 edit_modify_rep::position_get (observer o) {
376 //return super_correct (et, obtain_position (o));
377 return correct_cursor (et, obtain_position (o));