]> git.lyx.org Git - lyx.git/blob - src/table.C
Angus insetindex patch + protect patch from Dekel
[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         while(!s.length())
981             getline(is, s);
982         if (s.length() > 8)
983                 version = atoi(s.c_str() + 8);
984         else
985                 version = 1;
986         if (version < 5) {
987                 lyxerr << "Tabular format < 5 is not supported anymore\n"
988                         "Get an older version of LyX (< 1.1.x) for conversion!"
989                        << endl;
990                 WriteAlert(_("Warning:"),
991                            _("Tabular format < 5 is not supported anymore\n"),
992                            _("Get an older version of LyX (< 1.1.x) for conversion!"));
993                 if (version > 2) {
994                         is >> rows_arg >> columns_arg >> is_long_table_arg
995                            >> rotate_arg >> a >> b >> c >> d;
996                 } else
997                         is >> rows_arg >> columns_arg;
998                 Init(rows_arg, columns_arg);
999                 SetLongTable(is_long_table_arg);
1000                 SetRotateTable(rotate_arg);
1001                 string tmp;
1002                 for (i = 0; i < rows; ++i) {
1003                         getline(is, tmp);
1004                 }
1005                 for (i = 0; i < columns; ++i) {
1006                         getline(is, tmp);
1007                 }
1008                 for (i = 0; i < rows; ++i) {
1009                         for (j = 0; j < columns; ++j) {
1010                                 getline(is, tmp);
1011                         }
1012                 }
1013                 set_row_column_number_info();
1014                 return;
1015         }
1016         is >> rows_arg >> columns_arg >> is_long_table_arg
1017            >> rotate_arg >> a >> b >> c >> d;
1018         Init(rows_arg, columns_arg);
1019         SetLongTable(is_long_table_arg);
1020         SetRotateTable(rotate_arg);
1021         endhead = a;
1022         endfirsthead = b;
1023         endfoot = c;
1024         endlastfoot = d;
1025         for (i = 0; i < rows; ++i) {
1026                 a = b = c = d = e = f = g = h = 0;
1027                 is >> a >> b >> c >> d;
1028                 row_info[i].top_line = a;
1029                 row_info[i].bottom_line = b;
1030                 row_info[i].is_cont_row = c;
1031                 row_info[i].newpage = d;
1032         }
1033         for (i = 0; i < columns; ++i) {
1034                 string s1;
1035                 string s2;
1036                 is >> a >> b >> c;
1037                 char ch; // skip '"'
1038                 is >> ch;
1039                 getline(is, s1, '"');
1040                 is >> ch; // skip '"'
1041                 getline(is, s2, '"');
1042                 column_info[i].alignment = static_cast<char>(a);
1043                 column_info[i].left_line = b;
1044                 column_info[i].right_line = c;
1045                 column_info[i].p_width = s1;
1046                 column_info[i].align_special = s2;
1047         }
1048         for (i = 0; i < rows; ++i) {
1049                 for (j = 0; j < columns; ++j) {
1050                         string s1;
1051                         string s2;
1052                         is >> a >> b >> c >> d >> e >> f >> g;
1053                         char ch;
1054                         is >> ch; // skip '"'
1055                         getline(is, s1, '"');
1056                         is >> ch; // skip '"'
1057                         getline(is, s2, '"');
1058                         cell_info[i][j].multicolumn = static_cast<char>(a);
1059                         cell_info[i][j].alignment = static_cast<char>(b);
1060                         cell_info[i][j].top_line = static_cast<char>(c);
1061                         cell_info[i][j].bottom_line = static_cast<char>(d);
1062                         cell_info[i][j].has_cont_row = static_cast<bool>(e);
1063                         cell_info[i][j].rotate = static_cast<bool>(f);
1064                         cell_info[i][j].linebreaks = static_cast<bool>(g);
1065                         cell_info[i][j].align_special = s1;
1066                         cell_info[i][j].p_width = s2;
1067                 }
1068         }
1069         set_row_column_number_info();
1070 }
1071
1072
1073 // cell <0 will tex the preamble
1074 // returns the number of printed newlines
1075 int LyXTable::TexEndOfCell(ostream & os, int cell)
1076 {
1077     int i;
1078     int ret = 0;
1079     int tmp; // tmp2;
1080     int fcell, nvcell;
1081     if (ShouldBeVeryLastCell(cell)) {
1082         // the very end at the very beginning
1083         if (Linebreaks(cell))
1084                 os << "\\smallskip{}}";
1085         if (IsMultiColumn(cell))
1086                 os << '}';
1087         if (RotateCell(cell)) {
1088                 os << "\n\\end{sideways}";
1089             ++ret;
1090         }
1091         os << "\\\\\n";
1092         ++ret;
1093     
1094         tmp = 0;
1095         fcell = cell; 
1096         while (!IsFirstCell(fcell)) --fcell;
1097         for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1098             if (BottomLine(fcell + i))
1099                 ++tmp;
1100         }
1101         if (tmp == NumberOfCellsInRow(fcell)) {
1102                 os << "\\hline ";
1103         } else {
1104             tmp = 0;
1105             for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1106                 if (BottomLine(fcell + i)) {
1107                         os << "\\cline{"
1108                            << column_of_cell(fcell + i) + 1
1109                            << '-'
1110                            << right_column_of_cell(fcell + i) + 1
1111                            << "} ";
1112                     tmp = 1;
1113                 }
1114             }
1115         }
1116         if (tmp){
1117                 os << '\n';
1118             ++ret;
1119         }
1120         if (is_long_table)
1121                 os << "\\end{longtable}";
1122         else
1123                 os << "\\end{tabular}";
1124         if (rotate) {
1125                 os << "\n\\end{sideways}";
1126             ++ret;
1127         }
1128     } else {
1129         nvcell = NextVirtualCell(cell + 1);
1130         if (cell < 0){
1131             // preamble
1132             if (rotate) {
1133                     os << "\\begin{sideways}\n";
1134                 ++ret;
1135             }
1136             if (is_long_table)
1137                     os << "\\begin{longtable}{";
1138             else
1139                     os << "\\begin{tabular}{";
1140             for (i = 0; i < columns; ++i) {
1141                 if (column_info[i].left_line)
1142                         os << '|';
1143                 if (!column_info[i].align_special.empty()) {
1144                         os << column_info[i].align_special;
1145                 } else if (!column_info[i].p_width.empty()) {
1146                         os << "p{"
1147                            << column_info[i].p_width
1148                            << '}';
1149                 } else {
1150                     switch (column_info[i].alignment) {
1151                       case LYX_ALIGN_LEFT:
1152                               os << 'l';
1153                           break;
1154                       case LYX_ALIGN_RIGHT:
1155                               os << 'r';
1156                           break;
1157                       default:
1158                               os << 'c';
1159                           break;
1160                     }
1161                 }
1162                 if (column_info[i].right_line)
1163                         os << '|';
1164             }
1165             os << "}\n";
1166             ++ret;
1167             tmp = 0;
1168             if (GetNumberOfCells()) {
1169                 fcell = 0;
1170                 for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1171                     if (TopLine(fcell + i))
1172                         ++tmp;
1173                 }
1174                 if (tmp == NumberOfCellsInRow(fcell)){
1175                         os << "\\hline ";
1176                 } else {
1177                     tmp = 0;
1178                     for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1179                         if (TopLine(fcell + i)) {
1180                                 os << "\\cline{"
1181                                    << column_of_cell(fcell + i) + 1
1182                                    << '-'
1183                                    << right_column_of_cell(fcell + i) + 1
1184                                    << "} ";
1185                                 tmp = 1;
1186                         }
1187                     }
1188                 }
1189                 if (tmp){
1190                         os << '\n';
1191                     ++ret;
1192                 }
1193             }
1194             if (RotateCell(0)) {
1195                     os << "\\begin{sideways}\n";
1196                 ++ret;
1197             }
1198         } else {
1199             // usual cells
1200             if (Linebreaks(cell))
1201                     os << "\\smallskip{}}";
1202             if (IsMultiColumn(cell)){
1203                     os << '}';
1204             }
1205             if (RotateCell(cell)) {
1206                     os << "\n\\end{sideways}";
1207                 ++ret;
1208             }
1209             if (IsLastCell(cell)) {
1210                 int row = row_of_cell(cell);
1211                 string hline1, hline2;
1212                 bool print_hline = true;
1213                 bool flag1 = IsLongTable() &&
1214                     ((row == endhead) || (row == endfirsthead) ||
1215                      (row == endfoot) || (row == endlastfoot));
1216                 ++row;
1217                 bool flag2 = IsLongTable() &&
1218                     ((row <= endhead) || (row <= endfirsthead) ||
1219                      (row <= endfoot) || (row <= endlastfoot));
1220                 --row;
1221                 // print the bottom hline only if (otherwise it is doubled):
1222                 // - is no LongTable
1223                 // - there IS a first-header
1224                 // - the next row is no special header/footer
1225                 //   & this row is no special header/footer
1226                 // - the next row is a special header/footer
1227                 //   & this row is a special header/footer
1228                 bool pr_top_hline = (flag1 && flag2) || (!flag1 && !flag2) ||
1229                     (endfirsthead == endhead);
1230                 os << "\\\\\n";
1231                 ++ret;
1232                 tmp = 0;
1233                 fcell = cell;
1234                 while (!IsFirstCell(fcell))
1235                     --fcell;
1236                 for (i = 0; i < NumberOfCellsInRow(cell); ++i) {
1237                     if (BottomLine(fcell + i))
1238                         ++tmp;
1239                 }
1240                 if (tmp == NumberOfCellsInRow(cell)){
1241                         os << "\\hline ";
1242                     hline1 = "\\hline ";
1243                 } else {
1244                     tmp = 0;
1245                     for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1246                         if (BottomLine(fcell + i)){
1247                                 os << "\\cline{"
1248                                    << column_of_cell(fcell + i) + 1
1249                                    << '-'
1250                                    << right_column_of_cell(fcell + i) + 1
1251                                    << "} ";
1252                             hline1 += "\\cline{";
1253                             hline1 += tostr(column_of_cell(fcell + i) + 1);
1254                             hline1 += '-';
1255                             hline1 += tostr(right_column_of_cell(fcell + i) + 1);
1256                             hline1 += "} ";
1257                             tmp = 1;
1258                         }
1259                     }
1260                 }
1261                 if (tmp){
1262                         os << '\n';
1263                     ++ret;
1264                 }
1265                 if (IsLongTable() && (row == endfoot)) {
1266                         os << "\\endfoot\n";
1267                     ++ret;
1268                     print_hline = false; // no double line below footer
1269                 }
1270                 if (IsLongTable() && (row == endlastfoot)) {
1271                         os << "\\endlastfoot\n";
1272                     ++ret;
1273                     print_hline = false; // no double line below footer
1274                 }
1275                 if (IsLongTable() && row_info[row].newpage) {
1276                         os << "\\newpage\n";
1277                     ++ret;
1278                     print_hline = false; // no line below a \\newpage-command
1279                 }
1280                 tmp = 0;
1281                 if (nvcell < numberofcells
1282                     && (cell < GetNumberOfCells() - 1)
1283                     && !ShouldBeVeryLastCell(cell)) {
1284                     fcell = nvcell;
1285                     for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1286                         if (TopLine(fcell + i))
1287                             ++tmp;
1288                     }
1289                     if (tmp == NumberOfCellsInRow(fcell)) {
1290                         if (print_hline)
1291                                 os << "\\hline ";
1292                         hline2 = "\\hline ";
1293                     } else {
1294                         tmp = 0;
1295                         for (i = 0; i < NumberOfCellsInRow(fcell); ++i) {
1296                             if (TopLine(fcell + i)) {
1297                                 if (print_hline) {
1298                                         os << "\\cline{"
1299                                            << column_of_cell(fcell + i) + 1
1300                                            << '-'
1301                                            << right_column_of_cell(fcell + i) + 1
1302                                            << "} ";
1303                                 }
1304                                 hline2 += "\\cline{";
1305                                 hline2 += tostr(column_of_cell(fcell+i)+1);
1306                                 hline2 += '-';
1307                                 hline2 += tostr(right_column_of_cell(fcell+i)+1);
1308                                 hline2 += "} ";
1309                                 tmp = 1;
1310                             }
1311                         }
1312                     }
1313                     if (tmp && print_hline){
1314                             os << '\n';
1315                         ++ret;
1316                     }
1317                 }
1318                 // the order here is important as if one defines two
1319                 // or more things in one line only the first entry is
1320                 // displayed the other are set to an empty-row. This
1321                 // is important if I have a footer and want that the
1322                 // lastfooter is NOT displayed!!!
1323                 bool sflag2 = (row == endhead) || (row == endfirsthead) ||
1324                     (row == endfoot) || (row == endlastfoot);
1325                 --row;
1326 //                sflag2 = IsLongTable() && (row >= 0) &&
1327 //                    (sflag2 || (row == endhead) || (row == endfirsthead));
1328                 row += 2;
1329                 bool sflag1 = IsLongTable() && (row != endhead) &&
1330                     (row != endfirsthead) &&
1331                     ((row == endfoot) || (row == endlastfoot));
1332                 --row;
1333                 if (IsLongTable() && (row == endhead)) {
1334                         os << "\\endhead\n";
1335                     ++ret;
1336                 }
1337                 if (IsLongTable() && (row == endfirsthead)) {
1338                         os << "\\endfirsthead\n";
1339                     ++ret;
1340                 }
1341                 if (sflag1) { // add the \hline for next foot row
1342                     if (!hline1.empty()) {
1343                             os << hline1 + '\n';
1344                         ++ret;
1345                     }
1346                 }
1347                 // add the \hline for the first row
1348                 if (pr_top_hline && sflag2) {
1349                     if (!hline2.empty()) {
1350                             os << hline2 + '\n';
1351                         ++ret;
1352                     }
1353                 }
1354                 if (nvcell < numberofcells && RotateCell(nvcell)) {
1355                         os << "\\begin{sideways}\n";
1356                     ++ret;
1357                 }
1358             } else {
1359                     os << "&\n";
1360                 ++ret;
1361                 if (nvcell < numberofcells && RotateCell(nvcell)) {
1362                         os << "\\begin{sideways}\n";
1363                     ++ret;
1364                 }
1365             }
1366         }
1367         if (nvcell < numberofcells && IsMultiColumn(nvcell)) {
1368                 os << "\\multicolumn{"
1369                    << cells_in_multicolumn(nvcell)
1370                    << "}{";
1371             if (!cellinfo_of_cell(nvcell)->align_special.empty()) {
1372                     os << cellinfo_of_cell(nvcell)->align_special
1373                        << "}{";
1374             } else {
1375                 if (LeftLine(nvcell))
1376                         os << '|';
1377                 if (!GetPWidth(nvcell).empty()) {
1378                         os << "p{"
1379                            << GetPWidth(nvcell)
1380                            << '}';
1381                 } else {
1382                     switch (GetAlignment(nvcell)) {
1383                     case LYX_ALIGN_LEFT: os << 'l'; break;
1384                     case LYX_ALIGN_RIGHT: os << 'r'; break;
1385                     default:  os << 'c'; break;
1386                     }
1387                 }
1388                 if (RightLine(nvcell))
1389                         os << '|';
1390                 //if (column_of_cell(cell+2)!= 0 && LeftLine(cell+2))
1391                 if (((nvcell + 1) < numberofcells) &&
1392                     (NextVirtualCell(nvcell+1) < numberofcells) &&
1393                     (column_of_cell(NextVirtualCell(nvcell+1))!= 0) &&
1394                     LeftLine(NextVirtualCell(nvcell+1)))
1395                         os << '|';
1396                 
1397                 os << "}{";
1398             }
1399         }
1400         if (nvcell < numberofcells && Linebreaks(nvcell)) {
1401                 os << "\\parbox[t]{"
1402                    << GetPWidth(nvcell)
1403                    << "}{\\smallskip{}";
1404         }
1405     }
1406     return ret;
1407 }
1408
1409
1410 #if 0
1411 // cell <0 will tex the preamble
1412 // returns the number of printed newlines
1413 int LyXTable::RoffEndOfCell(ostream & os, int cell)
1414 {
1415     int ret = 0;
1416
1417     if (cell == GetNumberOfCells() - 1){
1418         // the very end at the very beginning
1419         if (CellHasContRow(cell) >= 0) {
1420                 os << "\nT}";
1421             ++ret;
1422         }
1423         os << "\n";
1424         ++ret;
1425         if (row_info[row_of_cell(cell)].bottom_line) {
1426                 os << "_\n";
1427             ++ret;
1428         }
1429         os << ".TE\n.pl 1c";
1430     } else {  
1431         if (cell < 0) {
1432             int fcell = 0;
1433             // preamble
1434             os << "\n.pl 500c\n.TS\n";
1435             for (int j = 0; j < rows; ++j) {
1436                 for (int i = 0; i < columns; ++i, ++fcell) {
1437                     if (column_info[i].left_line)
1438                             os << " | ";
1439                     if (cell_info[j][i].multicolumn == CELL_PART_OF_MULTICOLUMN)
1440                             os << "s";
1441                     else {
1442                         switch (column_info[i].alignment) {
1443                           case LYX_ALIGN_LEFT:
1444                                   os << "l";
1445                               break;
1446                           case LYX_ALIGN_RIGHT:
1447                                   os << "r";
1448                               break;
1449                           default:
1450                                   os << "c";
1451                               break;
1452                         }
1453                     }
1454                     if (!column_info[i].p_width.empty())
1455                             os << "w(" << column_info[i].p_width << ")";
1456                     if (column_info[i].right_line)
1457                             os << " | ";
1458                 }
1459                 if ((j + 1) < rows) {
1460                         os << "\n";
1461                     ++ret;
1462                 }
1463             }
1464             os << ".\n";
1465             ++ret;
1466             if (row_info[0].top_line) {
1467                     os << "_\n";
1468                 ++ret;
1469             }
1470             if (CellHasContRow(0) >= 0) {
1471                     os << "T{\n";
1472                 ++ret;
1473             }
1474         } else {
1475             // usual cells
1476             if (CellHasContRow(cell) >= 0) {
1477                     os << "\nT}";
1478                 ++ret;
1479             }
1480             if (right_column_of_cell(cell) == columns -1){
1481                     os << "\n";
1482                 ++ret;
1483                 int row = row_of_cell(cell);
1484                 if (row_info[row++].bottom_line) {
1485                         os << "_\n";
1486                     ++ret;
1487                 }
1488                 if ((row < rows) && row_info[row].top_line) {
1489                         os << "_\n";
1490                     ++ret;
1491                 }
1492             } else
1493                     os << "\t";
1494             if ((cell < GetNumberOfCells() - 1) &&
1495                 (CellHasContRow(cell+1) >= 0)) {
1496                     os << "T{\n";
1497                 ++ret;
1498             }
1499         }
1500     }
1501     return ret;
1502 }
1503 #endif
1504
1505
1506 char const *LyXTable::getDocBookAlign(int cell, bool isColumn)
1507 {
1508     int i;
1509     if (isColumn)
1510        i = cell;
1511     else
1512        i = column_of_cell(cell);
1513     if (!isColumn && IsMultiColumn(cell)) {
1514        if (!cellinfo_of_cell(cell)->align_special.empty()) {
1515            return cellinfo_of_cell(cell)->align_special.c_str();
1516        } else {
1517            switch (GetAlignment(cell)) {
1518            case LYX_ALIGN_LEFT:
1519                return "left";
1520            case LYX_ALIGN_RIGHT:
1521                return "right";
1522            default:
1523                return "center";
1524            }
1525        }
1526     } else {
1527        if (!column_info[i].align_special.empty()) {
1528            return column_info[i].align_special.c_str();
1529        }
1530 #ifdef IGNORE_THIS_FOR_NOW
1531        else if (!column_info[i].p_width.empty()) {
1532            file += "p{";
1533            file += column_info[i].p_width;
1534            file += '}';
1535        }
1536 #endif
1537        else {
1538            switch (column_info[i].alignment) {
1539            case LYX_ALIGN_LEFT:
1540                return "left";
1541            case LYX_ALIGN_RIGHT:
1542                return "right";
1543            default:
1544                return "center";
1545            }
1546        }
1547     }
1548 }
1549
1550
1551 // cell <0 will tex the preamble
1552 // returns the number of printed newlines
1553 int LyXTable::DocBookEndOfCell(ostream & os, int cell, int & depth)
1554 {
1555     int i;
1556     int ret = 0;
1557     //int tmp; // tmp2; // unused
1558     int nvcell; // fcell; // unused
1559     if (ShouldBeVeryLastCell(cell)) {
1560             os << newlineAndDepth(--depth)
1561                << "</ENTRY>"
1562                << newlineAndDepth(--depth)
1563                << "</ROW>"
1564                << newlineAndDepth(--depth)
1565                << "</TBODY>"
1566                << newlineAndDepth(--depth);
1567         if (is_long_table)
1568                 os << "</TGROUP>";
1569         else
1570                 os << "</TGROUP>"
1571                    << newlineAndDepth(--depth);
1572         ret += 4;
1573     } else {
1574         nvcell = NextVirtualCell(cell + 1);
1575         if (cell < 0) {
1576             // preamble
1577             if (is_long_table)
1578                     os << "<TGROUP ";
1579             else
1580                     os << "<TGROUP ";
1581             os << "COLS='"
1582                << columns
1583                << "' COLSEP='1' ROWSEP='1'>"
1584                << newlineAndDepth(++depth);
1585             ++ret;
1586             for (i = 0; i < columns; ++i) {
1587                     os << "<COLSPEC ALIGN='"
1588                        << getDocBookAlign(i, true)
1589                        << "' COLNAME='col"
1590                        << i + 1
1591                        << "' COLNUM='"
1592                        << i + 1
1593                        << "' COLSEP='";
1594                if (i == (columns-1)) {
1595                        os << '1';
1596                } else {
1597                    if (column_info[i].right_line ||
1598                        column_info[i+1].left_line)
1599                            os << '1';
1600                    else
1601                            os << '0';
1602                }
1603                os << "'>"
1604                   << newlineAndDepth(depth);
1605                 ++ret;
1606 #ifdef NOT_HANDLED_YET_AS_I_DONT_KNOW_HOW
1607                 if (column_info[i].left_line)
1608                         os << '|';
1609 #endif
1610             }
1611             os << "<TBODY>"
1612                << newlineAndDepth(++depth)
1613                << "<ROW>"
1614                << newlineAndDepth(++depth)
1615                << "<ENTRY ALIGN='"
1616                << getDocBookAlign(0)
1617                << "'";
1618            if (IsMultiColumn(0)) {
1619                    os << " NAMEST='col1' NAMEEND='col"
1620                       << cells_in_multicolumn(0)
1621                       << "'";
1622            }
1623            os << ">"
1624               << newlineAndDepth(++depth);
1625             ret += 3;
1626         } else {
1627             if (IsLastCell(cell)) {
1628                     os << newlineAndDepth(--depth)
1629                        << "</ENTRY>"
1630                        << newlineAndDepth(--depth)
1631                        << "</ROW>"
1632                        << newlineAndDepth(depth)
1633                        << "<ROW>"
1634                        << newlineAndDepth(++depth)
1635                        << "<ENTRY ALIGN='"
1636                        << getDocBookAlign(cell + 1)
1637                        << "' VALIGN='middle'";
1638                if (IsMultiColumn(cell + 1)) {
1639                        os << " NAMEST='col"
1640                           << column_of_cell(cell+1) + 1
1641                           << "' NAMEEND='col"
1642                           << column_of_cell(cell + 1) +
1643                                cells_in_multicolumn(cell + 1)
1644                           << "'";
1645                }
1646                os << ">"
1647                   << newlineAndDepth(++depth);
1648                 ret += 4;
1649             } else {
1650                     os << newlineAndDepth(--depth)
1651                        << "</ENTRY>"
1652                        << newlineAndDepth(depth)
1653                        << "<ENTRY ALIGN='"
1654                        << getDocBookAlign(cell + 1)
1655                        << "' VALIGN='middle'";
1656                if (IsMultiColumn(cell + 1)) {
1657                        os << " NAMEST='col"
1658                           << column_of_cell(cell+1) + 1
1659                           << "' NAMEEND='col"
1660                           << column_of_cell(cell+1) +
1661                                cells_in_multicolumn(cell+1)
1662                           << "'";
1663                }
1664                os << ">"
1665                   << newlineAndDepth(++depth);
1666                 ret += 3;
1667             }
1668         }
1669     }
1670     return ret;
1671 }
1672
1673
1674 bool LyXTable::IsMultiColumn(int cell)
1675 {
1676     int fvcell = FirstVirtualCell(cell);
1677
1678     return (cellinfo_of_cell(fvcell)->multicolumn != LyXTable::CELL_NORMAL);
1679 }
1680
1681
1682 LyXTable::cellstruct* LyXTable::cellinfo_of_cell(int cell)
1683 {
1684     int row = row_of_cell(cell);
1685     int column = column_of_cell(cell);
1686     return  &cell_info[row][column];
1687 }
1688    
1689
1690 void LyXTable::SetMultiColumn(int cell, int number)
1691 {
1692     int fvcell = FirstVirtualCell(cell);
1693     int new_width = cellinfo_of_cell(fvcell)->width_of_cell;
1694     
1695     cellinfo_of_cell(fvcell)->multicolumn = LyXTable::CELL_BEGIN_OF_MULTICOLUMN;
1696     cellinfo_of_cell(fvcell)->alignment = column_info[column_of_cell(fvcell)].alignment;
1697     cellinfo_of_cell(fvcell)->top_line = row_info[row_of_cell(fvcell)].top_line;
1698     cellinfo_of_cell(fvcell)->bottom_line = row_info[row_of_cell(fvcell)].bottom_line;
1699     for (number--; number > 0; --number) {
1700         cellinfo_of_cell(fvcell+number)->multicolumn = 
1701             LyXTable::CELL_PART_OF_MULTICOLUMN;
1702         new_width += cellinfo_of_cell(fvcell+number)->width_of_cell;
1703     }
1704     set_row_column_number_info();
1705     SetWidthOfCell(fvcell, new_width);
1706 }
1707
1708
1709 int LyXTable::cells_in_multicolumn(int cell)
1710 {
1711     int row = row_of_cell(cell);
1712     int column = column_of_cell(cell);
1713     int result = 1;
1714     ++column;
1715     while (column < columns && cell_info[row][column].multicolumn
1716            == LyXTable::CELL_PART_OF_MULTICOLUMN){
1717         ++result;
1718         ++column;
1719     }
1720     return result;
1721 }
1722
1723
1724 int  LyXTable::UnsetMultiColumn(int cell)
1725 {
1726     int fvcell = FirstVirtualCell(cell);
1727     int row = row_of_cell(fvcell);
1728     int column = column_of_cell(fvcell);
1729     
1730     int result = 0;
1731     
1732     if (cell_info[row][column].multicolumn
1733         == LyXTable::CELL_BEGIN_OF_MULTICOLUMN){
1734         cell_info[row][column].multicolumn = LyXTable::CELL_NORMAL;
1735         ++column;
1736         while (column < columns &&
1737                cell_info[row][column].multicolumn
1738                == LyXTable::CELL_PART_OF_MULTICOLUMN){
1739             cell_info[row][column].multicolumn = 
1740                 LyXTable::CELL_NORMAL;
1741             ++column;
1742             ++result;
1743         }
1744     }
1745     set_row_column_number_info();
1746     return result;
1747 }
1748
1749
1750 void LyXTable::delete_column(int column)
1751 {
1752     int i, j;
1753     columnstruct * column_info2 = new columnstruct[columns-1];
1754    
1755     for (i = 0; i < column; ++i) {
1756         column_info2[i] = column_info[i];
1757     }
1758     for (i = column; i < columns - 1; ++i) {
1759         column_info2[i] = column_info[i + 1];
1760     }
1761    
1762     delete[] column_info;
1763     column_info = column_info2;
1764
1765     for (i = 0; i < rows; ++i) {
1766         cellstruct * tmp = cell_info[i];
1767         cell_info[i] = new cellstruct[columns - 1];
1768         for (j = 0; j < column; ++j) {
1769             cell_info[i][j] = tmp[j];
1770         }
1771         for (j = column; j < columns - 1; ++j) {
1772             cell_info[i][j] = tmp[j + 1];
1773         }
1774         delete[] tmp;
1775     }
1776
1777     --columns;
1778     Reinit();
1779 }
1780
1781
1782 void LyXTable::SetLongTable(int what)
1783 {
1784     is_long_table = what;
1785 }
1786
1787
1788 bool LyXTable::IsLongTable()
1789 {
1790     return is_long_table;
1791 }
1792
1793 void LyXTable::SetRotateTable(int what)
1794 {
1795     rotate = what;
1796 }
1797
1798 bool LyXTable::RotateTable()
1799 {
1800     return rotate;
1801 }
1802
1803 void LyXTable::SetRotateCell(int cell, int what)
1804 {
1805     cellinfo_of_cell(cell)->rotate = what;
1806 }
1807
1808 bool LyXTable::RotateCell(int cell)
1809 {
1810     return cellinfo_of_cell(cell)->rotate;
1811 }
1812
1813 bool LyXTable::NeedRotating()
1814 {
1815     if (rotate)
1816         return true;
1817     for (int i = 0; i < rows; ++i) {
1818         for (int j = 0; j < columns; ++j) {
1819             if (cell_info[i][j].rotate)
1820                 return true;
1821         }
1822     }
1823     return false;
1824 }
1825
1826 void LyXTable::AppendContRow(int cell)
1827 {
1828     int row = row_of_cell(cell)+1;
1829
1830     if (!RowHasContRow(cell) || (CellHasContRow(cell)>= 0))
1831         AppendRow(cell);
1832     row_info[row].is_cont_row = true;
1833     row_info[row].top_line = false;
1834     cell_info[row-1][column_of_cell(cell)].has_cont_row = true;
1835     Reinit();
1836 }
1837
1838 bool LyXTable::IsContRow(int cell)
1839 {
1840     return row_info[row_of_cell(cell)].is_cont_row;
1841 }
1842
1843 int LyXTable::CellHasContRow(int cell)
1844 {
1845     int row = row_of_cell(cell);
1846
1847     if (VeryLastRow(cell))
1848         return -1;
1849     if (cell_info[row][column_of_cell(cell)].has_cont_row)
1850         return cell_info[row+1][column_of_cell(cell)].cellno;
1851     return -1;
1852 }
1853
1854 bool LyXTable::RowHasContRow(int cell)
1855 {
1856     int row = row_of_cell(cell) + 1;
1857
1858     if (row < rows)
1859         return row_info[row].is_cont_row;
1860     return false;
1861 }
1862
1863 int LyXTable::FirstVirtualCell(int cell)
1864 {
1865     if (!IsContRow(cell))
1866         return cell;
1867     int row = row_of_cell(cell);
1868     int column = column_of_cell(cell);
1869     for(; (row > 0) && IsContRow(cell_info[row][column].cellno); --row)
1870         ;
1871     return cell_info[row][column].cellno;
1872 }
1873
1874
1875 int LyXTable::NextVirtualCell(int cell)
1876 {
1877     if (!IsContRow(cell))
1878         return cell;
1879     int row = row_of_cell(cell);
1880     for(;(row < rows - 1) && IsContRow(cell_info[row][0].cellno); ++row)
1881         ;
1882     // what if(row >= rows) ?
1883     return cell_info[row][0].cellno;
1884 }
1885
1886
1887 bool LyXTable::ShouldBeVeryLastCell(int cell)
1888 // "very last cell" ..of what? the row? the table?
1889 // "Cell" in this context appears to not count `virtual' cells
1890 {
1891     int fcell = cell + 1;
1892
1893     if (cell == GetNumberOfCells() - 1)
1894         return true; // not really sure if I should return false here
1895     if (!IsContRow(fcell))
1896         return false;
1897     while((fcell < GetNumberOfCells() - 1) && IsContRow(fcell))
1898         ++fcell;
1899     if (fcell < GetNumberOfCells() - 1)
1900         return false;
1901     return true;
1902 }
1903
1904 bool LyXTable::ShouldBeVeryLastRow(int cell)
1905 {
1906     if (CellHasContRow(cell)>= 0)
1907         return false;
1908     int row = row_of_cell(cell) + 1;
1909     int column = column_of_cell(cell);
1910     while((row < rows) && IsContRow(cell_info[row][column].cellno))
1911         ++row;
1912     if (row < rows)
1913         return false; // found another valid row
1914     // I do not have any valid row after the actual
1915     return true;
1916 }
1917
1918 int LyXTable::GetCellAbove(int cell)
1919 {
1920     int row = row_of_cell(cell);
1921     
1922     if (row > 0)
1923         return cell_info[row-1][column_of_cell(cell)].cellno;
1924     return cell;
1925 }
1926
1927 int LyXTable::GetCellNumber(int column, int row)
1928 {
1929     if (column >= columns)
1930         column = columns - 1;
1931     else if (column < 0)
1932         column = 0;
1933     if (row >= rows)
1934         row = rows - 1;
1935     else if (row < 0)
1936         row = 0;
1937     
1938     return cell_info[row][column].cellno;
1939 }
1940
1941 void LyXTable::SetLinebreaks(int cell, bool what)
1942 {
1943     cellinfo_of_cell(FirstVirtualCell(cell))->linebreaks = what;
1944 }
1945
1946 bool LyXTable::Linebreaks(int cell)
1947 {
1948     int fvcell = FirstVirtualCell(cell);
1949
1950     if (column_info[column_of_cell(fvcell)].p_width.empty() &&
1951         !(IsMultiColumn(fvcell) && !cellinfo_of_cell(fvcell)->p_width.empty()))
1952         return false;
1953     return cellinfo_of_cell(fvcell)->linebreaks;
1954 }
1955
1956 void LyXTable::SetLTHead(int cell, bool first)
1957 {
1958     int row = row_of_cell(cell);
1959
1960     if (first) {
1961         if (row == endfirsthead)
1962             endfirsthead = -1;
1963         else
1964             endfirsthead = row;
1965     } else {
1966         if (row == endhead)
1967             endhead = -1;
1968         else
1969             endhead = row;
1970     }
1971 }
1972
1973 bool LyXTable::RowOfLTHead(int cell)
1974 {
1975     if ((endhead+1) > rows)
1976         endhead = -1;
1977     return (row_of_cell(cell) == endhead);
1978 }
1979
1980 bool LyXTable::RowOfLTFirstHead(int cell)
1981 {
1982     if ((endfirsthead+1) > rows)
1983         endfirsthead = -1;
1984     return (row_of_cell(cell) == endfirsthead);
1985 }
1986
1987 void LyXTable::SetLTFoot(int cell, bool last)
1988 {
1989     int row = row_of_cell(cell);
1990
1991     if (last) {
1992         if (row == endlastfoot)
1993             endlastfoot = -1;
1994         else
1995             endlastfoot = row;
1996     } else {
1997         if (row == endfoot)
1998             endfoot = -1;
1999         else
2000             endfoot = row;
2001     }
2002 }
2003
2004 bool LyXTable::RowOfLTFoot(int cell)
2005 {
2006     if ((endfoot+1) > rows) {
2007         endfoot = -1;
2008         return false;
2009     }
2010     return (row_of_cell(cell) == endfoot);
2011 }
2012
2013 bool LyXTable::RowOfLTLastFoot(int cell)
2014 {
2015     if ((endlastfoot+1) > rows)
2016         endlastfoot = -1;
2017     return (row_of_cell(cell) == endlastfoot);
2018 }
2019
2020 void LyXTable::SetLTNewPage(int cell, bool what)
2021 {
2022     row_info[row_of_cell(cell)].newpage = what;
2023 }
2024
2025 bool LyXTable::LTNewPage(int cell)
2026 {
2027     return row_info[row_of_cell(cell)].newpage;
2028 }
2029
2030 void LyXTable::SetAscentOfRow(int row, int height)
2031 {
2032     if (row >= rows)
2033         return;
2034     row_info[row].ascent_of_row = height;
2035 }
2036
2037 void LyXTable::SetDescentOfRow(int row, int height)
2038 {
2039     if (row >= rows)
2040         return;
2041     row_info[row].descent_of_row = height;
2042 }
2043
2044 int LyXTable::AscentOfRow(int row)
2045 {
2046     if (row >= rows)
2047         return 0;
2048     return row_info[row].ascent_of_row;
2049 }
2050
2051 int LyXTable::DescentOfRow(int row)
2052 {
2053     if (row >= rows)
2054         return 0;
2055     return row_info[row].descent_of_row;
2056 }
2057
2058 int LyXTable::HeightOfTable()
2059 {
2060     int
2061         height,
2062         row;
2063
2064     for(row=0,height=0;(row<rows); ++row)
2065         height += AscentOfRow(row) + DescentOfRow(row) +
2066             AdditionalHeight(GetCellNumber(0,row));
2067     return height;
2068 }
2069
2070 bool LyXTable::IsPartOfMultiColumn(int row, int column)
2071 {
2072     if ((row >= rows) || (column >= columns))
2073         return false;
2074     return (cell_info[row][column].multicolumn==CELL_PART_OF_MULTICOLUMN);
2075 }
2076
2077 int LyXTable::Latex(ostream &)
2078 {
2079     return 0;
2080 }