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