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