Back to index

texmacs  1.0.7.15
edit_table.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_table.cpp
00004 * DESCRIPTION: modify tables
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 "edit_table.hpp"
00013 
00014 /******************************************************************************
00015 * Constructors and destructors
00016 ******************************************************************************/
00017 
00018 edit_table_rep::edit_table_rep (): cell_mode ("cell") {}
00019 edit_table_rep::~edit_table_rep () {}
00020 
00021 /******************************************************************************
00022 * Elementary subroutines for table manipulation
00023 ******************************************************************************/
00024 
00025 static tree
00026 empty_cell () {
00027   return "";
00028 }
00029 
00030 bool
00031 is_empty_cell (tree t) {
00032   return
00033     t == "" ||
00034     (is_func (t, DOCUMENT, 1) && is_empty_cell (t[0])) ||
00035     (is_compound (t, "cell-inert", 2) && is_empty_cell (t[1])) ||
00036     (is_compound (t, "cell-input", 3) && is_empty_cell (t[1])) ||
00037     (is_compound (t, "cell-output", 3) && is_empty_cell (t[2]));
00038 }
00039 
00040 static tree
00041 empty_row (int nr_cols) {
00042   int i;
00043   tree R (ROW, nr_cols);
00044   for (i=0; i<nr_cols; i++)
00045     R[i]= tree (CELL, empty_cell ());
00046   return R;
00047 }
00048 
00049 static tree
00050 empty_table (int nr_rows, int nr_cols) {
00051   int i;
00052   tree T (TABLE, nr_rows);
00053   for (i=0; i<nr_rows; i++)
00054     T[i]= empty_row (nr_cols);
00055   return T;
00056 }
00057 
00058 static void
00059 table_get_extents (tree T, int& nr_rows, int& nr_cols) {
00060   while (is_func (T, TFORMAT)) T= T[N(T)-1];
00061   nr_rows= N(T);
00062   T= T[0];
00063   while (is_func (T, TFORMAT)) T= T[N(T)-1];
00064   nr_cols= N(T);
00065 }
00066 
00067 static void
00068 table_set (tree& T, int row, int col, tree t) {
00069   tree* ptr= &T;
00070   while (is_func (*ptr, TFORMAT)) ptr= & ((*ptr) [N(*ptr)-1]);
00071   ptr= & ((*ptr) [row]);
00072   while (is_func (*ptr, TFORMAT)) ptr= & ((*ptr) [N(*ptr)-1]);
00073   ptr= & ((*ptr) [col]);
00074   while (is_func (*ptr, TFORMAT)) ptr= & ((*ptr) [N(*ptr)-1]);
00075   if (is_func (*ptr, CELL, 1)) ptr= & ((*ptr) [0]);
00076   *ptr= t;
00077 }
00078 
00079 static tree
00080 table_get (tree T, int row, int col) {
00081   while (is_func (T, TFORMAT)) T= T [N(T)-1];
00082   T= T [row];
00083   while (is_func (T, TFORMAT)) T= T [N(T)-1];
00084   T= T [col];
00085   while (is_func (T, TFORMAT)) T= T [N(T)-1];
00086   if (is_func (T, CELL, 1)) T= T [0];
00087   return T;
00088 }
00089 
00090 /******************************************************************************
00091 * Searching the format, table, rows and cells
00092 ******************************************************************************/
00093 
00094 path
00095 edit_table_rep::search_format () {
00096   path p= search_table ();
00097   return search_format (p);
00098 }
00099 
00100 path
00101 edit_table_rep::search_format (path p) {
00102   if (!(rp < p)) return path ();
00103   if (is_func (subtree (et, p), TFORMAT)) return p;
00104   if (is_func (subtree (et, path_up (p)), TFORMAT)) return path_up (p);
00105   return p;
00106 }
00107 
00108 path
00109 edit_table_rep::search_format (int& row, int& col) {
00110   path p= search_table (row, col);
00111   if (is_nil (p)) return p;
00112   if (is_func (subtree (et, p), TFORMAT)) return p;
00113   if (is_func (subtree (et, path_up (p)), TFORMAT)) return path_up (p);
00114   insert_node (p * 0, TFORMAT);
00115   return p;
00116 }
00117 
00118 path
00119 edit_table_rep::search_table () {
00120   return search_upwards (TABLE);
00121 }
00122 
00123 path
00124 edit_table_rep::search_table (path fp) {
00125   tree st= subtree (et, fp);
00126   if (is_func (st, TABLE)) return fp;
00127   if (is_func (st, TFORMAT)) return search_table (fp * (N(st)-1));
00128   return path ();
00129 }
00130 
00131 path
00132 edit_table_rep::search_table (int& row, int& col) {
00133   row= col= 0;
00134   path p= search_table ();
00135   if (is_nil (p)) return p;
00136   path q= p, r= tail (tp, N(p));
00137 
00138   if (N(r) <= 1) return path ();
00139   row= r->item;
00140   while (true) {
00141     if (is_nil (r)) return r;
00142     q= q * r->item;
00143     r= r->next;
00144     if (is_func (subtree (et, q), ROW)) break;
00145   }
00146 
00147   if (N(r) <= 1) return path ();
00148   col= r->item;
00149   while (true) {
00150     if (is_nil (r)) return r;
00151     q= q * r->item;
00152     r= r->next;
00153     if (!is_func (subtree (et, q), TFORMAT)) break;
00154   }
00155 
00156   return p;
00157 }
00158 
00159 path
00160 edit_table_rep::search_row (path fp, int row) {
00161   fp= search_table (fp) * row;
00162   tree st= subtree (et, fp);
00163   if (!is_func (st, ROW))
00164     return search_row (fp, N(st)-1);
00165   return fp;
00166 }
00167 
00168 path
00169 edit_table_rep::search_cell (path p, int col) {
00170   p= p * col;
00171   tree st= subtree (et, p);
00172   if (is_func (st, TFORMAT))
00173     return search_cell (p, N(st)-1);
00174   if (is_func (st, CELL, 1)) return p * 0;
00175   return p;
00176 }
00177 
00178 path
00179 edit_table_rep::search_cell (path fp, int row, int col) {
00180   return search_cell (search_row (fp, row), col);
00181 }
00182 
00183 /******************************************************************************
00184 * Analyzing with statements in format
00185 ******************************************************************************/
00186 
00187 void
00188 edit_table_rep::with_raw_read (tree with, int& i1, int& j1, int& i2, int& j2) {
00189   i1= as_int (with[0]);
00190   i2= as_int (with[1]);
00191   j1= as_int (with[2]);
00192   j2= as_int (with[3]);
00193 }
00194 
00195 void
00196 edit_table_rep::with_decode (int nr_rows, int nr_cols,
00197                           int& i1, int& j1, int& i2, int& j2)
00198 {
00199   i1= (i1>=0? i1-1: nr_rows+i1);
00200   i2= (i2> 0? i2-1: nr_rows+i2);
00201   j1= (j1>=0? j1-1: nr_cols+j1);
00202   j2= (j2> 0? j2-1: nr_cols+j2);
00203 }
00204 
00205 void
00206 edit_table_rep::with_decode (int nr_rows, int nr_cols,
00207                           int& I1, int& J1, int& I2, int& J2,
00208                           int& i1, int& j1, int& i2, int& j2)
00209 {
00210   i1= I1; j1= J1; i2= I2; j2=J2;
00211   with_decode (nr_rows, nr_cols, i1, j1, i2, j2);
00212 }
00213 
00214 void
00215 edit_table_rep::with_read (tree with, int nr_rows, int nr_cols,
00216                         int& i1, int& j1, int& i2, int& j2)
00217 {
00218   with_raw_read (with, i1, j1, i2, j2);
00219   with_decode (nr_rows, nr_cols, i1, j1, i2, j2);
00220 }
00221 
00222 void
00223 edit_table_rep::with_read (tree with, int nr_rows, int nr_cols,
00224                         int& I1, int& J1, int& I2, int& J2,
00225                         int& i1, int& j1, int& i2, int& j2)
00226 {
00227   with_raw_read (with, I1, J1, I2, J2);
00228   i1= I1; j1= J1; i2= I2; j2=J2;
00229   with_decode (nr_rows, nr_cols, i1, j1, i2, j2);
00230 }
00231 
00232 /******************************************************************************
00233 * Formatting primitives
00234 ******************************************************************************/
00235 
00236 tree
00237 edit_table_rep::table_get_format (path fp) {
00238   tree fm= get_env_value (CELL_FORMAT, fp * 0);
00239   tree st= subtree (et, fp);
00240   return fm * st (0, N(st)-1);
00241 }
00242 
00243 void
00244 edit_table_rep::table_set_format (path fp, string var, tree val) {
00245   table_del_format (fp, var);
00246   tree with (TWITH, var, val);
00247   tree st= subtree (et, fp);
00248   insert (fp * (N(st)-1), tree (TFORMAT, with));
00249 }
00250 
00251 tree
00252 edit_table_rep::table_get_format (path fp, string var) {
00253   tree st= table_get_format (fp);
00254   int k, n= N(st);
00255   tree val= get_env_value (var);
00256   for (k=0; k<n; k++)
00257     if (is_func (st[k], TWITH, 2) && (st[k][0] == var))
00258       val= st[k][1];
00259   return val;
00260 }
00261 
00262 void
00263 edit_table_rep::table_del_format (path fp, string var) {
00264   tree st= subtree (et, fp);
00265   int k, n= N(st);
00266   for (k=n-2; k>=0; k--)
00267     if (is_func (st[k], TWITH, 2))
00268       if ((var == "") || (var == st[k][0]))
00269        remove (fp * k, 1);
00270 }
00271 
00272 void
00273 edit_table_rep::table_set_format (
00274   path fp, int I1, int J1, int I2, int J2, string var, tree val)
00275 {
00276   table_del_format (fp, I1, J1, I2, J2, var);
00277   tree with (CWITH);
00278   with << as_string (I1) << as_string (I2)
00279        << as_string (J1) << as_string (J2)
00280        << var << val;
00281   tree st= subtree (et, fp);
00282   insert (fp * (N(st)-1), tree (TFORMAT, with));
00283 }
00284 
00285 tree
00286 edit_table_rep::table_get_format (
00287   path fp, int I1, int J1, int I2, int J2, string var)
00288 {
00289   int i1, j1, i2, j2;
00290   int nr_rows, nr_cols;
00291   tree st= table_get_format (fp);
00292   table_get_extents (fp, nr_rows, nr_cols);
00293   with_decode (nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
00294 
00295   int k, n= N(st);
00296   tree val= get_env_value (var);
00297   for (k=0; k<n; k++)
00298     if (is_func (st[k], CWITH, 6) && (st[k][4] == var)) {
00299       int row1, col1, row2, col2;
00300       with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
00301       if ((row1<=i1) && (col1<=j1) && (row2>=i2) && (col2>=j2))
00302        val= st[k][5];
00303     }
00304   return val;
00305 }
00306 
00307 void
00308 edit_table_rep::table_del_format (
00309   path fp, int I1, int J1, int I2, int J2, string var)
00310 {
00311   int i1, j1, i2, j2;
00312   int nr_rows, nr_cols;
00313   tree st= subtree (et, fp);
00314   table_get_extents (fp, nr_rows, nr_cols);
00315   with_decode (nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
00316 
00317   int k, n= N(st);
00318   for (k=n-2; k>=0; k--)
00319     if (is_func (st[k], CWITH, 6))
00320       if ((var == "") || (var == st[k][4])) {
00321        int row1, col1, row2, col2;
00322        with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
00323        if ((row1>=i1) && (col1>=j1) && (row2<=i2) && (col2<=j2))
00324          remove (fp * k, 1);
00325       }
00326 }
00327 
00328 void
00329 edit_table_rep::table_get_format (
00330   path fp, string var, tree** val, int nr_rows, int nr_cols)
00331 {
00332   int i, j;
00333   tree def_val= get_env_value (var, fp);
00334   for (i=0; i<nr_rows; i++)
00335     for (j=0; j<nr_cols; j++)
00336       val[i][j]= def_val;
00337 
00338   tree st= table_get_format (fp);
00339   int k, n= N(st);
00340   for (k=0; k<n; k++)
00341     if (is_func (st[k], CWITH, 6) && (st[k][4] == var)) {
00342       int row1, col1, row2, col2;
00343       with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
00344       for (i=row1; i<=row2; i++)
00345        for (j=col1; j<=col2; j++)
00346          val[i][j]= st[k][5];
00347     }
00348 }
00349 
00350 void
00351 edit_table_rep::table_individualize (path fp, string var) {
00352   int nr_rows, nr_cols;
00353   tree st= subtree (et, fp);
00354   table_get_extents (fp, nr_rows, nr_cols);
00355 
00356   int k, n= N(st);
00357   for (k=n-2; k>=0; k--)
00358     if (is_func (st[k], CWITH, 6))
00359       if ((var == "") || (var == st[k][4])) {
00360        int i, j, row1, col1, row2, col2;
00361        with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
00362        if ((row1==row2) && (col1==col2)) continue;
00363        row1= max (row1, 0); row2= min (row2, nr_rows-1);
00364        col1= max (col1, 0); col2= min (col2, nr_cols-1);
00365        tree ins_format (TFORMAT);
00366        for (i=row1; i<=row2; i++)
00367          for (j=col1; j<=col2; j++) {
00368            tree with (CWITH);
00369            with << as_string (i+1) << as_string (i+1)
00370                << as_string (j+1) << as_string (j+1)
00371                << copy (st[k][4]) << copy (st[k][5]) << copy (st[k][6]);
00372            ins_format << with;
00373          }
00374        remove (fp * k, 1);
00375        insert (fp * k, ins_format);
00376       }
00377 }
00378 
00379 void
00380 edit_table_rep::table_format_center (path fp, int row, int col) {
00381   int nr_rows, nr_cols;
00382   tree st= subtree (et, fp);
00383   table_get_extents (fp, nr_rows, nr_cols);
00384   int Row1= row+1;
00385   int Col1= col+1;
00386   int Row2= row-nr_rows;
00387   int Col2= col-nr_cols;
00388 
00389   int k, n= N(st);
00390   for (k=n-2; k>=0; k--)
00391     if (is_func (st[k], CWITH, 6)) {
00392       int I1, I2, J1, J2, i1, i2, j1, j2;
00393       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
00394 
00395       if (i1 == row) I1= Row1;
00396       else if (i1 < row) I1= i1+1;
00397       else I1= i1-nr_rows;
00398       if (i2 == row) I2= Row2;
00399       else if (i2 < row) I2= i2+1;
00400       else I2= i2-nr_rows;
00401 
00402       if (j1 == col) J1= Col1;
00403       else if (j1 < col) J1= j1+1;
00404       else J1= j1-nr_cols;
00405       if (j2 == col) J2= Col2;
00406       else if (j2 < col) J2= j2+1;
00407       else J2= j2-nr_cols;
00408 
00409       assign (fp * path (k, 0), as_string (I1));
00410       assign (fp * path (k, 1), as_string (I2));
00411       assign (fp * path (k, 2), as_string (J1));
00412       assign (fp * path (k, 3), as_string (J2));
00413     }
00414 }
00415 
00416 /******************************************************************************
00417 * Inserting and deleteing new rows and columns
00418 ******************************************************************************/
00419 
00420 void
00421 edit_table_rep::table_get_extents (path fp, int& nr_rows, int& nr_cols) {
00422   ::table_get_extents (subtree (et, fp), nr_rows, nr_cols);
00423 }
00424 
00425 void
00426 edit_table_rep::table_set_extents (path fp, int nr_rows, int nr_cols) {
00427   int old_rows, old_cols;
00428   table_get_extents (fp, old_rows, old_cols);
00429   if (nr_rows > old_rows || nr_cols > old_cols)
00430     table_insert (fp, old_rows, old_cols,
00431                   max (0, nr_rows - old_rows),
00432                   max (0, nr_cols - old_cols));
00433   if (nr_rows < old_rows || nr_cols < old_cols)
00434     table_remove (fp, nr_rows, nr_cols,
00435                   max (0, old_rows - nr_rows),
00436                   max (0, old_cols - nr_cols));
00437 }
00438 
00439 void
00440 edit_table_rep::table_get_limits (
00441   path fp, int& i1, int& j1, int& i2, int& j2) 
00442 {
00443   i1= max (1, as_int (table_get_format (fp, TABLE_MIN_ROWS)));
00444   j1= max (1, as_int (table_get_format (fp, TABLE_MIN_COLS)));
00445   i2= as_int (table_get_format (fp, TABLE_MAX_ROWS));
00446   j2= as_int (table_get_format (fp, TABLE_MAX_COLS));
00447   if (i2<i1) i2= 0x7fffffff;
00448   if (j2<i1) j2= 0x7fffffff;
00449 }
00450 
00451 void
00452 edit_table_rep::table_remove (path fp, int row, int col, int delr, int delc) {
00453   path p= search_table (fp);
00454   int nr_rows, nr_cols;
00455   table_get_extents (p, nr_rows, nr_cols);
00456   tree T= subtree (et, p);
00457   if (delr>0)
00458     if (row+delr <= N(T)) {
00459       if (delr == N(T)) {
00460        destroy_table ();
00461        return;
00462       }
00463       remove (p * row, delr);
00464     }
00465 
00466   T= subtree (et, p);
00467   if (delc>0)
00468     for (row=0; row<N(T); row++) {
00469       path q= search_row (p, row);
00470       tree R= subtree (et, q);
00471       if (col+delc <= N(R)) {
00472        if (delc == N(R)) {
00473          destroy_table ();
00474          return;
00475        }
00476        remove (q * col, delc);
00477       }
00478     }
00479 
00480   tree st= subtree (et, fp);
00481   if (!is_func (st, TFORMAT)) return;
00482   int k, n= N(st);
00483   for (k=n-2; k>=0; k--)
00484     if (is_func (st[k], CWITH, 6)) {
00485       int I1, I2, J1, J2, i1, i2, j1, j2;
00486       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
00487       if (delr>0) {
00488        if ((row<=i1) && (i2<row+delr)) { remove (fp * k, 1); continue; }
00489        if ((I1>0) && (i1>=row))
00490          assign (fp * path (k, 0), as_string (I1- min (delr, i1- row)));
00491        if ((I1<0) && (i1<row+delr))
00492          assign (fp * path (k, 0), as_string (I1+ delr+ min (0, row- 1- i1)));
00493        if ((I2>0) && (i2>=row))
00494          assign (fp * path (k, 1), as_string (I2- min (delr, i2- row)));
00495        if ((I2<0) && (i2<row+delr))
00496          assign (fp * path (k, 1), as_string (I2+ delr+ min (0, row- 1- i2)));
00497       }
00498       if (delc>0) {
00499        if ((col<=j1) && (j2<col+delc)) { remove (fp * k, 1); continue; }
00500        if ((J1>0) && (j1>=col))
00501          assign (fp * path (k, 2), as_string (J1- min (delc, j1- col)));
00502        if ((J1<0) && (j1<col+delc))
00503          assign (fp * path (k, 2), as_string (J1+ delc+ min (0, col- 1- j1)));
00504        if ((J2>0) && (j2>=col))
00505          assign (fp * path (k, 3), as_string (J2- min (delc, j2- col)));
00506        if ((J2<0) && (j2<col+delc))
00507          assign (fp * path (k, 3), as_string (J2+ delc+ min (0, col- 1- j2)));
00508       }
00509     }
00510 }
00511 
00512 void
00513 edit_table_rep::table_insert (path fp, int row, int col, int insr, int insc) {
00514   path p= search_table (fp);
00515   int nr_rows, nr_cols;
00516   table_get_extents (p, nr_rows, nr_cols);
00517   tree T= subtree (et, p);
00518   if (insr>0)
00519     if (row <= N(T))
00520       insert (p * row, empty_table (insr, nr_cols));
00521 
00522   T= subtree (et, p);
00523   if (insc>0)
00524     for (row=0; row<N(T); row++) {
00525       path q= search_row (p, row);
00526       tree R= subtree (et, q);
00527       if (col <= N(R))
00528        insert (q * col, empty_row (insc));
00529     }
00530 
00531   tree st= subtree (et, fp);
00532   if (!is_func (st, TFORMAT)) return;
00533   int k, n= N(st);
00534   for (k=n-2; k>=0; k--)
00535     if (is_func (st[k], CWITH, 6)) {
00536       int I1, I2, J1, J2, i1, i2, j1, j2;
00537       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
00538       if (insr>0) {
00539        bool flag= (I1<=0) || (I2>=0);
00540        if ((I1>0) && ((i1>row) || (flag && (i1==row))))
00541          assign (fp* path (k,0), as_string (I1+insr));
00542        if ((I1<0) && (i1<row))
00543          assign (fp* path (k,0), as_string (I1-insr));
00544        if ((I2>0) && (i2>=row))
00545          assign (fp* path (k,1), as_string (I2+insr));
00546        if ((I2<0) && ((i2<row-1) || (flag && (i2==row-1))))
00547          assign (fp* path (k,1), as_string (I2-insr));
00548       }
00549       if (insc>0) {
00550        bool flag= (J1<=0) || (J2>=0);
00551        if ((J1>0) && ((j1>col) || (flag && (j1==col))))
00552          assign (fp * path (k,2), as_string (J1+insc));
00553        if ((J1<0) && (j1<col))
00554          assign (fp * path (k,2), as_string (J1-insc));
00555        if ((J2>0) && (j2>=col))
00556          assign (fp * path (k,3), as_string (J2+insc));
00557        if ((J2<0) && ((j2<col-1) || (flag && (j2==col-1))))
00558          assign (fp * path (k,3), as_string (J2-insc));
00559       }
00560     }
00561 }
00562 
00563 /******************************************************************************
00564 * Cursor positioning
00565 ******************************************************************************/
00566 
00567 void
00568 edit_table_rep::table_bound (
00569   path fp, int& row1, int& col1, int& row2, int& col2)
00570 {
00571   fp= search_format (fp);
00572   if (!is_func (subtree (et, fp), TFORMAT)) return;
00573 
00574   int i, j, ii, jj, nr_rows, nr_cols;
00575   table_get_extents (fp, nr_rows, nr_cols);
00576   tree** rs= tm_new_array<tree*> (nr_rows);
00577   tree** cs= tm_new_array<tree*> (nr_rows);
00578   for (i=0; i<nr_rows; i++) {
00579     rs[i]= tm_new_array<tree> (nr_cols);
00580     cs[i]= tm_new_array<tree> (nr_cols);
00581   }
00582   table_get_format (fp, CELL_ROW_SPAN, rs, nr_rows, nr_cols);
00583   table_get_format (fp, CELL_COL_SPAN, cs, nr_rows, nr_cols);
00584 
00585   for (i=0; i<nr_rows; i++)
00586     for (j=0; j<nr_cols; j++) {
00587       int m= min (as_int (rs[i][j]), nr_rows-i);
00588       int n= min (as_int (rs[i][j]), nr_cols-j);
00589       if ((m>1) || (n>1)) {
00590        if ((row1 < i+m) && (col1 < j+n) && (row2 >= i) && (col2 >= j)) {
00591          row1= min (row1, i);
00592          col1= min (col1, j);
00593          row2= max (row2, i+m-1);
00594          col2= max (col2, j+n-1);
00595        }
00596        for (ii=0; ii<m; ii++)
00597          for (jj=0; jj<n; jj++) {
00598            rs[i+ii][j+jj]= "0";
00599            cs[i+ii][j+jj]= "0";
00600          }
00601       }
00602     }
00603   
00604   for (i=0; i<nr_rows; i++) {
00605     tm_delete_array (rs[i]);
00606     tm_delete_array (cs[i]);
00607   }
00608   tm_delete_array (rs);
00609   tm_delete_array (cs);
00610 }
00611 
00612 void
00613 edit_table_rep::table_go_to (path fp, int row, int col, bool at_start) {
00614   int nr_rows, nr_cols;
00615   fp= search_format (fp);
00616   table_get_extents (fp, nr_rows, nr_cols);
00617   if (row<0) row= 0;
00618   if (col<0) col= 0;
00619   if (row>=nr_rows) row= nr_rows-1;
00620   if (col>=nr_cols) col= nr_cols-1;
00621   if (is_func (subtree (et, fp), TFORMAT)) {
00622     int row2= row, col2= col;
00623     table_bound (fp, row, col, row2, col2);
00624   }
00625   path q= search_cell (fp, row, col);
00626   go_to_border (q, at_start);
00627 }
00628 
00629 void
00630 edit_table_rep::table_go_to_border (path fp, bool right) {
00631   while ((rp < fp) && (is_func (subtree (et, path_up (fp)), TFORMAT)))
00632     fp= path_up (fp);
00633   if ((rp < fp) &&
00634       is_document (subtree (et, path_up (fp))) &&
00635       (rp < path_up (fp)) &&
00636       is_extension (subtree (et, path_up (fp, 2)), 1))
00637     fp= path_up (fp);
00638   if ((rp < fp) && is_extension (subtree (et, path_up (fp)), 1))
00639     fp= path_up (fp);
00640   if ((rp < fp) && is_func (subtree (et, path_up (fp)), SUBTABLE, 1))
00641     fp= path_up (fp);
00642   go_to_border (fp, right);
00643 }
00644 
00645 void
00646 edit_table_rep::back_table (path p, bool forward) {
00647   while (true) {
00648     tree st= subtree (et, p);
00649     if (!is_func (st, TFORMAT)) break;
00650     if (!is_func (st [N(st)-1], TABLE)) {
00651       back_general (p, forward);
00652       return;
00653     }
00654     p= p * (N(st)-1);
00655   }
00656   while (rp < p) {
00657     tree st= subtree (et, p);
00658     if (is_func (st, TABLE)) break;
00659     p= path_up (p);
00660   }
00661   if (!(rp < p)) return;
00662 
00663   if (forward) table_go_to (p, 0, 0, true);
00664   else {
00665     int nr_rows, nr_cols;
00666     table_get_extents (p, nr_rows, nr_cols);
00667     table_go_to (p, nr_rows-1, nr_cols-1, false);
00668   }
00669 }
00670 
00671 void
00672 edit_table_rep::back_in_table (tree t, path p, bool forward) {
00673   if (is_func (t, TFORMAT) &&
00674       (is_func (subtree (et, path_up (p, 2)), INACTIVE) || in_source ()))
00675     {
00676       remove_empty_argument (p, forward);
00677       return;
00678     }
00679 
00680   int i, j, row, col, nr_rows, nr_cols;
00681   p= search_table (row, col);
00682   if (is_nil (p)) return;
00683   table_get_extents (p, nr_rows, nr_cols);
00684 
00685   bool flag=true;
00686   for (j=0; j<nr_cols; j++) {
00687     path q= search_cell (p, row, j);
00688     flag= flag && is_empty_cell (subtree (et, q));
00689   }
00690   if (flag) {
00691     int i1, j1, i2, j2;
00692     path fp= search_format ();
00693     if (is_nil (fp)) return;
00694     table_get_limits (fp, i1, j1, i2, j2);
00695     if (nr_rows-1 >= i1) {
00696       table_remove_row (forward, true);
00697       return;
00698     }
00699   }
00700 
00701   flag= true;
00702   for (i=0; i<nr_rows; i++) {
00703     path q= search_cell (p, i, col);
00704     flag= flag && is_empty_cell (subtree (et, q));
00705   }
00706   if (flag) {
00707     int i1, j1, i2, j2;
00708     path fp= search_format ();
00709     if (is_nil (fp)) return;
00710     table_get_limits (fp, i1, j1, i2, j2);
00711     if (nr_cols-1 >= j1) {
00712       table_remove_column (forward, true);
00713       return;
00714     }
00715   }
00716 
00717   flag=true;
00718   for (i=0; i<nr_rows; i++)
00719     for (j=0; j<nr_cols; j++) {
00720       path q= search_cell (p, i, j);
00721       flag= flag && is_empty_cell (subtree (et, q));
00722     }
00723   if (flag) {
00724     destroy_table ();
00725     return;
00726   }
00727 
00728   if (forward) {
00729     if (col<(nr_cols-1)) { table_go_to (p, row, col+1, true); return; }
00730     if (row<(nr_rows-1)) { table_go_to (p, row+1, 0, true); return; }
00731   }
00732   else {
00733     if (col>0) { table_go_to (p, row, col-1, false); return; }
00734     if (row>0) { table_go_to (p, row-1, nr_cols-1, false); return; }
00735   }
00736   table_go_to_border (p, !forward);
00737 }
00738 
00739 /******************************************************************************
00740 * Routines for subtables
00741 ******************************************************************************/
00742 
00743 tree
00744 edit_table_rep::table_get_subtable (
00745   path fp, int row1, int col1, int row2, int col2)
00746 {
00747   return table_get_subtable (fp, row1, col1, row2, col2, false);
00748 }
00749 
00750 tree
00751 edit_table_rep::table_get_subtable (
00752   path fp, int row1, int col1, int row2, int col2, bool recurse)
00753 {
00754   path p= search_table (fp);
00755   int i, j, nr_rows, nr_cols;
00756   table_get_extents (p, nr_rows, nr_cols);
00757   tree st= subtree (et, p);
00758   tree subtable (TABLE, row2+1-row1);
00759   for (i=row1; i<=row2; i++) {
00760     tree sr= st[i];
00761     tree sub_row (ROW, col2+1-col1);
00762     while (is_func (sr, TFORMAT)) sr= sr[N(sr)-1];
00763     for (j=col1; j<=col2; j++)
00764       sub_row[j-col1]= copy (sr[j]);
00765     subtable[i-row1]= sub_row;
00766   }
00767 
00768   st= subtree (et, fp);
00769   if ((!recurse) && (!is_func (st, TFORMAT))) return subtable;
00770   if (recurse) st= table_get_format (fp);
00771   else st= st (0, N(st)-1);
00772   int k, n= N(st);
00773   tree sub_format (TFORMAT);
00774   for (k=0; k<n; k++)
00775     if (is_func (st[k], CWITH, 6)) {
00776       int I1, I2, J1, J2, i1, i2, j1, j2;
00777       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
00778       if ((i1<=row2) && (i2>=row1) && (j1<=col2) && (j2>=col1)) {
00779        I1= min (max (0, i1- row1), row2- row1) + 1;
00780        I2= min (max (0, i2- row1), row2- row1) + 1;
00781        J1= min (max (0, j1- col1), col2- col1) + 1;
00782        J2= min (max (0, j2- col1), col2- col1) + 1;
00783        tree with (CWITH);
00784        with << as_string (I1) << as_string (I2)
00785             << as_string (J1) << as_string (J2)
00786             << copy (st[k][4]) << copy (st[k][5]);
00787        sub_format << with;
00788       }
00789     }
00790   sub_format << subtable;
00791   return sub_format;
00792 }
00793 
00794 static tree
00795 shift_subtable (tree st, int sh_row, int sh_col) {
00796   st= copy (st);
00797   int k, n= N(st);
00798   for (k=0; k<n-1; k++)
00799     if (is_func (st[k], CWITH, 6)) {
00800       st[k][0]= as_string (as_int (st[k][0]) + sh_row);
00801       st[k][1]= as_string (as_int (st[k][1]) + sh_row);
00802       st[k][2]= as_string (as_int (st[k][2]) + sh_col);
00803       st[k][3]= as_string (as_int (st[k][3]) + sh_col);
00804     }
00805   return st;
00806 }
00807 
00808 void
00809 edit_table_rep::table_write_subtable (
00810   path fp, int row, int col, tree subt)
00811 {
00812   int nr_rows, nr_cols, sub_rows, sub_cols;
00813   table_get_extents (fp, nr_rows, nr_cols);
00814   ::table_get_extents (subt, sub_rows, sub_cols);
00815   if ((nr_rows < row+sub_rows) || (nr_cols < col+sub_cols)) return;
00816 
00817   path old_tp= tp;
00818   tp= fp * 0;
00819   bool calc_flag= inside ("calc-table");
00820   tp= old_tp;
00821   if (calc_flag)
00822     subt= as_tree (call ("calc-table-renumber", object (subt),
00823                          object (row + 1), object (col + 1)));
00824 
00825   if (is_func (subtree (et, fp), TFORMAT) &&
00826       is_func (subt, TFORMAT))
00827     {
00828       tree sh_subt= shift_subtable (subt, row, col);
00829       sh_subt= sh_subt (0, N(sh_subt)-1);
00830       tree st= subtree (et, fp);
00831       insert (fp * (N(st)-1), sh_subt);
00832       subt= subt [N(subt)-1];
00833     }
00834 
00835   int i, j;
00836   for (i=0; i<sub_rows; i++) {
00837     path rp  = search_row (fp, i+row);
00838     tree subr= subt[i];
00839     while (is_func (subr, TFORMAT)) subr= subr [N(subr)-1];
00840     for (j=0; j<sub_cols; j++) {
00841       path cp  = search_cell (rp, j+col);
00842       tree subc= subr[j];
00843       while (is_func (subc, TFORMAT)) subc= subc [N(subr)-1];
00844       if (is_func (subc, CELL, 1)) subc= subc[0];
00845       assign (cp, copy (subc));
00846     }
00847   }
00848 }
00849 
00850 void
00851 edit_table_rep::table_hor_insert_subtable (path fp, int col, tree subt) {
00852   int nr_rows, nr_cols, sub_rows, sub_cols;
00853   table_get_extents (fp, nr_rows, nr_cols);
00854   ::table_get_extents (subt, sub_rows, sub_cols);
00855   if (sub_rows != nr_rows) return;
00856   table_insert (fp, 0, col, 0, sub_cols);
00857   table_write_subtable (fp, 0, col, subt);
00858 }
00859 
00860 void
00861 edit_table_rep::table_ver_insert_subtable (path fp, int row, tree subt) {
00862   int nr_rows, nr_cols, sub_rows, sub_cols;
00863   table_get_extents (fp, nr_rows, nr_cols);
00864   ::table_get_extents (subt, sub_rows, sub_cols);
00865   if (sub_cols != nr_cols) return;
00866   table_insert (fp, row, 0, sub_rows, 0);
00867   table_write_subtable (fp, row, 0, subt);
00868 }
00869 
00870 /******************************************************************************
00871 * Decorations
00872 ******************************************************************************/
00873 
00874 void
00875 edit_table_rep::table_force_decoration (path fp, int row, int col) {
00876   row++; col++;
00877   tree old= table_get_format (fp, row, col, row, col, CELL_DECORATION);
00878   if (old == "") {
00879     tree f (TFORMAT, tree (TABLE, tree (ROW, tree (TMARKER))));
00880     table_set_format (fp, row, col, row, col, CELL_DECORATION, f);
00881   }
00882 }
00883 
00884 static void
00885 search_decoration (tree T, int& row, int& col) {
00886   while (is_func (T, TFORMAT)) T= T [N(T)-1];
00887   for (row=0; row<N(T); row++) {
00888     tree R= T[row];
00889     while (is_func (R, TFORMAT)) R= R [N(R)-1];
00890     for (col=0; col<N(R); col++) {
00891       tree C= R[col];
00892       while (is_func (C, TFORMAT)) C= C [N(C)-1];
00893       if (C == tree (TMARKER)) return;
00894     }
00895   }
00896   FAILED ("decoration not found");
00897 }
00898 
00899 static tree
00900 table_format_undecorate (tree st, int row, int col, int dec_row, int dec_col) {
00901   tree fm (TFORMAT);
00902   int k, n= N(st);
00903   for (k=0; k<n-1; k++)
00904     if ((as_int (st[k][0]) <= (row+1)) && (as_int (st[k][1]) >= (row+1)) &&
00905        (as_int (st[k][2]) <= (col+1)) && (as_int (st[k][3]) >= (col+1)))
00906       if (is_func (st[k], CWITH, 6) && (st[k][4] != CELL_DECORATION)) {
00907        tree with= copy (st[k]);
00908        with[0]= as_string (dec_row+1);
00909        with[1]= as_string (dec_row+1);
00910        with[2]= as_string (dec_col+1);
00911        with[3]= as_string (dec_col+1);
00912        fm << with;
00913       }
00914   return fm;
00915 }
00916 
00917 static tree
00918 table_undecorate (tree st, int row, int col) {
00919   int k, n= N(st);
00920   for (k=0; k<n-1; k++)
00921     if ((as_int (st[k][0]) == (row+1)) && (as_int (st[k][2]) == (col+1)))
00922       if (is_func (st[k], CWITH, 6) && (st[k][4] == CELL_DECORATION)) {
00923        int dec_row= 0, dec_col= 0;
00924        tree T= copy (st[k][5]);
00925        search_decoration (T, dec_row, dec_col);
00926        table_set (T, dec_row, dec_col, table_get (st[n-1], row, col));
00927        tree F= table_format_undecorate (st, row, col, dec_row, dec_col);
00928        return F * T;
00929       }
00930   FAILED ("decoration not found");
00931   return "";
00932 }
00933 
00934 void
00935 edit_table_rep::table_hor_decorate (path fp, int col, int cbef, int caft) {
00936   tree st= subtree (et, fp);
00937   if (!is_func (st, TFORMAT)) return;
00938   if (cbef+caft == 0) return;
00939   int i, j, k, nr_rows, nr_cols;
00940   path p= search_table (fp);
00941   table_get_extents (p, nr_rows, nr_cols);
00942   table_individualize (fp, CELL_DECORATION);
00943 
00944   for (i=0; i<nr_rows; i++)
00945     for (j=col-cbef; j<=col+caft; j++)
00946       table_force_decoration (fp, i, j);
00947 
00948   tree t1, t2;
00949   if (caft>0)
00950     t2= table_get_subtable (fp, 0, col+1   , nr_rows-1, col+caft, true);
00951   if (cbef>0)
00952     t1= table_get_subtable (fp, 0, col-cbef, nr_rows-1, col-1   , true);
00953   if (caft>0) table_remove (fp, 0, col+1   , 0, caft);
00954   if (cbef>0) table_remove (fp, 0, col-cbef, 0, cbef);
00955   col -= cbef;
00956 
00957   st= subtree (et, fp);
00958   int n= N(st);
00959   for (k=0; k<n-1; k++)
00960     if (is_func (st[k], CWITH, 6) && (st[k][4] == CELL_DECORATION)) {
00961       int i1, j1, i2, j2;
00962       with_read (st[k], nr_rows, nr_cols, i1, j1, i2, j2);
00963       if (j1 != col) continue;
00964       for (j=0; j<caft; j++) {
00965        tree inst= table_undecorate (t2, i1, j);
00966        int sub_rows, sub_cols;
00967        ::table_get_extents (st[k][5], sub_rows, sub_cols);
00968        table_hor_insert_subtable (fp * path (k, 5), sub_cols, inst);
00969       }
00970       for (j=cbef-1; j>=0; j--) {
00971        tree inst= table_undecorate (t1, i1, j);
00972        table_hor_insert_subtable (fp * path (k, 5), 0, inst);
00973       }
00974     }
00975 }
00976 
00977 void
00978 edit_table_rep::table_ver_decorate (path fp, int row, int rbef, int raft) {
00979   tree st= subtree (et, fp);
00980   if (!is_func (st, TFORMAT)) return;
00981   if (rbef+raft == 0) return;
00982   int i, j, k, nr_rows, nr_cols;
00983   path p= search_table (fp);
00984   table_get_extents (p, nr_rows, nr_cols);
00985   table_individualize (fp, CELL_DECORATION);
00986 
00987   for (i=row-rbef; i<=row+raft; i++)
00988     for (j=0; j<nr_cols; j++)
00989       table_force_decoration (fp, i, j);
00990 
00991   tree t1, t2;
00992   if (raft>0)
00993     t2= table_get_subtable (fp, row+1   , 0, row+raft, nr_cols-1, true);
00994   if (rbef>0)
00995     t1= table_get_subtable (fp, row-rbef, 0, row-1   , nr_cols-1, true);
00996   if (raft>0) table_remove (fp, row+1   , 0, raft, 0);
00997   if (rbef>0) table_remove (fp, row-rbef, 0, rbef, 0);
00998   row -= rbef;
00999 
01000   st= subtree (et, fp);
01001   int n= N(st);
01002   for (k=0; k<n-1; k++)
01003     if (is_func (st[k], CWITH, 6) && (st[k][4] == CELL_DECORATION)) {
01004       int i1, j1, i2, j2;
01005       with_read (st[k], nr_rows, nr_cols, i1, j1, i2, j2);
01006       if (i1 != row) continue;
01007       for (i=0; i<raft; i++) {
01008        tree inst= table_undecorate (t2, i, j1);
01009        int sub_rows, sub_cols;
01010        ::table_get_extents (st[k][5], sub_rows, sub_cols);
01011        table_ver_insert_subtable (fp * path (k, 5), sub_rows, inst);
01012       }
01013       for (i=rbef-1; i>=0; i--) {
01014        tree inst= table_undecorate (t1, i, j1);
01015        table_ver_insert_subtable (fp * path (k, 5), 0, inst);
01016       }
01017     }
01018 }
01019 
01020 /******************************************************************************
01021 * User interface
01022 ******************************************************************************/
01023 
01024 void
01025 edit_table_rep::make_table (int nr_rows, int nr_cols) {
01026   //cout << "make_table " << nr_rows << ", " << nr_cols << "\n";
01027   tree T= empty_table (nr_rows, nr_cols);
01028   path p (0, 0, 0, 0);
01029   tree format_T (TFORMAT, T);
01030   insert_tree (format_T, path (N(format_T)-1, p));
01031 
01032   int i1, j1, i2, j2;
01033   path fp= search_format ();
01034   if (is_nil (fp)) return;
01035   table_get_limits (fp, i1, j1, i2, j2);
01036   if ((nr_rows<i1) || (nr_cols<j1)) {
01037     T= empty_table (max (nr_rows, i1), max (nr_cols, j1));
01038     format_T= tree (TFORMAT, T);
01039     assign (fp, format_T);
01040     go_to (fp * path (N(format_T)-1, p));
01041   }
01042 
01043   string hyphen= as_string (table_get_format (fp, TABLE_HYPHEN));
01044   if (hyphen == "y") {
01045     path q= fp;
01046     if (is_extension (subtree (et, path_up (q)), 1)) q= path_up (q);
01047     tree st= subtree (et, path_up (q));
01048     if (is_document (st)) insert_node (fp * 0, DOCUMENT);
01049     else if (is_concat (st) && is_document (subtree (et, path_up (q, 2)))) {
01050       int n= N(st), l= last_item (q);
01051       insert_node (fp * 0, DOCUMENT);
01052       if (l != (n-1)) {
01053        split (path_inc (q));
01054        correct_concat (path_inc (path_up (q)));
01055       }
01056       if (l != 0) {
01057        split (q);
01058        correct_concat (path_inc (path_up (q)));
01059       }
01060       correct_concat (path_up (q));
01061     }
01062   }
01063 
01064   table_correct_block_content ();
01065   set_message (concat (kbd_shortcut ("(structured-insert-down)"),
01066                      ": new row",
01067                      kbd_shortcut ("(structured-insert-right)"),
01068                      ": new column"),
01069               "table");
01070 }
01071 
01072 void
01073 edit_table_rep::make_subtable (int nr_rows, int nr_cols) {
01074   path cp= search_upwards (CELL);
01075   if (is_nil (cp)) return;
01076   tree T= empty_table (nr_rows, nr_cols);
01077   path p (0, 0, 0, 0);
01078   T= tree (TFORMAT, T);
01079   p= path (N(T)-1, p);
01080   T= tree (SUBTABLE, T);
01081   p= path (0, p);
01082   assign (cp * 0, T);
01083   go_to (cp * path (0, p));
01084   table_correct_block_content ();
01085   set_message (concat (kbd_shortcut ("(structured-insert-down)"),
01086                      ": new row",
01087                      kbd_shortcut ("(structured-insert-right)"),
01088                      ": new column"),
01089               "table");
01090 }
01091 
01092 void
01093 edit_table_rep::destroy_table () {
01094   path fp= search_format ();
01095   if (is_nil (fp)) return;
01096   while (rp < fp) {
01097     tree st= subtree (et, path_up (fp));
01098     if (!is_func (st, TFORMAT)) break;
01099     fp= path_up (fp);
01100   }
01101   if ((rp < fp) &&
01102       is_document (subtree (et, path_up (fp))) &&
01103       (rp < path_up (fp)) &&
01104       is_extension (subtree (et, path_up (fp, 2)), 1))
01105     fp= path_up (fp);
01106   if ((rp < fp) && is_extension (subtree (et, path_up (fp)), 1))
01107     fp= path_up (fp);
01108   if ((rp < fp) && is_func (subtree (et, path_up (fp)), SUBTABLE, 1))
01109     fp= path_up (fp);
01110   assign (fp, "");
01111   correct (path_up (fp));
01112 }
01113 
01114 void
01115 edit_table_rep::table_disactivate () {
01116   path fp= search_format ();
01117   if (is_nil (fp)) return;
01118   tree st= subtree (et, fp);
01119   if (!is_func (st, TFORMAT)) return;
01120   insert_node (fp * 0, INACTIVE);
01121   set_message ("return: reactivate", "deactivate table");
01122 }
01123 
01124 void
01125 edit_table_rep::table_extract_format () {
01126   path fp= search_format ();
01127   if (is_nil (fp)) return;
01128   tree fm= table_get_format (fp);
01129   fm << "";
01130   if (is_extension (subtree (et, path_up (fp)), 1)) fp= path_up (fp);
01131   assign (fp, fm);
01132   go_to (fp * path (N(fm)-1, 0));
01133 }
01134 
01135 void
01136 edit_table_rep::table_insert_row (bool forward) {
01137   int row, col;
01138   path fp= search_format (row, col);
01139   if (is_nil (fp)) return;
01140   int nr_rows, nr_cols, i1, j1, i2, j2;
01141   table_get_extents (fp, nr_rows, nr_cols);
01142   table_get_limits (fp, i1, j1, i2, j2);
01143   if (nr_rows+1 > i2) return;
01144   table_insert (fp, row + (forward? 1: 0), col, 1, 0);
01145   table_go_to (fp, row + (forward? 1: 0), col);
01146   table_correct_block_content ();
01147   table_resize_notify ();
01148 }
01149 
01150 void
01151 edit_table_rep::table_insert_column (bool forward) {
01152   int row, col;
01153   path fp= search_format (row, col);
01154   if (is_nil (fp)) return;
01155   int nr_rows, nr_cols, i1, j1, i2, j2;
01156   table_get_extents (fp, nr_rows, nr_cols);
01157   table_get_limits (fp, i1, j1, i2, j2);
01158   if (nr_cols+1 > j2) return;
01159   table_insert (fp, row, col + (forward? 1: 0), 0, 1);
01160   table_go_to (fp, row, col + (forward? 1: 0));
01161   table_correct_block_content ();
01162   table_resize_notify ();
01163 }
01164 
01165 void
01166 edit_table_rep::table_remove_row (bool forward, bool flag) {
01167   int row, col;
01168   path fp= search_format (row, col);
01169   if (is_nil (fp)) return;
01170   int nr_rows, nr_cols, i1, j1, i2, j2;
01171   table_get_extents (fp, nr_rows, nr_cols);
01172   table_get_limits (fp, i1, j1, i2, j2);
01173   if (nr_rows-1 < i1) destroy_table ();
01174   else if (flag) {
01175     table_remove (fp, row, col, 1, 0);
01176     int ncol= col;
01177     if ((!forward) && (col == 0)) ncol= nr_cols-1;
01178     if (forward && (col == nr_cols-1)) ncol= 0;
01179     table_go_to (fp, max (0, row + (forward? 0: -1)), ncol, forward);
01180   }
01181   else {
01182     if (!forward) row--;
01183     if (row >= 0) table_remove (fp, row, col, 1, 0);
01184     if (row < nr_rows-1 && forward) table_go_to (fp, row, col, forward);
01185     else if (forward || row < 0) table_go_to_border (fp, !forward);
01186   }
01187   table_correct_block_content ();
01188   table_resize_notify ();
01189 }
01190 
01191 void
01192 edit_table_rep::table_remove_column (bool forward, bool flag) {
01193   int row, col;
01194   path fp= search_format (row, col);
01195   if (is_nil (fp)) return;
01196   int nr_rows, nr_cols, i1, j1, i2, j2;
01197   table_get_extents (fp, nr_rows, nr_cols);
01198   table_get_limits (fp, i1, j1, i2, j2);
01199   if (nr_cols-1 < j1) destroy_table ();
01200   else if (flag) {
01201     table_remove (fp, row, col, 0, 1);
01202     int ncol= max (0, col + (forward? 0: -1));
01203     if ((!forward) && (col == 0)) ncol= nr_cols-1;
01204     if (forward && (col == nr_cols-1)) ncol= 0;
01205     table_go_to (fp, row, ncol, forward);
01206   }
01207   else {
01208     if (!forward) col--;
01209     if (col >= 0) table_remove (fp, row, col, 0, 1);
01210     if (col < nr_cols-1 && forward) table_go_to (fp, row, col, forward);
01211     else if (forward || col < 0) table_go_to_border (fp, !forward);
01212   }
01213   table_correct_block_content ();
01214   table_resize_notify ();
01215 }
01216 
01217 int
01218 edit_table_rep::table_nr_rows () {
01219   int nr_rows, nr_cols;
01220   path fp= search_format ();
01221   if (is_nil (fp)) return -1;
01222   table_get_extents (fp, nr_rows, nr_cols);
01223   return nr_rows;
01224 }
01225 
01226 int
01227 edit_table_rep::table_nr_columns () {
01228   int nr_rows, nr_cols;
01229   path fp= search_format ();
01230   if (is_nil (fp)) return -1;
01231   table_get_extents (fp, nr_rows, nr_cols);
01232   return nr_cols;
01233 }
01234 
01235 void
01236 edit_table_rep::table_set_extents (int rows, int cols) {
01237   path fp= search_format ();
01238   if (is_nil (fp)) return;
01239   int min_rows, min_cols, max_rows, max_cols;
01240   table_get_limits (fp, min_rows, min_cols, max_rows, max_cols);
01241   rows= min (max_rows, max (min_rows, rows));
01242   cols= min (max_cols, max (min_cols, cols));
01243   table_set_extents (fp, rows, cols);
01244 }
01245 
01246 int
01247 edit_table_rep::table_which_row () {
01248   int row, col;
01249   path fp= search_format (row, col);
01250   if (is_nil (fp)) return 0;
01251   return row+1;
01252 }
01253 
01254 int
01255 edit_table_rep::table_which_column () {
01256   int row, col;
01257   path fp= search_format (row, col);
01258   if (is_nil (fp)) return 0;
01259   return col+1;
01260 }
01261 
01262 path
01263 edit_table_rep::table_search_cell (int row, int col) {
01264   int nr_rows, nr_cols;
01265   path fp= search_format ();
01266   if (is_nil (fp)) return path ();
01267   table_get_extents (fp, nr_rows, nr_cols);
01268   if (row>0) row--; else row+=nr_rows;
01269   if (col>0) col--; else col+=nr_cols;
01270   if ((row<0) || (row>=nr_rows) || (col<0) || (col>=nr_cols)) return path ();
01271   return search_cell (fp, row, col);
01272 }
01273 
01274 void
01275 edit_table_rep::table_go_to (int row, int col) {
01276   int nr_rows, nr_cols;
01277   path fp= search_format ();
01278   if (is_nil (fp)) return;
01279   table_get_extents (fp, nr_rows, nr_cols);
01280   if (row>0) row--; else row+=nr_rows;
01281   if (col>0) col--; else col+=nr_cols;
01282   if ((row<0) || (row>=nr_rows) || (col<0) || (col>=nr_cols)) return;
01283   table_go_to (fp, row, col);
01284 }
01285 
01286 void
01287 edit_table_rep::table_set_format (string var, tree val) {
01288   if (val == "") table_del_format (var);
01289   else if (selection_active_table (false)) {
01290     int row1, col1, row2, col2;
01291     path fp= selection_get_subtable (row1, col1, row2, col2);
01292     if (is_nil (fp)) return;
01293     table_set_format (fp, var, val);
01294   }
01295   else {
01296     path fp= search_format ();
01297     if (is_nil (fp)) return;
01298     table_set_format (fp, var, val);
01299   }
01300 }
01301 
01302 string
01303 edit_table_rep::table_get_format (string var) {
01304   path fp= search_format ();
01305   if (is_nil (fp)) return "";
01306   return as_string (table_get_format (fp, var));
01307 }
01308 
01309 void
01310 edit_table_rep::table_del_format (string var) {
01311   if (selection_active_table (false)) {
01312     int row1, col1, row2, col2;
01313     path fp= selection_get_subtable (row1, col1, row2, col2);
01314     if (is_nil (fp)) return;
01315     table_del_format (fp, var);
01316   }
01317   else {
01318     path fp= search_format ();
01319     if (is_nil (fp)) return;
01320     table_del_format (fp, var);
01321   }
01322 }
01323 
01324 void
01325 edit_table_rep::table_format_center () {
01326   int row, col;
01327   path fp= search_format (row, col);
01328   if (is_nil (fp)) return;
01329   table_format_center (fp, row, col);
01330 }
01331 
01332 void
01333 edit_table_rep::table_row_decoration (bool forward) {
01334   int row, col, nr_rows, nr_cols;
01335   path fp= search_format (row, col);
01336   if (is_nil (fp)) return;
01337   table_get_extents (fp, nr_rows, nr_cols);
01338   if ((!forward) && (row > 0)) table_ver_decorate (fp, row, 1, 0);
01339   if (forward && (row < (nr_rows-1))) table_ver_decorate (fp, row, 0, 1);
01340 }
01341 
01342 void
01343 edit_table_rep::table_column_decoration (bool forward) {
01344   int row, col, nr_rows, nr_cols;
01345   path fp= search_format (row, col);
01346   if (is_nil (fp)) return;
01347   table_get_extents (fp, nr_rows, nr_cols);
01348   if ((!forward) && (col > 0)) table_hor_decorate (fp, col, 1, 0);
01349   if (forward && (col < (nr_cols-1))) table_hor_decorate (fp, col, 0, 1);
01350 }
01351 
01352 void
01353 edit_table_rep::table_correct_block_content () {
01354   int nr_rows, nr_cols;
01355   path fp= search_format ();
01356   if (is_nil (fp)) return;
01357   table_get_extents (fp, nr_rows, nr_cols);
01358   int row, col;
01359   for (row= 0; row < nr_rows; row++)
01360     for (col= 0; col < nr_cols; col++) {
01361       path cp= search_cell (fp, row, col);
01362       tree st= subtree (et, cp);
01363       tree t1= table_get_format (fp, row+1, col+1, row+1, col+1, CELL_BLOCK);
01364       tree t2= table_get_format (fp, row+1, col+1, row+1, col+1, CELL_HYPHEN);
01365       bool f1= (t1 == "no" || (t1 == "auto" && t2 == "n"));
01366       bool f2= (t1 == "yes" || (t1 == "auto" && is_atomic (t2) && t2 != "n"));
01367       if (f1 && is_document (st) && N(st) == 1)
01368        remove_node (cp * 0);
01369       else if (f2 && !is_document (st))
01370        insert_node (cp * 0, DOCUMENT);
01371     }
01372 }
01373 
01374 void
01375 edit_table_rep::table_resize_notify () {
01376   path p= search_table ();
01377   if (!is_nil (p))
01378     call ("table-resize-notify", object (subtree (et, p)));
01379 }
01380 
01381 void
01382 edit_table_rep::set_cell_mode (string mode) {
01383   cell_mode= mode;
01384 }
01385 
01386 string
01387 edit_table_rep::get_cell_mode () {
01388   return cell_mode;
01389 }
01390 
01391 void
01392 edit_table_rep::cell_set_format (string var, tree val) {
01393   if (selection_active_table (false)) {
01394     int row1, col1, row2, col2, rows, cols;
01395     path fp= selection_get_subtable (row1, col1, row2, col2);
01396     row1++; col1++; row2++; col2++;
01397     table_get_extents (fp, rows, cols);
01398     if (rows > row1 && row1 <= 2 && row2 == rows) row2= -1;
01399     if (cols > col1 && col1 <= 2 && col2 == cols) col2= -1;
01400     table_set_format (fp, row1, col1, row2, col2, var, val);
01401   }
01402   else {
01403     int row, col;
01404     path fp= search_format (row, col); row++; col++;
01405     if (is_nil (fp)) return;
01406     if (cell_mode=="row")
01407       table_set_format (fp, row, 1, row, -1, var, val);
01408     else if (cell_mode=="column")
01409       table_set_format (fp, 1, col, -1, col, var, val);
01410     else if (cell_mode=="table")
01411       table_set_format (fp, 1, 1, -1, -1, var, val);
01412     else table_set_format (fp, row, col, row, col, var, val);
01413   }
01414   table_correct_block_content ();
01415 }
01416 
01417 string
01418 edit_table_rep::cell_get_format (string var) {
01419   int row, col;
01420   path fp= search_format (row, col); row++; col++;
01421   if (is_nil (fp)) return "";
01422   if (cell_mode=="row")
01423     return as_string (table_get_format (fp, row, 1, row, -1, var));
01424   else if (cell_mode=="column")
01425     return as_string (table_get_format (fp, 1, col, -1, col, var));
01426   else if (cell_mode=="table")
01427     return as_string (table_get_format (fp, 1, 1, -1, -1, var));
01428   else return as_string (table_get_format (fp, row, col, row, col, var));
01429 }
01430 
01431 void
01432 edit_table_rep::cell_del_format (string var) {
01433   if (selection_active_table (false)) {
01434     int row1, col1, row2, col2;
01435     path fp= selection_get_subtable (row1, col1, row2, col2);
01436     table_del_format (fp, row1+1, col1+1, row2+1, col2+1, var);
01437   }
01438   else {
01439     int row, col;
01440     path fp= search_format (row, col); row++; col++;
01441     if (is_nil (fp)) return;
01442     if (cell_mode=="row") table_del_format (fp, row, 1, row, -1, var);
01443     else if (cell_mode=="column") table_del_format (fp, 1, col, -1, col, var);
01444     else if (cell_mode=="table") table_del_format (fp, 1, 1, -1, -1, var);
01445     else table_del_format (fp, row, col, row, col, var);
01446   }
01447   table_correct_block_content ();
01448 }
01449 
01450 void
01451 edit_table_rep::table_test () {
01452   path fp= search_format ();
01453   if (is_nil (fp)) return;
01454   cout << table_get_format (fp) << "\n";
01455 }