]> git.lyx.org Git - lyx.git/blob - src/table.C
small patch from jamatos
[lyx.git] / src / table.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *        Copyright 1995 Matthias Ettrich
7  *        Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== 
10  */
11
12 #include <config.h>
13
14 #include <algorithm>
15 #include <cstdlib>
16
17 #ifdef __GNUG__
18 #pragma implementation
19 #endif
20
21 #include "table.h"
22 #include "debug.h"
23 #include "vspace.h"
24 #include "layout.h"
25 #include "support/lstrings.h"
26 #include "support/lyxmanip.h"
27
28 using std::ostream;
29 using std::istream;
30 using std::max;
31 using std::endl;
32
33 static int const WIDTH_OF_LINE = 5;
34
35
36 /* konstruktor */
37 LyXTable::LyXTable(int rows_arg, int columns_arg)
38 {
39         Init(rows_arg, columns_arg);
40 }
41
42
43 LyXTable::LyXTable(LyXLex & lex)
44 {
45         istream & is = lex.getStream();
46         Read(is);
47 }
48
49
50 LyXTable::~LyXTable() {
51         delete[] rowofcell;
52         delete[] columnofcell;
53         delete[] column_info;
54         delete[] row_info;
55         for (int i = 0; i < rows; ++i) {
56                 delete[] cell_info[i]; // verify that this shoudn't be freed with delete
57         }
58         delete[] cell_info;
59 }
60
61
62 LyXTable * LyXTable::Clone()
63 {
64     LyXTable * result = new LyXTable(rows, columns);
65     int row, column;;
66
67     for (row = 0; row < rows; ++row) {
68         for (column = 0; column < columns; ++column) {
69             result->cell_info[row][column] = cell_info[row][column];
70         }
71     }
72
73     for (row = 0; row < rows; ++row) {
74         result->row_info[row] = row_info[row];
75     }
76
77     for (column = 0; column < columns; ++column) {
78         result->column_info[column].left_line = column_info[column].left_line;
79         result->column_info[column].right_line = column_info[column].right_line;
80         result->column_info[column].alignment = column_info[column].alignment;
81         result->column_info[column].p_width = column_info[column].p_width;
82         result->column_info[column].align_special = column_info[column].align_special;
83     }
84   
85     result->SetLongTable(is_long_table);
86     result->rotate = rotate;
87     result->Reinit();
88     return result;
89 }
90
91
92 /* activates all lines and sets all widths to 0 */ 
93 void LyXTable::Init(int rows_arg, int columns_arg)
94 {
95     int i, j;
96     rows = rows_arg;
97     columns = columns_arg;
98     column_info = new columnstruct[columns];
99     row_info = new rowstruct[rows];
100     cell_info = new cellstruct*[rows];
101
102     int cellno = 0;
103     for (i = 0; i < rows; ++i) {
104         cell_info[i] = new cellstruct[columns];
105         row_info[i].top_line = true;
106         row_info[i].bottom_line = false;
107         row_info[i].is_cont_row = false;
108         row_info[i].newpage = false;
109         for (j = 0; j < columns; ++j) {
110             cell_info[i][j].cellno = cellno++;
111             cell_info[i][j].width_of_cell = 0;
112             cell_info[i][j].multicolumn = LyXTable::CELL_NORMAL;
113             cell_info[i][j].alignment = LYX_ALIGN_CENTER;
114             cell_info[i][j].top_line = row_info[i].top_line;
115             cell_info[i][j].bottom_line = row_info[i].bottom_line;
116             cell_info[i][j].has_cont_row = false;
117             cell_info[i][j].rotate = false;
118             cell_info[i][j].linebreaks = false;
119         }
120     }
121     row_info[i-1].bottom_line = true;
122     row_info[0].bottom_line = true;
123
124     for (i = 0; i < columns; ++i) {
125         column_info[i].left_line = true;
126         column_info[i].right_line = false;
127         column_info[i].alignment = LYX_ALIGN_CENTER;
128         // set width_of_column to zero before it is used in
129         // calculate_width_of_column() (thornley)
130         column_info[i].width_of_column = 0;
131         calculate_width_of_column(i);
132     }
133     column_info[i-1].right_line = true;
134    
135     calculate_width_of_table();
136
137     rowofcell = 0;
138     columnofcell = 0;
139     set_row_column_number_info();
140     is_long_table = false;
141     rotate = 0;
142     endhead = -1;
143     endfirsthead = -1;
144     endfoot = -1;
145     endlastfoot = -1;
146 }
147
148
149 void LyXTable::AppendRow(int cell)
150 {
151     int row = row_of_cell(cell);
152     rowstruct * row_info2 = new rowstruct[rows + 1];
153     cellstruct ** cell_info2 = new cellstruct * [rows + 1];
154     int i;
155
156     for (i = 0; i <= row; ++i) {
157         cell_info2[i] = cell_info[i];
158         row_info2[i] = row_info[i];
159     }
160     for (i = rows - 1; i >= row; --i) {
161         cell_info2[i + 1] = cell_info[i];
162         row_info2[i + 1] = row_info[i];
163     }
164     for (i = row; row_info[i].is_cont_row; --i);
165     if (((row + 1) >= rows) || !row_info[row + 1].is_cont_row)
166         row_info2[row + 1].is_cont_row = false;
167     row_info2[row + 1].top_line = row_info[i].top_line;
168     cell_info2[row + 1] = new cellstruct[columns];
169     for (i = 0; i < columns; ++i) {
170         cell_info2[row + 1][i].width_of_cell = 0;
171         cell_info2[row + 1][i] = cell_info2[row][i];
172     }
173    
174     delete[] cell_info;
175     cell_info = cell_info2;
176     delete[] row_info;
177     row_info = row_info2;
178    
179     ++rows;
180    
181     Reinit();
182 }
183
184
185 void LyXTable::DeleteRow(int cell)
186 {
187         int row = row_of_cell(cell);
188         while(!row_info[row].is_cont_row && RowHasContRow(cell))
189             DeleteRow(cell_info[row+1][0].cellno);
190         rowstruct * row_info2 = new rowstruct[rows - 1];
191         cellstruct ** cell_info2 = new cellstruct * [rows - 1];
192
193         delete[] cell_info[row];
194         int i = 0;
195         for (; i < row; ++i) {
196                 cell_info2[i] = cell_info[i];
197                 row_info2[i] = row_info[i];
198         }
199         if (row_info[i].is_cont_row)
200             row_info2[i - 1].bottom_line = row_info[i].bottom_line;
201         for (i = row; i < rows - 1; ++i) {
202                 cell_info2[i] = cell_info[i + 1];
203                 row_info2[i] = row_info[i + 1];
204         }
205
206         delete[] cell_info;
207         cell_info = cell_info2;
208         delete[] row_info;
209         row_info = row_info2;
210    
211         --rows;
212
213         Reinit();
214 }
215
216
217 void LyXTable::AppendColumn(int cell)
218 {
219     int j;
220     columnstruct * column_info2 = new columnstruct[columns + 1];
221     int column = right_column_of_cell(cell);
222
223     int i = 0;
224     for (; i <= column; ++i) {
225         column_info2[i] = column_info[i];
226     }
227     for (i = columns - 1; i >= column; --i) {
228         column_info2[i + 1] = column_info[i];
229     }
230     
231     delete[] column_info;
232     column_info = column_info2;
233     
234     for (i = 0; i < rows; ++i) {
235         cellstruct * tmp = cell_info[i];
236         cell_info[i] = new cellstruct[columns + 1];
237         for (j = 0; j <= column; ++j) {
238             cell_info[i][j] = tmp[j];
239         }
240         for (j = column; j < columns; ++j) {
241             cell_info[i][j + 1] = tmp[j];
242         }
243         // care about multicolumns
244         if (cell_info[i][column + 1].multicolumn
245             == LyXTable::CELL_BEGIN_OF_MULTICOLUMN){
246             cell_info[i][column + 1].multicolumn = 
247                 LyXTable::CELL_PART_OF_MULTICOLUMN;
248         }
249         if (column + 1 == columns
250             || cell_info[i][column + 2].multicolumn
251             != LyXTable::CELL_PART_OF_MULTICOLUMN){
252             cell_info[i][column + 1].multicolumn = 
253                 LyXTable::CELL_NORMAL;
254         }
255         delete[] tmp;
256     }
257     
258     ++columns;
259     Reinit();
260 }
261
262
263 void LyXTable::Reinit()
264 {   
265         int j;
266
267         int i = 0;
268         for (; i < rows; ++i) {
269                 for (j = 0; j < columns; ++j) {
270                         cell_info[i][j].width_of_cell = 0;
271                         if ((i + 1 < rows) && !row_info[i+1].is_cont_row)
272                             cell_info[i][j].has_cont_row = false;
273                 }
274         }
275   
276         for (i = 0; i < columns; ++i) {
277                 calculate_width_of_column(i);
278         }
279         calculate_width_of_table();
280
281         set_row_column_number_info();
282 }
283
284
285 void LyXTable::set_row_column_number_info()
286 {
287         int c = 0;
288         int column = 0;
289         numberofcells = -1;
290         int row = 0;
291         for (; row < rows; ++row) {
292                 for (column = 0; column<columns; ++column) {
293                         if (cell_info[row][column].multicolumn
294                             != LyXTable::CELL_PART_OF_MULTICOLUMN)
295                                 ++numberofcells;
296                         cell_info[row][column].cellno = numberofcells;
297                 }
298         }
299         ++numberofcells; // because this is one more than as we start from 0
300         row = 0;
301         column = 0;
302
303         delete [] rowofcell;
304         rowofcell = new int[numberofcells];
305         delete [] columnofcell;
306         columnofcell = new int[numberofcells];
307   
308         while (c < numberofcells && row < rows && column < columns) {
309                 rowofcell[c] = row;
310                 columnofcell[c] = column;
311                 ++c;
312                 do {
313                         ++column;
314                 } while (column < columns &&
315                          cell_info[row][column].multicolumn
316                          == LyXTable::CELL_PART_OF_MULTICOLUMN);
317                 if (column == columns) {
318                         column = 0;
319                         ++row;
320                 }
321         }
322 }
323
324
325 void LyXTable::DeleteColumn(int cell)
326 {
327         int column1 = column_of_cell(cell);
328         int column2 = right_column_of_cell(cell);
329    
330         if (column1 == 0 && column2 == columns - 1)
331                 return;
332    
333         for (int column = column1; column <= column2; ++column) {
334                 delete_column(column1);
335         }
336         Reinit();
337 }
338
339
340 int LyXTable::GetNumberOfCells()
341 {
342         return numberofcells;
343 }
344
345
346 int LyXTable::NumberOfCellsInRow(int cell)
347 {
348         int row = row_of_cell(cell);
349         int result = 0;
350         for (int i = 0; i < columns; ++i) {
351                 if (cell_info[row][i].multicolumn != LyXTable::CELL_PART_OF_MULTICOLUMN)
352                         ++result;
353         }
354         return result;
355 }
356
357
358 int LyXTable::AppendCellAfterCell(int append_cell, int question_cell)
359 {
360         return (right_column_of_cell(append_cell) == 
361                 right_column_of_cell(question_cell));
362 }
363
364
365 int LyXTable::DeleteCellIfColumnIsDeleted(int cell, int delete_column_cell)
366 {
367     if (column_of_cell(delete_column_cell) == 0 && 
368         right_column_of_cell(delete_column_cell) == columns - 1)
369         return 0;
370     else
371         return
372             (column_of_cell(cell) >= column_of_cell(delete_column_cell) &&
373              column_of_cell(cell) <= right_column_of_cell(delete_column_cell));
374 }
375
376
377 /* returns 1 if there is a topline, returns 0 if not */ 
378 bool LyXTable::TopLine(int cell)
379 {
380     int row = row_of_cell(cell);
381     
382     if (IsContRow(cell))
383         return TopLine(cell_info[row-1][column_of_cell(cell)].cellno);
384     if (IsMultiColumn(cell))
385         return cellinfo_of_cell(cell)->top_line;
386     return row_info[row].top_line;
387 }
388
389
390 bool LyXTable::BottomLine(int cell)
391 {
392     //no bottom line underneath non-existent cells if you please
393     if(cell >= numberofcells)
394         return false;
395
396     int row = row_of_cell(cell);
397     
398     if (RowHasContRow(cell))
399         return BottomLine(cell_info[row+1][column_of_cell(cell)].cellno);
400     if (IsMultiColumn(cell))
401         return cellinfo_of_cell(cell)->bottom_line;
402     return row_info[row_of_cell(cell)].bottom_line;
403 }
404
405
406 bool LyXTable::LeftLine(int cell)
407 {
408         return column_info[column_of_cell(cell)].left_line;
409 }
410
411
412 bool LyXTable::RightLine(int cell)
413 {
414         return column_info[right_column_of_cell(cell)].right_line;
415 }
416
417
418 bool LyXTable::TopAlreadyDrawed(int cell)
419 {
420         if (AdditionalHeight(cell))
421                 return false;
422         int row = row_of_cell(cell);
423         if (row > 0){
424                 int column = column_of_cell(cell);
425                 while (column
426                        && cell_info[row-1][column].multicolumn
427                        == LyXTable::CELL_PART_OF_MULTICOLUMN)
428                         --column;
429                 if (cell_info[row-1][column].multicolumn
430                     == LyXTable::CELL_NORMAL)
431                         return row_info[row-1].bottom_line;
432                 else
433                         return cell_info[row-1][column].bottom_line;
434         }
435         return false;
436 }
437
438
439 bool LyXTable::VeryLastRow(int cell)
440 {
441         return (row_of_cell(cell) == rows - 1);
442 }
443
444
445 int LyXTable::AdditionalHeight(int cell)
446 {
447         int row = row_of_cell(cell);
448         if (!row) return 0;
449         
450         int top = 1; // bool top = true; ??
451         int bottom = 1; // bool bottom = true; ??
452         int column;
453
454         for (column = 0; column < columns - 1 && bottom; ++column) {
455                 switch (cell_info[row - 1][column].multicolumn) {
456                 case LyXTable::CELL_BEGIN_OF_MULTICOLUMN:
457                         bottom = cell_info[row - 1][column].bottom_line;
458                         break;
459                 case LyXTable::CELL_NORMAL:
460                         bottom = row_info[row - 1].bottom_line;
461                 }
462         }
463         for (column = 0; column < columns - 1 && top; ++column) {
464                 switch (cell_info[row][column].multicolumn){
465                 case LyXTable::CELL_BEGIN_OF_MULTICOLUMN:
466                         top = cell_info[row][column].top_line;
467                         break;
468                 case LyXTable::CELL_NORMAL:
469                         top = row_info[row].top_line;
470                 }
471         }
472         if (top && bottom)
473                 return WIDTH_OF_LINE;
474         return 0;
475 }
476
477
478 int LyXTable::AdditionalWidth(int cell)
479 {
480         // internally already set in SetWidthOfCell
481         // used to get it back in text.C
482         int col = right_column_of_cell(cell);
483         if (col < columns - 1 && column_info[col].right_line &&
484             column_info[col+1].left_line)
485                 return WIDTH_OF_LINE;
486         else
487                 return 0;
488 }
489
490
491 // returns the maximum over all rows 
492 int LyXTable::WidthOfColumn(int cell)
493 {
494         int column1 = column_of_cell(cell);
495         int column2 = right_column_of_cell(cell);
496         int result = 0;
497         int i = column1;
498         for (; i <= column2; ++i) {
499                 result += column_info[i].width_of_column;
500         }
501         return result;
502 }
503
504
505 int LyXTable::WidthOfTable()
506 {
507         return width_of_table;
508 }
509
510 /* returns 1 if a complete update is necessary, otherwise 0 */ 
511 bool LyXTable::SetWidthOfMulticolCell(int cell, int new_width)
512 {
513     if (!IsMultiColumn(cell))
514         return false;
515     
516     int row = row_of_cell(cell);
517     int column1 = column_of_cell(cell);
518     int column2 = right_column_of_cell(cell);
519
520     // first set columns to 0 so we can calculate the right width
521     int i = column1;
522     for (; i <= column2; ++i) {
523         cell_info[row][i].width_of_cell = 0;
524     }
525     // set the width to MAX_WIDTH until width > 0
526     int width = (new_width + 2 * WIDTH_OF_LINE);
527     for (i = column1; (i < column2) && (width > 0); ++i) {
528         cell_info[row][i].width_of_cell = column_info[i].width_of_column;
529         width -= column_info[i].width_of_column;
530     }
531     if (i == column2) {
532         cell_info[row][i].width_of_cell = width;
533     }
534     return true;
535 }
536
537
538 void LyXTable::recalculateMulticolCells(int cell, int new_width)
539 {
540         int row = row_of_cell(cell);
541         int column1 = column_of_cell(cell);
542         int column2 = right_column_of_cell(cell);
543
544     // first set columns to 0 so we can calculate the right width
545         int i = column1;
546     for (; i <= column2; ++i)
547         cell_info[row][i].width_of_cell = 0;
548     for(i = cell + 1; (i < numberofcells) && (!IsMultiColumn(i)); ++i)
549         ;
550     if (i < numberofcells)
551         recalculateMulticolCells(i, GetWidthOfCell(i) - (2 * WIDTH_OF_LINE));
552     SetWidthOfMulticolCell(cell, new_width);
553 }
554
555
556 /* returns 1 if a complete update is necessary, otherwise 0 */ 
557 bool LyXTable::SetWidthOfCell(int cell, int new_width)
558 {
559     int row = row_of_cell(cell);
560     int column1 = column_of_cell(cell);
561     int tmp = 0;
562     int width = 0;
563
564     if (IsMultiColumn(cell)) {
565         tmp = SetWidthOfMulticolCell(cell, new_width);
566     } else {
567         width = (new_width + 2*WIDTH_OF_LINE);
568         cell_info[row][column1].width_of_cell = width;
569         if (column_info[column1].right_line && (column1 < columns-1) &&
570             column_info[column1+1].left_line) // additional width
571             cell_info[row][column1].width_of_cell += WIDTH_OF_LINE;
572         tmp = calculate_width_of_column_NMC(column1);
573     }
574     if (tmp) {
575         int i;
576         for(i = 0; i<columns;++i)
577             calculate_width_of_column_NMC(i);
578         for(i = 0; (i<numberofcells) && !IsMultiColumn(i); ++i)
579             ;
580         if (i<numberofcells)
581             recalculateMulticolCells(i, GetWidthOfCell(i)-(2*WIDTH_OF_LINE));
582         for(i = 0; i<columns;++i)
583             calculate_width_of_column(i);
584         calculate_width_of_table();
585         return true;
586     }
587     return false;
588 }
589
590
591 bool LyXTable::SetAlignment(int cell, char align)
592 {
593     if (!IsMultiColumn(cell))
594         column_info[column_of_cell(cell)].alignment = align;
595     cellinfo_of_cell(cell)->alignment = align;
596     return true;
597 }
598
599 bool LyXTable::SetPWidth(int cell, string width)
600 {
601     int fvcell = FirstVirtualCell(cell);
602
603     if (IsMultiColumn(fvcell)) {
604 //        if (column_info[column_of_cell(cell)].p_width.empty())
605 //            column_info[column_of_cell(cell)].p_width = width;
606         cellinfo_of_cell(fvcell)->p_width = width;
607     } else {
608         column_info[column_of_cell(fvcell)].p_width = width;
609         if (!width.empty()) // do this only if there is a width
610                 SetAlignment(cell, LYX_ALIGN_LEFT);
611     }
612     return true;
613 }
614
615 bool LyXTable::SetAlignSpecial(int cell, string special, int what)
616 {
617     if (what == SET_SPECIAL_MULTI)
618         cellinfo_of_cell(cell)->align_special = special;
619     else
620         column_info[column_of_cell(cell)].align_special = special;
621     return true;
622 }
623
624 bool LyXTable::SetAllLines(int cell, bool line)
625 {
626     SetTopLine(cell, line);
627     SetBottomLine(cell, line);
628     SetRightLine(cell, line);
629     SetLeftLine(cell, line);
630     return true;
631 }
632
633 bool LyXTable::SetTopLine(int cell, bool line)
634 {
635     int row = row_of_cell(cell);
636
637     if (IsContRow(cell))
638         SetTopLine(cell_info[row-1][column_of_cell(cell)].cellno, line);
639     else if (!IsMultiColumn(cell))
640         row_info[row].top_line = line;
641     else
642         cellinfo_of_cell(cell)->top_line = line;
643     return true;
644 }
645
646
647 bool LyXTable::SetBottomLine(int cell, bool line)
648 {
649     int row = row_of_cell(cell);
650
651     if (RowHasContRow(cell))
652         SetBottomLine(cell_info[row+1][column_of_cell(cell)].cellno, line);
653     else if (!IsMultiColumn(cell))
654         row_info[row_of_cell(cell)].bottom_line = line;
655     else
656         cellinfo_of_cell(cell)->bottom_line = line;
657     return true;
658 }
659
660
661 bool LyXTable::SetLeftLine(int cell, bool line)
662 {
663         column_info[column_of_cell(cell)].left_line = line;
664         return true;
665 }
666
667
668 bool LyXTable::SetRightLine(int cell, bool line)
669 {
670         column_info[right_column_of_cell(cell)].right_line = line;
671         return true;
672 }
673
674
675 char LyXTable::GetAlignment(int cell)
676 {
677         if (IsMultiColumn(cell))
678                 return cellinfo_of_cell(cell)->alignment;
679         else
680                 return column_info[column_of_cell(cell)].alignment;
681 }
682
683 string LyXTable::GetPWidth(int cell)
684 {
685         int fvcell = FirstVirtualCell(cell);
686         
687         if (IsMultiColumn(fvcell)) // && !cellinfo_of_cell(cell)->p_width.empty())
688                 return cellinfo_of_cell(fvcell)->p_width;
689         return column_info[column_of_cell(fvcell)].p_width;
690 }
691
692 string LyXTable::GetAlignSpecial(int cell, int what)
693 {
694     if (what == SET_SPECIAL_MULTI)
695         return cellinfo_of_cell(cell)->align_special;
696     return column_info[column_of_cell(cell)].align_special;
697 }
698
699 int LyXTable::GetWidthOfCell(int cell)
700 {
701         int row = row_of_cell(cell);
702         int column1 = column_of_cell(cell);
703         int column2 = right_column_of_cell(cell);
704         int result = 0;
705         int i = column1;
706         for (; i <= column2; ++i) {
707                 result += cell_info[row][i].width_of_cell;
708         }
709   
710         result += AdditionalWidth(cell);
711   
712         return result;
713 }
714
715
716 int LyXTable::GetBeginningOfTextInCell(int cell)
717 {
718         int x = 0;
719    
720         switch (GetAlignment(cell)){
721         case LYX_ALIGN_CENTER:
722                 x += (WidthOfColumn(cell) - GetWidthOfCell(cell)) / 2;
723                 break;
724         case LYX_ALIGN_RIGHT:
725                 x += WidthOfColumn(cell) - GetWidthOfCell(cell) + AdditionalWidth(cell);
726                 break;
727         default: /* LYX_ALIGN_LEFT: nothing :-) */ 
728                 break;
729         }
730
731         // the LaTeX Way :-(
732         x += WIDTH_OF_LINE;
733         return x;
734 }
735
736
737 bool LyXTable::IsFirstCell(int cell)
738 {
739         return (column_of_cell(cell) == 0);
740 }
741
742 bool LyXTable::IsLastCell(int cell)
743 {
744         return (right_column_of_cell(cell) == (columns - 1));
745 }
746
747
748 bool LyXTable::calculate_width_of_column(int column)
749 {
750         int old_column_width = column_info[column].width_of_column;
751         int maximum = 0;
752
753         for (int i = 0; i < rows; ++i) {
754                 maximum = max(cell_info[i][column].width_of_cell, maximum);
755         }
756         column_info[column].width_of_column = maximum;
757         return (column_info[column].width_of_column != old_column_width);
758 }
759
760 bool LyXTable::calculate_width_of_column_NMC(int column)
761 {
762     int old_column_width = column_info[column].width_of_column;
763     int max = 0;
764     for (int i = 0; i < rows; ++i) {
765         if (!IsMultiColumn(GetCellNumber(column, i)) &&
766             (cell_info[i][column].width_of_cell > max)) {
767             max = cell_info[i][column].width_of_cell;
768         }
769     }
770     column_info[column].width_of_column = max;
771     return (column_info[column].width_of_column != old_column_width);
772 }
773
774 void LyXTable::calculate_width_of_table()
775 {
776         width_of_table = 0;
777         for (int i = 0; i < columns; ++i) {
778                 width_of_table += column_info[i].width_of_column;
779         }
780 }
781
782
783 int LyXTable::row_of_cell(int cell) 
784 {
785     if (cell >= numberofcells)
786         return rows-1;
787     else if (cell < 0)
788         return 0;
789     return rowofcell[cell];
790 }
791
792
793 int LyXTable::column_of_cell(int cell)
794 {
795     if (cell >= numberofcells)
796         return columns-1;
797     else if (cell < 0)
798         return 0;
799     return columnofcell[cell];
800 }
801
802
803 int LyXTable::right_column_of_cell(int cell) 
804 {
805         int row = row_of_cell(cell);
806         int column = column_of_cell(cell);
807         while (column < columns - 1 &&
808                cell_info[row][column+1].multicolumn == LyXTable::CELL_PART_OF_MULTICOLUMN)
809                 ++column;
810         return column;
811 }
812
813
814 void LyXTable::Write(ostream & os)
815 {
816     int i, j;
817     os << "multicol5\n"
818        << rows << " " << columns << " " << is_long_table << " "
819        << rotate << " " << endhead << " " << endfirsthead << " "
820        << endfoot << " " << endlastfoot << "\n";
821     for (i = 0; i < rows; ++i) {
822             os << row_info[i].top_line << " "
823                << row_info[i].bottom_line << " "
824                << row_info[i].is_cont_row << " "
825                << row_info[i].newpage << "\n";
826     }
827     for (i = 0; i < columns; ++i) {
828             os << column_info[i].alignment << " "
829                << column_info[i].left_line << " "
830                << column_info[i].right_line << " \""
831                << VSpace(column_info[i].p_width).asLyXCommand() << "\" \""
832                << column_info[i].align_special << "\"\n";
833     }
834
835     for (i = 0; i < rows; ++i) {
836         for (j = 0; j < columns; ++j) {
837                 os << cell_info[i][j].multicolumn << " "
838                    << cell_info[i][j].alignment << " "
839                    << cell_info[i][j].top_line << " "
840                    << cell_info[i][j].bottom_line << " "
841                    << cell_info[i][j].has_cont_row << " "
842                    << cell_info[i][j].rotate << " "
843                    << cell_info[i][j].linebreaks << " \""
844                    << cell_info[i][j].align_special << "\" \""
845                    << cell_info[i][j].p_width << "\"\n";
846         }
847     }
848 }
849
850
851 void LyXTable::Read(istream & is)
852 {
853         int version;
854         int i, j;
855         int rows_arg = 0;
856         int columns_arg = 0;
857         int is_long_table_arg = false;
858         int rotate_arg = false;
859         int a = -1;
860         int b = -1;
861         int c = -1;
862         int d = -1;
863         int e = 0;
864         int f = 0;
865         int g = 0;
866         int h = 0;
867         
868         string s;
869         getline(is, s);
870         if (s.length() > 8)
871                 version = atoi(s.c_str() + 8);
872         else
873                 version = 1;
874 #ifdef WITH_WARNINGS
875 #warning Insert a error message window here that this format is not supported anymore
876 #endif
877         if (version < 5) {
878                 lyxerr << "Tabular format < 5 is not supported anymore\n"
879                         "Get an older version of LyX (< 1.1.x) for conversion!"
880                        << endl;
881                 if (version > 2) {
882                         is >> rows_arg >> columns_arg >> is_long_table_arg
883                            >> rotate_arg >> a >> b >> c >> d;
884                 } else
885                         is >> rows_arg >> columns_arg;
886                 Init(rows_arg, columns_arg);
887                 SetLongTable(is_long_table_arg);
888                 SetRotateTable(rotate_arg);
889                 string tmp;
890                 for (i = 0; i < rows; ++i) {
891                         getline(is, tmp);
892                 }
893                 for (i = 0; i < columns; ++i) {
894                         getline(is, tmp);
895                 }
896                 for (i = 0; i < rows; ++i) {
897                         for (j = 0; j < columns; ++j) {
898                                 getline(is, tmp);
899                         }
900                 }
901                 set_row_column_number_info();
902                 return;
903         }
904         is >> rows_arg >> columns_arg >> is_long_table_arg
905            >> rotate_arg >> a >> b >> c >> d;
906         Init(rows_arg, columns_arg);
907         SetLongTable(is_long_table_arg);
908         SetRotateTable(rotate_arg);
909         endhead = a;
910         endfirsthead = b;
911         endfoot = c;
912         endlastfoot = d;
913         for (i = 0; i < rows; ++i) {
914                 a = b = c = d = e = f = g = h = 0;
915                 is >> a >> b >> c >> d;
916                 row_info[i].top_line = a;
917                 row_info[i].bottom_line = b;
918                 row_info[i].is_cont_row = c;
919                 row_info[i].newpage = d;
920         }
921         for (i = 0; i < columns; ++i) {
922                 string s1;
923                 string s2;
924                 is >> a >> b >> c;
925                 char ch; // skip '"'
926                 is >> ch;
927                 getline(is, s1, '"');
928                 is >> ch; // skip '"'
929                 getline(is, s2, '"');
930                 column_info[i].alignment = static_cast<char>(a);
931                 column_info[i].left_line = b;
932                 column_info[i].right_line = c;
933                 column_info[i].p_width = s1;
934                 column_info[i].align_special = s2;
935         }
936         for (i = 0; i < rows; ++i) {
937                 for (j = 0; j < columns; ++j) {
938                         string s1;
939                         string s2;
940                         is >> a >> b >> c >> d >> e >> f >> g;
941                         char ch;
942                         is >> ch; // skip '"'
943                         getline(is, s1, '"');
944                         is >> ch; // skip '"'
945                         getline(is, s2, '"');
946                         cell_info[i][j].multicolumn = static_cast<char>(a);
947                         cell_info[i][j].alignment = static_cast<char>(b);
948                         cell_info[i][j].top_line = static_cast<char>(c);
949                         cell_info[i][j].bottom_line = static_cast<char>(d);
950                         cell_info[i][j].has_cont_row = static_cast<bool>(e);
951                         cell_info[i][j].rotate = static_cast<bool>(f);
952                         cell_info[i][j].linebreaks = static_cast<bool>(g);
953                         cell_info[i][j].align_special = s1;
954                         cell_info[i][j].p_width = s2;
955                 }
956         }
957         set_row_column_number_info();
958 }
959
960
961 // cell <0 will tex the preamble
962 // returns the number of printed newlines
963 int LyXTable::TexEndOfCell(ostream & os, int cell)
964 {
965     int i;
966     int ret = 0;
967     int tmp; // tmp2;
968     int fcell, nvcell;
969     if (ShouldBeVeryLastCell(cell)) {
970         // the very end at the very beginning
971         if (Linebreaks(cell))
972                 os << "\\smallskip{}}";
973         if (IsMultiColumn(cell))
974                 os << '}';
975         if (RotateCell(cell)) {
976                 os << "\n\\end{sideways}";
977             ++ret;
978         }
979         os << "\\\\\n";
980         ++ret;
981     
982         tmp = 0;
983         fcell = cell; 
984         while (!IsFirstCell(fcell)) --fcell;
985         for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
986             if (BottomLine(fcell + i))
987                 ++tmp;
988         }
989         if (tmp == NumberOfCellsInRow(fcell)) {
990                 os << "\\hline ";
991         } else {
992             tmp = 0;
993             for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
994                 if (BottomLine(fcell + i)) {
995                         os << "\\cline{"
996                            << column_of_cell(fcell + i) + 1
997                            << '-'
998                            << right_column_of_cell(fcell + i) + 1
999                            << "} ";
1000                     tmp = 1;
1001                 }
1002             }
1003         }
1004         if (tmp){
1005                 os << '\n';
1006             ++ret;
1007         }
1008         if (is_long_table)
1009                 os << "\\end{longtable}";
1010         else
1011                 os << "\\end{tabular}";
1012         if (rotate) {
1013                 os << "\n\\end{sideways}";
1014             ++ret;
1015         }
1016     } else {
1017         nvcell = NextVirtualCell(cell + 1);
1018         if (cell < 0){
1019             // preamble
1020             if (rotate) {
1021                     os << "\\begin{sideways}\n";
1022                 ++ret;
1023             }
1024             if (is_long_table)
1025                     os << "\\begin{longtable}{";
1026             else
1027                     os << "\\begin{tabular}{";
1028             for (i = 0; i < columns; ++i) {
1029                 if (column_info[i].left_line)
1030                         os << '|';
1031                 if (!column_info[i].align_special.empty()) {
1032                         os << column_info[i].align_special;
1033                 } else if (!column_info[i].p_width.empty()) {
1034                         os << "p{"
1035                            << column_info[i].p_width
1036                            << '}';
1037                 } else {
1038                     switch (column_info[i].alignment) {
1039                       case LYX_ALIGN_LEFT:
1040                               os << 'l';
1041                           break;
1042                       case LYX_ALIGN_RIGHT:
1043                               os << 'r';
1044                           break;
1045                       default:
1046                               os << 'c';
1047                           break;
1048                     }
1049                 }
1050                 if (column_info[i].right_line)
1051                         os << '|';
1052             }
1053             os << "}\n";
1054             ++ret;
1055             tmp = 0;
1056             if (GetNumberOfCells()) {
1057                 fcell = 0;
1058                 for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1059                     if (TopLine(fcell + i))
1060                         ++tmp;
1061                 }
1062                 if (tmp == NumberOfCellsInRow(fcell)){
1063                         os << "\\hline ";
1064                 } else {
1065                     tmp = 0;
1066                     for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1067                         if (TopLine(fcell + i)) {
1068                                 os << "\\cline{"
1069                                    << column_of_cell(fcell + i) + 1
1070                                    << '-'
1071                                    << right_column_of_cell(fcell + i) + 1
1072                                    << "} ";
1073                                 tmp = 1;
1074                         }
1075                     }
1076                 }
1077                 if (tmp){
1078                         os << '\n';
1079                     ++ret;
1080                 }
1081             }
1082             if (RotateCell(0)) {
1083                     os << "\\begin{sideways}\n";
1084                 ++ret;
1085             }
1086         } else {
1087             // usual cells
1088             if (Linebreaks(cell))
1089                     os << "\\smallskip{}}";
1090             if (IsMultiColumn(cell)){
1091                     os << '}';
1092             }
1093             if (RotateCell(cell)) {
1094                     os << "\n\\end{sideways}";
1095                 ++ret;
1096             }
1097             if (IsLastCell(cell)) {
1098                 int row = row_of_cell(cell);
1099                 string hline1, hline2;
1100                 bool print_hline = true;
1101                 bool flag1 = IsLongTable() &&
1102                     ((row == endhead) || (row == endfirsthead) ||
1103                      (row == endfoot) || (row == endlastfoot));
1104                 ++row;
1105                 bool flag2 = IsLongTable() &&
1106                     ((row <= endhead) || (row <= endfirsthead) ||
1107                      (row <= endfoot) || (row <= endlastfoot));
1108                 --row;
1109                 // print the bottom hline only if (otherwise it is doubled):
1110                 // - is no LongTable
1111                 // - there IS a first-header
1112                 // - the next row is no special header/footer
1113                 //   & this row is no special header/footer
1114                 // - the next row is a special header/footer
1115                 //   & this row is a special header/footer
1116                 bool pr_top_hline = (flag1 && flag2) || (!flag1 && !flag2) ||
1117                     (endfirsthead == endhead);
1118                 os << "\\\\\n";
1119                 ++ret;
1120                 tmp = 0;
1121                 fcell = cell;
1122                 while (!IsFirstCell(fcell))
1123                     --fcell;
1124                 for (i = 0; i < NumberOfCellsInRow(cell); ++i) {
1125                     if (BottomLine(fcell + i))
1126                         ++tmp;
1127                 }
1128                 if (tmp == NumberOfCellsInRow(cell)){
1129                         os << "\\hline ";
1130                     hline1 = "\\hline ";
1131                 } else {
1132                     tmp = 0;
1133                     for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1134                         if (BottomLine(fcell + i)){
1135                                 os << "\\cline{"
1136                                    << column_of_cell(fcell + i) + 1
1137                                    << '-'
1138                                    << right_column_of_cell(fcell + i) + 1
1139                                    << "} ";
1140                             hline1 += "\\cline{";
1141                             hline1 += tostr(column_of_cell(fcell + i) + 1);
1142                             hline1 += '-';
1143                             hline1 += tostr(right_column_of_cell(fcell + i) + 1);
1144                             hline1 += "} ";
1145                             tmp = 1;
1146                         }
1147                     }
1148                 }
1149                 if (tmp){
1150                         os << '\n';
1151                     ++ret;
1152                 }
1153                 if (IsLongTable() && (row == endfoot)) {
1154                         os << "\\endfoot\n";
1155                     ++ret;
1156                     print_hline = false; // no double line below footer
1157                 }
1158                 if (IsLongTable() && (row == endlastfoot)) {
1159                         os << "\\endlastfoot\n";
1160                     ++ret;
1161                     print_hline = false; // no double line below footer
1162                 }
1163                 if (IsLongTable() && row_info[row].newpage) {
1164                         os << "\\newpage\n";
1165                     ++ret;
1166                     print_hline = false; // no line below a \\newpage-command
1167                 }
1168                 tmp = 0;
1169                 if (nvcell < numberofcells
1170                     && (cell < GetNumberOfCells() - 1)
1171                     && !ShouldBeVeryLastCell(cell)) {
1172                     fcell = nvcell;
1173                     for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1174                         if (TopLine(fcell + i))
1175                             ++tmp;
1176                     }
1177                     if (tmp == NumberOfCellsInRow(fcell)) {
1178                         if (print_hline)
1179                                 os << "\\hline ";
1180                         hline2 = "\\hline ";
1181                     } else {
1182                         tmp = 0;
1183                         for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1184                             if (TopLine(fcell + i)) {
1185                                 if (print_hline) {
1186                                         os << "\\cline{"
1187                                            << column_of_cell(fcell + i) + 1
1188                                            << '-'
1189                                            << right_column_of_cell(fcell + i) + 1
1190                                            << "} ";
1191                                 }
1192                                 hline2 += "\\cline{";
1193                                 hline2 += tostr(column_of_cell(fcell+i)+1);
1194                                 hline2 += '-';
1195                                 hline2 += tostr(right_column_of_cell(fcell+i)+1);
1196                                 hline2 += "} ";
1197                                 tmp = 1;
1198                             }
1199                         }
1200                     }
1201                     if (tmp && print_hline){
1202                             os << '\n';
1203                         ++ret;
1204                     }
1205                 }
1206                 // the order here is important as if one defines two
1207                 // or more things in one line only the first entry is
1208                 // displayed the other are set to an empty-row. This
1209                 // is important if I have a footer and want that the
1210                 // lastfooter is NOT displayed!!!
1211                 bool sflag2 = (row == endhead) || (row == endfirsthead) ||
1212                     (row == endfoot) || (row == endlastfoot);
1213                 --row;
1214 //                sflag2 = IsLongTable() && (row >= 0) &&
1215 //                    (sflag2 || (row == endhead) || (row == endfirsthead));
1216                 row += 2;
1217                 bool sflag1 = IsLongTable() && (row != endhead) &&
1218                     (row != endfirsthead) &&
1219                     ((row == endfoot) || (row == endlastfoot));
1220                 --row;
1221                 if (IsLongTable() && (row == endhead)) {
1222                         os << "\\endhead\n";
1223                     ++ret;
1224                 }
1225                 if (IsLongTable() && (row == endfirsthead)) {
1226                         os << "\\endfirsthead\n";
1227                     ++ret;
1228                 }
1229                 if (sflag1) { // add the \hline for next foot row
1230                     if (!hline1.empty()) {
1231                             os << hline1 + '\n';
1232                         ++ret;
1233                     }
1234                 }
1235                 // add the \hline for the first row
1236                 if (pr_top_hline && sflag2) {
1237                     if (!hline2.empty()) {
1238                             os << hline2 + '\n';
1239                         ++ret;
1240                     }
1241                 }
1242                 if (nvcell < numberofcells && RotateCell(nvcell)) {
1243                         os << "\\begin{sideways}\n";
1244                     ++ret;
1245                 }
1246             } else {
1247                     os << "&\n";
1248                 ++ret;
1249                 if (nvcell < numberofcells && RotateCell(nvcell)) {
1250                         os << "\\begin{sideways}\n";
1251                     ++ret;
1252                 }
1253             }
1254         }
1255         if (nvcell < numberofcells && IsMultiColumn(nvcell)) {
1256                 os << "\\multicolumn{"
1257                    << cells_in_multicolumn(nvcell)
1258                    << "}{";
1259             if (!cellinfo_of_cell(cell+1)->align_special.empty()) {
1260                     os << cellinfo_of_cell(cell+1)->align_special
1261                        << "}{";
1262             } else {
1263                 if (LeftLine(nvcell))
1264                         os << '|';
1265                 if (!GetPWidth(nvcell).empty()) {
1266                         os << "p{"
1267                            << GetPWidth(nvcell)
1268                            << '}';
1269                 } else {
1270                     switch (GetAlignment(nvcell)) {
1271                     case LYX_ALIGN_LEFT: os << 'l'; break;
1272                     case LYX_ALIGN_RIGHT: os << 'r'; break;
1273                     default:  os << 'c'; break;
1274                     }
1275                 }
1276                 if (RightLine(nvcell))
1277                         os << '|';
1278                 //if (column_of_cell(cell+2)!= 0 && LeftLine(cell+2))
1279                 if (((nvcell + 1) < numberofcells) &&
1280                     (NextVirtualCell(nvcell+1) < numberofcells) &&
1281                     (column_of_cell(NextVirtualCell(nvcell+1))!= 0) &&
1282                     LeftLine(NextVirtualCell(nvcell+1)))
1283                         os << '|';
1284                 
1285                 os << "}{";
1286             }
1287         }
1288         if (nvcell < numberofcells && Linebreaks(nvcell)) {
1289 //            !column_info[column_of_cell(nvcell)].p_width.empty()) {
1290                 os << "\\parbox{"
1291                    << GetPWidth(nvcell)
1292                    << "}{\\smallskip{}";
1293         }
1294     }
1295     return ret;
1296 }
1297
1298
1299 #if 0
1300 // cell <0 will tex the preamble
1301 // returns the number of printed newlines
1302 int LyXTable::RoffEndOfCell(ostream & os, int cell)
1303 {
1304     int ret = 0;
1305
1306     if (cell == GetNumberOfCells() - 1){
1307         // the very end at the very beginning
1308         if (CellHasContRow(cell) >= 0) {
1309                 os << "\nT}";
1310             ++ret;
1311         }
1312         os << "\n";
1313         ++ret;
1314         if (row_info[row_of_cell(cell)].bottom_line) {
1315                 os << "_\n";
1316             ++ret;
1317         }
1318         os << ".TE\n.pl 1c";
1319     } else {  
1320         if (cell < 0) {
1321             int fcell = 0;
1322             // preamble
1323             os << "\n.pl 500c\n.TS\n";
1324             for (int j = 0; j < rows; ++j) {
1325                 for (int i = 0; i < columns; ++i, ++fcell) {
1326                     if (column_info[i].left_line)
1327                             os << " | ";
1328                     if (cell_info[j][i].multicolumn == CELL_PART_OF_MULTICOLUMN)
1329                             os << "s";
1330                     else {
1331                         switch (column_info[i].alignment) {
1332                           case LYX_ALIGN_LEFT:
1333                                   os << "l";
1334                               break;
1335                           case LYX_ALIGN_RIGHT:
1336                                   os << "r";
1337                               break;
1338                           default:
1339                                   os << "c";
1340                               break;
1341                         }
1342                     }
1343                     if (!column_info[i].p_width.empty())
1344                             os << "w(" << column_info[i].p_width << ")";
1345                     if (column_info[i].right_line)
1346                             os << " | ";
1347                 }
1348                 if ((j + 1) < rows) {
1349                         os << "\n";
1350                     ++ret;
1351                 }
1352             }
1353             os << ".\n";
1354             ++ret;
1355             if (row_info[0].top_line) {
1356                     os << "_\n";
1357                 ++ret;
1358             }
1359             if (CellHasContRow(0) >= 0) {
1360                     os << "T{\n";
1361                 ++ret;
1362             }
1363         } else {
1364             // usual cells
1365             if (CellHasContRow(cell) >= 0) {
1366                     os << "\nT}";
1367                 ++ret;
1368             }
1369             if (right_column_of_cell(cell) == columns -1){
1370                     os << "\n";
1371                 ++ret;
1372                 int row = row_of_cell(cell);
1373                 if (row_info[row++].bottom_line) {
1374                         os << "_\n";
1375                     ++ret;
1376                 }
1377                 if ((row < rows) && row_info[row].top_line) {
1378                         os << "_\n";
1379                     ++ret;
1380                 }
1381             } else
1382                     os << "\t";
1383             if ((cell < GetNumberOfCells() - 1) &&
1384                 (CellHasContRow(cell+1) >= 0)) {
1385                     os << "T{\n";
1386                 ++ret;
1387             }
1388         }
1389     }
1390     return ret;
1391 }
1392 #endif
1393
1394
1395 char const *LyXTable::getDocBookAlign(int cell, bool isColumn)
1396 {
1397     int i;
1398     if (isColumn)
1399        i = cell;
1400     else
1401        i = column_of_cell(cell);
1402     if (!isColumn && IsMultiColumn(cell)) {
1403        if (!cellinfo_of_cell(cell)->align_special.empty()) {
1404            return cellinfo_of_cell(cell)->align_special.c_str();
1405        } else {
1406            switch (GetAlignment(cell)) {
1407            case LYX_ALIGN_LEFT:
1408                return "left";
1409            case LYX_ALIGN_RIGHT:
1410                return "right";
1411            default:
1412                return "center";
1413            }
1414        }
1415     } else {
1416        if (!column_info[i].align_special.empty()) {
1417            return column_info[i].align_special.c_str();
1418        }
1419 #ifdef IGNORE_THIS_FOR_NOW
1420        else if (!column_info[i].p_width.empty()) {
1421            file += "p{";
1422            file += column_info[i].p_width;
1423            file += '}';
1424        }
1425 #endif
1426        else {
1427            switch (column_info[i].alignment) {
1428            case LYX_ALIGN_LEFT:
1429                return "left";
1430            case LYX_ALIGN_RIGHT:
1431                return "right";
1432            default:
1433                return "center";
1434            }
1435        }
1436     }
1437 }
1438
1439
1440 // cell <0 will tex the preamble
1441 // returns the number of printed newlines
1442 int LyXTable::DocBookEndOfCell(ostream & os, int cell, int & depth)
1443 {
1444     int i;
1445     int ret = 0;
1446     //int tmp; // tmp2; // unused
1447     int nvcell; // fcell; // unused
1448     if (ShouldBeVeryLastCell(cell)) {
1449             os << newlineAndDepth(--depth)
1450                << "</ENTRY>"
1451                << newlineAndDepth(--depth)
1452                << "</ROW>"
1453                << newlineAndDepth(--depth)
1454                << "</TBODY>"
1455                << newlineAndDepth(--depth);
1456         if (is_long_table)
1457                 os << "</TGROUP>";
1458         else
1459                 os << "</TGROUP>"
1460                    << newlineAndDepth(--depth);
1461         ret += 4;
1462     } else {
1463         nvcell = NextVirtualCell(cell + 1);
1464         if (cell < 0) {
1465             // preamble
1466             if (is_long_table)
1467                     os << "<TGROUP ";
1468             else
1469                     os << "<TGROUP ";
1470             os << "COLS='"
1471                << columns
1472                << "' COLSEP='1' ROWSEP='1'>"
1473                << newlineAndDepth(++depth);
1474             ++ret;
1475             for (i = 0; i < columns; ++i) {
1476                     os << "<COLSPEC ALIGN='"
1477                        << getDocBookAlign(i, true)
1478                        << "' COLNAME='col"
1479                        << i + 1
1480                        << "' COLNUM='"
1481                        << i + 1
1482                        << "' COLSEP='";
1483                if (i == (columns-1)) {
1484                        os << '1';
1485                } else {
1486                    if (column_info[i].right_line ||
1487                        column_info[i+1].left_line)
1488                            os << '1';
1489                    else
1490                            os << '0';
1491                }
1492                os << "'>"
1493                   << newlineAndDepth(depth);
1494                 ++ret;
1495 #ifdef NOT_HANDLED_YET_AS_I_DONT_KNOW_HOW
1496                 if (column_info[i].left_line)
1497                         os << '|';
1498 #endif
1499             }
1500             os << "<TBODY>"
1501                << newlineAndDepth(++depth)
1502                << "<ROW>"
1503                << newlineAndDepth(++depth)
1504                << "<ENTRY ALIGN='"
1505                << getDocBookAlign(0)
1506                << "'";
1507            if (IsMultiColumn(0)) {
1508                    os << " NAMEST='col1' NAMEEND='col"
1509                       << cells_in_multicolumn(0)
1510                       << "'";
1511            }
1512            os << ">"
1513               << newlineAndDepth(++depth);
1514             ret += 3;
1515         } else {
1516             if (IsLastCell(cell)) {
1517                     os << newlineAndDepth(--depth)
1518                        << "</ENTRY>"
1519                        << newlineAndDepth(--depth)
1520                        << "</ROW>"
1521                        << newlineAndDepth(depth)
1522                        << "<ROW>"
1523                        << newlineAndDepth(++depth)
1524                        << "<ENTRY ALIGN='"
1525                        << getDocBookAlign(cell + 1)
1526                        << "' VALIGN='middle'";
1527                if (IsMultiColumn(cell + 1)) {
1528                        os << " NAMEST='col"
1529                           << column_of_cell(cell+1) + 1
1530                           << "' NAMEEND='col"
1531                           << column_of_cell(cell + 1) +
1532                                cells_in_multicolumn(cell + 1)
1533                           << "'";
1534                }
1535                os << ">"
1536                   << newlineAndDepth(++depth);
1537                 ret += 4;
1538             } else {
1539                     os << newlineAndDepth(--depth)
1540                        << "</ENTRY>"
1541                        << newlineAndDepth(depth)
1542                        << "<ENTRY ALIGN='"
1543                        << getDocBookAlign(cell + 1)
1544                        << "' VALIGN='middle'";
1545                if (IsMultiColumn(cell + 1)) {
1546                        os << " NAMEST='col"
1547                           << column_of_cell(cell+1) + 1
1548                           << "' NAMEEND='col"
1549                           << column_of_cell(cell+1) +
1550                                cells_in_multicolumn(cell+1)
1551                           << "'";
1552                }
1553                os << ">"
1554                   << newlineAndDepth(++depth);
1555                 ret += 3;
1556             }
1557         }
1558     }
1559     return ret;
1560 }
1561
1562
1563 bool LyXTable::IsMultiColumn(int cell)
1564 {
1565     int fvcell = FirstVirtualCell(cell);
1566
1567     return (cellinfo_of_cell(fvcell)->multicolumn != LyXTable::CELL_NORMAL);
1568 }
1569
1570
1571 LyXTable::cellstruct* LyXTable::cellinfo_of_cell(int cell)
1572 {
1573     int row = row_of_cell(cell);
1574     int column = column_of_cell(cell);
1575     return  &cell_info[row][column];
1576 }
1577    
1578
1579 void LyXTable::SetMultiColumn(int cell, int number)
1580 {
1581     int fvcell = FirstVirtualCell(cell);
1582     int new_width = cellinfo_of_cell(fvcell)->width_of_cell;
1583     
1584     cellinfo_of_cell(fvcell)->multicolumn = LyXTable::CELL_BEGIN_OF_MULTICOLUMN;
1585     cellinfo_of_cell(fvcell)->alignment = column_info[column_of_cell(fvcell)].alignment;
1586     cellinfo_of_cell(fvcell)->top_line = row_info[row_of_cell(fvcell)].top_line;
1587     cellinfo_of_cell(fvcell)->bottom_line = row_info[row_of_cell(fvcell)].bottom_line;
1588     for (number--; number > 0; --number) {
1589         cellinfo_of_cell(fvcell+number)->multicolumn = 
1590             LyXTable::CELL_PART_OF_MULTICOLUMN;
1591         new_width += cellinfo_of_cell(fvcell+number)->width_of_cell;
1592     }
1593     set_row_column_number_info();
1594     SetWidthOfCell(fvcell, new_width);
1595 }
1596
1597
1598 int LyXTable::cells_in_multicolumn(int cell)
1599 {
1600     int row = row_of_cell(cell);
1601     int column = column_of_cell(cell);
1602     int result = 1;
1603     ++column;
1604     while (column < columns && cell_info[row][column].multicolumn
1605            == LyXTable::CELL_PART_OF_MULTICOLUMN){
1606         ++result;
1607         ++column;
1608     }
1609     return result;
1610 }
1611
1612
1613 int  LyXTable::UnsetMultiColumn(int cell)
1614 {
1615     int fvcell = FirstVirtualCell(cell);
1616     int row = row_of_cell(fvcell);
1617     int column = column_of_cell(fvcell);
1618     
1619     int result = 0;
1620     
1621     if (cell_info[row][column].multicolumn
1622         == LyXTable::CELL_BEGIN_OF_MULTICOLUMN){
1623         cell_info[row][column].multicolumn = LyXTable::CELL_NORMAL;
1624         ++column;
1625         while (column < columns &&
1626                cell_info[row][column].multicolumn
1627                == LyXTable::CELL_PART_OF_MULTICOLUMN){
1628             cell_info[row][column].multicolumn = 
1629                 LyXTable::CELL_NORMAL;
1630             ++column;
1631             ++result;
1632         }
1633     }
1634     set_row_column_number_info();
1635     return result;
1636 }
1637
1638
1639 void LyXTable::delete_column(int column)
1640 {
1641     int i, j;
1642     columnstruct * column_info2 = new columnstruct[columns-1];
1643    
1644     for (i = 0; i < column; ++i) {
1645         column_info2[i] = column_info[i];
1646     }
1647     for (i = column; i < columns - 1; ++i) {
1648         column_info2[i] = column_info[i + 1];
1649     }
1650    
1651     delete[] column_info;
1652     column_info = column_info2;
1653
1654     for (i = 0; i < rows; ++i) {
1655         cellstruct * tmp = cell_info[i];
1656         cell_info[i] = new cellstruct[columns - 1];
1657         for (j = 0; j < column; ++j) {
1658             cell_info[i][j] = tmp[j];
1659         }
1660         for (j = column; j < columns - 1; ++j) {
1661             cell_info[i][j] = tmp[j + 1];
1662         }
1663         delete[] tmp;
1664     }
1665
1666     --columns;
1667     Reinit();
1668 }
1669
1670
1671 void LyXTable::SetLongTable(int what)
1672 {
1673     is_long_table = what;
1674 }
1675
1676
1677 bool LyXTable::IsLongTable()
1678 {
1679     return is_long_table;
1680 }
1681
1682 void LyXTable::SetRotateTable(int what)
1683 {
1684     rotate = what;
1685 }
1686
1687 bool LyXTable::RotateTable()
1688 {
1689     return rotate;
1690 }
1691
1692 void LyXTable::SetRotateCell(int cell, int what)
1693 {
1694     cellinfo_of_cell(cell)->rotate = what;
1695 }
1696
1697 bool LyXTable::RotateCell(int cell)
1698 {
1699     return cellinfo_of_cell(cell)->rotate;
1700 }
1701
1702 bool LyXTable::NeedRotating()
1703 {
1704     if (rotate)
1705         return true;
1706     for (int i = 0; i < rows; ++i) {
1707         for (int j = 0; j < columns; ++j) {
1708             if (cell_info[i][j].rotate)
1709                 return true;
1710         }
1711     }
1712     return false;
1713 }
1714
1715 void LyXTable::AppendContRow(int cell)
1716 {
1717     int row = row_of_cell(cell)+1;
1718
1719     if (!RowHasContRow(cell) || (CellHasContRow(cell)>= 0))
1720         AppendRow(cell);
1721     row_info[row].is_cont_row = true;
1722     row_info[row].top_line = false;
1723     cell_info[row-1][column_of_cell(cell)].has_cont_row = true;
1724     Reinit();
1725 }
1726
1727 bool LyXTable::IsContRow(int cell)
1728 {
1729     return row_info[row_of_cell(cell)].is_cont_row;
1730 }
1731
1732 int LyXTable::CellHasContRow(int cell)
1733 {
1734     int row = row_of_cell(cell);
1735
1736     if (VeryLastRow(cell))
1737         return -1;
1738     if (cell_info[row][column_of_cell(cell)].has_cont_row)
1739         return cell_info[row+1][column_of_cell(cell)].cellno;
1740     return -1;
1741 }
1742
1743 bool LyXTable::RowHasContRow(int cell)
1744 {
1745     int row = row_of_cell(cell) + 1;
1746
1747     if (row < rows)
1748         return row_info[row].is_cont_row;
1749     return false;
1750 }
1751
1752 int LyXTable::FirstVirtualCell(int cell)
1753 {
1754     if (!IsContRow(cell))
1755         return cell;
1756     int row = row_of_cell(cell);
1757     int column = column_of_cell(cell);
1758     for(; (row > 0) && IsContRow(cell_info[row][column].cellno); --row)
1759         ;
1760     return cell_info[row][column].cellno;
1761 }
1762
1763
1764 int LyXTable::NextVirtualCell(int cell)
1765 {
1766     if (!IsContRow(cell))
1767         return cell;
1768     int row = row_of_cell(cell);
1769     for(;(row < rows - 1) && IsContRow(cell_info[row][0].cellno); ++row)
1770         ;
1771     // what if(row >= rows) ?
1772     return cell_info[row][0].cellno;
1773 }
1774
1775
1776 bool LyXTable::ShouldBeVeryLastCell(int cell)
1777 // "very last cell" ..of what? the row? the table?
1778 // "Cell" in this context appears to not count `virtual' cells
1779 {
1780     int fcell = cell + 1;
1781
1782     if (cell == GetNumberOfCells() - 1)
1783         return true; // not really sure if I should return false here
1784     if (!IsContRow(fcell))
1785         return false;
1786     while((fcell < GetNumberOfCells() - 1) && IsContRow(fcell))
1787         ++fcell;
1788     if (fcell < GetNumberOfCells() - 1)
1789         return false;
1790     return true;
1791 }
1792
1793 bool LyXTable::ShouldBeVeryLastRow(int cell)
1794 {
1795     if (CellHasContRow(cell)>= 0)
1796         return false;
1797     int row = row_of_cell(cell) + 1;
1798     int column = column_of_cell(cell);
1799     while((row < rows) && IsContRow(cell_info[row][column].cellno))
1800         ++row;
1801     if (row < rows)
1802         return false; // found another valid row
1803     // I do not have any valid row after the actual
1804     return true;
1805 }
1806
1807 int LyXTable::GetCellAbove(int cell)
1808 {
1809     int row = row_of_cell(cell);
1810     
1811     if (row > 0)
1812         return cell_info[row-1][column_of_cell(cell)].cellno;
1813     return cell;
1814 }
1815
1816 int LyXTable::GetCellNumber(int column, int row)
1817 {
1818     if (column >= columns)
1819         column = columns - 1;
1820     else if (column < 0)
1821         column = 0;
1822     if (row >= rows)
1823         row = rows - 1;
1824     else if (row < 0)
1825         row = 0;
1826     
1827     return cell_info[row][column].cellno;
1828 }
1829
1830 void LyXTable::SetLinebreaks(int cell, bool what)
1831 {
1832     cellinfo_of_cell(FirstVirtualCell(cell))->linebreaks = what;
1833 }
1834
1835 bool LyXTable::Linebreaks(int cell)
1836 {
1837     int fvcell = FirstVirtualCell(cell);
1838
1839     if (column_info[column_of_cell(fvcell)].p_width.empty() &&
1840         !(IsMultiColumn(fvcell) && !cellinfo_of_cell(fvcell)->p_width.empty()))
1841         return false;
1842     return cellinfo_of_cell(fvcell)->linebreaks;
1843 }
1844
1845 void LyXTable::SetLTHead(int cell, bool first)
1846 {
1847     int row = row_of_cell(cell);
1848
1849     if (first) {
1850         if (row == endfirsthead)
1851             endfirsthead = -1;
1852         else
1853             endfirsthead = row;
1854     } else {
1855         if (row == endhead)
1856             endhead = -1;
1857         else
1858             endhead = row;
1859     }
1860 }
1861
1862 bool LyXTable::RowOfLTHead(int cell)
1863 {
1864     if ((endhead+1) > rows)
1865         endhead = -1;
1866     return (row_of_cell(cell) == endhead);
1867 }
1868
1869 bool LyXTable::RowOfLTFirstHead(int cell)
1870 {
1871     if ((endfirsthead+1) > rows)
1872         endfirsthead = -1;
1873     return (row_of_cell(cell) == endfirsthead);
1874 }
1875
1876 void LyXTable::SetLTFoot(int cell, bool last)
1877 {
1878     int row = row_of_cell(cell);
1879
1880     if (last) {
1881         if (row == endlastfoot)
1882             endlastfoot = -1;
1883         else
1884             endlastfoot = row;
1885     } else {
1886         if (row == endfoot)
1887             endfoot = -1;
1888         else
1889             endfoot = row;
1890     }
1891 }
1892
1893 bool LyXTable::RowOfLTFoot(int cell)
1894 {
1895     if ((endfoot+1) > rows) {
1896         endfoot = -1;
1897         return false;
1898     }
1899     return (row_of_cell(cell) == endfoot);
1900 }
1901
1902 bool LyXTable::RowOfLTLastFoot(int cell)
1903 {
1904     if ((endlastfoot+1) > rows)
1905         endlastfoot = -1;
1906     return (row_of_cell(cell) == endlastfoot);
1907 }
1908
1909 void LyXTable::SetLTNewPage(int cell, bool what)
1910 {
1911     row_info[row_of_cell(cell)].newpage = what;
1912 }
1913
1914 bool LyXTable::LTNewPage(int cell)
1915 {
1916     return row_info[row_of_cell(cell)].newpage;
1917 }