1 
2 /******************************************************************************
3 * MODULE     : edit_table.cpp
4 * DESCRIPTION: modify tables
5 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 
12 #include "edit_table.hpp"
13 
14 /******************************************************************************
15 * Constructors and destructors
16 ******************************************************************************/
17 
edit_table_rep()18 edit_table_rep::edit_table_rep (): cell_mode ("cell") {}
~edit_table_rep()19 edit_table_rep::~edit_table_rep () {}
20 
21 /******************************************************************************
22 * Elementary subroutines for table manipulation
23 ******************************************************************************/
24 
25 static tree
empty_cell()26 empty_cell () {
27   return "";
28 }
29 
30 bool
is_empty_cell(tree t)31 is_empty_cell (tree t) {
32   return
33     is_empty (t) ||
34     (is_compound (t, "cell-inert", 2) && is_empty_cell (t[1])) ||
35     (is_compound (t, "cell-input", 3) && is_empty_cell (t[1])) ||
36     (is_compound (t, "cell-output", 3) && is_empty_cell (t[2]));
37 }
38 
39 static tree
empty_row(int nr_cols)40 empty_row (int nr_cols) {
41   int i;
42   tree R (ROW, nr_cols);
43   for (i=0; i<nr_cols; i++)
44     R[i]= tree (CELL, empty_cell ());
45   return R;
46 }
47 
48 static tree
empty_table(int nr_rows,int nr_cols)49 empty_table (int nr_rows, int nr_cols) {
50   int i;
51   tree T (TABLE, nr_rows);
52   for (i=0; i<nr_rows; i++)
53     T[i]= empty_row (nr_cols);
54   return T;
55 }
56 
57 static void
table_get_extents(tree T,int & nr_rows,int & nr_cols)58 table_get_extents (tree T, int& nr_rows, int& nr_cols) {
59   while (is_func (T, TFORMAT)) T= T[N(T)-1];
60   nr_rows= N(T);
61   T= T[0];
62   while (is_func (T, TFORMAT)) T= T[N(T)-1];
63   nr_cols= N(T);
64 }
65 
66 static void
table_set(tree & T,int row,int col,tree t)67 table_set (tree& T, int row, int col, tree t) {
68   tree* ptr= &T;
69   while (is_func (*ptr, TFORMAT)) ptr= & ((*ptr) [N(*ptr)-1]);
70   ptr= & ((*ptr) [row]);
71   while (is_func (*ptr, TFORMAT)) ptr= & ((*ptr) [N(*ptr)-1]);
72   ptr= & ((*ptr) [col]);
73   while (is_func (*ptr, TFORMAT)) ptr= & ((*ptr) [N(*ptr)-1]);
74   if (is_func (*ptr, CELL, 1)) ptr= & ((*ptr) [0]);
75   *ptr= t;
76 }
77 
78 static tree
table_get(tree T,int row,int col)79 table_get (tree T, int row, int col) {
80   while (is_func (T, TFORMAT)) T= T [N(T)-1];
81   T= T [row];
82   while (is_func (T, TFORMAT)) T= T [N(T)-1];
83   T= T [col];
84   while (is_func (T, TFORMAT)) T= T [N(T)-1];
85   if (is_func (T, CELL, 1)) T= T [0];
86   return T;
87 }
88 
89 /******************************************************************************
90 * Searching the format, table, rows and cells
91 ******************************************************************************/
92 
93 path
search_format()94 edit_table_rep::search_format () {
95   path p= search_table ();
96   return search_format (p);
97 }
98 
99 path
search_format(path p)100 edit_table_rep::search_format (path p) {
101   if (!(rp < p)) return path ();
102   if (is_func (subtree (et, p), TFORMAT)) return p;
103   if (is_func (subtree (et, path_up (p)), TFORMAT)) return path_up (p);
104   return p;
105 }
106 
107 path
search_format(int & row,int & col)108 edit_table_rep::search_format (int& row, int& col) {
109   path p= search_table (row, col);
110   if (is_nil (p)) return p;
111   if (is_func (subtree (et, p), TFORMAT)) return p;
112   if (is_func (subtree (et, path_up (p)), TFORMAT)) return path_up (p);
113   insert_node (p * 0, TFORMAT);
114   return p;
115 }
116 
117 path
search_table()118 edit_table_rep::search_table () {
119   return search_upwards (TABLE);
120 }
121 
122 path
search_table(path fp)123 edit_table_rep::search_table (path fp) {
124   tree st= subtree (et, fp);
125   if (is_func (st, TABLE)) return fp;
126   if (is_func (st, TFORMAT)) return search_table (fp * (N(st)-1));
127   return path ();
128 }
129 
130 path
search_table(int & row,int & col)131 edit_table_rep::search_table (int& row, int& col) {
132   row= col= 0;
133   path p= search_table ();
134   if (is_nil (p)) return p;
135   path q= p, r= tail (tp, N(p));
136 
137   if (N(r) <= 1) return path ();
138   row= r->item;
139   while (true) {
140     if (is_nil (r)) return r;
141     q= q * r->item;
142     r= r->next;
143     if (is_func (subtree (et, q), ROW)) break;
144   }
145 
146   if (N(r) <= 1) return path ();
147   col= r->item;
148   while (true) {
149     if (is_nil (r)) return r;
150     q= q * r->item;
151     r= r->next;
152     if (!is_func (subtree (et, q), TFORMAT)) break;
153   }
154 
155   return p;
156 }
157 
158 path
search_row(path fp,int row)159 edit_table_rep::search_row (path fp, int row) {
160   fp= search_table (fp) * row;
161   tree st= subtree (et, fp);
162   if (!is_func (st, ROW))
163     return search_row (fp, N(st)-1);
164   return fp;
165 }
166 
167 path
search_cell(path p,int col)168 edit_table_rep::search_cell (path p, int col) {
169   p= p * col;
170   tree st= subtree (et, p);
171   if (is_func (st, TFORMAT))
172     return search_cell (p, N(st)-1);
173   if (is_func (st, CELL, 1)) return p * 0;
174   return p;
175 }
176 
177 path
search_cell(path fp,int row,int col)178 edit_table_rep::search_cell (path fp, int row, int col) {
179   return search_cell (search_row (fp, row), col);
180 }
181 
182 /******************************************************************************
183 * Analyzing with statements in format
184 ******************************************************************************/
185 
186 void
with_raw_read(tree with,int & i1,int & j1,int & i2,int & j2)187 edit_table_rep::with_raw_read (tree with, int& i1, int& j1, int& i2, int& j2) {
188   i1= as_int (with[0]);
189   i2= as_int (with[1]);
190   j1= as_int (with[2]);
191   j2= as_int (with[3]);
192 }
193 
194 void
with_decode(int nr_rows,int nr_cols,int & i1,int & j1,int & i2,int & j2)195 edit_table_rep::with_decode (int nr_rows, int nr_cols,
196 			     int& i1, int& j1, int& i2, int& j2)
197 {
198   i1= (i1>=0? i1-1: nr_rows+i1);
199   i2= (i2> 0? i2-1: nr_rows+i2);
200   j1= (j1>=0? j1-1: nr_cols+j1);
201   j2= (j2> 0? j2-1: nr_cols+j2);
202 }
203 
204 void
with_decode(int nr_rows,int nr_cols,int & I1,int & J1,int & I2,int & J2,int & i1,int & j1,int & i2,int & j2)205 edit_table_rep::with_decode (int nr_rows, int nr_cols,
206 			     int& I1, int& J1, int& I2, int& J2,
207 			     int& i1, int& j1, int& i2, int& j2)
208 {
209   i1= I1; j1= J1; i2= I2; j2=J2;
210   with_decode (nr_rows, nr_cols, i1, j1, i2, j2);
211 }
212 
213 void
with_read(tree with,int nr_rows,int nr_cols,int & i1,int & j1,int & i2,int & j2)214 edit_table_rep::with_read (tree with, int nr_rows, int nr_cols,
215 			   int& i1, int& j1, int& i2, int& j2)
216 {
217   with_raw_read (with, i1, j1, i2, j2);
218   with_decode (nr_rows, nr_cols, i1, j1, i2, j2);
219 }
220 
221 void
with_read(tree with,int nr_rows,int nr_cols,int & I1,int & J1,int & I2,int & J2,int & i1,int & j1,int & i2,int & j2)222 edit_table_rep::with_read (tree with, int nr_rows, int nr_cols,
223 			   int& I1, int& J1, int& I2, int& J2,
224 			   int& i1, int& j1, int& i2, int& j2)
225 {
226   with_raw_read (with, I1, J1, I2, J2);
227   i1= I1; j1= J1; i2= I2; j2=J2;
228   with_decode (nr_rows, nr_cols, i1, j1, i2, j2);
229 }
230 
231 /******************************************************************************
232 * Formatting primitives
233 ******************************************************************************/
234 
235 tree
table_get_format(path fp)236 edit_table_rep::table_get_format (path fp) {
237   tree fm= get_env_value (CELL_FORMAT, fp * 0);
238   tree st= subtree (et, fp);
239   return fm * st (0, N(st)-1);
240 }
241 
242 void
table_set_format(path fp,string var,tree val)243 edit_table_rep::table_set_format (path fp, string var, tree val) {
244   table_del_format (fp, var);
245   tree with (TWITH, var, val);
246   tree st= subtree (et, fp);
247   insert (fp * (N(st)-1), tree (TFORMAT, with));
248 }
249 
250 tree
table_get_format(path fp,string var)251 edit_table_rep::table_get_format (path fp, string var) {
252   tree st= table_get_format (fp);
253   int k, n= N(st);
254   tree val= get_env_value (var);
255   for (k=0; k<n; k++)
256     if (is_func (st[k], TWITH, 2) && (st[k][0] == var))
257       val= st[k][1];
258   return val;
259 }
260 
261 void
table_del_format(path fp,string var)262 edit_table_rep::table_del_format (path fp, string var) {
263   tree st= subtree (et, fp);
264   int k, n= N(st);
265   for (k=n-2; k>=0; k--)
266     if (is_func (st[k], TWITH, 2))
267       if ((var == "") || (var == st[k][0]))
268 	remove (fp * k, 1);
269 }
270 
271 void
table_set_format(path fp,int I1,int J1,int I2,int J2,string var,tree val)272 edit_table_rep::table_set_format (
273   path fp, int I1, int J1, int I2, int J2, string var, tree val)
274 {
275   table_del_format (fp, I1, J1, I2, J2, var);
276   tree with (CWITH);
277   with << as_string (I1) << as_string (I2)
278        << as_string (J1) << as_string (J2)
279        << var << val;
280   tree st= subtree (et, fp);
281   insert (fp * (N(st)-1), tree (TFORMAT, with));
282 }
283 
284 tree
table_get_format(path fp,int I1,int J1,int I2,int J2,string var)285 edit_table_rep::table_get_format (
286   path fp, int I1, int J1, int I2, int J2, string var)
287 {
288   int i1, j1, i2, j2;
289   int nr_rows, nr_cols;
290   tree st= table_get_format (fp);
291   table_get_extents (fp, nr_rows, nr_cols);
292   with_decode (nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
293 
294   int k, n= N(st);
295   tree val= get_env_value (var);
296   for (k=0; k<n; k++)
297     if (is_func (st[k], CWITH, 6) && (st[k][4] == var)) {
298       int row1, col1, row2, col2;
299       with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
300       if ((row1<=i1) && (col1<=j1) && (row2>=i2) && (col2>=j2))
301 	val= st[k][5];
302     }
303   return val;
304 }
305 
306 void
table_del_format(path fp,int I1,int J1,int I2,int J2,string var)307 edit_table_rep::table_del_format (
308   path fp, int I1, int J1, int I2, int J2, string var)
309 {
310   int i1, j1, i2, j2;
311   int nr_rows, nr_cols;
312   tree st= subtree (et, fp);
313   table_get_extents (fp, nr_rows, nr_cols);
314   with_decode (nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
315 
316   int k, n= N(st);
317   for (k=n-2; k>=0; k--)
318     if (is_func (st[k], CWITH, 6))
319       if ((var == "") || (var == st[k][4])) {
320 	int row1, col1, row2, col2;
321 	with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
322 	if ((row1>=i1) && (col1>=j1) && (row2<=i2) && (col2<=j2))
323 	  remove (fp * k, 1);
324       }
325 }
326 
327 void
table_get_format(path fp,string var,tree ** val,int nr_rows,int nr_cols)328 edit_table_rep::table_get_format (
329   path fp, string var, tree** val, int nr_rows, int nr_cols)
330 {
331   int i, j;
332   tree def_val= get_env_value (var, fp);
333   for (i=0; i<nr_rows; i++)
334     for (j=0; j<nr_cols; j++)
335       val[i][j]= def_val;
336 
337   tree st= table_get_format (fp);
338   int k, n= N(st);
339   for (k=0; k<n; k++)
340     if (is_func (st[k], CWITH, 6) && (st[k][4] == var)) {
341       int row1, col1, row2, col2;
342       with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
343       for (i=row1; i<=row2; i++)
344 	for (j=col1; j<=col2; j++)
345 	  val[i][j]= st[k][5];
346     }
347 }
348 
349 void
table_individualize(path fp,string var)350 edit_table_rep::table_individualize (path fp, string var) {
351   int nr_rows, nr_cols;
352   tree st= subtree (et, fp);
353   table_get_extents (fp, nr_rows, nr_cols);
354 
355   int k, n= N(st);
356   for (k=n-2; k>=0; k--)
357     if (is_func (st[k], CWITH, 6))
358       if ((var == "") || (var == st[k][4])) {
359 	int i, j, row1, col1, row2, col2;
360 	with_read (st[k], nr_rows, nr_cols, row1, col1, row2, col2);
361 	if ((row1==row2) && (col1==col2)) continue;
362 	row1= max (row1, 0); row2= min (row2, nr_rows-1);
363 	col1= max (col1, 0); col2= min (col2, nr_cols-1);
364 	tree ins_format (TFORMAT);
365 	for (i=row1; i<=row2; i++)
366 	  for (j=col1; j<=col2; j++) {
367 	    tree with (CWITH);
368 	    with << as_string (i+1) << as_string (i+1)
369 		 << as_string (j+1) << as_string (j+1)
370 		 << copy (st[k][4]) << copy (st[k][5]) << copy (st[k][6]);
371 	    ins_format << with;
372 	  }
373 	remove (fp * k, 1);
374 	insert (fp * k, ins_format);
375       }
376 }
377 
378 void
table_format_center(path fp,int row,int col)379 edit_table_rep::table_format_center (path fp, int row, int col) {
380   int nr_rows, nr_cols;
381   tree st= subtree (et, fp);
382   table_get_extents (fp, nr_rows, nr_cols);
383   int Row1= row+1;
384   int Col1= col+1;
385   int Row2= row-nr_rows;
386   int Col2= col-nr_cols;
387 
388   int k, n= N(st);
389   for (k=n-2; k>=0; k--)
390     if (is_func (st[k], CWITH, 6)) {
391       int I1, I2, J1, J2, i1, i2, j1, j2;
392       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
393 
394       if (i1 == row) I1= Row1;
395       else if (i1 < row) I1= i1+1;
396       else I1= i1-nr_rows;
397       if (i2 == row) I2= Row2;
398       else if (i2 < row) I2= i2+1;
399       else I2= i2-nr_rows;
400 
401       if (j1 == col) J1= Col1;
402       else if (j1 < col) J1= j1+1;
403       else J1= j1-nr_cols;
404       if (j2 == col) J2= Col2;
405       else if (j2 < col) J2= j2+1;
406       else J2= j2-nr_cols;
407 
408       assign (fp * path (k, 0), as_string (I1));
409       assign (fp * path (k, 1), as_string (I2));
410       assign (fp * path (k, 2), as_string (J1));
411       assign (fp * path (k, 3), as_string (J2));
412     }
413 }
414 
415 /******************************************************************************
416 * Inserting and deleteing new rows and columns
417 ******************************************************************************/
418 
419 void
table_get_extents(path fp,int & nr_rows,int & nr_cols)420 edit_table_rep::table_get_extents (path fp, int& nr_rows, int& nr_cols) {
421   ::table_get_extents (subtree (et, fp), nr_rows, nr_cols);
422 }
423 
424 void
table_set_extents(path fp,int nr_rows,int nr_cols)425 edit_table_rep::table_set_extents (path fp, int nr_rows, int nr_cols) {
426   int old_rows, old_cols;
427   table_get_extents (fp, old_rows, old_cols);
428   if (nr_rows > old_rows || nr_cols > old_cols)
429     table_insert (fp, old_rows, old_cols,
430                   max (0, nr_rows - old_rows),
431                   max (0, nr_cols - old_cols));
432   if (nr_rows < old_rows || nr_cols < old_cols)
433     table_remove (fp, nr_rows, nr_cols,
434                   max (0, old_rows - nr_rows),
435                   max (0, old_cols - nr_cols));
436 }
437 
438 void
table_get_limits(path fp,int & i1,int & j1,int & i2,int & j2)439 edit_table_rep::table_get_limits (
440   path fp, int& i1, int& j1, int& i2, int& j2)
441 {
442   i1= max (1, as_int (table_get_format (fp, TABLE_MIN_ROWS)));
443   j1= max (1, as_int (table_get_format (fp, TABLE_MIN_COLS)));
444   i2= as_int (table_get_format (fp, TABLE_MAX_ROWS));
445   j2= as_int (table_get_format (fp, TABLE_MAX_COLS));
446   if (i2<i1) i2= 0x7fffffff;
447   if (j2<i1) j2= 0x7fffffff;
448 }
449 
450 void
table_remove(path fp,int row,int col,int delr,int delc)451 edit_table_rep::table_remove (path fp, int row, int col, int delr, int delc) {
452   path p= search_table (fp);
453   int nr_rows, nr_cols;
454   table_get_extents (p, nr_rows, nr_cols);
455   tree T= subtree (et, p);
456   if (delr>0)
457     if (row+delr <= N(T)) {
458       if (delr == N(T)) {
459 	destroy_table ();
460 	return;
461       }
462       remove (p * row, delr);
463     }
464 
465   T= subtree (et, p);
466   if (delc>0)
467     for (row=0; row<N(T); row++) {
468       path q= search_row (p, row);
469       tree R= subtree (et, q);
470       if (col+delc <= N(R)) {
471 	if (delc == N(R)) {
472 	  destroy_table ();
473 	  return;
474 	}
475 	remove (q * col, delc);
476       }
477     }
478 
479   tree st= subtree (et, fp);
480   if (!is_func (st, TFORMAT)) return;
481   int k, n= N(st);
482   for (k=n-2; k>=0; k--)
483     if (is_func (st[k], CWITH, 6)) {
484       int I1, I2, J1, J2, i1, i2, j1, j2;
485       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
486       if (delr>0) {
487 	if ((row<=i1) && (i2<row+delr)) { remove (fp * k, 1); continue; }
488 	if ((I1>0) && (i1>=row))
489 	  assign (fp * path (k, 0), as_string (I1- min (delr, i1- row)));
490 	if ((I1<0) && (i1<row+delr))
491 	  assign (fp * path (k, 0), as_string (I1+ delr+ min (0, row- 1- i1)));
492 	if ((I2>0) && (i2>=row))
493 	  assign (fp * path (k, 1), as_string (I2- min (delr, i2- row)));
494 	if ((I2<0) && (i2<row+delr))
495 	  assign (fp * path (k, 1), as_string (I2+ delr+ min (0, row- 1- i2)));
496       }
497       if (delc>0) {
498 	if ((col<=j1) && (j2<col+delc)) { remove (fp * k, 1); continue; }
499 	if ((J1>0) && (j1>=col))
500 	  assign (fp * path (k, 2), as_string (J1- min (delc, j1- col)));
501 	if ((J1<0) && (j1<col+delc))
502 	  assign (fp * path (k, 2), as_string (J1+ delc+ min (0, col- 1- j1)));
503 	if ((J2>0) && (j2>=col))
504 	  assign (fp * path (k, 3), as_string (J2- min (delc, j2- col)));
505 	if ((J2<0) && (j2<col+delc))
506 	  assign (fp * path (k, 3), as_string (J2+ delc+ min (0, col- 1- j2)));
507       }
508     }
509 }
510 
511 void
table_insert(path fp,int row,int col,int insr,int insc)512 edit_table_rep::table_insert (path fp, int row, int col, int insr, int insc) {
513   path p= search_table (fp);
514   int nr_rows, nr_cols;
515   table_get_extents (p, nr_rows, nr_cols);
516   tree T= subtree (et, p);
517   if (insr>0)
518     if (row <= N(T))
519       insert (p * row, empty_table (insr, nr_cols));
520 
521   T= subtree (et, p);
522   if (insc>0)
523     for (row=0; row<N(T); row++) {
524       path q= search_row (p, row);
525       tree R= subtree (et, q);
526       if (col <= N(R))
527 	insert (q * col, empty_row (insc));
528     }
529 
530   tree st= subtree (et, fp);
531   if (!is_func (st, TFORMAT)) return;
532   int k, n= N(st);
533   for (k=n-2; k>=0; k--)
534     if (is_func (st[k], CWITH, 6)) {
535       int I1, I2, J1, J2, i1, i2, j1, j2;
536       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
537       if (insr>0) {
538 	bool flag= (I1<=0) || (I2>=0);
539 	if ((I1>0) && ((i1>row) || (flag && (i1==row))))
540 	  assign (fp* path (k,0), as_string (I1+insr));
541 	if ((I1<0) && (i1<row))
542 	  assign (fp* path (k,0), as_string (I1-insr));
543 	if ((I2>0) && (i2>=row))
544 	  assign (fp* path (k,1), as_string (I2+insr));
545 	if ((I2<0) && ((i2<row-1) || (flag && (i2==row-1))))
546 	  assign (fp* path (k,1), as_string (I2-insr));
547       }
548       if (insc>0) {
549 	bool flag= (J1<=0) || (J2>=0);
550 	if ((J1>0) && ((j1>col) || (flag && (j1==col))))
551 	  assign (fp * path (k,2), as_string (J1+insc));
552 	if ((J1<0) && (j1<col))
553 	  assign (fp * path (k,2), as_string (J1-insc));
554 	if ((J2>0) && (j2>=col))
555 	  assign (fp * path (k,3), as_string (J2+insc));
556 	if ((J2<0) && ((j2<col-1) || (flag && (j2==col-1))))
557 	  assign (fp * path (k,3), as_string (J2-insc));
558       }
559     }
560 }
561 
562 /******************************************************************************
563 * Cursor positioning
564 ******************************************************************************/
565 
566 void
table_bound(path fp,int & row1,int & col1,int & row2,int & col2)567 edit_table_rep::table_bound (
568   path fp, int& row1, int& col1, int& row2, int& col2)
569 {
570   fp= search_format (fp);
571   if (!is_func (subtree (et, fp), TFORMAT)) return;
572 
573   int i, j, ii, jj, nr_rows, nr_cols;
574   table_get_extents (fp, nr_rows, nr_cols);
575   tree** rs= tm_new_array<tree*> (nr_rows);
576   tree** cs= tm_new_array<tree*> (nr_rows);
577   for (i=0; i<nr_rows; i++) {
578     rs[i]= tm_new_array<tree> (nr_cols);
579     cs[i]= tm_new_array<tree> (nr_cols);
580   }
581   table_get_format (fp, CELL_ROW_SPAN, rs, nr_rows, nr_cols);
582   table_get_format (fp, CELL_COL_SPAN, cs, nr_rows, nr_cols);
583 
584   for (i=0; i<nr_rows; i++)
585     for (j=0; j<nr_cols; j++) {
586       int m= min (as_int (rs[i][j]), nr_rows-i);
587       int n= min (as_int (rs[i][j]), nr_cols-j);
588       if ((m>1) || (n>1)) {
589 	if ((row1 < i+m) && (col1 < j+n) && (row2 >= i) && (col2 >= j)) {
590 	  row1= min (row1, i);
591 	  col1= min (col1, j);
592 	  row2= max (row2, i+m-1);
593 	  col2= max (col2, j+n-1);
594 	}
595 	for (ii=0; ii<m; ii++)
596 	  for (jj=0; jj<n; jj++) {
597 	    rs[i+ii][j+jj]= "0";
598 	    cs[i+ii][j+jj]= "0";
599 	  }
600       }
601     }
602 
603   for (i=0; i<nr_rows; i++) {
604     tm_delete_array (rs[i]);
605     tm_delete_array (cs[i]);
606   }
607   tm_delete_array (rs);
608   tm_delete_array (cs);
609 }
610 
611 void
table_go_to(path fp,int row,int col,bool at_start)612 edit_table_rep::table_go_to (path fp, int row, int col, bool at_start) {
613   int nr_rows, nr_cols;
614   fp= search_format (fp);
615   table_get_extents (fp, nr_rows, nr_cols);
616   if (row<0) row= 0;
617   if (col<0) col= 0;
618   if (row>=nr_rows) row= nr_rows-1;
619   if (col>=nr_cols) col= nr_cols-1;
620   if (is_func (subtree (et, fp), TFORMAT)) {
621     int row2= row, col2= col;
622     table_bound (fp, row, col, row2, col2);
623   }
624   path q= search_cell (fp, row, col);
625   go_to_border (q, at_start);
626 }
627 
628 void
table_go_to_border(path fp,bool right)629 edit_table_rep::table_go_to_border (path fp, bool right) {
630   while ((rp < fp) && (is_func (subtree (et, path_up (fp)), TFORMAT)))
631     fp= path_up (fp);
632   if ((rp < fp) &&
633       is_document (subtree (et, path_up (fp))) &&
634       (rp < path_up (fp)) &&
635       is_extension (subtree (et, path_up (fp, 2)), 1))
636     fp= path_up (fp);
637   if ((rp < fp) && is_extension (subtree (et, path_up (fp)), 1))
638     fp= path_up (fp);
639   if ((rp < fp) && is_func (subtree (et, path_up (fp)), SUBTABLE, 1))
640     fp= path_up (fp);
641   go_to_border (fp, right);
642 }
643 
644 void
back_table(path p,bool forward)645 edit_table_rep::back_table (path p, bool forward) {
646   while (true) {
647     tree st= subtree (et, p);
648     if (!is_func (st, TFORMAT)) break;
649     if (!is_func (st [N(st)-1], TABLE)) {
650       back_general (p, forward);
651       return;
652     }
653     p= p * (N(st)-1);
654   }
655   while (rp < p) {
656     tree st= subtree (et, p);
657     if (is_func (st, TABLE)) break;
658     p= path_up (p);
659   }
660   if (!(rp < p)) return;
661 
662   if (forward) table_go_to (p, 0, 0, true);
663   else {
664     int nr_rows, nr_cols;
665     table_get_extents (p, nr_rows, nr_cols);
666     table_go_to (p, nr_rows-1, nr_cols-1, false);
667   }
668 }
669 
670 void
back_in_table(tree t,path p,bool forward)671 edit_table_rep::back_in_table (tree t, path p, bool forward) {
672   if (is_func (t, TFORMAT) &&
673       (is_func (subtree (et, path_up (p, 2)), INACTIVE) || in_source ()))
674     {
675       remove_empty_argument (p, forward);
676       return;
677     }
678 
679   int i, j, row, col, nr_rows, nr_cols;
680   p= search_table (row, col);
681   if (is_nil (p)) return;
682   table_get_extents (p, nr_rows, nr_cols);
683 
684   bool flag=true;
685   for (j=0; j<nr_cols; j++) {
686     path q= search_cell (p, row, j);
687     flag= flag && is_empty_cell (subtree (et, q));
688   }
689   if (flag) {
690     int i1, j1, i2, j2;
691     path fp= search_format ();
692     if (is_nil (fp)) return;
693     table_get_limits (fp, i1, j1, i2, j2);
694     if (nr_rows-1 >= i1) {
695       table_remove_row (forward, true);
696       return;
697     }
698   }
699 
700   flag= true;
701   for (i=0; i<nr_rows; i++) {
702     path q= search_cell (p, i, col);
703     flag= flag && is_empty_cell (subtree (et, q));
704   }
705   if (flag) {
706     int i1, j1, i2, j2;
707     path fp= search_format ();
708     if (is_nil (fp)) return;
709     table_get_limits (fp, i1, j1, i2, j2);
710     if (nr_cols-1 >= j1) {
711       table_remove_column (forward, true);
712       return;
713     }
714   }
715 
716   flag=true;
717   for (i=0; i<nr_rows; i++)
718     for (j=0; j<nr_cols; j++) {
719       path q= search_cell (p, i, j);
720       flag= flag && is_empty_cell (subtree (et, q));
721     }
722   if (flag) {
723     destroy_table ();
724     return;
725   }
726 
727   if (forward) {
728     if (col<(nr_cols-1)) { table_go_to (p, row, col+1, true); return; }
729     if (row<(nr_rows-1)) { table_go_to (p, row+1, 0, true); return; }
730   }
731   else {
732     if (col>0) { table_go_to (p, row, col-1, false); return; }
733     if (row>0) { table_go_to (p, row-1, nr_cols-1, false); return; }
734   }
735   table_go_to_border (p, !forward);
736 }
737 
738 /******************************************************************************
739 * Routines for subtables
740 ******************************************************************************/
741 
742 tree
table_get_subtable(path fp,int row1,int col1,int row2,int col2)743 edit_table_rep::table_get_subtable (
744   path fp, int row1, int col1, int row2, int col2)
745 {
746   return table_get_subtable (fp, row1, col1, row2, col2, false);
747 }
748 
749 tree
table_get_subtable(path fp,int row1,int col1,int row2,int col2,bool recurse)750 edit_table_rep::table_get_subtable (
751   path fp, int row1, int col1, int row2, int col2, bool recurse)
752 {
753   path p= search_table (fp);
754   int i, j, nr_rows, nr_cols;
755   table_get_extents (p, nr_rows, nr_cols);
756   tree st= subtree (et, p);
757   tree subtable (TABLE, row2+1-row1);
758   for (i=row1; i<=row2; i++) {
759     tree sr= st[i];
760     tree sub_row (ROW, col2+1-col1);
761     while (is_func (sr, TFORMAT)) sr= sr[N(sr)-1];
762     for (j=col1; j<=col2; j++)
763       sub_row[j-col1]= copy (sr[j]);
764     subtable[i-row1]= sub_row;
765   }
766 
767   st= subtree (et, fp);
768   if ((!recurse) && (!is_func (st, TFORMAT))) return subtable;
769   if (recurse) st= table_get_format (fp);
770   else st= st (0, N(st)-1);
771   int k, n= N(st);
772   tree sub_format (TFORMAT);
773   for (k=0; k<n; k++)
774     if (is_func (st[k], CWITH, 6)) {
775       int I1, I2, J1, J2, i1, i2, j1, j2;
776       with_read (st[k], nr_rows, nr_cols, I1, J1, I2, J2, i1, j1, i2, j2);
777       if ((i1<=row2) && (i2>=row1) && (j1<=col2) && (j2>=col1)) {
778 	I1= min (max (0, i1- row1), row2- row1) + 1;
779 	I2= min (max (0, i2- row1), row2- row1) + 1;
780 	J1= min (max (0, j1- col1), col2- col1) + 1;
781 	J2= min (max (0, j2- col1), col2- col1) + 1;
782 	tree with (CWITH);
783 	with << as_string (I1) << as_string (I2)
784 	     << as_string (J1) << as_string (J2)
785 	     << copy (st[k][4]) << copy (st[k][5]);
786 	sub_format << with;
787       }
788     }
789   sub_format << subtable;
790   return sub_format;
791 }
792 
793 static tree
shift_subtable(tree st,int sh_row,int sh_col)794 shift_subtable (tree st, int sh_row, int sh_col) {
795   st= copy (st);
796   int k, n= N(st);
797   for (k=0; k<n-1; k++)
798     if (is_func (st[k], CWITH, 6)) {
799       st[k][0]= as_string (as_int (st[k][0]) + sh_row);
800       st[k][1]= as_string (as_int (st[k][1]) + sh_row);
801       st[k][2]= as_string (as_int (st[k][2]) + sh_col);
802       st[k][3]= as_string (as_int (st[k][3]) + sh_col);
803     }
804   return st;
805 }
806 
807 void
table_write_subtable(path fp,int row,int col,tree subt)808 edit_table_rep::table_write_subtable (
809   path fp, int row, int col, tree subt)
810 {
811   int nr_rows, nr_cols, sub_rows, sub_cols;
812   int min_rows, min_cols, max_rows, max_cols;
813   table_get_extents (fp, nr_rows, nr_cols);
814   ::table_get_extents (subt, sub_rows, sub_cols);
815   table_get_limits (fp, min_rows, min_cols, max_rows, max_cols);
816   if ((max_rows < row + sub_rows) || (max_cols < col + sub_cols)) return;
817   if ((nr_rows < row + sub_rows) || (nr_cols < col + sub_cols))
818     table_set_extents (fp, max (nr_rows, row + sub_rows),
819                            max (nr_cols, col + sub_cols));
820 
821   path old_tp= tp;
822   tp= fp * 0;
823   bool calc_flag= inside ("calc-table");
824   tp= old_tp;
825   if (calc_flag)
826     subt= as_tree (call ("calc-table-renumber", object (subt),
827                          object (row + 1), object (col + 1)));
828 
829   if (is_func (subtree (et, fp), TFORMAT) &&
830       is_func (subt, TFORMAT))
831     {
832       tree sh_subt= shift_subtable (subt, row, col);
833       sh_subt= sh_subt (0, N(sh_subt)-1);
834       tree st= subtree (et, fp);
835       insert (fp * (N(st)-1), sh_subt);
836       subt= subt [N(subt)-1];
837     }
838 
839   int i, j;
840   for (i=0; i<sub_rows; i++) {
841     path rp  = search_row (fp, i+row);
842     tree subr= subt[i];
843     while (is_func (subr, TFORMAT)) subr= subr [N(subr)-1];
844     for (j=0; j<sub_cols; j++) {
845       path cp  = search_cell (rp, j+col);
846       tree subc= subr[j];
847       while (is_func (subc, TFORMAT)) subc= subc [N(subr)-1];
848       if (is_func (subc, CELL, 1)) subc= subc[0];
849       assign (cp, copy (subc));
850     }
851   }
852 }
853 
854 void
table_hor_insert_subtable(path fp,int col,tree subt)855 edit_table_rep::table_hor_insert_subtable (path fp, int col, tree subt) {
856   int nr_rows, nr_cols, sub_rows, sub_cols;
857   table_get_extents (fp, nr_rows, nr_cols);
858   ::table_get_extents (subt, sub_rows, sub_cols);
859   if (sub_rows != nr_rows) return;
860   table_insert (fp, 0, col, 0, sub_cols);
861   table_write_subtable (fp, 0, col, subt);
862 }
863 
864 void
table_ver_insert_subtable(path fp,int row,tree subt)865 edit_table_rep::table_ver_insert_subtable (path fp, int row, tree subt) {
866   int nr_rows, nr_cols, sub_rows, sub_cols;
867   table_get_extents (fp, nr_rows, nr_cols);
868   ::table_get_extents (subt, sub_rows, sub_cols);
869   if (sub_cols != nr_cols) return;
870   table_insert (fp, row, 0, sub_rows, 0);
871   table_write_subtable (fp, row, 0, subt);
872 }
873 
874 /******************************************************************************
875 * Decorations
876 ******************************************************************************/
877 
878 void
table_force_decoration(path fp,int row,int col)879 edit_table_rep::table_force_decoration (path fp, int row, int col) {
880   row++; col++;
881   tree old= table_get_format (fp, row, col, row, col, CELL_DECORATION);
882   if (old == "") {
883     tree f (TFORMAT, tree (TABLE, tree (ROW, tree (TMARKER))));
884     table_set_format (fp, row, col, row, col, CELL_DECORATION, f);
885   }
886 }
887 
888 static void
search_decoration(tree T,int & row,int & col)889 search_decoration (tree T, int& row, int& col) {
890   while (is_func (T, TFORMAT)) T= T [N(T)-1];
891   for (row=0; row<N(T); row++) {
892     tree R= T[row];
893     while (is_func (R, TFORMAT)) R= R [N(R)-1];
894     for (col=0; col<N(R); col++) {
895       tree C= R[col];
896       while (is_func (C, TFORMAT)) C= C [N(C)-1];
897       if (C == tree (TMARKER)) return;
898     }
899   }
900   FAILED ("decoration not found");
901 }
902 
903 static tree
table_format_undecorate(tree st,int row,int col,int dec_row,int dec_col)904 table_format_undecorate (tree st, int row, int col, int dec_row, int dec_col) {
905   tree fm (TFORMAT);
906   int k, n= N(st);
907   for (k=0; k<n-1; k++)
908     if ((as_int (st[k][0]) <= (row+1)) && (as_int (st[k][1]) >= (row+1)) &&
909 	(as_int (st[k][2]) <= (col+1)) && (as_int (st[k][3]) >= (col+1)))
910       if (is_func (st[k], CWITH, 6) && (st[k][4] != CELL_DECORATION)) {
911 	tree with= copy (st[k]);
912 	with[0]= as_string (dec_row+1);
913 	with[1]= as_string (dec_row+1);
914 	with[2]= as_string (dec_col+1);
915 	with[3]= as_string (dec_col+1);
916 	fm << with;
917       }
918   return fm;
919 }
920 
921 static tree
table_undecorate(tree st,int row,int col)922 table_undecorate (tree st, int row, int col) {
923   int k, n= N(st);
924   for (k=0; k<n-1; k++)
925     if ((as_int (st[k][0]) == (row+1)) && (as_int (st[k][2]) == (col+1)))
926       if (is_func (st[k], CWITH, 6) && (st[k][4] == CELL_DECORATION)) {
927 	int dec_row= 0, dec_col= 0;
928 	tree T= copy (st[k][5]);
929 	search_decoration (T, dec_row, dec_col);
930 	table_set (T, dec_row, dec_col, table_get (st[n-1], row, col));
931 	tree F= table_format_undecorate (st, row, col, dec_row, dec_col);
932 	return F * T;
933       }
934   FAILED ("decoration not found");
935   return "";
936 }
937 
938 void
table_hor_decorate(path fp,int col,int cbef,int caft)939 edit_table_rep::table_hor_decorate (path fp, int col, int cbef, int caft) {
940   tree st= subtree (et, fp);
941   if (!is_func (st, TFORMAT)) return;
942   if (cbef+caft == 0) return;
943   int i, j, k, nr_rows, nr_cols;
944   path p= search_table (fp);
945   table_get_extents (p, nr_rows, nr_cols);
946   table_individualize (fp, CELL_DECORATION);
947 
948   for (i=0; i<nr_rows; i++)
949     for (j=col-cbef; j<=col+caft; j++)
950       table_force_decoration (fp, i, j);
951 
952   tree t1, t2;
953   if (caft>0)
954     t2= table_get_subtable (fp, 0, col+1   , nr_rows-1, col+caft, true);
955   if (cbef>0)
956     t1= table_get_subtable (fp, 0, col-cbef, nr_rows-1, col-1   , true);
957   if (caft>0) table_remove (fp, 0, col+1   , 0, caft);
958   if (cbef>0) table_remove (fp, 0, col-cbef, 0, cbef);
959   col -= cbef;
960 
961   st= subtree (et, fp);
962   int n= N(st);
963   for (k=0; k<n-1; k++)
964     if (is_func (st[k], CWITH, 6) && (st[k][4] == CELL_DECORATION)) {
965       int i1, j1, i2, j2;
966       with_read (st[k], nr_rows, nr_cols, i1, j1, i2, j2);
967       if (j1 != col) continue;
968       for (j=0; j<caft; j++) {
969 	tree inst= table_undecorate (t2, i1, j);
970 	int sub_rows, sub_cols;
971 	::table_get_extents (st[k][5], sub_rows, sub_cols);
972 	table_hor_insert_subtable (fp * path (k, 5), sub_cols, inst);
973       }
974       for (j=cbef-1; j>=0; j--) {
975 	tree inst= table_undecorate (t1, i1, j);
976 	table_hor_insert_subtable (fp * path (k, 5), 0, inst);
977       }
978     }
979 }
980 
981 void
table_ver_decorate(path fp,int row,int rbef,int raft)982 edit_table_rep::table_ver_decorate (path fp, int row, int rbef, int raft) {
983   tree st= subtree (et, fp);
984   if (!is_func (st, TFORMAT)) return;
985   if (rbef+raft == 0) return;
986   int i, j, k, nr_rows, nr_cols;
987   path p= search_table (fp);
988   table_get_extents (p, nr_rows, nr_cols);
989   table_individualize (fp, CELL_DECORATION);
990 
991   for (i=row-rbef; i<=row+raft; i++)
992     for (j=0; j<nr_cols; j++)
993       table_force_decoration (fp, i, j);
994 
995   tree t1, t2;
996   if (raft>0)
997     t2= table_get_subtable (fp, row+1   , 0, row+raft, nr_cols-1, true);
998   if (rbef>0)
999     t1= table_get_subtable (fp, row-rbef, 0, row-1   , nr_cols-1, true);
1000   if (raft>0) table_remove (fp, row+1   , 0, raft, 0);
1001   if (rbef>0) table_remove (fp, row-rbef, 0, rbef, 0);
1002   row -= rbef;
1003 
1004   st= subtree (et, fp);
1005   int n= N(st);
1006   for (k=0; k<n-1; k++)
1007     if (is_func (st[k], CWITH, 6) && (st[k][4] == CELL_DECORATION)) {
1008       int i1, j1, i2, j2;
1009       with_read (st[k], nr_rows, nr_cols, i1, j1, i2, j2);
1010       if (i1 != row) continue;
1011       for (i=0; i<raft; i++) {
1012 	tree inst= table_undecorate (t2, i, j1);
1013 	int sub_rows, sub_cols;
1014 	::table_get_extents (st[k][5], sub_rows, sub_cols);
1015 	table_ver_insert_subtable (fp * path (k, 5), sub_rows, inst);
1016       }
1017       for (i=rbef-1; i>=0; i--) {
1018 	tree inst= table_undecorate (t1, i, j1);
1019 	table_ver_insert_subtable (fp * path (k, 5), 0, inst);
1020       }
1021     }
1022 }
1023 
1024 /******************************************************************************
1025 * User interface
1026 ******************************************************************************/
1027 
1028 void
make_table(int nr_rows,int nr_cols)1029 edit_table_rep::make_table (int nr_rows, int nr_cols) {
1030   //cout << "make_table " << nr_rows << ", " << nr_cols << "\n";
1031   tree T= empty_table (nr_rows, nr_cols);
1032   path p (0, 0, 0, 0);
1033   tree format_T (TFORMAT, T);
1034   insert_tree (format_T, path (N(format_T)-1, p));
1035 
1036   int i1, j1, i2, j2;
1037   path fp= search_format ();
1038   if (is_nil (fp)) return;
1039   typeset_invalidate_env (); // FIXME: dirty hack for getting correct limits
1040   table_get_limits (fp, i1, j1, i2, j2);
1041   if ((nr_rows<i1) || (nr_cols<j1)) {
1042     T= empty_table (max (nr_rows, i1), max (nr_cols, j1));
1043     format_T= tree (TFORMAT, T);
1044     assign (fp, format_T);
1045     go_to (fp * path (N(format_T)-1, p));
1046   }
1047 
1048   string hyphen= as_string (table_get_format (fp, TABLE_HYPHEN));
1049   string block = as_string (table_get_format (fp, TABLE_BLOCK));
1050   if (hyphen == "y" || block == "yes") {
1051     path q= fp;
1052     if (is_extension (subtree (et, path_up (q)), 1)) q= path_up (q);
1053     tree st= subtree (et, path_up (q));
1054     if (is_document (st)) insert_node (fp * 0, DOCUMENT);
1055     else if (is_concat (st) && is_document (subtree (et, path_up (q, 2)))) {
1056       int n= N(st), l= last_item (q);
1057       insert_node (fp * 0, DOCUMENT);
1058       if (l != (n-1)) {
1059 	split (path_inc (q));
1060 	correct_concat (path_inc (path_up (q)));
1061       }
1062       if (l != 0) {
1063 	split (q);
1064 	correct_concat (path_inc (path_up (q)));
1065       }
1066       correct_concat (path_up (q));
1067     }
1068   }
1069 
1070   table_correct_block_content ();
1071   set_message (concat (kbd_shortcut ("(structured-insert-down)"),
1072 		       ": new row",
1073 		       kbd_shortcut ("(structured-insert-right)"),
1074 		       ": new column"),
1075 	       "table");
1076 }
1077 
1078 void
make_subtable(int nr_rows,int nr_cols)1079 edit_table_rep::make_subtable (int nr_rows, int nr_cols) {
1080   path cp= search_upwards (CELL);
1081   if (is_nil (cp)) return;
1082   tree T= empty_table (nr_rows, nr_cols);
1083   path p (0, 0, 0, 0);
1084   T= tree (TFORMAT, T);
1085   p= path (N(T)-1, p);
1086   T= tree (SUBTABLE, T);
1087   p= path (0, p);
1088   assign (cp * 0, T);
1089   go_to (cp * path (0, p));
1090   table_correct_block_content ();
1091   set_message (concat (kbd_shortcut ("(structured-insert-down)"),
1092 		       ": new row",
1093 		       kbd_shortcut ("(structured-insert-right)"),
1094 		       ": new column"),
1095 	       "table");
1096 }
1097 
1098 void
destroy_table()1099 edit_table_rep::destroy_table () {
1100   path fp= search_format ();
1101   if (is_nil (fp)) return;
1102   while (rp < fp) {
1103     tree st= subtree (et, path_up (fp));
1104     if (!is_func (st, TFORMAT)) break;
1105     fp= path_up (fp);
1106   }
1107   if ((rp < fp) &&
1108       is_document (subtree (et, path_up (fp))) &&
1109       (rp < path_up (fp)) &&
1110       is_extension (subtree (et, path_up (fp, 2)), 1))
1111     fp= path_up (fp);
1112   if ((rp < fp) && is_extension (subtree (et, path_up (fp)), 1))
1113     fp= path_up (fp);
1114   if ((rp < fp) && is_func (subtree (et, path_up (fp)), SUBTABLE, 1))
1115     fp= path_up (fp);
1116   assign (fp, "");
1117   correct (path_up (fp));
1118 }
1119 
1120 void
table_deactivate()1121 edit_table_rep::table_deactivate () {
1122   path fp= search_format ();
1123   if (is_nil (fp)) return;
1124   tree st= subtree (et, fp);
1125   if (!is_func (st, TFORMAT)) return;
1126   insert_node (fp * 0, INACTIVE);
1127   set_message ("return: reactivate", "deactivate table");
1128 }
1129 
1130 void
table_extract_format()1131 edit_table_rep::table_extract_format () {
1132   path fp= search_format ();
1133   if (is_nil (fp)) return;
1134   tree fm= table_get_format (fp);
1135   fm << "";
1136   if (is_extension (subtree (et, path_up (fp)), 1)) fp= path_up (fp);
1137   assign (fp, fm);
1138   go_to (fp * path (N(fm)-1, 0));
1139 }
1140 
1141 void
table_insert_row(bool forward)1142 edit_table_rep::table_insert_row (bool forward) {
1143   int row, col;
1144   path fp= search_format (row, col);
1145   if (is_nil (fp)) return;
1146   int nr_rows, nr_cols, i1, j1, i2, j2;
1147   table_get_extents (fp, nr_rows, nr_cols);
1148   table_get_limits (fp, i1, j1, i2, j2);
1149   if (nr_rows+1 > i2) return;
1150   table_insert (fp, row + (forward? 1: 0), col, 1, 0);
1151   table_go_to (fp, row + (forward? 1: 0), col);
1152   table_correct_block_content ();
1153   table_resize_notify ();
1154 }
1155 
1156 void
table_insert_column(bool forward)1157 edit_table_rep::table_insert_column (bool forward) {
1158   int row, col;
1159   path fp= search_format (row, col);
1160   if (is_nil (fp)) return;
1161   int nr_rows, nr_cols, i1, j1, i2, j2;
1162   table_get_extents (fp, nr_rows, nr_cols);
1163   table_get_limits (fp, i1, j1, i2, j2);
1164   if (nr_cols+1 > j2) return;
1165   table_insert (fp, row, col + (forward? 1: 0), 0, 1);
1166   table_go_to (fp, row, col + (forward? 1: 0));
1167   table_correct_block_content ();
1168   table_resize_notify ();
1169 }
1170 
1171 void
table_remove_row(bool forward,bool flag)1172 edit_table_rep::table_remove_row (bool forward, bool flag) {
1173   int row, col;
1174   path fp= search_format (row, col);
1175   if (is_nil (fp)) return;
1176   int nr_rows, nr_cols, i1, j1, i2, j2;
1177   table_get_extents (fp, nr_rows, nr_cols);
1178   table_get_limits (fp, i1, j1, i2, j2);
1179   if (nr_rows-1 < i1) destroy_table ();
1180   else if (flag) {
1181     table_remove (fp, row, col, 1, 0);
1182     int ncol= col;
1183     if ((!forward) && (col == 0)) ncol= nr_cols-1;
1184     if (forward && (col == nr_cols-1)) ncol= 0;
1185     table_go_to (fp, max (0, row + (forward? 0: -1)), ncol, forward);
1186   }
1187   else {
1188     if (!forward) row--;
1189     if (row >= 0) table_remove (fp, row, col, 1, 0);
1190     if (row < nr_rows-1 && forward) table_go_to (fp, row, col, forward);
1191     else if (forward || row < 0) table_go_to_border (fp, !forward);
1192   }
1193   table_correct_block_content ();
1194   table_resize_notify ();
1195 }
1196 
1197 void
table_remove_column(bool forward,bool flag)1198 edit_table_rep::table_remove_column (bool forward, bool flag) {
1199   int row, col;
1200   path fp= search_format (row, col);
1201   if (is_nil (fp)) return;
1202   int nr_rows, nr_cols, i1, j1, i2, j2;
1203   table_get_extents (fp, nr_rows, nr_cols);
1204   table_get_limits (fp, i1, j1, i2, j2);
1205   if (nr_cols-1 < j1) destroy_table ();
1206   else if (flag) {
1207     table_remove (fp, row, col, 0, 1);
1208     int ncol= max (0, col + (forward? 0: -1));
1209     if ((!forward) && (col == 0)) ncol= nr_cols-1;
1210     if (forward && (col == nr_cols-1)) ncol= 0;
1211     table_go_to (fp, row, ncol, forward);
1212   }
1213   else {
1214     if (!forward) col--;
1215     if (col >= 0) table_remove (fp, row, col, 0, 1);
1216     if (col < nr_cols-1 && forward) table_go_to (fp, row, col, forward);
1217     else if (forward || col < 0) table_go_to_border (fp, !forward);
1218   }
1219   table_correct_block_content ();
1220   table_resize_notify ();
1221 }
1222 
1223 int
table_nr_rows()1224 edit_table_rep::table_nr_rows () {
1225   int nr_rows, nr_cols;
1226   path fp= search_format ();
1227   if (is_nil (fp)) return -1;
1228   table_get_extents (fp, nr_rows, nr_cols);
1229   return nr_rows;
1230 }
1231 
1232 int
table_nr_columns()1233 edit_table_rep::table_nr_columns () {
1234   int nr_rows, nr_cols;
1235   path fp= search_format ();
1236   if (is_nil (fp)) return -1;
1237   table_get_extents (fp, nr_rows, nr_cols);
1238   return nr_cols;
1239 }
1240 
1241 array<int>
table_get_extents()1242 edit_table_rep::table_get_extents () {
1243   array<int> r;
1244   int nr_rows, nr_cols;
1245   path fp= search_format ();
1246   if (is_nil (fp)) return r;
1247   table_get_extents (fp, nr_rows, nr_cols);
1248   r << nr_rows << nr_cols;
1249   return r;
1250 }
1251 
1252 void
table_set_extents(int rows,int cols)1253 edit_table_rep::table_set_extents (int rows, int cols) {
1254   path fp= search_format ();
1255   if (is_nil (fp)) return;
1256   int min_rows, min_cols, max_rows, max_cols;
1257   table_get_limits (fp, min_rows, min_cols, max_rows, max_cols);
1258   rows= min (max_rows, max (min_rows, rows));
1259   cols= min (max_cols, max (min_cols, cols));
1260   table_set_extents (fp, rows, cols);
1261 }
1262 
1263 int
table_which_row()1264 edit_table_rep::table_which_row () {
1265   int row, col;
1266   path fp= search_format (row, col);
1267   if (is_nil (fp)) return 0;
1268   return row+1;
1269 }
1270 
1271 int
table_which_column()1272 edit_table_rep::table_which_column () {
1273   int row, col;
1274   path fp= search_format (row, col);
1275   if (is_nil (fp)) return 0;
1276   return col+1;
1277 }
1278 
1279 array<int>
table_which_cells()1280 edit_table_rep::table_which_cells () {
1281   array<int> r;
1282   if (selection_active_table (false)) {
1283     int row1, col1, row2, col2;
1284     path fp= selection_get_subtable (row1, col1, row2, col2);
1285     if (is_nil (fp)) return r;
1286     r << row1+1 << row2+1 << col1+1 << col2+1;
1287   }
1288   else {
1289     int row, col;
1290     path fp= search_format (row, col);
1291     if (is_nil (fp)) return array<int> ();
1292     row++; col++;
1293     r << row << row << col << col;
1294   }
1295   return r;
1296 }
1297 
1298 path
table_search_cell(int row,int col)1299 edit_table_rep::table_search_cell (int row, int col) {
1300   int nr_rows, nr_cols;
1301   path fp= search_format ();
1302   if (is_nil (fp)) return path ();
1303   table_get_extents (fp, nr_rows, nr_cols);
1304   if (row>0) row--; else row+=nr_rows;
1305   if (col>0) col--; else col+=nr_cols;
1306   if ((row<0) || (row>=nr_rows) || (col<0) || (col>=nr_cols)) return path ();
1307   return search_cell (fp, row, col);
1308 }
1309 
1310 void
table_go_to(int row,int col)1311 edit_table_rep::table_go_to (int row, int col) {
1312   int nr_rows, nr_cols;
1313   path fp= search_format ();
1314   if (is_nil (fp)) return;
1315   table_get_extents (fp, nr_rows, nr_cols);
1316   if (row>0) row--; else row+=nr_rows;
1317   if (col>0) col--; else col+=nr_cols;
1318   if ((row<0) || (row>=nr_rows) || (col<0) || (col>=nr_cols)) return;
1319   table_go_to (fp, row, col);
1320 }
1321 
1322 void
table_set_format(string var,tree val)1323 edit_table_rep::table_set_format (string var, tree val) {
1324   if (val == "") table_del_format (var);
1325   else if (selection_active_table (false)) {
1326     int row1, col1, row2, col2;
1327     path fp= selection_get_subtable (row1, col1, row2, col2);
1328     if (is_nil (fp)) return;
1329     table_set_format (fp, var, val);
1330   }
1331   else {
1332     path fp= search_format ();
1333     if (is_nil (fp)) return;
1334     table_set_format (fp, var, val);
1335   }
1336 }
1337 
1338 tree
table_get_format()1339 edit_table_rep::table_get_format () {
1340   path fp= search_format ();
1341   if (is_nil (fp)) return "";
1342   return table_get_format (fp);
1343 }
1344 
1345 string
table_get_format(string var)1346 edit_table_rep::table_get_format (string var) {
1347   path fp= search_format ();
1348   if (is_nil (fp)) return "";
1349   return as_string (table_get_format (fp, var));
1350 }
1351 
1352 void
table_del_format(string var)1353 edit_table_rep::table_del_format (string var) {
1354   if (selection_active_table (false)) {
1355     int row1, col1, row2, col2;
1356     path fp= selection_get_subtable (row1, col1, row2, col2);
1357     if (is_nil (fp)) return;
1358     table_del_format (fp, var);
1359   }
1360   else {
1361     path fp= search_format ();
1362     if (is_nil (fp)) return;
1363     table_del_format (fp, var);
1364   }
1365 }
1366 
1367 void
table_format_center()1368 edit_table_rep::table_format_center () {
1369   int row, col;
1370   path fp= search_format (row, col);
1371   if (is_nil (fp)) return;
1372   table_format_center (fp, row, col);
1373 }
1374 
1375 void
table_row_decoration(bool forward)1376 edit_table_rep::table_row_decoration (bool forward) {
1377   int row, col, nr_rows, nr_cols;
1378   path fp= search_format (row, col);
1379   if (is_nil (fp)) return;
1380   table_get_extents (fp, nr_rows, nr_cols);
1381   if ((!forward) && (row > 0)) table_ver_decorate (fp, row, 1, 0);
1382   if (forward && (row < (nr_rows-1))) table_ver_decorate (fp, row, 0, 1);
1383 }
1384 
1385 void
table_column_decoration(bool forward)1386 edit_table_rep::table_column_decoration (bool forward) {
1387   int row, col, nr_rows, nr_cols;
1388   path fp= search_format (row, col);
1389   if (is_nil (fp)) return;
1390   table_get_extents (fp, nr_rows, nr_cols);
1391   if ((!forward) && (col > 0)) table_hor_decorate (fp, col, 1, 0);
1392   if (forward && (col < (nr_cols-1))) table_hor_decorate (fp, col, 0, 1);
1393 }
1394 
1395 void
table_correct_block_content()1396 edit_table_rep::table_correct_block_content () {
1397   int nr_rows, nr_cols;
1398   path fp= search_format ();
1399   if (is_nil (fp)) return;
1400   table_get_extents (fp, nr_rows, nr_cols);
1401   int row, col;
1402   for (row= 0; row < nr_rows; row++)
1403     for (col= 0; col < nr_cols; col++) {
1404       path cp= search_cell (fp, row, col);
1405       tree st= subtree (et, cp);
1406       tree t1= table_get_format (fp, row+1, col+1, row+1, col+1, CELL_BLOCK);
1407       tree t2= table_get_format (fp, row+1, col+1, row+1, col+1, CELL_HYPHEN);
1408       bool f1= (t1 == "no" || (t1 == "auto" && t2 == "n"));
1409       bool f2= (t1 == "yes" || (t1 == "auto" && is_atomic (t2) && t2 != "n"));
1410       if (f1 && is_document (st) && N(st) == 1)
1411 	remove_node (cp * 0);
1412       else if (f2 && !is_document (st))
1413 	insert_node (cp * 0, DOCUMENT);
1414     }
1415 }
1416 
1417 void
table_resize_notify()1418 edit_table_rep::table_resize_notify () {
1419   path p= search_table ();
1420   if (!is_nil (p))
1421     call ("table-resize-notify", object (subtree (et, p)));
1422 }
1423 
1424 void
set_cell_mode(string mode)1425 edit_table_rep::set_cell_mode (string mode) {
1426   cell_mode= mode;
1427 }
1428 
1429 string
get_cell_mode()1430 edit_table_rep::get_cell_mode () {
1431   return cell_mode;
1432 }
1433 
1434 void
cell_set_format(string var,tree val)1435 edit_table_rep::cell_set_format (string var, tree val) {
1436   if (selection_active_table (false)) {
1437     int row1, col1, row2, col2, rows, cols;
1438     path fp= selection_get_subtable (row1, col1, row2, col2);
1439     row1++; col1++; row2++; col2++;
1440     table_get_extents (fp, rows, cols);
1441     if (rows > row1 && row1 <= 2 && row2 == rows) row2= -1;
1442     if (cols > col1 && col1 <= 2 && col2 == cols) col2= -1;
1443     table_set_format (fp, row1, col1, row2, col2, var, val);
1444   }
1445   else {
1446     int row, col;
1447     path fp= search_format (row, col); row++; col++;
1448     if (is_nil (fp)) return;
1449     if (cell_mode=="row")
1450       table_set_format (fp, row, 1, row, -1, var, val);
1451     else if (cell_mode=="column")
1452       table_set_format (fp, 1, col, -1, col, var, val);
1453     else if (cell_mode=="table")
1454       table_set_format (fp, 1, 1, -1, -1, var, val);
1455     else table_set_format (fp, row, col, row, col, var, val);
1456   }
1457   table_correct_block_content ();
1458 }
1459 
1460 string
cell_get_format(string var)1461 edit_table_rep::cell_get_format (string var) {
1462   int row, col;
1463   path fp= search_format (row, col); row++; col++;
1464   if (is_nil (fp)) return "";
1465   if (cell_mode=="row")
1466     return as_string (table_get_format (fp, row, 1, row, -1, var));
1467   else if (cell_mode=="column")
1468     return as_string (table_get_format (fp, 1, col, -1, col, var));
1469   else if (cell_mode=="table")
1470     return as_string (table_get_format (fp, 1, 1, -1, -1, var));
1471   else return as_string (table_get_format (fp, row, col, row, col, var));
1472 }
1473 
1474 void
cell_del_format(string var)1475 edit_table_rep::cell_del_format (string var) {
1476   if (selection_active_table (false)) {
1477     int row1, col1, row2, col2;
1478     path fp= selection_get_subtable (row1, col1, row2, col2);
1479     table_del_format (fp, row1+1, col1+1, row2+1, col2+1, var);
1480   }
1481   else {
1482     int row, col;
1483     path fp= search_format (row, col); row++; col++;
1484     if (is_nil (fp)) return;
1485     if (cell_mode=="row") table_del_format (fp, row, 1, row, -1, var);
1486     else if (cell_mode=="column") table_del_format (fp, 1, col, -1, col, var);
1487     else if (cell_mode=="table") table_del_format (fp, 1, 1, -1, -1, var);
1488     else table_del_format (fp, row, col, row, col, var);
1489   }
1490   table_correct_block_content ();
1491 }
1492 
1493 void
table_test()1494 edit_table_rep::table_test () {
1495   path fp= search_format ();
1496   if (is_nil (fp)) return;
1497   cout << table_get_format (fp) << "\n";
1498 }
1499