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