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