Back to index

texmacs  1.0.7.15
edit_modify.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_modify.cpp
00004 * DESCRIPTION: base routines for modifying the edit tree + notification
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "modification.hpp"
00013 #include "edit_modify.hpp"
00014 #include "tm_window.hpp"
00015 #ifdef EXPERIMENTAL
00016 #include "../../Style/Memorizer/clean_copy.hpp"
00017 #endif
00018 
00019 /******************************************************************************
00020 * Constructors and destructors
00021 ******************************************************************************/
00022 
00023 edit_modify_rep::edit_modify_rep ():
00024   author (new_author ()),
00025   arch (author, rp) {}
00026 edit_modify_rep::~edit_modify_rep () {}
00027 
00028 /******************************************************************************
00029 * Notification of changes in document
00030 ******************************************************************************/
00031 
00032 void
00033 edit_modify_rep::notify_assign (path p, tree u) {
00034   (void) u;
00035   if (!(rp <= p)) return;
00036   cur_pos= position_new (tp);
00037   ::notify_assign (get_typesetter (), p / rp, u);
00038 }
00039 
00040 void
00041 edit_modify_rep::notify_insert (path p, tree u) {
00042   if (!(rp <= p)) return;
00043   cur_pos= position_new (tp);
00044   ::notify_insert (get_typesetter (), p / rp, u);
00045 }
00046 
00047 void
00048 edit_modify_rep::notify_remove (path p, int nr) {
00049   if (!(rp <= p)) return;
00050   cur_pos= position_new (tp);
00051   ::notify_remove (get_typesetter (), p / rp, nr);
00052 }
00053 
00054 void
00055 edit_modify_rep::notify_split (path p) {
00056   if (!(rp <= p)) return;
00057   cur_pos= position_new (tp);
00058   ::notify_split (get_typesetter (), p / rp);
00059 }
00060 
00061 void
00062 edit_modify_rep::notify_join (path p) {
00063   if (!(rp <= p)) return;
00064   cur_pos= position_new (tp);
00065   ::notify_join (get_typesetter (), p / rp);
00066 }
00067 
00068 void
00069 edit_modify_rep::notify_assign_node (path p, tree_label op) {
00070   if (!(rp <= p)) return;
00071   cur_pos= position_new (tp);
00072   ::notify_assign_node (get_typesetter (), p / rp, op);
00073 }
00074 
00075 void
00076 edit_modify_rep::notify_insert_node (path p, tree t) {
00077   if (!(rp <= p)) return;
00078   cur_pos= position_new (tp);
00079   ::notify_insert_node (get_typesetter (), p / rp, t);
00080 }
00081 
00082 void
00083 edit_modify_rep::notify_remove_node (path p) {
00084   if (!(rp <= p)) return;
00085   cur_pos= position_new (tp);
00086   ::notify_remove_node (get_typesetter (), p / rp);
00087 }
00088 
00089 void
00090 edit_modify_rep::notify_set_cursor (path p, tree data) {
00091   if (!(rp <= p)) return;
00092   if (data[0] == as_string (author)) {
00093     if (is_compound (data, "cursor", 1) ||
00094         is_compound (data, "cursor-clear", 1)) {
00095       if (tp != p) {
00096         tp= p;
00097         go_to_correct (tp);
00098       }
00099       if (is_compound (data, "cursor-clear", 1)) {
00100         //cout << "Clear selection\n";
00101         select (tp, tp);
00102       }
00103     }
00104     else if (is_compound (data, "start", 1)) {
00105       if (selection_get_start () != p) {
00106         //cout << "Set start selection: " << p << "\n";
00107         select (p, p);
00108       }
00109     }
00110     else if (is_compound (data, "end", 1)) {
00111       if (selection_get_end () != p) {
00112         //cout << "Set end selection: " << p << "\n";
00113         selection_set_end (p);
00114       }
00115     }
00116   }
00117 }
00118 
00119 void
00120 edit_modify_rep::post_notify (path p) {
00121   // cout << "Post notify\n";
00122   if (!(rp <= p)) return;
00123   selection_cancel ();
00124   notify_change (THE_TREE);
00125   tp= position_get (cur_pos);
00126   position_delete (cur_pos);
00127   cur_pos= nil_observer;
00128   go_to_correct (tp);
00129   /*
00130   cout << "et= " << et << "\n";
00131   cout << "tp= " << tp << "\n\n";
00132   */
00133 }
00134 
00135 /******************************************************************************
00136 * Hooks / notify changes to editor
00137 ******************************************************************************/
00138 
00139 // FIXME: the notification might be slow when we have many
00140 // open buffers. In the future, we might obtain the relevant editors
00141 // from all possible prefixes of p using a hashtable
00142 
00143 // FIXME: the undo system is not safe when a change is made inside
00144 // a buffer which has no editor attached to it
00145 
00146 void
00147 edit_assign (editor_rep* ed, path pp, tree u) {
00148   path p= copy (pp);
00149   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00150   ed->notify_assign (p, u);
00151 }
00152 
00153 void
00154 edit_insert (editor_rep* ed, path pp, tree u) {
00155   path p= copy (pp);
00156   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00157   ed->notify_insert (p, u);
00158 }
00159 
00160 void
00161 edit_remove (editor_rep* ed, path pp, int nr) {
00162   path p= copy (pp);
00163   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00164   if (nr <= 0) return;
00165   ed->notify_remove (p, nr);
00166 }
00167 
00168 void
00169 edit_split (editor_rep* ed, path pp) {
00170   path p= copy (pp);
00171   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00172   ed->notify_split (p);
00173 }
00174 
00175 void
00176 edit_join (editor_rep* ed, path pp) {
00177   path p= copy (pp);
00178   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00179   if (N(p)<1) FAILED ("path too short in join");
00180   ed->notify_join (p);
00181 }
00182 
00183 void
00184 edit_assign_node (editor_rep* ed, path pp, tree_label op) {
00185   path p= copy (pp);
00186   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00187   ed->notify_assign_node (p, op);
00188 }
00189 
00190 void
00191 edit_insert_node (editor_rep* ed, path pp, tree t) {
00192   path p= copy (pp);
00193   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00194   ed->notify_insert_node (p, t);
00195 }
00196 
00197 void
00198 edit_remove_node (editor_rep* ed, path pp) {
00199   path p= copy (pp);
00200   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00201   ed->notify_remove_node (p);
00202 }
00203 
00204 void
00205 edit_set_cursor (editor_rep* ed, path pp, tree data) {
00206   path p= copy (pp);
00207   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00208   ed->notify_set_cursor (p, data);
00209 }
00210 
00211 void
00212 edit_announce (editor_rep* ed, modification mod) {
00213   switch (mod->k) {
00214   case MOD_ASSIGN:
00215     edit_assign (ed, mod->p, mod->t);
00216     break;
00217   case MOD_INSERT:
00218     edit_insert (ed, mod->p, mod->t);
00219     break;
00220   case MOD_REMOVE:
00221     edit_remove (ed, path_up (mod->p), last_item (mod->p));
00222     break;
00223   case MOD_SPLIT:
00224     edit_split (ed, mod->p);
00225     break;
00226   case MOD_JOIN:
00227     edit_join (ed, mod->p);
00228     break;
00229   case MOD_ASSIGN_NODE:
00230     edit_assign_node (ed, mod->p, L(mod));
00231     break;
00232   case MOD_INSERT_NODE:
00233     edit_insert_node (ed, mod->p, mod->t);
00234     break;
00235   case MOD_REMOVE_NODE:
00236     edit_remove_node (ed, mod->p);
00237     break;
00238   case MOD_SET_CURSOR:
00239     edit_set_cursor (ed, mod->p, mod->t);
00240     break;
00241   default: FAILED ("invalid modification type");
00242   }
00243 }
00244 
00245 void
00246 edit_done (editor_rep* ed, modification mod) {
00247   path p= copy (mod->p);
00248   ASSERT (ed->the_buffer_path() <= p, "invalid modification");
00249   if (mod->k != MOD_SET_CURSOR)
00250     ed->post_notify (p);
00251 #ifdef EXPERIMENTAL
00252   copy_announce (subtree (ed->et, ed->rp), ed->cct, mod / ed->rp);
00253 #endif
00254 }
00255 
00256 void
00257 edit_touch (editor_rep* ed, path p) {
00258   //cout << "Touch " << p << "\n";
00259   ASSERT (ed->the_buffer_path() <= p, "invalid touch");
00260   ed -> typeset_invalidate (p);
00261 }
00262 
00263 /******************************************************************************
00264 * undo and redo handling
00265 ******************************************************************************/
00266 
00267 void
00268 edit_modify_rep::clear_undo_history () {
00269   global_clear_history ();
00270 }
00271 
00272 double
00273 edit_modify_rep::this_author () {
00274   return author;
00275 }
00276 
00277 void
00278 edit_modify_rep::archive_state () {
00279   path sp1= selection_get_start ();
00280   path sp2= selection_get_end ();
00281   if (path_less (sp1, sp2)) {
00282     //cout << "Selection: " << sp1 << "--" << sp2 << "\n";
00283     set_cursor (sp2, compound ("end", as_string (author)));
00284     set_cursor (sp1, compound ("start", as_string (author)));
00285     set_cursor (tp, compound ("cursor", as_string (author)));
00286   }
00287   else set_cursor (tp, compound ("cursor-clear", as_string (author)));
00288 }
00289 
00290 void
00291 edit_modify_rep::start_editing () {
00292   set_author (this_author ());
00293 }
00294 
00295 void
00296 edit_modify_rep::end_editing () {
00297   global_confirm ();
00298 }
00299 
00300 void
00301 edit_modify_rep::start_slave (double a) {
00302   arch->start_slave (a);
00303 }
00304 
00305 void
00306 edit_modify_rep::mark_start (double a) {
00307   arch->mark_start (a);
00308 }
00309 
00310 bool
00311 edit_modify_rep::mark_cancel (double a) {
00312   return arch->mark_cancel (a);
00313 }
00314 
00315 void
00316 edit_modify_rep::mark_end (double a) {
00317   arch->mark_end (a);
00318 }
00319 
00320 void
00321 edit_modify_rep::add_undo_mark () {
00322   arch->confirm ();
00323 }
00324 
00325 void
00326 edit_modify_rep::remove_undo_mark () {
00327   arch->retract ();
00328 }
00329 
00330 int
00331 edit_modify_rep::undo_possibilities () {
00332   return arch->undo_possibilities ();
00333 }
00334 
00335 void
00336 edit_modify_rep::undo (bool redoable) {
00337   interrupt_shortcut ();
00338   arch->forget_cursor ();
00339   if (inside_graphics () && !as_bool (eval ("graphics-undo-enabled"))) {
00340     eval ("(graphics-reset-context 'undo)"); return; }
00341   if (arch->undo_possibilities () == 0) {
00342     set_message ("No more undo information available", "undo"); return; }
00343   if (redoable) {
00344     path p= arch->undo ();
00345     if (!is_nil (p)) go_to (p);
00346   }
00347   else arch->forget ();
00348   if (arch->conform_save ()) {
00349     set_message ("Your document is back in its original state", "undo");
00350     beep (); }
00351   if (inside_graphics ())
00352     eval ("(graphics-reset-context 'undo)");
00353 }
00354 
00355 void
00356 edit_modify_rep::unredoable_undo () {
00357   undo (false);
00358 }
00359 
00360 void
00361 edit_modify_rep::undo (int i) {
00362   ASSERT (i == 0, "invalid undo");
00363   undo (true);
00364 }
00365 
00366 int
00367 edit_modify_rep::redo_possibilities () {
00368   return arch->redo_possibilities ();
00369 }
00370 
00371 void
00372 edit_modify_rep::redo (int i) {
00373   interrupt_shortcut ();
00374   arch->forget_cursor ();
00375   if (arch->redo_possibilities () == 0) {
00376     set_message ("No more redo information available", "redo"); return; }
00377   path p= arch->redo (i);
00378   if (!is_nil (p)) go_to (p);
00379   if (arch->conform_save ()) {
00380     set_message ("Your document is back in its original state", "undo");
00381     beep (); }
00382 }
00383 
00384 void
00385 edit_modify_rep::require_save () {
00386   arch->require_autosave ();
00387   arch->require_save ();
00388 }
00389 
00390 void
00391 edit_modify_rep::notify_save (bool real_save) {
00392   arch->confirm ();
00393   arch->notify_autosave ();
00394   if (real_save) arch->notify_save ();
00395 }
00396 
00397 bool
00398 edit_modify_rep::need_save (bool real_save) {
00399   if (arch->conform_save ()) return false;
00400   if (real_save) return true;
00401   return !arch->conform_autosave ();
00402 }
00403 
00404 void
00405 edit_modify_rep::show_history () {
00406   arch->show_all ();
00407 }
00408 
00409 /******************************************************************************
00410 * handling multiple cursor positions
00411 ******************************************************************************/
00412 
00413 observer
00414 edit_modify_rep::position_new (path p) {
00415   tree st= subtree (et, path_up (p));
00416   int index= last_item (p);
00417   observer o= tree_position (st, index);
00418   attach_observer (st, o);
00419   return o;
00420 }
00421 
00422 void
00423 edit_modify_rep::position_delete (observer o) {
00424   tree st;
00425   int  index;
00426   if (o->get_position (st, index))
00427     detach_observer (st, o);
00428 }
00429 
00430 void
00431 edit_modify_rep::position_set (observer o, path p) {
00432   tree st= subtree (et, path_up (p));
00433   int index= last_item (p);
00434   o->set_position (st, index);
00435 }
00436 
00437 path
00438 edit_modify_rep::position_get (observer o) {
00439   //return super_correct (et, obtain_position (o));
00440   return correct_cursor (et, obtain_position (o));
00441 }