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