Back to index

texmacs  1.0.7.15
edit_select.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_select.cpp
00004 * DESCRIPTION: Selection handling
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 "Replace/edit_select.hpp"
00013 #include "Interface/edit_interface.hpp"
00014 #include "convert.hpp"
00015 #include "packrat.hpp"
00016 #include "tree_select.hpp"
00017 #include "drd_mode.hpp"
00018 
00019 /******************************************************************************
00020 * Internationalization
00021 ******************************************************************************/
00022 
00023 string
00024 selection_encode (string lan, string s) {
00025   if ((lan == "czech") || (lan == "hungarian") ||
00026       (lan == "polish") || (lan == "slovene"))
00027     return cork_to_il2 (s);
00028   else if ((lan == "bulgarian") || (lan == "russian"))
00029     return koi8_to_iso (s);
00030   else if (lan == "ukrainian")
00031     return koi8uk_to_iso (s);
00032   else if (lan == "spanish")
00033     return spanish_to_ispanish (s);
00034   else if (lan == "german")
00035     return german_to_igerman (s);
00036   else return s;
00037 }
00038 
00039 string
00040 selection_decode (string lan, string s) {
00041   if ((lan == "czech") || (lan == "hungarian") ||
00042       (lan == "polish") || (lan == "slovene"))
00043     return il2_to_cork (s);
00044   else if ((lan == "bulgarian") || (lan == "russian"))
00045     return iso_to_koi8 (s);
00046   else if (lan == "ukrainian")
00047     return iso_to_koi8uk (s);
00048   else if (lan == "spanish")
00049     return ispanish_to_spanish (s);
00050   else if (lan == "german")
00051     return igerman_to_german (s);
00052   else return s;
00053 }
00054 
00055 /******************************************************************************
00056 * Constructor and destructor
00057 ******************************************************************************/
00058 
00059 edit_select_rep::edit_select_rep ():
00060   selecting (false), shift_selecting (false), mid_p (),
00061   selection_import ("texmacs"), selection_export ("texmacs"),
00062   focus_p (), focus_hold (false) {}
00063 edit_select_rep::~edit_select_rep () {}
00064 
00065 /******************************************************************************
00066 * Semantic selections
00067 ******************************************************************************/
00068 
00069 path
00070 edit_select_rep::semantic_root (path p) {
00071   while (p != rp) {
00072     tree st= subtree (et, path_up (p));
00073     if (path_up (p) != rp && is_func (st, DOCUMENT, 1))
00074       st= subtree (et, path_up (p, 2));
00075     if (is_func (st, CELL)) break;
00076     if (is_compound (st) && N(st) == 1) {
00077       tree env= drd->get_env (L(st), 0);
00078       tree mt= drd_env_read (env, MODE);
00079       tree pt= drd_env_read (env, "prog-language");
00080       if (mt == "math") break;
00081       if (mt == "prog" && pt == "minimal") break;
00082       if (mt == "text") return rp;
00083     }
00084     p= path_up (p);
00085   }
00086   return p;
00087 }
00088 
00089 bool
00090 edit_select_rep::semantic_active (path q) {
00091   if (as_string (eval ("(get-preference \"semantic editing\")")) == "on") {
00092     path p= semantic_root (q);
00093     //cout << subtree (et, p) << ", " << p << " -> " << end (et, p) << "\n";
00094     tree mt= get_env_value (MODE, end (et, p));
00095     tree lt= get_env_value (MODE_LANGUAGE (mt->label), end (et, p));
00096     string lan= (is_atomic (lt)? lt->label: string ("std-math"));
00097     if (mt == "math" || (mt == "prog" && lan == "minimal"))
00098       return packrat_available_path (lan, subtree (et, p), q / p);
00099   }
00100   return false;
00101 }
00102 
00103 bool
00104 edit_select_rep::semantic_select (path p, path& q1, path& q2, int mode) {
00105   if (!semantic_active (p)) return false;
00106   if (mode < 2 && get_preference ("semantic selections") != "on") return false;
00107   p= semantic_root (p);
00108   while (p != rp && !(p <= q1 && p <= q2))
00109     p= semantic_root (path_up (p));
00110   tree mt= get_env_value (MODE, end (et, p));
00111   tree lt= get_env_value (MODE_LANGUAGE (mt->label), end (et, p));
00112   string lan= (is_atomic (lt)? lt->label: string ("std-math"));
00113   path p1= q1 / p, p2= q2 / p;
00114   path cp= (p <= tp? tp / p: path ());
00115   tree st= subtree (et, p);
00116   bool ret= packrat_select (lan, "Main", st, cp, p1, p2, mode);
00117   if (ret) {
00118     q1= p * p1;
00119     q2= p * p2;
00120   }
00121   return ret;
00122 }
00123 
00124 /******************************************************************************
00125 * Selecting particular things
00126 ******************************************************************************/
00127 
00128 void
00129 edit_select_rep::select (path p1, path p2) {
00130   //cout << "Select " << p1 << " -- " << p2 << "\n";
00131   if (start_p == p1 && end_p == p2) return;
00132   if (!(rp <= p1 && rp <= p2)) return;
00133   if (start_p == end_p && p1 == p2) {
00134     start_p= copy (p1);
00135     end_p  = copy (p2);
00136     return;
00137   }
00138   if (p1 != p2) {
00139     path cp= common (p1, p2);
00140     tree st= subtree (et, cp);
00141     if (!is_func (st, TABLE) && !is_func (st, ROW))
00142       (void) semantic_select (cp, p1, p2, 0);
00143   }
00144   if (path_less (p1, p2)) {
00145     start_p= copy (p1);
00146     end_p  = copy (p2);
00147   }
00148   else {
00149     start_p= copy (p2);
00150     end_p  = copy (p1);
00151   }
00152   notify_change (THE_SELECTION);
00153 }
00154 
00155 void
00156 edit_select_rep::select (path p) {
00157   select (start (et, p), end (et, p));
00158 }
00159 
00160 void
00161 edit_select_rep::select_all () {
00162   select (rp);
00163 }
00164 
00165 void
00166 edit_select_rep::select_line () {
00167   select (search_parent_upwards (DOCUMENT));
00168 }
00169 
00170 void edit_select_rep::get_selection (path& start, path& end) {
00171   start= copy (start_p); end= copy (end_p); }
00172 void edit_select_rep::set_selection (path start, path end) {
00173   select (start, end); }
00174 
00175 /******************************************************************************
00176 * For interface with cursor movement
00177 ******************************************************************************/
00178 
00179 void
00180 edit_select_rep::select_from_cursor () {
00181   if (selecting) {
00182     select (mid_p, tp);
00183     if (shift_selecting) selecting = false;
00184   }
00185 }
00186 
00187 void
00188 edit_select_rep::select_from_cursor_if_active () {
00189   if (selecting) select (mid_p, tp);
00190   else selection_cancel ();
00191 }
00192 
00193 void
00194 edit_select_rep::select_from_keyboard (bool flag) {
00195   selecting= flag;
00196   shift_selecting= false;
00197   if (flag) {
00198     start_p= copy (tp);
00199     mid_p  = copy (tp);
00200     end_p  = copy (tp);
00201   }
00202   else mid_p= rp;
00203 }
00204 
00205 void
00206 edit_select_rep::select_from_shift_keyboard () {
00207   if (!shift_selecting || end_p == start_p) mid_p= copy (tp);
00208   selecting= true;
00209   shift_selecting= true;
00210 }
00211 
00212 /******************************************************************************
00213 * Enlarging an existing selection
00214 ******************************************************************************/
00215 
00216 static int
00217 breaking_force (char c) {
00218   if (c == ' ') return 3;
00219   if (is_punctuation (c)) return 2;
00220   if (is_iso_alpha (c) || is_digit (c)) return 0;
00221   return 1;
00222 }
00223 
00224 void
00225 edit_select_rep::select_enlarge_text () {
00226   path p= common (start_p, end_p);
00227   if (start_p == end_p) p= path_up (p);
00228   tree st= subtree (et, p);
00229   ASSERT (is_atomic (st), "non textual tree");
00230   string s= st->label;
00231   string mode= get_env_string (MODE);
00232   int i1= last_item (start_p), j1= i1;
00233   int i2= last_item (end_p), j2= i2;
00234   path q= path_up (p);
00235 
00236   if (mode == "text" || mode == "src") {
00237     int i, f= 4;
00238     if (i1 > 0) {
00239       i= i1; tm_char_backwards (s, i);
00240       f= min (f, breaking_force (s[i]));
00241     }
00242     if (i2 < N(s))
00243       f= min (f, breaking_force (s[i2]));
00244 
00245     while (i1 > 0) {
00246       i= i1; tm_char_backwards (s, i);
00247       if (breaking_force (s[i]) > f) break;
00248       i1= i;
00249     }
00250     while (i2 < N(s)) {
00251       if (breaking_force (s[i2]) > f) break;
00252       tm_char_forwards (s, i2);
00253     }
00254 
00255     if (i1 < i2 && (i1 != j1 || i2 != j2)) {
00256       if (is_concat (subtree (et, q)) && i1 == 0 && i2 == N(s))
00257        select (q * 0, q * 1);
00258       else select (p * i1, p * i2);
00259       return;
00260     }
00261   }
00262 
00263   if (is_concat (subtree (et, q)) || (i1 == 0 && i2 == N(s)))
00264     select (q * 0, q * 1);
00265   else select (p * 0, p * N(s));
00266 }
00267 
00268 bool
00269 incomplete_script_selection (tree t, path lp, path rp) {
00270   if (!is_func (t, CONCAT)) return false;
00271   if (N(lp) < 2 || N(rp) < 2) return false;
00272   int l= lp->item, r= rp->item;
00273   if (is_func (t[l], RSUB) || is_func (t[l], RSUP)) return true;
00274   if (is_func (t[r], LSUB) || is_func (t[r], LSUP)) return true;
00275   if (l  >0    && (is_func (t[l-1], LSUB) || is_func (t[l-1], LSUP))) return true;
00276   if (r+1<N(t) && (is_func (t[r+1], RSUB) || is_func (t[r+1], RSUP))) return true;
00277   return false;
00278 }
00279 
00280 void
00281 edit_select_rep::select_enlarge () {
00282   path sp, sq;
00283   if (start_p == end_p) {
00284     sp= path_up (start_p);
00285     sq= sp;
00286   }
00287   else {
00288     sp= common (start_p, end_p);
00289     if (!(rp < sp)) {
00290       selection_cancel ();
00291       set_message ("", "");
00292       return;
00293     }
00294     sq= path_up (sp);
00295   }
00296   path pp= sp, p1= start_p, p2= end_p;
00297   if (start_p == pp * 0 && end_p == pp * right_index (subtree (et, pp)))
00298     if (!is_nil (pp)) pp= path_up (pp);
00299   if (is_func (subtree (et, pp), TFORMAT)) pp= path_up (pp);
00300   if (semantic_select (pp, p1, p2, 1))
00301     select (p1, p2);
00302   else {
00303     if (is_atomic (subtree (et, sp))) select_enlarge_text ();
00304     else select (sq * 0, sq * 1);
00305   }
00306 
00307   path p = common (start_p, end_p);
00308   tree st= subtree (et, p);
00309   if (drd->var_without_border (L(st)) ||
00310       is_func (st, TFORMAT) ||
00311       is_func (st, DOCUMENT, 1) ||
00312       is_script (st) ||
00313       incomplete_script_selection (st, start_p / p, end_p / p))
00314     select_enlarge ();
00315   else {
00316     tree s;
00317     if (is_atomic (st)) s= "text";
00318     else if (is_func (st, COMPOUND)) s= as_string (st[0]);
00319     else if (is_func (st, WITH)) s= concat ("with ", as_string (st[0]));
00320     else s= as_string (L(st));
00321     set_message (concat ("selected ", s), "enlarge selection");
00322   }
00323   selecting= shift_selecting= false;
00324 }
00325 
00326 static bool
00327 stop_enlarge_environmental (tree t) {
00328   if (is_func (t, WITH, 3) && (t[0] == MODE) && (t[1] == "math")) return true;
00329   if (!is_extension (t)) return false;
00330   if (is_multi_paragraph (t)) return true;
00331   string s= as_string (L(t));
00332   return
00333     (s == "part") ||
00334     (s == "chapter") ||
00335     (s == "section") ||
00336     (s == "subsection") ||
00337     (s == "subsubsection") ||
00338     (s == "paragraph") ||
00339     (s == "subparagraph");
00340 }
00341 
00342 void
00343 edit_select_rep::select_enlarge_environmental () {
00344   select_enlarge ();
00345   if (end_p == start_p) return;
00346   path p= common (start_p, end_p);
00347   tree st= subtree (et, p);
00348   if (stop_enlarge_environmental (st)) return;
00349   select_enlarge_environmental ();
00350 }
00351 
00352 /******************************************************************************
00353 * Test whether selection is active
00354 ******************************************************************************/
00355 
00356 bool
00357 edit_select_rep::selection_active_any () {
00358   return end_p != start_p;
00359   // return made_selection;
00360 }
00361 
00362 bool
00363 edit_select_rep::selection_active_normal () {
00364   return selection_active_any () && (!selection_active_table ());
00365 }
00366 
00367 bool
00368 edit_select_rep::selection_active_table (bool strict) {
00369   if (!selection_active_any ()) return false;
00370   path p= common (start_p, end_p);
00371   if ((p == start_p) || (p == end_p)) p= path_up (p);
00372   tree t= subtree (et, p);
00373   return
00374     is_func (t, TFORMAT) || is_func (t, TABLE) ||
00375     is_func (t, ROW) || is_func (t, CELL) ||
00376     (!strict && N(t) == 1 && is_func (t[0], TFORMAT));
00377 }
00378 
00379 bool
00380 edit_select_rep::selection_active_small () {
00381   if (!selection_active_normal ()) return false;
00382   path p1, p2;
00383   selection_get (p1, p2);
00384   if (p2 == p1) return false;
00385   if (is_multi_paragraph (subtree (et, common (p1, p2)))) return false;
00386   return true;
00387 }
00388 
00389 bool
00390 edit_select_rep::selection_active_enlarging () {
00391   return (selecting || (end_p != start_p)) && (mid_p == tp);
00392 }
00393 
00394 /******************************************************************************
00395 * Subroutines for table selections
00396 ******************************************************************************/
00397 
00398 static path
00399 table_search_format (tree t, path p) {
00400   tree st= subtree (t, p);
00401   if (is_func (st, TFORMAT) && is_func (st[N(st)-1], TABLE)) return p;
00402   while ((!is_nil (p)) && (!is_func (subtree (t, p), TABLE))) p= path_up (p);
00403   if ((!is_nil (p)) && (is_func (subtree (t, path_up (p)), TFORMAT)))
00404     p= path_up (p);
00405   return p;
00406 }
00407 
00408 static void
00409 table_search_coordinates (tree t, path p, int& row, int& col) {
00410   row= col= 0;
00411   while (true) {
00412     if (is_nil (p)) p= path (1);
00413     if (p == path (0)) p= path (0, 0);
00414     if (p == path (1)) p= path (N(t)-1, 1);
00415     if (is_func (t, TFORMAT));
00416     else if (is_func (t, TABLE)) row= p->item;
00417     else if (is_func (t, ROW)) col= p->item;
00418     else return;
00419     t= t [p->item];
00420     p= p->next;
00421   }
00422 }
00423 
00424 static path
00425 table_search_cell (tree t, int row, int col) {
00426   path p;
00427   while (is_func (t, TFORMAT)) {
00428     p= p * (N(t)-1);
00429     t= t [N(t)-1];
00430   }
00431   p= p * row;
00432   t= t [row];
00433   while (is_func (t, TFORMAT)) {
00434     p= p * (N(t)-1);
00435     t= t [N(t)-1];
00436   }
00437   p= p * col;
00438   t= t [col];
00439   while (is_func (t, TFORMAT)) {
00440     p= p * (N(t)-1);
00441     t= t [N(t)-1];
00442   }
00443   return p;
00444 }
00445 
00446 /******************************************************************************
00447 * Get the selection
00448 ******************************************************************************/
00449 
00450 void
00451 edit_select_rep::selection_correct (path i1, path i2, path& o1, path& o2) {
00452   ASSERT (rp <= i1 && rp <= i2, "paths not inside document");
00453   int old_mode= get_access_mode ();
00454   if (get_init_string (MODE) == "src")
00455     set_access_mode (DRD_ACCESS_SOURCE);
00456   ::selection_correct (subtree (et, rp), i1 / rp, i2 / rp, o1, o2);
00457   set_access_mode (old_mode);
00458   o1= rp * o1; o2= rp * o2;
00459 }
00460 
00461 path
00462 edit_select_rep::selection_get_subtable (
00463   int& row1, int& col1, int& row2, int& col2)
00464 {
00465   if (selection_active_table ()) {
00466     path fp= ::table_search_format (et, common (start_p, end_p));
00467     if (is_nil (fp)) return fp;
00468     tree st= subtree (et, fp);
00469     table_search_coordinates (st, tail (start_p, N(fp)), row1, col1);
00470     table_search_coordinates (st, tail (end_p, N(fp)), row2, col2);
00471     if (row1>row2) { int tmp= row1; row1= row2; row2= tmp; }
00472     if (col1>col2) { int tmp= col1; col1= col2; col2= tmp; }
00473     table_bound (fp, row1, col1, row2, col2);
00474     return fp;
00475   }
00476   else if (selection_active_table (false)) {
00477     path fp= ::table_search_format (et, common (start_p, end_p) * 0);
00478     if (is_nil (fp)) return fp;
00479     path p= fp;
00480     tree st;
00481     while (true) {
00482       st= subtree (et, p);
00483       if (is_func (st, TABLE) && N(st) > 0 && is_func (st[0], ROW)) break;
00484       if (!is_func (st, TFORMAT)) return path ();
00485       p= p * (N(st) - 1);
00486     }
00487     row1= 0; col1= 0;
00488     row2= N(st)-1; col2= N(st[0])-1;
00489     return fp;
00490   }
00491   else return path ();
00492 }
00493 
00494 void
00495 edit_select_rep::selection_get (selection& sel) {
00496   if (selection_active_table ()) {
00497     int row1, col1, row2, col2;
00498     path fp= selection_get_subtable (row1, col1, row2, col2);
00499     tree st= subtree (et, fp);
00500 
00501     int i, j;
00502     rectangle r (0, 0, 0, 0);
00503     for (i=row1; i<=row2; i++)
00504       for (j=col1; j<=col2; j++) {
00505        path cp= fp * ::table_search_cell (st, i, j);
00506        sel= eb->find_check_selection (cp * 0, cp * 1);
00507        if (sel->valid) {
00508          rectangles rs= sel->rs;
00509          if (r != rectangle (0, 0, 0, 0)) rs= rectangles (r, rs);
00510          r= least_upper_bound (rs);
00511        }
00512       }
00513     sel= selection (rectangles (r), fp * 0, fp * 1);
00514   }
00515   else {
00516     path p_start, p_end;
00517     //cout << "Find " << start_p << " -- " << end_p << "\n";
00518     selection_correct (start_p, end_p, p_start, p_end);
00519     //cout << "Find " << p_start << " -- " << p_end << "\n";
00520     sel= eb->find_check_selection (p_start, p_end);
00521     //cout << "sel= " << sel << "\n";
00522   }
00523 }
00524 
00525 void
00526 edit_select_rep::selection_get (path& start, path& end) {
00527   if (selection_active_table ()) {
00528     int row1, col1, row2, col2;
00529     path fp= selection_get_subtable (row1, col1, row2, col2);
00530     start= fp * 0;
00531     end= fp * 1;
00532   }
00533   else selection_correct (start_p, end_p, start, end);
00534   /*
00535   selection sel; selection_get (sel);
00536   start= sel->start;
00537   end  = sel->end;
00538   */
00539 }
00540 
00541 path
00542 edit_select_rep::selection_get_start () {
00543   return start_p;
00544 }
00545 
00546 path
00547 edit_select_rep::selection_get_end () {
00548   return end_p;
00549 }
00550 
00551 tree
00552 edit_select_rep::selection_get () {
00553   if (!selection_active_any ()) return "";
00554   if (selection_active_table ()) {
00555     int row1, col1, row2, col2;
00556     path fp= selection_get_subtable (row1, col1, row2, col2);
00557     return table_get_subtable (fp, row1, col1, row2, col2);
00558   }
00559   else {
00560     path start, end;
00561     // cout << "Selecting...\n";
00562     selection_get (start, end);
00563     // cout << "Between paths: " << start << " and " << end << "\n";
00564     tree t= selection_compute (et, start, end);
00565     // cout << "Selection : " << t << "\n";
00566     return simplify_correct (t);
00567   }
00568 }
00569 
00570 path
00571 edit_select_rep::selection_get_path () {
00572   path start, end;
00573   selection_get (start, end);
00574   if (end == start && end_p != start_p)
00575     return path_up (start);
00576   return common (start, end);
00577 }
00578 
00579 path
00580 edit_select_rep::selection_get_cursor_path () {
00581   if (!selection_active_any ()) return tp;
00582   return start (et, selection_get_path ());
00583 }
00584 
00585 tree
00586 edit_select_rep::selection_get_env_value (string var) {
00587   if (!selection_active_any ()) return get_env_value (var);
00588   return get_env_value (var, selection_get_cursor_path ());
00589 }
00590 
00591 /******************************************************************************
00592 * Copy and paste
00593 ******************************************************************************/
00594 
00595 void
00596 edit_select_rep::selection_raw_set (string key, tree t) {
00597   (void) ::set_selection (key, t, "", "texmacs");
00598 }
00599 
00600 tree
00601 edit_select_rep::selection_raw_get (string key) {
00602   tree t; string s;
00603   (void) ::get_selection (key, t, s, "texmacs");
00604   return t;
00605 }
00606 
00607 void
00608 edit_select_rep::selection_set_start (path p) {
00609   if (!selection_active_any ()) {
00610     if (rp < start_p) select (start_p, start_p);
00611     else select (tp, tp);
00612   }
00613   if (is_nil (p)) selection_set_start (tp);
00614   else if (path_less_eq (end_p, p)) select (p, p);
00615   else if (rp < p) select (p, end_p);
00616 }
00617 
00618 void
00619 edit_select_rep::selection_set_end (path p) {
00620   if (is_nil (p)) selection_set_end (tp);
00621   else if (path_less_eq (p, start_p)) select (p, p);
00622   else if (rp < p) select (start_p, p);
00623 }
00624 
00625 void
00626 edit_select_rep::selection_set_paths (path start, path end) {
00627   if (is_nil (start) || is_nil (end)) selection_set_paths (tp, tp);
00628   else if (path_less_eq (end, start)) select (start, start);
00629   else if (rp < start && rp < end) select (start, end);
00630 }
00631 
00632 void
00633 edit_select_rep::selection_set (string key, tree t, bool persistant) {
00634   selecting= shift_selecting= false;
00635   string mode= as_string (selection_get_env_value (MODE));
00636   string lan = as_string (selection_get_env_value (MODE_LANGUAGE (mode)));
00637   tree sel= tuple ("texmacs", t, mode, lan);
00638   /* TODO: add mode="graphics" somewhere in the context of the <graphics>
00639      tag. To be done when implementing the different embeddings for
00640      nicely copying graphics into text, text into graphics, etc. */
00641   string s;
00642   if (key == "primary" || key == "mouse") {
00643     if (selection_export == "verbatim") t= exec_verbatim (t, tp);
00644     if (selection_export == "html") t= exec_html (t, tp);
00645     if (selection_export == "latex") t= exec_latex (t, tp);
00646     if ((selection_export == "latex") && (mode == "math"))
00647       t= compound ("math", t);
00648     s= tree_to_generic (t, selection_export * "-snippet");
00649     s= selection_encode (lan, s);
00650   }
00651   if (::set_selection (key, sel, s, selection_export) && !persistant)
00652     selection_cancel ();
00653 }
00654 
00655 void
00656 edit_select_rep::selection_set (tree t) {
00657   selection_set ("primary", t);
00658 }
00659 
00660 void
00661 edit_select_rep::selection_copy (string key) {
00662   if (inside_active_graphics ()) {
00663     tree t= as_tree (eval ("(graphics-copy)"));
00664     selection_set (key, t);
00665     return;
00666   }
00667   if (selection_active_any ()) {
00668     path old_tp= tp;
00669     selection sel; selection_get (sel);
00670     go_to (sel->end);
00671     tree t= selection_get ();
00672     go_to (sel->start);
00673     selection_set (key, t);
00674     go_to (old_tp);
00675   }
00676 }
00677 
00678 void
00679 edit_select_rep::selection_paste (string key) {
00680   tree t; string s;
00681   (void) ::get_selection (key, t, s, selection_import);
00682   if (inside_active_graphics ()) {
00683     if (is_tuple (t, "texmacs", 3))
00684       call ("graphics-paste", t[1]);
00685     return;
00686   }
00687   if (is_tuple (t, "extern", 1)) {
00688     string mode= get_env_string (MODE);
00689     string lan = get_env_string (MODE_LANGUAGE (mode));
00690     if ((selection_import == "latex") && (mode == "prog")) mode= "verbatim";
00691     if ((selection_import == "latex") && (mode == "math")) mode= "latex-math";
00692     if ((selection_import == "html") && (mode == "prog")) mode= "verbatim";
00693     string fm= selection_import * "-snippet";
00694     tree doc= generic_to_tree (selection_decode(lan, as_string(t[1])), fm);
00695     if (is_func (doc, DOCUMENT, 1)) doc= doc[0]; // temporary fix
00696     insert_tree (doc);
00697   }
00698   if (is_tuple (t, "texmacs", 3)) {
00699     string mode= get_env_string (MODE);
00700     string lan = get_env_string (MODE_LANGUAGE (mode));
00701     if (is_compound (t[1], "text", 1) && mode == "text")
00702       t= tuple ("texmacs", t[1][0], "text", lan);
00703     if (is_compound (t[1], "math", 1) && mode == "math")
00704       t= tuple ("texmacs", t[1][0], "math", lan);
00705     if (mode == "math" && t[2] == "text")
00706       set_message ("Error: invalid paste of text into a formula", "paste");
00707     else if (mode == "prog" && t[2] == "math") {
00708       tree in= tuple (lan, t[1]);
00709       tree r= stree_to_tree (call ("plugin-math-input", tree_to_stree (in)));
00710       insert_tree (r);
00711     }
00712     else {
00713       if ((t[2] != mode) && (t[2] != "src") && (mode != "src") &&
00714          ((t[2] == "math") || (mode == "math"))) {
00715         if (t[2] == "math")
00716           insert_tree (compound ("math", ""), path (0, 0));
00717         else if (t[2] == "text")
00718           insert_tree (compound ("text", ""), path (0, 0));
00719         else
00720           insert_tree (tree (WITH, copy (MODE), copy (t[2]), ""), path (2, 0));
00721       }
00722       if (is_func (t[1], TFORMAT) || is_func (t[1], TABLE)) {
00723        int row, col;
00724        path fp= search_format (row, col);
00725        if (is_nil (fp)) insert_tree (compound (copy (TABULAR), t[1]));
00726        else table_write_subtable (fp, row, col, t[1]);
00727       }
00728       else insert_tree (t[1]);
00729     }
00730   }
00731 }
00732 
00733 void
00734 edit_select_rep::selection_clear (string key) {
00735   ::clear_selection (key);
00736 }
00737 
00738 void
00739 edit_select_rep::selection_cancel () {
00740   selecting= shift_selecting= false;
00741   if (end_p == start_p) return;
00742   select (start_p, start_p);
00743 }
00744 
00745 void
00746 edit_select_rep::selection_set_import (string fm) {
00747   selection_import= fm;
00748 }
00749 
00750 void
00751 edit_select_rep::selection_set_export (string fm) {
00752   selection_export= fm;
00753 }
00754 
00755 string
00756 edit_select_rep::selection_get_import () {
00757   return selection_import;
00758 }
00759 
00760 string
00761 edit_select_rep::selection_get_export () {
00762   return selection_export;
00763 }
00764 
00765 /******************************************************************************
00766 * Cutting the selection
00767 ******************************************************************************/
00768 
00769 void
00770 edit_select_rep::cut (path p) {
00771   cut (start (et, p), end (et, p));
00772 }
00773 
00774 void
00775 edit_select_rep::cut (path p1, path p2) {
00776   path p = common (p1, p2);
00777   tree st= subtree (et, p);
00778   raw_cut (p1, p2);
00779   if (!is_func (st, TFORMAT) &&
00780       !is_func (st, TABLE) &&
00781       !is_func (st, ROW) &&
00782       !is_document (subtree (et, p)) &&
00783       is_concat (subtree (et, path_up (p))))
00784     correct_concat (path_up (p));
00785 }
00786 
00787 void
00788 edit_select_rep::raw_cut (path p1, path p2) {
00789   if (p2 == p1) return;
00790   path p = common (p1, p2);
00791   tree t = subtree (et, p);
00792   int  n = N(p);
00793   int  i1= p1[n];
00794   int  i2= p2[n];
00795 
00796   if (is_document (t) || is_concat (t)) {
00797     path q1= copy (p); q1 << path (i1, end (t[i1]));
00798     path q2= copy (p); q2 << path (i2, start (t[i2]));
00799     raw_cut (q2, p2);
00800     if (i2>i1+1) remove (p * (i1+1), i2-i1-1);
00801     raw_cut (p1, q1);
00802     if (is_concat (t)) correct_concat (p);
00803     else remove_return (p * i1);
00804     return;
00805   }
00806 
00807   if (is_func (t, TFORMAT) || is_func (t, TABLE) || is_func (t, ROW)) {
00808     path fp= ::table_search_format (et, p);
00809     tree st= subtree (et, fp);
00810     int row1, col1, row2, col2;
00811     table_search_coordinates (st, tail (p1, N(fp)), row1, col1);
00812     table_search_coordinates (st, tail (p2, N(fp)), row2, col2);
00813     if (row1>row2) { int tmp= row1; row1= row2; row2= tmp; }
00814     if (col1>col2) { int tmp= col1; col1= col2; col2= tmp; }
00815 
00816     int i, j;
00817     for (i=row1; i<=row2; i++)
00818       for (j=col1; j<=col2; j++) {
00819         path cp= fp * ::table_search_cell (st, i, j);
00820         if (is_func (subtree (et, cp), CELL, 1)) cp= cp * 0;
00821         assign (cp, "");
00822       }
00823     path cp= fp * ::table_search_cell (st, row1, col1);
00824     go_to (cp * path (0, 0));
00825 
00826     if (is_func (st, TFORMAT))
00827       table_del_format (fp, row1+1, col1+1, row2+1, col2+1, "");
00828 
00829     if (fp == search_format ()) {
00830       table_correct_block_content ();
00831       table_resize_notify ();
00832     }
00833     else {
00834       observer obs= position_new (tp);
00835       go_to (start (et, fp * ::table_search_cell (st, row1, col1)));
00836       table_correct_block_content ();
00837       table_resize_notify ();
00838       go_to (position_get (obs));
00839       position_delete (obs);
00840     }
00841     return;
00842   }
00843 
00844   if (is_compound (t) && (!is_format (t))) {
00845     assign (p, "");
00846     return;
00847   }
00848 
00849   if ((N(p1) != (N(p)+1)) || (N(p2) != (N(p)+1))) {
00850     cerr << "t = " << t << "\n";
00851     cerr << "p = " << p << "\n";
00852     cerr << "p1= " << p1 << "\n";
00853     cerr << "p2= " << p2 << "\n";
00854     FAILED ("invalid cut");
00855   }
00856 
00857   if (is_atomic (t)) {
00858     int pos= last_item (p1);
00859     int nr = last_item (p2)-pos;
00860     if (nr>0) remove (p1, nr);
00861   }
00862   else {
00863     if ((last_item (p1) != 0) || (last_item (p2) != 1)) {
00864       cerr << "t = " << t << "\n";
00865       cerr << "p = " << p << "\n";
00866       cerr << "p1= " << p1 << "\n";
00867       cerr << "p2= " << p2 << "\n";
00868       FAILED ("invalid object cut");
00869     }
00870     assign (p, "");
00871   }
00872 }
00873 
00874 void
00875 edit_select_rep::selection_cut (string key) {
00876   if (inside_active_graphics ()) {
00877     if (key != "none") {
00878       tree t= as_tree (eval ("(graphics-cut)"));
00879       selection_set (key, t);
00880     }
00881   }
00882   else if (selection_active_any ()) {
00883     path p1, p2;
00884     if (selection_active_table ()) {
00885       p1= start_p; p2= end_p;
00886       if(key != "none") {
00887         tree sel= selection_get ();
00888         selection_set (key, sel);
00889       }
00890     }
00891     else {
00892       selection_get (p1, p2);
00893       go_to (p2);
00894       if (p2 == p1) return;
00895       if (key != "none") {
00896         tree sel= selection_compute (et, p1, p2);
00897         selection_set (key, simplify_correct (sel));
00898       }
00899     }
00900     cut (p1, p2);
00901   }
00902 }
00903 
00904 tree
00905 edit_select_rep::selection_get_cut () {
00906   tree t= selection_get ();
00907   selection_cut ("none");
00908   return t;
00909 }
00910 
00911 void
00912 edit_select_rep::selection_move () {
00913   observer pos= position_new (tp);
00914   tree t= selection_get_cut ();
00915   go_to (position_get (pos));
00916   insert_tree (t);
00917   position_delete (pos);
00918 }
00919 
00920 /******************************************************************************
00921 * Focus related routines
00922 ******************************************************************************/
00923 
00924 path
00925 edit_select_rep::manual_focus_get () {
00926   return focus_p;
00927 }
00928 
00929 void
00930 edit_select_rep::manual_focus_set (path p, bool force) {
00931   //cout << "Set focus " << p << ", " << force << ", " << focus_hold << "\n";
00932   if (is_nil (p) && focus_hold && !force) return;
00933   focus_p= p;
00934   focus_hold= !is_nil (p);
00935 }
00936 
00937 void
00938 edit_select_rep::manual_focus_release () {
00939   focus_hold= false;
00940 }
00941 
00942 path
00943 edit_select_rep::focus_search (path p, bool skip_flag, bool up_flag) {
00944   //cout << "Search focus " << p << ", " << skip_flag << ", " << up_flag << "\n";
00945   if (!(rp < p)) return rp;
00946   tree st= subtree (et, p);
00947   if (!skip_flag) return p;
00948   if (none_accessible (st) && p == path_up (tp) && last_item (tp) != 0)
00949     return p;
00950   if (is_atomic (st) ||
00951       is_func (st, DOCUMENT) ||
00952       is_func (st, CONCAT) ||
00953       is_func (st, TFORMAT) ||
00954       is_func (st, TABLE) ||
00955       is_func (st, ROW) ||
00956       is_func (st, CELL) ||
00957       is_compound (st, "shown") ||
00958       is_func (st, HIDDEN) ||
00959       up_flag)
00960     return focus_search (path_up (p), skip_flag, false);
00961   return p;
00962 }
00963 
00964 path
00965 edit_select_rep::focus_get (bool skip_flag) {
00966   //cout << "Search focus " << focus_p << ", " << skip_flag << "\n";
00967   if (!is_nil (focus_p))
00968     return focus_search (focus_p, skip_flag, false);
00969   if (selection_active_any ())
00970     return focus_search (selection_get_path (), skip_flag, false);
00971   else
00972     return focus_search (path_up (tp), skip_flag, true);
00973 }