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