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