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