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