]> git.lyx.org Git - lyx.git/blob - src/tabular.C
a41f430d30d7dd7d258b9c20db5db5746c5b18db
[lyx.git] / src / tabular.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 2000 The LyX Team.
7  *
8  *           @author: Jürgen Vigna
9  *
10  * ====================================================== 
11  */
12
13 #include <config.h>
14
15 #ifdef __GNUG__
16 #pragma implementation
17 #endif
18
19 #include <algorithm>
20 #include <cstdlib>
21
22 #include "tabular.h"
23 #include "debug.h"
24 #include "vspace.h"
25 #include "layout.h"
26 #include "lyx_gui_misc.h"
27 #include "buffer.h"
28 #include "BufferView.h"
29 #include "Painter.h"
30 #include "LaTeXFeatures.h"
31 #include "support/lstrings.h"
32 #include "support/lyxmanip.h"
33 #include "insets/insettabular.h"
34 #include "insets/insettext.h"
35
36 using std::ostream;
37 using std::istream;
38 using std::getline;
39 using std::max;
40 using std::endl;
41 using std::vector;
42
43 static int const WIDTH_OF_LINE = 5;
44
45 /// Define a few methods for the inner structs
46
47 LyXTabular::cellstruct::cellstruct() 
48 {
49     cellno = 0;
50     width_of_cell = 0;
51     multicolumn = LyXTabular::CELL_NORMAL;
52     alignment = LYX_ALIGN_CENTER;
53     valignment = LYX_VALIGN_TOP;
54     top_line = true;
55     bottom_line = false;
56     left_line = true;
57     right_line = false;
58     usebox = BOX_NONE;
59     rotate = false;
60 }
61
62
63 LyXTabular::rowstruct::rowstruct() 
64 {
65     top_line = true;
66     bottom_line = false;
67     ascent_of_row = 0;
68     descent_of_row = 0;
69     newpage = false;
70 }
71
72
73 LyXTabular::columnstruct::columnstruct() 
74 {
75     left_line = true;
76     right_line = false;
77     alignment = LYX_ALIGN_CENTER;
78     valignment = LYX_VALIGN_TOP;
79     width_of_column = 0;
80 }
81
82
83 /* konstruktor */
84 LyXTabular::LyXTabular(InsetTabular * inset, int rows_arg, int columns_arg)
85 {
86     owner_ = inset;
87     Init(rows_arg, columns_arg);
88 }
89
90
91 LyXTabular::LyXTabular(InsetTabular * inset, LyXTabular const & lt)
92 {
93     owner_ = inset;
94     Init(lt.rows_, lt.columns_);
95 #ifdef WITH_WARNINGS
96 #warning Jürgen, can you make it the other way round. So that copy assignment depends on the copy constructor and not the other way. (Lgb)
97 #endif
98     operator=(lt);
99 }
100
101
102 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
103 {
104     owner_ = inset;
105     Read(buf, lex);
106 }
107
108
109 LyXTabular & LyXTabular::operator=(LyXTabular const & lt)
110 {
111     // If this and lt is not of the same size we have a serious bug
112     // So then it is ok to throw an exception, or for now
113     // call abort()
114     Assert(rows_ == lt.rows_ && columns_ == lt.columns_);
115
116     cell_info = lt.cell_info;
117     row_info = lt.row_info;
118     column_info = lt.column_info;
119
120     // long tabular stuff
121     SetLongTabular(lt.is_long_tabular);
122     endhead = lt.endhead;
123     endfoot = lt.endfoot;
124     endfirsthead = lt.endfirsthead;
125     endlastfoot = lt.endlastfoot;
126
127     rotate = lt.rotate;
128
129     Reinit();
130     
131     return *this;
132 }
133
134
135 LyXTabular * LyXTabular::Clone(InsetTabular * inset)
136 {
137     LyXTabular * result = new LyXTabular(inset, *this);
138     // don't know if this is good but I need to Clone also
139     // the text-insets here, this is for the Undo-facility!
140     for (int i = 0; i < rows_; ++i) {
141         for (int j = 0; j < columns_; ++j) {
142             result->cell_info[i][j].inset = cell_info[i][j].inset;
143             result->cell_info[i][j].inset.setOwner(inset);
144         }
145     }
146     return result;
147 }
148
149
150 /* activates all lines and sets all widths to 0 */ 
151 void LyXTabular::Init(int rows_arg, int columns_arg)
152 {
153     rows_ = rows_arg;
154     columns_ = columns_arg;
155     row_info = row_vector(rows_, rowstruct());
156     column_info = column_vector(columns_, columnstruct());
157     cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct()));
158
159     int cellno = 0;
160     for (int i = 0; i < rows_; ++i) {
161         for (int j = 0; j < columns_; ++j) {
162             cell_info[i][j].inset.setOwner(owner_);
163             cell_info[i][j].inset.SetDrawFrame(0, InsetText::LOCKED);
164             cell_info[i][j].cellno = cellno++;
165         }
166         cell_info[i].back().right_line = true;
167     }
168     row_info.back().bottom_line = true;
169     row_info.front().bottom_line = true;
170
171     for (int i = 0; i < columns_; ++i) {
172         calculate_width_of_column(i);
173     }
174     column_info.back().right_line = true;
175    
176     calculate_width_of_tabular();
177
178     rowofcell = vector<int>();
179     columnofcell = vector<int>();
180     set_row_column_number_info();
181     is_long_tabular = false;
182     rotate = false;
183     endhead = 0;
184     endfirsthead = 0;
185     endfoot = 0;
186     endlastfoot = 0;
187 }
188
189
190 void LyXTabular::AppendRow(int cell)
191 {
192     ++rows_;
193    
194     int row = row_of_cell(cell);
195
196     row_vector::iterator rit = row_info.begin() + row;
197     row_info.insert(rit, rowstruct());
198
199 #if 0
200     cell_vvector::iterator cit = cell_info.begin() + row;
201     cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct()));
202 #else
203     cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
204                                                           cellstruct()));
205
206     for (int i = 0; i <= row; ++i) {
207         for (int j = 0; j < columns_; ++j) {
208             c_info[i][j] = cell_info[i][j];
209         }
210     }
211     for (int i = row + 1; i < rows_; ++i) {
212         for (int j = 0; j < columns_; ++j) {
213             c_info[i][j] = cell_info[i-1][j];
214         }
215     }
216     cell_info = c_info;
217     ++row;
218     for (int j = 0; j < columns_; ++j) {
219         cell_info[row][j].inset.clear();
220     }
221 #endif
222     Reinit();
223 }
224
225
226 void LyXTabular::DeleteRow(int row)
227 {
228     // Why make it so hard? (Lgb)
229     //if (!(rows_ - 1))
230     //return;
231     if (rows_ == 1) return; // Not allowed to delete last row
232         
233     row_info.erase(row_info.begin() + row); //&row_info[row]);
234     cell_info.erase(cell_info.begin() + row); //&cell_info[row]);
235     --rows_;
236     Reinit();
237 }
238
239
240 void LyXTabular::AppendColumn(int cell)
241 {
242     ++columns_;
243    
244     cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
245                                                           cellstruct()));
246     int const column = column_of_cell(cell);
247     column_vector::iterator cit = column_info.begin() + column + 1;
248     column_info.insert(cit, columnstruct());
249
250     for (int i = 0; i < rows_; ++i) {
251         for (int j = 0; j <= column; ++j) {
252             c_info[i][j] = cell_info[i][j];
253         }
254         for (int j = column + 1; j < columns_; ++j) {
255             c_info[i][j] = cell_info[i][j - 1];
256         }
257         // care about multicolumns
258         if (cell_info[i][column + 1].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
259             cell_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
260         }
261         if ((column + 1) == columns_ ||
262             cell_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN) {
263             cell_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
264         }
265     }
266     cell_info = c_info;
267     //++column;
268     for (int i = 0; i < rows_; ++i) {
269         //cell_info[i][column].inset.clear();
270         cell_info[i][column + 1].inset.clear();
271     }
272     Reinit();
273 }
274
275
276 void LyXTabular::DeleteColumn(int column)
277 {
278     // Similar to DeleteRow
279     //if (!(columns_ - 1))
280     //return;
281     if (columns_ == 1) return; // Not allowed to delete last column
282          
283     column_info.erase(column_info.begin() + column);
284     for (int i = 0; i < rows_; ++i) {
285         cell_info[i].erase(cell_info[i].begin() + column);
286     }
287     --columns_;
288     Reinit();
289 }
290
291
292 void LyXTabular::Reinit()
293 {   
294     for (int i = 0; i < rows_; ++i) {
295         for (int j = 0; j < columns_; ++j) {
296             cell_info[i][j].width_of_cell = 0;
297             cell_info[i][j].inset.setOwner(owner_);
298         }
299     }
300   
301     for (int i = 0; i < columns_; ++i) {
302         calculate_width_of_column(i);
303     }
304     calculate_width_of_tabular();
305
306     set_row_column_number_info();
307 }
308
309
310 void LyXTabular::set_row_column_number_info(bool oldformat)
311 {
312     numberofcells = -1;
313     for (int row = 0; row < rows_; ++row) {
314         for (int column = 0; column<columns_; ++column) {
315             if (cell_info[row][column].multicolumn
316                 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
317                 ++numberofcells;
318             cell_info[row][column].cellno = numberofcells;
319         }
320     }
321     ++numberofcells; // because this is one more than as we start from 0
322
323     rowofcell.resize(numberofcells);
324     columnofcell.resize(numberofcells);
325
326     for (int row = 0, column = 0, c = 0;
327          c < numberofcells && row < rows_ && column < columns_;) {
328         rowofcell[c] = row;
329         columnofcell[c] = column;
330         ++c;
331         do {
332             ++column;
333         } while (column < columns_ &&
334                  cell_info[row][column].multicolumn
335                  == LyXTabular::CELL_PART_OF_MULTICOLUMN);
336         if (column == columns_) {
337             column = 0;
338             ++row;
339         }
340     }
341
342     for (int row = 0; row < rows_; ++row) {
343         for (int column = 0; column < columns_; ++column) {
344             if (IsPartOfMultiColumn(row,column))
345                 continue;
346             // now set the right line of multicolumns right for oldformat read
347             if (oldformat &&
348                 cell_info[row][column].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
349             {
350                 int cn=cells_in_multicolumn(cell_info[row][column].cellno);
351                 cell_info[row][column].right_line =
352                     cell_info[row][column+cn-1].right_line;
353             }
354             cell_info[row][column].inset.SetAutoBreakRows(
355                 !GetPWidth(GetCellNumber(row, column)).empty());
356         }
357     }
358 }
359
360
361 int LyXTabular::GetNumberOfCells() const
362 {
363     return numberofcells;
364 }
365
366
367 int LyXTabular::NumberOfCellsInRow(int cell) const
368 {
369     int const row = row_of_cell(cell);
370     int result = 0;
371     for (int i = 0; i < columns_; ++i) {
372         if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
373             ++result;
374     }
375     return result;
376 }
377
378
379 /* returns 1 if there is a topline, returns 0 if not */ 
380 bool LyXTabular::TopLine(int cell, bool onlycolumn) const
381 {
382     int const row = row_of_cell(cell);
383     
384     if (!onlycolumn && IsMultiColumn(cell))
385         return cellinfo_of_cell(cell)->top_line;
386     return row_info[row].top_line;
387 }
388
389
390 bool LyXTabular::BottomLine(int cell, bool onlycolumn) const
391 {
392     // no bottom line underneath non-existent cells if you please
393     // Isn't that a programming error? Is so this should
394     // be an Assert instead. (Lgb)
395     if (cell >= numberofcells)
396         return false;
397
398     if (!onlycolumn && IsMultiColumn(cell))
399         return cellinfo_of_cell(cell)->bottom_line;
400     return row_info[row_of_cell(cell)].bottom_line;
401 }
402
403
404 bool LyXTabular::LeftLine(int cell, bool onlycolumn) const
405 {
406     if (!onlycolumn && IsMultiColumn(cell))
407         return cellinfo_of_cell(cell)->left_line;
408     return column_info[column_of_cell(cell)].left_line;
409 }
410
411
412 bool LyXTabular::RightLine(int cell, bool onlycolumn) const
413 {
414     if (!onlycolumn && IsMultiColumn(cell))
415         return cellinfo_of_cell(cell)->right_line;
416     return column_info[right_column_of_cell(cell)].right_line;
417 }
418
419
420 bool LyXTabular::TopAlreadyDrawed(int cell) const
421 {
422     if (GetAdditionalHeight(cell))
423         return false;
424     int row = row_of_cell(cell);
425     if (row > 0) {
426         int column = column_of_cell(cell);
427         --row;
428         while (column
429                && cell_info[row][column].multicolumn
430                == LyXTabular::CELL_PART_OF_MULTICOLUMN)
431             --column;
432         if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
433             return row_info[row].bottom_line;
434         else
435             return cell_info[row][column].bottom_line;
436     }
437     return false;
438 }
439
440
441 bool LyXTabular::LeftAlreadyDrawed(int cell) const
442 {
443     int column = column_of_cell(cell);
444     if (column > 0) {
445         int row = row_of_cell(cell);
446         while (--column &&
447                (cell_info[row][column].multicolumn ==
448                 LyXTabular::CELL_PART_OF_MULTICOLUMN));
449         if (GetAdditionalWidth(cell_info[row][column].cellno))
450             return false;
451         return column_info[column].right_line;
452     }
453     return false;
454 }
455
456
457 bool LyXTabular::IsLastRow(int cell) const
458 {
459     return (row_of_cell(cell) == rows_ - 1);
460 }
461
462
463 int LyXTabular::GetAdditionalHeight(int cell) const
464 {
465     int const row = row_of_cell(cell);
466     if (!row) return 0;
467
468     bool top = true;
469     bool bottom = true;
470
471     for (int column = 0; column < columns_ - 1 && bottom; ++column) {
472         switch (cell_info[row - 1][column].multicolumn) {
473         case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
474             bottom = cell_info[row - 1][column].bottom_line;
475             break;
476         case LyXTabular::CELL_NORMAL:
477             bottom = row_info[row - 1].bottom_line;
478         }
479     }
480     for (int column = 0; column < columns_ - 1 && top; ++column) {
481         switch (cell_info[row][column].multicolumn){
482         case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
483             top = cell_info[row][column].top_line;
484             break;
485         case LyXTabular::CELL_NORMAL:
486             top = row_info[row].top_line;
487         }
488     }
489     if (top && bottom)
490         return WIDTH_OF_LINE;
491     return 0;
492 }
493
494
495 int LyXTabular::GetAdditionalWidth(int cell) const
496 {
497     // internally already set in SetWidthOfCell
498     // used to get it back in text.C
499     int const col = right_column_of_cell(cell);
500     if (col < columns_ - 1 && column_info[col].right_line &&
501         column_info[col+1].left_line)
502         return WIDTH_OF_LINE;
503     else
504         return 0;
505 }
506
507
508 // returns the maximum over all rows 
509 int LyXTabular::GetWidthOfColumn(int cell) const
510 {
511     int const column1 = column_of_cell(cell);
512     int const column2 = right_column_of_cell(cell);
513     int result = 0;
514     for (int i = column1; i <= column2; ++i) {
515         result += column_info[i].width_of_column;
516     }
517     return result;
518 }
519
520
521 int LyXTabular::GetWidthOfTabular() const
522 {
523     return width_of_tabular;
524 }
525
526
527 /* returns 1 if a complete update is necessary, otherwise 0 */ 
528 bool LyXTabular::SetWidthOfMulticolCell(int cell, int new_width)
529 {
530     if (!IsMultiColumn(cell))
531         return false;
532     
533     int const row = row_of_cell(cell);
534     int const column1 = column_of_cell(cell);
535     int const column2 = right_column_of_cell(cell);
536
537     // first set columns to 0 so we can calculate the right width
538     for (int i = column1; 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
544     int i = column1;
545     for (; i < column2 && width > column_info[i].width_of_column; ++i) {
546         cell_info[row][i].width_of_cell = column_info[i].width_of_column;
547         width -= column_info[i].width_of_column;
548     }
549     if (width > 0) {
550         cell_info[row][i].width_of_cell = width;
551     }
552     return true;
553 }
554
555
556 void LyXTabular::recalculateMulticolCells(int cell, int new_width)
557 {
558     int const row = row_of_cell(cell);
559     int const column1 = column_of_cell(cell);
560     int const column2 = right_column_of_cell(cell);
561
562     // first set columns to 0 so we can calculate the right width
563     int i = column1;
564     for (; i <= column2; ++i)
565         cell_info[row][i].width_of_cell = 0;
566     for (i = cell + 1; (i < numberofcells) && (!IsMultiColumn(i)); ++i)
567         ;
568     if (i < numberofcells)
569         recalculateMulticolCells(i, GetWidthOfCell(i) - (2 * WIDTH_OF_LINE));
570     SetWidthOfMulticolCell(cell, new_width);
571 }
572
573
574 /* returns 1 if a complete update is necessary, otherwise 0 */ 
575 bool LyXTabular::SetWidthOfCell(int cell, int new_width)
576 {
577     int const row = row_of_cell(cell);
578     int const column1 = column_of_cell(cell);
579     bool tmp = false;
580     int width = 0;
581
582     if (GetWidthOfCell(cell) == (new_width+2*WIDTH_OF_LINE))
583         return false;
584     if (IsMultiColumn(cell, true)) {
585         tmp = SetWidthOfMulticolCell(cell, new_width);
586     } else {
587         width = (new_width + 2*WIDTH_OF_LINE);
588         cell_info[row][column1].width_of_cell = width;
589         if (column_info[column1].right_line && (column1 < columns_-1) &&
590             column_info[column1+1].left_line) // additional width
591             cell_info[row][column1].width_of_cell += WIDTH_OF_LINE;
592         tmp = calculate_width_of_column_NMC(column1);
593     }
594     if (tmp) {
595         int i = 0;
596         for (; i<columns_; ++i)
597             calculate_width_of_column_NMC(i);
598         for (i = 0; (i < numberofcells) && !IsMultiColumn(i); ++i)
599             ;
600         if (i < numberofcells)
601             recalculateMulticolCells(i, GetWidthOfCell(i)-(2 * WIDTH_OF_LINE));
602         for (i = 0; i < columns_; ++i)
603             calculate_width_of_column(i);
604         calculate_width_of_tabular();
605         return true;
606     }
607     return false;
608 }
609
610
611 bool LyXTabular::SetAlignment(int cell, LyXAlignment align, bool onlycolumn)
612 {
613     if (!IsMultiColumn(cell) || onlycolumn)
614         column_info[column_of_cell(cell)].alignment = align;
615     if (!onlycolumn)
616         cellinfo_of_cell(cell)->alignment = align;
617     return true;
618 }
619
620
621 bool LyXTabular::SetVAlignment(int cell, VAlignment align, bool onlycolumn)
622 {
623     if (!IsMultiColumn(cell) || onlycolumn)
624         column_info[column_of_cell(cell)].valignment = align;
625     if (!onlycolumn)
626         cellinfo_of_cell(cell)->valignment = align;
627     return true;
628 }
629
630
631 bool LyXTabular::SetColumnPWidth(int cell, string const & width)
632 {
633     bool flag = !width.empty();
634     int const j = column_of_cell(cell);
635
636     column_info[j].p_width = width;
637     if (flag) // do this only if there is a width
638         SetAlignment(cell, LYX_ALIGN_LEFT);
639     for (int i = 0; i < rows_; ++i) {
640         int c = GetCellNumber(i, j);
641         flag = !GetPWidth(c).empty(); // because of multicolumns!
642         GetCellInset(c)->SetAutoBreakRows(flag);
643     }
644     return true;
645 }
646
647
648 bool LyXTabular::SetMColumnPWidth(int cell, string const & width)
649 {
650     bool const flag = !width.empty();
651
652     cellinfo_of_cell(cell)->p_width = width;
653     if (IsMultiColumn(cell)) {
654         GetCellInset(cell)->SetAutoBreakRows(flag);
655         return true;
656     }
657     return false;
658 }
659
660
661 bool LyXTabular::SetAlignSpecial(int cell, string const & special,
662                                  LyXTabular::Feature what)
663 {
664     if (what == SET_SPECIAL_MULTI)
665         cellinfo_of_cell(cell)->align_special = special;
666     else
667         column_info[column_of_cell(cell)].align_special = special;
668     return true;
669 }
670
671
672 bool LyXTabular::SetAllLines(int cell, bool line)
673 {
674     SetTopLine(cell, line);
675     SetBottomLine(cell, line);
676     SetRightLine(cell, line);
677     SetLeftLine(cell, line);
678     return true;
679 }
680
681
682 bool LyXTabular::SetTopLine(int cell, bool line, bool onlycolumn)
683 {
684     int const row = row_of_cell(cell);
685
686     if (onlycolumn || !IsMultiColumn(cell))
687         row_info[row].top_line = line;
688     else
689         cellinfo_of_cell(cell)->top_line = line;
690     return true;
691 }
692
693
694 bool LyXTabular::SetBottomLine(int cell, bool line, bool onlycolumn)
695 {
696     if (onlycolumn || !IsMultiColumn(cell))
697         row_info[row_of_cell(cell)].bottom_line = line;
698     else
699         cellinfo_of_cell(cell)->bottom_line = line;
700     return true;
701 }
702
703
704 bool LyXTabular::SetLeftLine(int cell, bool line, bool onlycolumn)
705 {
706     if (onlycolumn || !IsMultiColumn(cell))
707         column_info[column_of_cell(cell)].left_line = line;
708     else
709         cellinfo_of_cell(cell)->left_line = line;
710     return true;
711 }
712
713
714 bool LyXTabular::SetRightLine(int cell, bool line, bool onlycolumn)
715 {
716     if (onlycolumn || !IsMultiColumn(cell))
717         column_info[right_column_of_cell(cell)].right_line = line;
718     else
719         cellinfo_of_cell(cell)->right_line = line;
720     return true;
721 }
722
723
724 LyXAlignment LyXTabular::GetAlignment(int cell, bool onlycolumn) const
725 {
726     if (!onlycolumn && IsMultiColumn(cell))
727         return cellinfo_of_cell(cell)->alignment;
728     else
729         return column_info[column_of_cell(cell)].alignment;
730 }
731
732
733 LyXTabular::VAlignment
734 LyXTabular::GetVAlignment(int cell, bool onlycolumn) const
735 {
736     if (!onlycolumn && IsMultiColumn(cell))
737         return cellinfo_of_cell(cell)->valignment;
738     else
739         return column_info[column_of_cell(cell)].valignment;
740 }
741
742
743 string const LyXTabular::GetPWidth(int cell) const
744 {
745     if (IsMultiColumn(cell))
746         return cellinfo_of_cell(cell)->p_width;
747     return column_info[column_of_cell(cell)].p_width;
748 }
749
750
751 string const LyXTabular::GetColumnPWidth(int cell) const
752 {
753     return column_info[column_of_cell(cell)].p_width;
754 }
755
756
757 string const LyXTabular::GetMColumnPWidth(int cell) const
758 {
759     if (IsMultiColumn(cell))
760         return cellinfo_of_cell(cell)->p_width;
761     return string();
762 }
763
764
765 string const LyXTabular::GetAlignSpecial(int cell, int what) const
766 {
767     if (what == SET_SPECIAL_MULTI)
768         return cellinfo_of_cell(cell)->align_special;
769     return column_info[column_of_cell(cell)].align_special;
770 }
771
772
773 int LyXTabular::GetWidthOfCell(int cell) const
774 {
775     int const row = row_of_cell(cell);
776     int const column1 = column_of_cell(cell);
777     int const column2 = right_column_of_cell(cell);
778     int result = 0;
779     for (int i = column1; i <= column2; ++i) {
780         result += cell_info[row][i].width_of_cell;
781     }
782     return result;
783 }
784
785
786 int LyXTabular::GetBeginningOfTextInCell(int cell) const
787 {
788     int x = 0;
789    
790     switch (GetAlignment(cell)){
791     case LYX_ALIGN_CENTER:
792         x += (GetWidthOfColumn(cell) - GetWidthOfCell(cell)) / 2;
793         break;
794     case LYX_ALIGN_RIGHT:
795         x += GetWidthOfColumn(cell) - GetWidthOfCell(cell);
796         // + GetAdditionalWidth(cell);
797         break;
798     default: /* LYX_ALIGN_LEFT: nothing :-) */ 
799         break;
800     }
801     
802     // the LaTeX Way :-(
803     x += WIDTH_OF_LINE;
804     return x;
805 }
806
807
808 bool LyXTabular::IsFirstCellInRow(int cell) const
809 {
810     return column_of_cell(cell) == 0;
811 }
812
813
814 int LyXTabular::GetFirstCellInRow(int row) const
815 {
816     if (row > (rows_-1))
817         row = rows_ - 1;
818     return cell_info[row][0].cellno;
819 }
820
821 bool LyXTabular::IsLastCellInRow(int cell) const
822 {
823     return (right_column_of_cell(cell) == (columns_ - 1));
824 }
825
826
827 int LyXTabular::GetLastCellInRow(int row) const
828 {
829     if (row > (rows_-1))
830         row = rows_ - 1;
831     return cell_info[row][columns_-1].cellno;
832 }
833
834
835 bool LyXTabular::calculate_width_of_column(int column)
836 {
837     int const old_column_width = column_info[column].width_of_column;
838     int maximum = 0;
839     
840     for (int i = 0; i < rows_; ++i) {
841         maximum = max(cell_info[i][column].width_of_cell, maximum);
842     }
843     column_info[column].width_of_column = maximum;
844     return (column_info[column].width_of_column != old_column_width);
845 }
846
847
848 //
849 // calculate the with of the column without regarding REAL MultiColumn
850 // cells. This means MultiColumn-cells spanning more than 1 column.
851 //
852 bool LyXTabular::calculate_width_of_column_NMC(int column)
853 {
854     int const old_column_width = column_info[column].width_of_column;
855     int max = 0;
856     for (int i = 0; i < rows_; ++i) {
857         if (!IsMultiColumn(GetCellNumber(i, column), true) &&
858             (cell_info[i][column].width_of_cell > max)) {
859             max = cell_info[i][column].width_of_cell;
860         }
861     }
862     column_info[column].width_of_column = max;
863     return (column_info[column].width_of_column != old_column_width);
864 }
865
866
867 void LyXTabular::calculate_width_of_tabular()
868 {
869     width_of_tabular = 0;
870     for (int i = 0; i < columns_; ++i) {
871         width_of_tabular += column_info[i].width_of_column;
872     }
873 }
874
875
876 int LyXTabular::row_of_cell(int cell) const
877 {
878     if (cell >= numberofcells)
879         return rows_ - 1;
880     else if (cell < 0)
881         return 0;
882     return rowofcell[cell];
883 }
884
885
886 int LyXTabular::column_of_cell(int cell) const
887 {
888     if (cell >= numberofcells)
889         return columns_ - 1;
890     else if (cell < 0)
891         return 0;
892     return columnofcell[cell];
893 }
894
895
896 int LyXTabular::right_column_of_cell(int cell) const
897 {
898     int const row = row_of_cell(cell);
899     int column = column_of_cell(cell);
900     while (column < (columns_ - 1) &&
901            cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
902         ++column;
903     return column;
904 }
905
906
907 // Perfect case for a template... (Lgb)
908 #if 1
909 template<class T>
910 string const write_attribute(string const & name, T const & t)
911 {
912      string str = " " + name + "=\"" + tostr(t) + "\"";
913      return str;
914 }
915
916 template <>
917 string const write_attribute(string const & name, bool const & b)
918 {
919         return write_attribute(name, int(b));
920 }
921
922 #else
923
924 string const write_attribute(string const & name, int value)
925 {
926     string str = " " + name + "=\"" + tostr(value) + "\"";
927     return str;
928 }
929
930
931 string const write_attribute(string const & name, string const & value)
932 {
933     string str = " " + name + "=\"" + value + "\"";
934     return str;
935 }
936
937
938 string const write_attribute(string const & name, bool value)
939 {
940     string str = " " + name + "=\"" + tostr(static_cast<int>(value)) + "\"";
941     return str;
942 }
943 #endif
944
945
946 //  #if 0
947 //  static inline
948 //  string const type2string(LyXAlignment num)
949 //  {
950 //      switch(num) {
951 //      case LYX_ALIGN_NONE:
952 //      return "none";
953 //      case LYX_ALIGN_BLOCK:
954 //      return "block";
955 //      case LYX_ALIGN_LEFT:
956 //      return "left";
957 //      case LYX_ALIGN_CENTER:
958 //      return "center";
959 //      case LYX_ALIGN_RIGHT:
960 //      return "right";
961 //      case LYX_ALIGN_LAYOUT:
962 //      return "layout";
963 //      case LYX_ALIGN_SPECIAL:
964 //      return "special";
965 //      }
966 //      return string();
967 //  }
968
969
970 //  static inline
971 //  string const type2string(LyXTabular::VAlignment num)
972 //  {
973 //      switch(num) {
974 //      case LyXTabular::LYX_VALIGN_TOP:
975 //      return "top";
976 //      case LyXTabular::LYX_VALIGN_CENTER:
977 //      return "center";
978 //      case LyXTabular::LYX_VALIGN_BOTTOM:
979 //      return "bottom";
980 //      }
981 //      return string();
982 //  }
983
984
985 //  static inline
986 //  string const type2string(LyXTabular::BoxType num)
987 //  {
988 //      switch(num) {
989 //      case LyXTabular::BOX_NONE:
990 //      return "none";
991 //      case LyXTabular::BOX_PARBOX:
992 //      return "parbox";
993 //      case LyXTabular::BOX_MINIPAGE:
994 //      return "minipage";
995 //      }
996 //      return string();
997 //  }
998
999 //  static inline
1000 //  string const type2string(bool flag)
1001 //  {
1002 //      return (flag ? "true" : "false");
1003 //  }
1004 //  #else
1005 template<>
1006 inline
1007 string const tostr(LyXAlignment const & num)
1008 {
1009     switch(num) {
1010     case LYX_ALIGN_NONE:
1011         return "none";
1012     case LYX_ALIGN_BLOCK:
1013         return "block";
1014     case LYX_ALIGN_LEFT:
1015         return "left";
1016     case LYX_ALIGN_CENTER:
1017         return "center";
1018     case LYX_ALIGN_RIGHT:
1019         return "right";
1020     case LYX_ALIGN_LAYOUT:
1021         return "layout";
1022     case LYX_ALIGN_SPECIAL:
1023         return "special";
1024     }
1025     return string();
1026 }
1027
1028
1029 template<>
1030 inline
1031 string const tostr(LyXTabular::VAlignment const & num)
1032 {
1033     switch(num) {
1034     case LyXTabular::LYX_VALIGN_TOP:
1035         return "top";
1036     case LyXTabular::LYX_VALIGN_CENTER:
1037         return "center";
1038     case LyXTabular::LYX_VALIGN_BOTTOM:
1039         return "bottom";
1040     }
1041     return string();
1042 }
1043
1044
1045 template<>
1046 inline
1047 string const tostr(LyXTabular::BoxType const & num)
1048 {
1049     switch(num) {
1050     case LyXTabular::BOX_NONE:
1051         return "none";
1052     case LyXTabular::BOX_PARBOX:
1053         return "parbox";
1054     case LyXTabular::BOX_MINIPAGE:
1055         return "minipage";
1056     }
1057     return string();
1058 }
1059
1060 // We already have a function like this in lstring.h (Lgb)
1061 //string const type2string(bool flag)
1062 //{
1063 //    return (flag ? "true" : "false");
1064 //}
1065
1066
1067 //#endif
1068
1069
1070
1071
1072 void LyXTabular::Write(Buffer const * buf, ostream & os) const
1073 {
1074     // header line
1075     os << "<LyXTabular"
1076        << write_attribute("version", 2)
1077        << write_attribute("rows", rows_)
1078        << write_attribute("columns", columns_)
1079        << ">\n";
1080     // global longtable options
1081     os << "<Features"
1082 //#if 0
1083 //       << write_attribute("rotate", type2string(rotate))
1084 //       << write_attribute("islongtable", type2string(is_long_tabular))
1085 //#else
1086        << write_attribute("rotate", tostr(rotate))
1087        << write_attribute("islongtable", tostr(is_long_tabular))
1088 //#endif
1089        << write_attribute("endhead", endhead)
1090        << write_attribute("endfirsthead", endfirsthead)
1091        << write_attribute("endfoot", endfoot)
1092        << write_attribute("endlastfoot", endlastfoot)
1093        << ">\n";
1094     for (int j = 0; j < columns_; ++j) {
1095         os << "<Column"
1096 //#if 0
1097 //         << write_attribute("alignment", type2string(column_info[j].alignment))
1098 //         << write_attribute("valignment", type2string(column_info[j].valignment))
1099 //         << write_attribute("leftline", type2string(column_info[j].left_line))
1100 //         << write_attribute("rightline", type2string(column_info[j].right_line))
1101 //#else
1102            << write_attribute("alignment", tostr(column_info[j].alignment))
1103            << write_attribute("valignment", tostr(column_info[j].valignment))
1104            << write_attribute("leftline", tostr(column_info[j].left_line))
1105            << write_attribute("rightline", tostr(column_info[j].right_line))
1106 //#endif
1107            << write_attribute("width",
1108                               VSpace(column_info[j].p_width)
1109                               .asLyXCommand())
1110            << write_attribute("special", column_info[j].align_special)
1111            << ">\n";
1112     }
1113     for (int i = 0; i < rows_; ++i) {
1114         os << "<Row"
1115 //#if 0
1116 //         << write_attribute("topline", type2string(row_info[i].top_line))
1117 //         << write_attribute("bottomline", type2string(row_info[i].bottom_line))
1118 //         << write_attribute("newpage", type2string(row_info[i].newpage))
1119 //#else
1120            << write_attribute("topline", tostr(row_info[i].top_line))
1121            << write_attribute("bottomline", tostr(row_info[i].bottom_line))
1122            << write_attribute("newpage", tostr(row_info[i].newpage))
1123 //#endif
1124            << ">\n";
1125         for (int j = 0; j < columns_; ++j) {
1126 #if 0
1127             if (!i) {
1128                 os << "<Column"
1129 //#if 0
1130 //                 << write_attribute("alignment", type2string(column_info[j].alignment))
1131 //                 << write_attribute("valignment", type2string(column_info[j].valignment))
1132 //                 << write_attribute("leftline", type2string(column_info[j].left_line))
1133 //                 << write_attribute("rightline", type2string(column_info[j].right_line))
1134 //#else
1135                    << write_attribute("alignment", tostr(column_info[j].alignment))
1136                    << write_attribute("valignment", tostr(column_info[j].valignment))
1137                    << write_attribute("leftline", tostr(column_info[j].left_line))
1138                    << write_attribute("rightline", tostr(column_info[j].right_line))
1139
1140 //#endif
1141                    << write_attribute("width",
1142                                       VSpace(column_info[j].p_width)
1143                                       .asLyXCommand())
1144                    << write_attribute("special", column_info[j].align_special)
1145                    << ">\n";
1146             } else {
1147                 os << "<Column>\n";
1148             }
1149 #endif
1150             os << "<Cell"
1151                << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1152 //#if 0
1153 //             << write_attribute("alignment", type2string(cell_info[i][j].alignment))
1154 //             << write_attribute("valignment", type2string(cell_info[i][j].valignment))
1155 //             << write_attribute("topline", type2string(cell_info[i][j].top_line))
1156 //             << write_attribute("bottomline", type2string(cell_info[i][j].bottom_line))
1157 //             << write_attribute("leftline", type2string(cell_info[i][j].left_line))
1158 //             << write_attribute("rightline", type2string(cell_info[i][j].right_line))
1159 //             << write_attribute("rotate", type2string(cell_info[i][j].rotate))
1160 //             << write_attribute("usebox", type2string(cell_info[i][j].usebox))
1161 //#else
1162                << write_attribute("alignment", tostr(cell_info[i][j].alignment))
1163                << write_attribute("valignment", tostr(cell_info[i][j].valignment))
1164                << write_attribute("topline", tostr(cell_info[i][j].top_line))
1165                << write_attribute("bottomline", tostr(cell_info[i][j].bottom_line))
1166                << write_attribute("leftline", tostr(cell_info[i][j].left_line))
1167                << write_attribute("rightline", tostr(cell_info[i][j].right_line))
1168                << write_attribute("rotate", tostr(cell_info[i][j].rotate))
1169                << write_attribute("usebox", tostr(cell_info[i][j].usebox))
1170 //#endif
1171                << write_attribute("width", cell_info[i][j].p_width)
1172                << write_attribute("special", cell_info[i][j].align_special)
1173                << ">\n";
1174             os << "\\begin_inset ";
1175             cell_info[i][j].inset.Write(buf, os);
1176             os << "\n\\end_inset \n"
1177                << "</Cell>\n";
1178 #if 0
1179                << "</Column>\n";
1180 #endif
1181         }
1182         os << "</Row>\n";
1183     }
1184     os << "</LyXTabular>\n";
1185 }
1186
1187
1188 // I would have liked a fromstr template a lot better. (Lgb)
1189
1190 static inline
1191 bool string2type(string const str, LyXAlignment & num)
1192 {
1193     if (str == "none")
1194         num = LYX_ALIGN_NONE;
1195     else if (str == "block")
1196         num = LYX_ALIGN_BLOCK;
1197     else if (str == "left")
1198         num = LYX_ALIGN_LEFT;
1199     else if (str == "center")
1200         num = LYX_ALIGN_CENTER;
1201     else if (str == "right")
1202         num = LYX_ALIGN_RIGHT;
1203     else
1204         return false;
1205     return true;
1206 }
1207
1208
1209 static inline
1210 bool string2type(string const str, LyXTabular::VAlignment & num)
1211 {
1212     if (str == "top")
1213         num = LyXTabular::LYX_VALIGN_TOP;
1214     else if (str == "center")
1215         num = LyXTabular::LYX_VALIGN_CENTER;
1216     else if (str == "bottom")
1217         num = LyXTabular::LYX_VALIGN_BOTTOM;
1218     else
1219         return false;
1220     return true;
1221 }
1222
1223
1224 static inline
1225 bool string2type(string const str, LyXTabular::BoxType & num)
1226 {
1227     if (str == "none")
1228         num = LyXTabular::BOX_NONE;
1229     else if (str == "parbox")
1230         num = LyXTabular::BOX_PARBOX;
1231     else if (str == "minipage")
1232         num = LyXTabular::BOX_MINIPAGE;
1233     else
1234         return false;
1235     return true;
1236 }
1237
1238
1239 static inline
1240 bool string2type(string const str, bool & num)
1241 {
1242     if (str == "true")
1243         num = true;
1244     else if (str == "false")
1245         num = false;
1246     else
1247         return false;
1248     return true;
1249 }
1250
1251
1252 static
1253 bool getTokenValue(string const & str, const char * token, string & ret)
1254 {
1255     size_t token_length = strlen(token);
1256     string::size_type pos = str.find(token);
1257
1258     if (pos == string::npos || pos+token_length+1 >= str.length()
1259         || str[pos+token_length] != '=')
1260         return false;
1261     ret.erase();
1262     pos += token_length + 1;
1263     char ch = str[pos];
1264     if ((ch != '"') && (ch != '\'')) { // only read till next space
1265         ret += ch;
1266         ch = ' ';
1267     }
1268     while((pos < str.length() - 1) && (str[++pos] != ch))
1269         ret += str[pos];
1270
1271     return true;
1272 }
1273
1274
1275 //#define USE_OLD_READFORMAT
1276
1277 //#ifndef USE_OLD_READFORMAT
1278 static
1279 bool getTokenValue(string const & str, const char * token, int & num)
1280 {
1281     string tmp;
1282     if (!getTokenValue(str, token, tmp))
1283         return false;
1284     num = strToInt(tmp);
1285     return true;
1286 }
1287
1288
1289 static
1290 bool getTokenValue(string const & str, const char * token, LyXAlignment & num)
1291 {
1292     string tmp;
1293     if (!getTokenValue(str, token, tmp))
1294         return false;
1295     return string2type(tmp, num);
1296 }
1297
1298
1299 static
1300 bool getTokenValue(string const & str, const char * token,
1301                    LyXTabular::VAlignment & num)
1302 {
1303     string tmp;
1304     if (!getTokenValue(str, token, tmp))
1305         return false;
1306     return string2type(tmp, num);
1307 }
1308
1309
1310 static
1311 bool getTokenValue(string const & str, const char * token,
1312                    LyXTabular::BoxType & num)
1313 {
1314     string tmp;
1315     if (!getTokenValue(str, token, tmp))
1316         return false;
1317     return string2type(tmp, num);
1318 }
1319
1320
1321 static
1322 bool getTokenValue(string const & str, const char * token, bool & flag)
1323 {
1324     string tmp;
1325     if (!getTokenValue(str, token, tmp))
1326         return false;
1327     return string2type(tmp, flag);
1328 }    
1329
1330 //#else
1331
1332 //  static
1333 //  bool getTokenValue(string const & str, const char * token, int & num)
1334 //  {
1335 //      string::size_type pos = str.find(token);
1336 //      char ch = str[pos + strlen(token)];
1337
1338 //      if ((pos == string::npos) || (ch != '='))
1339 //      return false;
1340 //      string ret;
1341 //      pos += strlen(token) + 1;
1342 //      ch = str[pos];
1343 //      if ((ch != '"') && (ch != '\'')) { // only read till next space
1344 //      if (!isdigit(ch))
1345 //          return false;
1346 //      ret += ch;
1347 //      }
1348 //      ++pos;
1349 //      while((pos < str.length() - 1) && isdigit(str[pos]))
1350 //      ret += str[pos++];
1351
1352 //      num = strToInt(ret);
1353 //      return true;
1354 //  }
1355
1356
1357 //  static
1358 //  bool getTokenValue(string const & str, const char * token, LyXAlignment & num)
1359 //  {
1360 //      int tmp;
1361 //      bool const ret = getTokenValue(str, token, tmp);
1362 //      num = static_cast<LyXAlignment>(tmp);
1363 //      return ret;
1364 //  }
1365
1366
1367 //  static
1368 //  bool getTokenValue(string const & str, const char * token,
1369 //                 LyXTabular::VAlignment & num)
1370 //  {
1371 //      int tmp;
1372 //      bool const ret = getTokenValue(str, token, tmp);
1373 //      num = static_cast<LyXTabular::VAlignment>(tmp);
1374 //      return ret;
1375 //  }
1376
1377
1378 //  static
1379 //  bool getTokenValue(string const & str, const char * token,
1380 //                 LyXTabular::BoxType & num)
1381 //  {
1382 //      int tmp;
1383 //      bool ret = getTokenValue(str, token, tmp);
1384 //      num = static_cast<LyXTabular::BoxType>(tmp);
1385 //      return ret;
1386 //  }
1387
1388
1389 //  static
1390 //  bool getTokenValue(string const & str, const char * token, bool & flag)
1391 //  {
1392 //      string::size_type pos = str.find(token);
1393 //      char ch = str[pos + strlen(token)];
1394
1395 //      if ((pos == string::npos) || (ch != '='))
1396 //      return false;
1397 //      string ret;
1398 //      pos += strlen(token) + 1;
1399 //      ch = str[pos];
1400 //      if ((ch != '"') && (ch != '\'')) { // only read till next space
1401 //      if (!isdigit(ch))
1402 //          return false;
1403 //      ret += ch;
1404 //      }
1405 //      ++pos;
1406 //      while((pos < str.length() - 1) && isdigit(str[pos]))
1407 //      ret += str[pos++];
1408
1409 //      flag = strToInt(ret);
1410 //      return true;
1411 //  }
1412
1413 //  #endif
1414
1415 static inline
1416 void l_getline(istream & is, string & str)
1417 {
1418     getline(is, str);
1419     while(str.empty())
1420         getline(is, str);
1421 }
1422
1423
1424 //#ifndef USE_OLD_READFORMAT
1425
1426 void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
1427 {
1428         string line;
1429         istream & is = lex.getStream();
1430
1431         l_getline(is, line);
1432         if (!prefixIs(line, "<LyXTabular ")) {
1433                 OldFormatRead(lex, line);
1434                 return;
1435         }
1436
1437         int version;
1438         if (!getTokenValue(line, "version", version))
1439                 return;
1440         if (version == 1)
1441                 ReadOld(buf, is, lex, line);
1442         else if (version == 2)
1443                 ReadNew(buf, is, lex, line);
1444 }
1445
1446
1447 //#if 0
1448 //void LyXTabular::ReadNew(Buffer const * buf, LyXLex & lex)
1449 //{
1450 //    string line;
1451 //    istream & is = lex.getStream();
1452 //
1453 //    l_getline(is, line);
1454 //    if (!prefixIs(line, "<LyXTabular ")) {
1455 //      OldFormatRead(lex, line);
1456 //      return;
1457 //    }
1458 //
1459 //    int version;
1460 //    if (!getTokenValue(line, "version", version))
1461 //      return;
1462 //#else
1463 void LyXTabular::ReadNew(Buffer const * buf, istream & is,
1464                          LyXLex & lex, string const & l)
1465 {
1466     string line(l);
1467 //#endif    
1468     int rows_arg;
1469     if (!getTokenValue(line, "rows", rows_arg))
1470         return;
1471     int columns_arg;
1472     if (!getTokenValue(line, "columns", columns_arg))
1473         return;
1474     Init(rows_arg, columns_arg);
1475     l_getline(is, line);
1476     if (!prefixIs(line, "<Features")) {
1477         lyxerr << "Wrong tabular format (expected <Feture ...> got" <<
1478             line << ")" << endl;
1479         return;
1480     }
1481     getTokenValue(line, "rotate", rotate);
1482     getTokenValue(line, "islongtable", is_long_tabular);
1483     getTokenValue(line, "endhead", endhead);
1484     getTokenValue(line, "endfirsthead", endfirsthead);
1485     getTokenValue(line, "endfoot", endfoot);
1486     getTokenValue(line, "endlastfoot", endlastfoot);
1487
1488     for (int j = 0; j < columns_; ++j) {
1489         l_getline(is,line);
1490         if (!prefixIs(line,"<Column")) {
1491             lyxerr << "Wrong tabular format (expected <Column ...> got" <<
1492                 line << ")" << endl;
1493             return;
1494         }
1495         getTokenValue(line, "alignment", column_info[j].alignment);
1496         getTokenValue(line, "valignment", column_info[j].valignment);
1497         getTokenValue(line, "leftline", column_info[j].left_line);
1498         getTokenValue(line, "rightline", column_info[j].right_line);
1499         getTokenValue(line, "width", column_info[j].p_width);
1500         getTokenValue(line, "special", column_info[j].align_special);
1501     }
1502
1503     for (int i = 0; i < rows_; ++i) {
1504         l_getline(is, line);
1505         if (!prefixIs(line, "<Row")) {
1506             lyxerr << "Wrong tabular format (expected <Row ...> got" <<
1507                 line << ")" << endl;
1508             return;
1509         }
1510         getTokenValue(line, "topline", row_info[i].top_line);
1511         getTokenValue(line, "bottomline", row_info[i].bottom_line);
1512         getTokenValue(line, "newpage", row_info[i].newpage);
1513         for (int j = 0; j < columns_; ++j) {
1514             l_getline(is, line);
1515             if (!prefixIs(line, "<Cell")) {
1516                 lyxerr << "Wrong tabular format (expected <Cell ...> got" <<
1517                     line << ")" << endl;
1518                 return;
1519             }
1520             getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1521             getTokenValue(line, "alignment", cell_info[i][j].alignment);
1522             getTokenValue(line, "valignment", cell_info[i][j].valignment);
1523             getTokenValue(line, "topline", cell_info[i][j].top_line);
1524             getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1525             getTokenValue(line, "leftline", cell_info[i][j].left_line);
1526             getTokenValue(line, "rightline", cell_info[i][j].right_line);
1527             getTokenValue(line, "rotate", cell_info[i][j].rotate);
1528             getTokenValue(line, "usebox", cell_info[i][j].usebox);
1529             getTokenValue(line, "width", cell_info[i][j].p_width);
1530             getTokenValue(line, "special", cell_info[i][j].align_special);
1531             l_getline(is, line);
1532             if (prefixIs(line, "\\begin_inset")) {
1533                 cell_info[i][j].inset.Read(buf, lex);
1534                 l_getline(is, line);
1535             }
1536             if (line != "</Cell>") {
1537                 lyxerr << "Wrong tabular format (expected </Cell> got" <<
1538                     line << ")" << endl;
1539                 return;
1540             }
1541         }
1542         l_getline(is, line);
1543         if (line != "</Row>") {
1544             lyxerr << "Wrong tabular format (expected </Row> got" <<
1545                 line << ")" << endl;
1546             return;
1547         }
1548     }
1549     while (line != "</LyXTabular>") {
1550         l_getline(is, line);
1551     }
1552     set_row_column_number_info();
1553 }
1554
1555 //  #else
1556
1557 //  void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
1558 //  {
1559 //      string line;
1560 //      istream & is = lex.getStream();
1561
1562 //      l_getline(is, line);
1563 //      if (!prefixIs(line, "<LyXTabular ")) {
1564 //      OldFormatRead(lex, line);
1565 //      return;
1566 //      }
1567
1568 //      int version;
1569 //      int rows_arg;
1570 //      int columns_arg;
1571 //      if (!getTokenValue(line, "version", version))
1572 //      return;
1573 //      if (!getTokenValue(line, "rows", rows_arg))
1574 //      return;
1575 //      if (!getTokenValue(line, "columns", columns_arg))
1576 //      return;
1577 //      Init(rows_arg, columns_arg);
1578 //      l_getline(is, line);
1579 //      if (!prefixIs(line, "<Features ")) {
1580 //      lyxerr << "Wrong tabular format (expected <Feture ...> got" <<
1581 //          line << ")" << endl;
1582 //      return;
1583 //      }
1584 //      getTokenValue(line, "islongtable", is_long_tabular);
1585 //      getTokenValue(line, "endhead", endhead);
1586 //      getTokenValue(line, "endfirsthead", endfirsthead);
1587 //      getTokenValue(line, "endfoot", endfoot);
1588 //      getTokenValue(line, "endlastfoot", endlastfoot);
1589
1590 //      for (int i = 0; i < rows_; ++i) {
1591 //      l_getline(is, line);
1592 //      if (!prefixIs(line, "<Row ")) {
1593 //          lyxerr << "Wrong tabular format (expected <Row ...> got" <<
1594 //              line << ")" << endl;
1595 //          return;
1596 //      }
1597 //      getTokenValue(line, "topline", row_info[i].top_line);
1598 //      getTokenValue(line, "bottomline", row_info[i].bottom_line);
1599 //      getTokenValue(line, "newpage", row_info[i].newpage);
1600 //      for (int j = 0; j < columns_; ++j) {
1601 //          l_getline(is,line);
1602 //          if (!prefixIs(line,"<Column")) {
1603 //              lyxerr << "Wrong tabular format (expected <Column ...> got" <<
1604 //                  line << ")" << endl;
1605 //              return;
1606 //          }
1607 //          if (!i) {
1608 //              getTokenValue(line, "alignment", column_info[j].alignment);
1609 //              getTokenValue(line, "valignment", column_info[j].valignment);
1610 //              getTokenValue(line, "leftline", column_info[j].left_line);
1611 //              getTokenValue(line, "rightline", column_info[j].right_line);
1612 //              getTokenValue(line, "width", column_info[j].p_width);
1613 //              getTokenValue(line, "special", column_info[j].align_special);
1614 //          }
1615 //          l_getline(is, line);
1616 //          if (!prefixIs(line, "<Cell")) {
1617 //              lyxerr << "Wrong tabular format (expected <Cell ...> got" <<
1618 //                  line << ")" << endl;
1619 //              return;
1620 //          }
1621 //          getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1622 //          getTokenValue(line, "alignment", cell_info[i][j].alignment);
1623 //          getTokenValue(line, "valignment", cell_info[i][j].valignment);
1624 //          getTokenValue(line, "topline", cell_info[i][j].top_line);
1625 //          getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1626 //          getTokenValue(line, "leftline", cell_info[i][j].left_line);
1627 //          getTokenValue(line, "rightline", cell_info[i][j].right_line);
1628 //          getTokenValue(line, "rotate", cell_info[i][j].rotate);
1629 //          getTokenValue(line, "usebox", cell_info[i][j].usebox);
1630 //          getTokenValue(line, "width", cell_info[i][j].p_width);
1631 //          getTokenValue(line, "special", cell_info[i][j].align_special);
1632 //          l_getline(is, line);
1633 //          if (prefixIs(line, "\\begin_inset")) {
1634 //              cell_info[i][j].inset.Read(buf, lex);
1635 //              l_getline(is, line);
1636 //          }
1637 //          if (line != "</Cell>") {
1638 //              lyxerr << "Wrong tabular format (expected </Cell> got" <<
1639 //                  line << ")" << endl;
1640 //              return;
1641 //          }
1642 //          l_getline(is, line);
1643 //          if (line != "</Column>") {
1644 //              lyxerr << "Wrong tabular format (expected </Column> got" <<
1645 //                  line << ")" << endl;
1646 //              return;
1647 //          }
1648 //      }
1649 //      l_getline(is, line);
1650 //      if (line != "</Row>") {
1651 //          lyxerr << "Wrong tabular format (expected </Row> got" <<
1652 //              line << ")" << endl;
1653 //          return;
1654 //      }
1655 //      }
1656 //      while (line != "</LyXTabular>") {
1657 //      l_getline(is, line);
1658 //      }
1659 //      set_row_column_number_info();
1660 //  }
1661 //  #endif
1662
1663 void LyXTabular::OldFormatRead(LyXLex & lex, string const & fl)
1664 {
1665     int version;
1666     int i, j;
1667     int rows_arg = 0;
1668     int columns_arg = 0;
1669     int is_long_tabular_arg = false;
1670     int rotate_arg = false;
1671     int a = -1;
1672     int b = -1;
1673     int c = -1;
1674     int d = -1;
1675     int e = 0;
1676     int f = 0;
1677     int g = 0;
1678         
1679     istream & is = lex.getStream();
1680     string s(fl);
1681     if (s.length() > 8)
1682         version = lyx::atoi(s.substr(8, string::npos));
1683     else
1684         version = 1;
1685
1686     vector<int> cont_row_info;
1687
1688     if (version < 5) {
1689         lyxerr << "Tabular format < 5 is not supported anymore\n"
1690             "Get an older version of LyX (< 1.1.x) for conversion!"
1691                << endl;
1692         WriteAlert(_("Warning:"),
1693                    _("Tabular format < 5 is not supported anymore\n"),
1694                    _("Get an older version of LyX (< 1.1.x) for conversion!"));
1695         if (version > 2) {
1696             is >> rows_arg >> columns_arg >> is_long_tabular_arg
1697                >> rotate_arg >> a >> b >> c >> d;
1698         } else
1699             is >> rows_arg >> columns_arg;
1700         Init(rows_arg, columns_arg);
1701         cont_row_info = vector<int>(rows_arg);
1702         SetLongTabular(is_long_tabular_arg);
1703         SetRotateTabular(rotate_arg);
1704         string tmp;
1705         for (i = 0; i < rows_; ++i) {
1706             getline(is, tmp);
1707             cont_row_info[i] = false;
1708         }
1709         for (i = 0; i < columns_; ++i) {
1710             getline(is, tmp);
1711         }
1712         for (i = 0; i < rows_; ++i) {
1713             for (j = 0; j < columns_; ++j) {
1714                 getline(is, tmp);
1715             }
1716         }
1717     } else {
1718         is >> rows_arg >> columns_arg >> is_long_tabular_arg
1719            >> rotate_arg >> a >> b >> c >> d;
1720         Init(rows_arg, columns_arg);
1721         cont_row_info = vector<int>(rows_arg);
1722         SetLongTabular(is_long_tabular_arg);
1723         SetRotateTabular(rotate_arg);
1724         endhead = a + 1;
1725         endfirsthead = b + 1;
1726         endfoot = c + 1;
1727         endlastfoot = d + 1;
1728         for (i = 0; i < rows_; ++i) {
1729             a = b = c = d = e = f = g = 0;
1730             is >> a >> b >> c >> d;
1731             row_info[i].top_line = a;
1732             row_info[i].bottom_line = b;
1733             cont_row_info[i] = c;
1734             row_info[i].newpage = d;
1735         }
1736         for (i = 0; i < columns_; ++i) {
1737             string s1;
1738             string s2;
1739             is >> a >> b >> c;
1740 #if 1
1741             char ch; // skip '"'
1742             is >> ch;
1743 #else
1744             // ignore is buggy but we will use it later (Lgb)
1745             is.ignore(); // skip '"'
1746 #endif    
1747             getline(is, s1, '"');
1748 #if 1
1749             is >> ch; // skip '"'
1750 #else
1751             // ignore is buggy but we will use it later (Lgb)
1752             is.ignore(); // skip '"'
1753 #endif
1754             getline(is, s2, '"');
1755             column_info[i].alignment = static_cast<LyXAlignment>(a);
1756             column_info[i].left_line = b;
1757             column_info[i].right_line = c;
1758             column_info[i].p_width = s1;
1759             column_info[i].align_special = s2;
1760         }
1761         for (i = 0; i < rows_; ++i) {
1762             for (j = 0; j < columns_; ++j) {
1763                 string s1;
1764                 string s2;
1765                 is >> a >> b >> c >> d >> e >> f >> g;
1766 #if 1
1767                 char ch;
1768                 is >> ch; // skip '"'
1769 #else
1770                 // ignore is buggy but we will use it later (Lgb)
1771                 is.ignore(); // skip '"'
1772 #endif
1773                 getline(is, s1, '"');
1774 #if 1
1775                 is >> ch; // skip '"'
1776 #else
1777                 // ignore is buggy but we will use it later (Lgb)
1778                 is.ignore(); // skip '"'
1779 #endif
1780                 getline(is, s2, '"');
1781                 cell_info[i][j].multicolumn = static_cast<char>(a);
1782                 cell_info[i][j].alignment = static_cast<LyXAlignment>(b);
1783                 cell_info[i][j].top_line = static_cast<char>(c);
1784                 cell_info[i][j].bottom_line = static_cast<char>(d);
1785                 cell_info[i][j].left_line = column_info[j].left_line;
1786                 cell_info[i][j].right_line = column_info[j].right_line;
1787                 cell_info[i][j].rotate = static_cast<bool>(f);
1788                 cell_info[i][j].usebox = static_cast<BoxType>(g);
1789                 cell_info[i][j].align_special = s1;
1790                 cell_info[i][j].p_width = s2;
1791             }
1792         }
1793     }
1794     set_row_column_number_info(true);
1795
1796     LyXParagraph * par = new LyXParagraph;
1797     LyXParagraph * return_par = 0;
1798 #ifndef NEW_INSETS
1799     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
1800     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
1801 #endif
1802     string tmptok;
1803     int pos = 0;
1804     char depth = 0;
1805     LyXFont font(LyXFont::ALL_INHERIT);
1806     font.setLanguage(owner_->BufferOwner()->GetLanguage());
1807
1808     while (lex.IsOK()) {
1809         lex.nextToken();
1810         string const token = lex.GetString();
1811         if (token.empty())
1812             continue;
1813         if (token == "\\layout"
1814             || token == "\\end_float"
1815             || token == "\\end_deeper") {
1816             lex.pushToken(token);
1817             break;
1818         }
1819         if (owner_->BufferOwner()->parseSingleLyXformat2Token(lex, par,
1820                                                               return_par,
1821                                                               token, pos,
1822                                                               depth, font
1823 #ifndef NEW_INSETS
1824                                                               ,
1825                                                               footnoteflag,
1826                                                               footnotekind
1827 #endif
1828                 ))
1829         {
1830             // the_end read
1831             lex.pushToken(token);
1832             break;
1833         }
1834         if (return_par) {
1835             lex.printError("New Paragraph allocated! This should not happen!");
1836             lex.pushToken(token);
1837             delete par;
1838             par = return_par;
1839             break;
1840         }
1841     }
1842     // now we have the par we should fill the insets with this!
1843     int cell = 0;
1844     InsetText * inset = GetCellInset(cell);
1845     int row;
1846
1847     for (int i = 0; i < par->Last(); ++i) {
1848         if (par->IsNewline(i)) {
1849             ++cell;
1850             if (cell > GetNumberOfCells()) {
1851                 lyxerr << "Some error in reading old table format occured!" <<
1852                     endl << "Terminating when reading cell[" << cell << "]!" <<
1853                     endl;
1854                 delete par;
1855                 return;
1856             }
1857             row = row_of_cell(cell);
1858             if (cont_row_info[row]) {
1859                 DeleteRow(row);
1860                 cont_row_info.erase(cont_row_info.begin() + row); //&cont_row_info[row]);
1861                 while(!IsFirstCellInRow(--cell));
1862             } else {
1863                 inset = GetCellInset(cell);
1864                 continue;
1865             }
1866             inset = GetCellInset(cell);
1867             row = row_of_cell(cell);
1868             if (!cell_info[row_of_cell(cell)][column_of_cell(cell)].usebox)
1869             {
1870                 // insert a space instead
1871                 par->Erase(i);
1872                 par->InsertChar(i, ' ');
1873             }
1874         }
1875         par->CopyIntoMinibuffer(*owner_->BufferOwner(), i);
1876         inset->par->InsertFromMinibuffer(inset->par->Last());
1877     }
1878     delete par;
1879     Reinit();
1880 }
1881
1882
1883 string const LyXTabular::GetDocBookAlign(int cell, bool isColumn) const
1884 {
1885     int const i = isColumn ? cell : column_of_cell(cell);
1886         
1887     if (!isColumn && IsMultiColumn(cell)) {
1888        if (!cellinfo_of_cell(cell)->align_special.empty()) {
1889            return cellinfo_of_cell(cell)->align_special;
1890        } else {
1891            switch (GetAlignment(cell)) {
1892            case LYX_ALIGN_LEFT:
1893                return "left";
1894            case LYX_ALIGN_RIGHT:
1895                return "right";
1896            default:
1897                return "center";
1898            }
1899        }
1900     } else {
1901        if (!column_info[i].align_special.empty()) {
1902            return column_info[i].align_special;
1903        }
1904 #ifdef IGNORE_THIS_FOR_NOW
1905        else if (!column_info[i].p_width.empty()) {
1906            file += "p{";
1907            file += column_info[i].p_width;
1908            file += '}';
1909        }
1910 #endif
1911        else {
1912            switch (column_info[i].alignment) {
1913            case LYX_ALIGN_LEFT:
1914                return "left";
1915            case LYX_ALIGN_RIGHT:
1916                return "right";
1917            default:
1918                return "center";
1919            }
1920        }
1921     }
1922 }
1923
1924
1925 // cell <0 will tex the preamble
1926 // returns the number of printed newlines
1927 int LyXTabular::DocBookEndOfCell(ostream & os, int cell, int & depth) const
1928 {
1929     int ret = 0;
1930     if (IsLastCell(cell)) {
1931             os << newlineAndDepth(--depth)
1932                << "</ENTRY>"
1933                << newlineAndDepth(--depth)
1934                << "</ROW>"
1935                << newlineAndDepth(--depth)
1936                << "</TBODY>"
1937                << newlineAndDepth(--depth);
1938         if (is_long_tabular)
1939                 os << "</TGROUP>";
1940         else
1941                 os << "</TGROUP>"
1942                    << newlineAndDepth(--depth);
1943         ret += 4;
1944     } else {
1945         if (cell < 0) {
1946             // preamble
1947             if (is_long_tabular)
1948                     os << "<TGROUP ";
1949             else
1950                     os << "<TGROUP ";
1951             os << "COLS='"
1952                << columns_
1953                << "' COLSEP='1' ROWSEP='1'>"
1954                << newlineAndDepth(++depth);
1955             ++ret;
1956             for (int i = 0; i < columns_; ++i) {
1957                     os << "<COLSPEC ALIGN='"
1958                        << GetDocBookAlign(i, true)
1959                        << "' COLNAME='col"
1960                        << i + 1
1961                        << "' COLNUM='"
1962                        << i + 1
1963                        << "' COLSEP='";
1964                if (i == (columns_-1)) {
1965                        os << '1';
1966                } else {
1967                    if (column_info[i].right_line ||
1968                        column_info[i+1].left_line)
1969                            os << '1';
1970                    else
1971                            os << '0';
1972                }
1973                os << "'>"
1974                   << newlineAndDepth(depth);
1975                 ++ret;
1976 #ifdef NOT_HANDLED_YET_AS_I_DONT_KNOW_HOW
1977                 if (column_info[i].left_line)
1978                         os << '|';
1979 #endif
1980             }
1981             os << "<TBODY>"
1982                << newlineAndDepth(++depth)
1983                << "<ROW>"
1984                << newlineAndDepth(++depth)
1985                << "<ENTRY ALIGN='"
1986                << GetDocBookAlign(0)
1987                << "'";
1988            if (IsMultiColumn(0)) {
1989                    os << " NAMEST='col1' NAMEEND='col"
1990                       << cells_in_multicolumn(0)
1991                       << "'";
1992            }
1993            os << ">"
1994               << newlineAndDepth(++depth);
1995             ret += 3;
1996         } else {
1997             if (IsLastCellInRow(cell)) {
1998                     os << newlineAndDepth(--depth)
1999                        << "</ENTRY>"
2000                        << newlineAndDepth(--depth)
2001                        << "</ROW>"
2002                        << newlineAndDepth(depth)
2003                        << "<ROW>"
2004                        << newlineAndDepth(++depth)
2005                        << "<ENTRY ALIGN='"
2006                        << GetDocBookAlign(cell + 1)
2007                        << "' VALIGN='middle'";
2008                if (IsMultiColumn(cell + 1)) {
2009                        os << " NAMEST='col"
2010                           << column_of_cell(cell + 1) + 1
2011                           << "' NAMEEND='col"
2012                           << column_of_cell(cell + 1) +
2013                                cells_in_multicolumn(cell + 1)
2014                           << "'";
2015                }
2016                os << ">"
2017                   << newlineAndDepth(++depth);
2018                 ret += 4;
2019             } else {
2020                     os << newlineAndDepth(--depth)
2021                        << "</ENTRY>"
2022                        << newlineAndDepth(depth)
2023                        << "<ENTRY ALIGN='"
2024                        << GetDocBookAlign(cell + 1)
2025                        << "' VALIGN='middle'";
2026                if (IsMultiColumn(cell + 1)) {
2027                        os << " NAMEST='col"
2028                           << column_of_cell(cell + 1) + 1
2029                           << "' NAMEEND='col"
2030                           << column_of_cell(cell + 1) +
2031                                cells_in_multicolumn(cell + 1)
2032                           << "'";
2033                }
2034                os << ">"
2035                   << newlineAndDepth(++depth);
2036                 ret += 3;
2037             }
2038         }
2039     }
2040     return ret;
2041 }
2042
2043
2044 bool LyXTabular::IsMultiColumn(int cell, bool real) const
2045 {
2046     return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
2047         (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
2048 }
2049
2050
2051 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
2052 {
2053     int const row = row_of_cell(cell);
2054     int const column = column_of_cell(cell);
2055     return  &cell_info[row][column];
2056 }
2057
2058
2059 void LyXTabular::SetMultiColumn(int cell, int number)
2060 {
2061     cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
2062     cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
2063     cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
2064     cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
2065     for (number--; number > 0; --number) {
2066         cellinfo_of_cell(cell+number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
2067     }
2068     set_row_column_number_info();
2069 }
2070
2071
2072 int LyXTabular::cells_in_multicolumn(int cell) const
2073 {
2074     int const row = row_of_cell(cell);
2075     int column = column_of_cell(cell);
2076     int result = 1;
2077     ++column;
2078     while ((column < columns_) &&
2079            cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
2080     {
2081         ++result;
2082         ++column;
2083     }
2084     return result;
2085 }
2086
2087
2088 int LyXTabular::UnsetMultiColumn(int cell)
2089 {
2090     int const row = row_of_cell(cell);
2091     int column = column_of_cell(cell);
2092     
2093     int result = 0;
2094     
2095     if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
2096         cell_info[row][column].multicolumn = CELL_NORMAL;
2097         ++column;
2098         while ((column < columns_) &&
2099                (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
2100         {
2101             cell_info[row][column].multicolumn = CELL_NORMAL;
2102             ++column;
2103             ++result;
2104         }
2105     }
2106     set_row_column_number_info();
2107     return result;
2108 }
2109
2110
2111 void LyXTabular::SetLongTabular(bool what)
2112 {
2113     is_long_tabular = what;
2114 }
2115
2116
2117 bool LyXTabular::IsLongTabular() const
2118 {
2119     return is_long_tabular;
2120 }
2121
2122
2123 void LyXTabular::SetRotateTabular(bool flag)
2124 {
2125     rotate = flag;
2126 }
2127
2128
2129 bool LyXTabular::GetRotateTabular() const
2130 {
2131     return rotate;
2132 }
2133
2134
2135 void LyXTabular::SetRotateCell(int cell, bool flag)
2136 {
2137     cellinfo_of_cell(cell)->rotate = flag;
2138 }
2139
2140
2141 bool LyXTabular::GetRotateCell(int cell) const
2142 {
2143     return cellinfo_of_cell(cell)->rotate;
2144 }
2145
2146
2147 bool LyXTabular::NeedRotating() const
2148 {
2149     if (rotate)
2150         return true;
2151     for (int i = 0; i < rows_; ++i) {
2152         for (int j = 0; j < columns_; ++j) {
2153             if (cell_info[i][j].rotate)
2154                 return true;
2155         }
2156     }
2157     return false;
2158 }
2159
2160
2161 bool LyXTabular::IsLastCell(int cell) const
2162 {
2163     if ((cell + 1) < GetNumberOfCells())
2164         return false;
2165     return true;
2166 }
2167
2168
2169 int LyXTabular::GetCellAbove(int cell) const
2170 {
2171     if (row_of_cell(cell) > 0)
2172         return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
2173     return cell;
2174 }
2175
2176
2177 int LyXTabular::GetCellBelow(int cell) const
2178 {
2179     if (row_of_cell(cell) + 1 < rows_)
2180         return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
2181     return cell;
2182 }
2183
2184
2185 int LyXTabular::GetLastCellAbove(int cell) const
2186 {
2187     if (row_of_cell(cell) <= 0)
2188         return cell;
2189     if (!IsMultiColumn(cell))
2190         return GetCellAbove(cell);
2191     return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
2192 }
2193
2194
2195 int LyXTabular::GetLastCellBelow(int cell) const
2196 {
2197     if (row_of_cell(cell) + 1 >= rows_)
2198         return cell;
2199     if (!IsMultiColumn(cell))
2200         return GetCellBelow(cell);
2201     return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
2202 }
2203
2204
2205 int LyXTabular::GetCellNumber(int row, int column) const
2206 {
2207     if (column >= columns_)
2208         column = columns_ - 1;
2209     else if (column < 0)
2210         column = 0;
2211     if (row >= rows_)
2212         row = rows_ - 1;
2213     else if (row < 0)
2214         row = 0;
2215     
2216     return cell_info[row][column].cellno;
2217 }
2218
2219
2220 void LyXTabular::SetUsebox(int cell, BoxType type)
2221 {
2222     cellinfo_of_cell(cell)->usebox = type;
2223 }
2224
2225
2226 LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
2227 {
2228     if (column_info[column_of_cell(cell)].p_width.empty() &&
2229         !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.empty()))
2230         return BOX_NONE;
2231     if (cellinfo_of_cell(cell)->usebox > 1)
2232         return cellinfo_of_cell(cell)->usebox;
2233     return UseParbox(cell);
2234 }
2235
2236
2237 void LyXTabular::SetLTHead(int cell, bool first)
2238 {
2239     int const row = row_of_cell(cell);
2240     int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
2241
2242     if (first) {
2243         if (endfirsthead == val)
2244             endfirsthead = 0;
2245         else
2246             endfirsthead = val;
2247     } else {
2248         if (endhead == val)
2249             endhead = 0;
2250         else
2251             endhead = val;
2252     }
2253 }
2254
2255
2256 bool LyXTabular::GetRowOfLTHead(int cell, int & row) const
2257 {
2258     row = endhead;
2259     if (abs(endhead) > rows_)
2260         return false;
2261     return (row_of_cell(cell) == abs(endhead) - 1);
2262 }
2263
2264
2265 bool LyXTabular::GetRowOfLTFirstHead(int cell, int & row) const
2266 {
2267     row = endfirsthead;
2268     if (abs(endfirsthead) > rows_)
2269         return false;
2270     return (row_of_cell(cell) == abs(endfirsthead) - 1);
2271 }
2272
2273
2274 void LyXTabular::SetLTFoot(int cell, bool last)
2275 {
2276     int const row = row_of_cell(cell);
2277     int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
2278
2279     if (last) {
2280         if (endlastfoot == val)
2281             endlastfoot = 0;
2282         else
2283             endlastfoot = val;
2284     } else {
2285         if (endfoot == val)
2286             endfoot = 0;
2287         else
2288             endfoot = val;
2289     }
2290 }
2291
2292
2293 bool LyXTabular::GetRowOfLTFoot(int cell, int & row) const
2294 {
2295     row = endfoot;
2296     if ((endfoot + 1) > rows_)
2297         return false;
2298     return (row_of_cell(cell) == abs(endfoot) - 1);
2299 }
2300
2301
2302 bool LyXTabular::GetRowOfLTLastFoot(int cell, int & row) const
2303 {
2304     row = endlastfoot;
2305     if (abs(endlastfoot) > rows_)
2306         return false;
2307     return (row_of_cell(cell) == (abs(endlastfoot)-1));
2308 }
2309
2310
2311 void LyXTabular::SetLTNewPage(int cell, bool what)
2312 {
2313     row_info[row_of_cell(cell)].newpage = what;
2314 }
2315
2316
2317 bool LyXTabular::GetLTNewPage(int cell) const
2318 {
2319     return row_info[row_of_cell(cell)].newpage;
2320 }
2321
2322
2323 bool LyXTabular::SetAscentOfRow(int row, int height)
2324 {
2325     if ((row >= rows_) || (row_info[row].ascent_of_row == height))
2326         return false;
2327     row_info[row].ascent_of_row = height;
2328     return true;
2329 }
2330
2331
2332 bool LyXTabular::SetDescentOfRow(int row, int height)
2333 {
2334     if ((row >= rows_) || (row_info[row].descent_of_row == height))
2335         return false;
2336     row_info[row].descent_of_row = height;
2337     return true;
2338 }
2339
2340
2341 int LyXTabular::GetAscentOfRow(int row) const
2342 {
2343     if (row >= rows_)
2344         return 0;
2345     return row_info[row].ascent_of_row;
2346 }
2347
2348
2349 int LyXTabular::GetDescentOfRow(int row) const
2350 {
2351     if (row >= rows_)
2352         return 0;
2353     return row_info[row].descent_of_row;
2354 }
2355
2356
2357 int LyXTabular::GetHeightOfTabular() const
2358 {
2359     int height = 0;
2360
2361     for (int row = 0; row < rows_; ++row)
2362         height += GetAscentOfRow(row) + GetDescentOfRow(row) +
2363             GetAdditionalHeight(GetCellNumber(row, 0));
2364     return height;
2365 }
2366
2367
2368 bool LyXTabular::IsPartOfMultiColumn(int row, int column) const
2369 {
2370     if ((row >= rows_) || (column >= columns_))
2371         return false;
2372     return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
2373 }
2374
2375
2376 int LyXTabular::TeXTopHLine(ostream & os, int row) const
2377 {
2378     if ((row < 0) || (row >= rows_))
2379         return 0;
2380
2381     int const fcell = GetFirstCellInRow(row);
2382     int const n = NumberOfCellsInRow(fcell) + fcell;
2383     int tmp = 0;
2384
2385     for (int i = fcell; i < n; ++i) {
2386         if (TopLine(i))
2387             ++tmp;
2388     }
2389     if (tmp == (n - fcell)){
2390         os << "\\hline ";
2391     } else if (tmp) {
2392         for (int i = fcell; i < n; ++i) {
2393             if (TopLine(i)) {
2394                 os << "\\cline{"
2395                    << column_of_cell(i) + 1
2396                    << '-'
2397                    << right_column_of_cell(i) + 1
2398                    << "} ";
2399             }
2400         }
2401     } else {
2402         return 0;
2403     }
2404     os << "\n";
2405     return 1;
2406 }
2407
2408
2409 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
2410 {
2411     if ((row < 0) || (row >= rows_))
2412         return 0;
2413
2414     int const fcell = GetFirstCellInRow(row);
2415     int const n = NumberOfCellsInRow(fcell) + fcell;
2416     int tmp = 0;
2417
2418     for (int i = fcell; i < n; ++i) {
2419         if (BottomLine(i))
2420             ++tmp;
2421     }
2422     if (tmp == (n-fcell)){
2423         os << "\\hline";
2424     } else if (tmp) {
2425         for (int i = fcell; i < n; ++i) {
2426             if (BottomLine(i)) {
2427                 os << "\\cline{"
2428                    << column_of_cell(i) + 1
2429                    << '-'
2430                    << right_column_of_cell(i) + 1
2431                    << "} ";
2432             }
2433         }
2434     } else {
2435         return 0;
2436     }
2437     os << "\n";
2438     return 1;
2439 }
2440
2441
2442 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
2443 {
2444     int ret = 0;
2445
2446     if (GetRotateCell(cell)) {
2447         os << "\\begin{sideways}\n";
2448         ++ret;
2449     }
2450     if (IsMultiColumn(cell)) {
2451         os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
2452         if (!cellinfo_of_cell(cell)->align_special.empty()) {
2453             os << cellinfo_of_cell(cell)->align_special << "}{";
2454         } else {
2455             if (LeftLine(cell))
2456                 os << '|';
2457             if (!GetPWidth(cell).empty()) {
2458                 switch (GetVAlignment(cell)) {
2459                 case LYX_VALIGN_TOP:
2460                     os << "p";
2461                     break;
2462                 case LYX_VALIGN_CENTER:
2463                     os << "m";
2464                     break;
2465                 case LYX_VALIGN_BOTTOM:
2466                     os << "b";
2467                     break;
2468                 }
2469                 os << "{" << GetPWidth(cell) << '}';
2470             } else {
2471                 switch (GetAlignment(cell)) {
2472                 case LYX_ALIGN_LEFT:
2473                     os << 'l';
2474                     break;
2475                 case LYX_ALIGN_RIGHT:
2476                     os << 'r';
2477                     break;
2478                 default:
2479                     os << 'c';
2480                     break;
2481                 }
2482             }
2483             if (RightLine(cell))
2484                 os << '|';
2485             if (((cell + 1) < numberofcells) && !IsFirstCellInRow(cell+1) &&
2486                 LeftLine(cell+1))
2487                 os << '|';
2488             os << "}{";
2489         }
2490     }
2491     if (GetUsebox(cell) == BOX_PARBOX) {
2492         os << "\\parbox[";
2493         switch (GetVAlignment(cell)) {
2494         case LYX_VALIGN_TOP:
2495             os << "t";
2496             break;
2497         case LYX_VALIGN_CENTER:
2498             os << "c";
2499             break;
2500         case LYX_VALIGN_BOTTOM:
2501             os << "b";
2502             break;
2503         }
2504         os << "]{" << GetPWidth(cell) << "}{";
2505     } else if (GetUsebox(cell) == BOX_MINIPAGE) {
2506         os << "\\begin{minipage}[";
2507         switch (GetVAlignment(cell)) {
2508         case LYX_VALIGN_TOP:
2509             os << "t";
2510             break;
2511         case LYX_VALIGN_CENTER:
2512             os << "m";
2513             break;
2514         case LYX_VALIGN_BOTTOM:
2515             os << "b";
2516             break;
2517         }
2518         os << "]{" << GetPWidth(cell) << "}\n";
2519         ++ret;
2520     }
2521     return ret;
2522 }
2523
2524
2525 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
2526 {
2527     int ret = 0;
2528
2529     // usual cells
2530     if (GetUsebox(cell) == BOX_PARBOX)
2531         os << "}";
2532     else if (GetUsebox(cell) == BOX_MINIPAGE) {
2533         os << "%\n\\end{minipage}";
2534         ret += 2;
2535     }
2536     if (IsMultiColumn(cell)){
2537         os << '}';
2538     }
2539     if (GetRotateCell(cell)) {
2540         os << "%\n\\end{sideways}";
2541         ++ret;
2542     }
2543     return ret;
2544 }
2545
2546
2547 int LyXTabular::Latex(Buffer const * buf,
2548                       ostream & os, bool fragile, bool fp) const
2549 {
2550     int ret = 0;
2551     int cell = 0;
2552
2553     //+---------------------------------------------------------------------
2554     //+                      first the opening preamble                    +
2555     //+---------------------------------------------------------------------
2556
2557     if (rotate) {
2558         os << "\\begin{sideways}\n";
2559         ++ret;
2560     }
2561     if (is_long_tabular)
2562         os << "\\begin{longtable}{";
2563     else
2564         os << "\\begin{tabular}{";
2565     for (int i = 0; i < columns_; ++i) {
2566         if (column_info[i].left_line)
2567             os << '|';
2568         if (!column_info[i].align_special.empty()) {
2569             os << column_info[i].align_special;
2570         } else if (!column_info[i].p_width.empty()) {
2571             switch (column_info[i].valignment) {
2572             case LYX_VALIGN_TOP:
2573                 os << "p";
2574                 break;
2575             case LYX_VALIGN_CENTER:
2576                 os << "m";
2577                 break;
2578             case LYX_VALIGN_BOTTOM:
2579                 os << "b";
2580                 break;
2581             }
2582             os << "{"
2583                << column_info[i].p_width
2584                << '}';
2585         } else {
2586             switch (column_info[i].alignment) {
2587             case LYX_ALIGN_LEFT:
2588                 os << 'l';
2589                 break;
2590             case LYX_ALIGN_RIGHT:
2591                 os << 'r';
2592                 break;
2593             default:
2594                 os << 'c';
2595                 break;
2596             }
2597         }
2598         if (column_info[i].right_line)
2599             os << '|';
2600     }
2601     os << "}\n";
2602     ++ret;
2603
2604     //+---------------------------------------------------------------------
2605     //+                      the single row and columns (cells)            +
2606     //+---------------------------------------------------------------------
2607
2608     //int bret;
2609     for (int i = 0; i < rows_; ++i) {
2610         ret += TeXTopHLine(os, i);
2611         int bret = ret;
2612         if (IsLongTabular()) {
2613             if ((endhead < 0) && (i == (abs(endhead)-1))) {
2614                 os << "\\endhead\n";
2615                 ++ret;
2616             }
2617             if ((endfirsthead < 0) && (i == (abs(endfirsthead)-1))) {
2618                 os << "\\endfirsthead\n";
2619                 ++ret;
2620             }
2621             if ((endfoot < 0) && (i == (abs(endfoot)-1))) {
2622                 os << "\\endfoot\n";
2623                 ++ret;
2624             }
2625             if ((endlastfoot < 0) && (i == (abs(endlastfoot)-1))) {
2626                 os << "\\endlastfoot\n";
2627                 ++ret;
2628             }
2629         }
2630         if (ret > bret) {
2631             ret += TeXBottomHLine(os, i-1);
2632             ret += TeXTopHLine(os, i);
2633         }
2634         for (int j = 0; j < columns_; ++j) {
2635             if (IsPartOfMultiColumn(i,j))
2636                 continue;
2637             ret += TeXCellPreamble(os, cell);
2638             InsetText * inset = GetCellInset(cell);
2639
2640             bool rtl = inset->par->isRightToLeftPar(buf->params) &&
2641                     inset->par->Last() > 0 && GetPWidth(cell).empty();
2642             if (rtl)
2643                 os << "\\R{";
2644             ret += inset->Latex(buf, os, fragile, fp);
2645             if (rtl)
2646                 os << "}";
2647
2648             ret += TeXCellPostamble(os, cell);
2649             if (!IsLastCellInRow(cell)) { // not last cell in row
2650                 os << "&\n";
2651                 ++ret;
2652             }
2653             ++cell;
2654         }
2655         os << "\\\\\n";
2656         ret += TeXBottomHLine(os, i);
2657         bret = ret;
2658         if (IsLongTabular()) {
2659             if ((endhead > 0) && (i == (endhead - 1))) {
2660                 os << "\\endhead\n";
2661                 ++ret;
2662             }
2663             if ((endfirsthead > 0) && (i == (endfirsthead - 1))) {
2664                 os << "\\endfirsthead\n";
2665                 ++ret;
2666             }
2667             if ((endfoot > 0) && (i == (endfoot - 1))) {
2668                 os << "\\endfoot\n";
2669                 ++ret;
2670             }
2671             if ((endlastfoot > 0) && (i == (endlastfoot - 1))) {
2672                 os << "\\endlastfoot\n";
2673                 ++ret;
2674             }
2675 //          if (ret > bret)
2676 //              ret += TeXBottomHLine(os, i);
2677             if (row_info[i].newpage) {
2678                 os << "\\newpage\n";
2679                 ++ret;
2680             }
2681         }
2682     }
2683
2684     //+---------------------------------------------------------------------
2685     //+                      the closing of the tabular                    +
2686     //+---------------------------------------------------------------------
2687
2688     if (is_long_tabular)
2689         os << "\\end{longtable}";
2690     else
2691         os << "\\end{tabular}";
2692     if (rotate) {
2693         os << "\n\\end{sideways}";
2694         ++ret;
2695     }
2696
2697     return ret;
2698 }
2699
2700
2701 int LyXTabular::DocBook(Buffer const * buf, ostream & os) const
2702 {
2703     int ret = 0;
2704
2705     //+---------------------------------------------------------------------
2706     //+                      first the opening preamble                    +
2707     //+---------------------------------------------------------------------
2708
2709     os << "<tgroup cols=\"" << columns_
2710        << "\" colsep=\"1\" rowsep=\"1\">\n";
2711     
2712     for (int i = 0; i < columns_; ++i) {
2713         os << "<colspec colname=\"col" << i << "\" align=\"";
2714         switch (column_info[i].alignment) {
2715         case LYX_ALIGN_LEFT:
2716             os << "left";
2717             break;
2718         case LYX_ALIGN_RIGHT:
2719             os << "right";
2720             break;
2721         default:
2722             os << "center";
2723             break;
2724         }
2725         os << "\"/>\n";
2726         ++ret;
2727     }
2728
2729     //+---------------------------------------------------------------------
2730     //+                      the single row and columns (cells)            +
2731     //+---------------------------------------------------------------------
2732
2733     int cell = 0;
2734     os << "<tbody>\n";
2735     for (int i = 0; i < rows_; ++i) {
2736         os << "<row>\n";
2737         for (int j = 0; j < columns_; ++j) {
2738             if (IsPartOfMultiColumn(i, j))
2739                 continue;
2740             
2741             os << "<entry align=\"";
2742             switch (GetAlignment(cell)) {
2743             case LYX_ALIGN_LEFT:
2744                 os << "left";
2745                 break;
2746             case LYX_ALIGN_RIGHT:
2747                 os << "right";
2748                 break;
2749             default:
2750                 os << "center";
2751                 break;
2752             }
2753             
2754             os << "\" valign=\"";
2755             switch (GetVAlignment(cell)) {
2756             case LYX_VALIGN_TOP:
2757                 os << "top";
2758                 break;
2759             case LYX_VALIGN_BOTTOM:
2760                 os << "bottom";
2761                 break;
2762             case LYX_VALIGN_CENTER:
2763                 os << "middle";
2764             }
2765             os << "\"";
2766             
2767             if (IsMultiColumn(cell)) {
2768                 os << " namest=\"col" << j << "\" ";
2769                 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< "\"";
2770             }
2771             
2772             os << ">";
2773             ret += GetCellInset(cell)->DocBook(buf, os);
2774             os << "</entry>";
2775             ++cell;
2776         }
2777         os << "</row>\n";
2778     }
2779     os << "</tbody>\n";
2780     //+---------------------------------------------------------------------
2781     //+                      the closing of the tabular                    +
2782     //+---------------------------------------------------------------------
2783
2784     os << "</tgroup>";
2785     ++ret;
2786
2787     return ret;
2788 }
2789
2790
2791 static
2792 inline
2793 void print_n_chars(ostream & os, unsigned char ch, int n)
2794 {
2795         os << string(n, ch);
2796 }
2797
2798
2799 int LyXTabular::AsciiTopHLine(ostream & os, int row,
2800                               vector<unsigned int> const & clen) const
2801 {
2802     int const fcell = GetFirstCellInRow(row);
2803     int const n = NumberOfCellsInRow(fcell) + fcell;
2804     int tmp = 0;
2805
2806     for (int i = fcell; i < n; ++i) {
2807         if (TopLine(i)) {
2808             ++tmp;
2809             break;
2810         }
2811     }
2812     if (!tmp)
2813         return 0;
2814
2815     unsigned char ch;
2816     for (int i = fcell; i < n; ++i) {
2817         if (TopLine(i)) {
2818             if (LeftLine(i))
2819                 os << "+-";
2820             else
2821                 os << "--";
2822             ch = '-';
2823         } else {
2824             os << "  ";
2825             ch = ' ';
2826         }
2827         int column = column_of_cell(i);
2828         int len = clen[column];
2829         while(IsPartOfMultiColumn(row, ++column))
2830             len += clen[column] + 4;
2831         print_n_chars(os, ch, len);
2832         if (TopLine(i)) {
2833             if (RightLine(i))
2834                 os << "-+";
2835             else
2836                 os << "--";
2837         } else {
2838             os << "  ";
2839         }
2840     }
2841     os << endl;
2842     return 1;
2843 }
2844
2845
2846 int LyXTabular::AsciiBottomHLine(ostream & os, int row,
2847                                  vector<unsigned int> const & clen) const
2848 {
2849     int const fcell = GetFirstCellInRow(row);
2850     int const n = NumberOfCellsInRow(fcell) + fcell;
2851     int tmp = 0;
2852
2853     for (int i = fcell; i < n; ++i) {
2854         if (BottomLine(i)) {
2855             ++tmp;
2856             break;
2857         }
2858     }
2859     if (!tmp)
2860         return 0;
2861
2862     unsigned char ch;
2863     for (int i = fcell; i < n; ++i) {
2864         if (BottomLine(i)) {
2865             if (LeftLine(i))
2866                 os << "+-";
2867             else
2868                 os << "--";
2869             ch = '-';
2870         } else {
2871             os << "  ";
2872             ch = ' ';
2873         }
2874         int column = column_of_cell(i);
2875         int len = clen[column];
2876         while(IsPartOfMultiColumn(row, ++column))
2877             len += clen[column] + 4;
2878         print_n_chars(os, ch, len);
2879         if (BottomLine(i)) {
2880             if (RightLine(i))
2881                 os << "-+";
2882             else
2883                 os << "--";
2884         } else {
2885             os << "  ";
2886         }
2887     }
2888     os << endl;
2889     return 1;
2890 }
2891
2892
2893 int LyXTabular::AsciiPrintCell(Buffer const * buf, ostream & os,
2894                                int cell, int row, int column,
2895                                vector<unsigned int> const & clen) const
2896 {
2897     ostringstream sstr;
2898     int ret = GetCellInset(cell)->Ascii(buf, sstr, 0);
2899
2900     if (LeftLine(cell))
2901         os << "| ";
2902     else
2903         os << "  ";
2904
2905     unsigned int len1 = sstr.str().length();
2906     unsigned int len2 = clen[column];
2907     while(IsPartOfMultiColumn(row, ++column))
2908         len2 += clen[column] + 4;
2909     len2 -= len1;
2910
2911     switch (GetAlignment(cell)) {
2912     default:
2913     case LYX_ALIGN_LEFT:
2914         len1 = 0;
2915         break;
2916     case LYX_ALIGN_RIGHT:
2917         len1 = len2;
2918         len2 = 0;
2919         break;
2920     case LYX_ALIGN_CENTER:
2921         len1 = len2 / 2;
2922         len2 -= len1;
2923         break;
2924     }
2925
2926     for (unsigned int i = 0; i < len1; ++i)
2927         os << " ";
2928     os << sstr.str();
2929     for (unsigned int i = 0; i < len2; ++i)
2930         os << " ";
2931     if (RightLine(cell))
2932         os << " |";
2933     else
2934         os << "  ";
2935
2936     return ret * 0; // eh? (Lgb)
2937 }
2938
2939
2940 int LyXTabular::Ascii(Buffer const * buf, ostream & os) const
2941 {
2942     int ret = 0;
2943
2944     //+---------------------------------------------------------------------
2945     //+           first calculate the width of the single columns          +
2946     //+---------------------------------------------------------------------
2947     vector<unsigned int> clen(columns_);
2948
2949     // first all non (real) multicolumn cells!
2950     for (int j = 0; j < columns_; ++j) {
2951         clen[j] = 0;
2952         for (int i = 0; i < rows_; ++i) {
2953             int cell = GetCellNumber(i, j);
2954             if (IsMultiColumn(cell, true))
2955                 continue;
2956             ostringstream sstr;
2957             GetCellInset(cell)->Ascii(buf, sstr, 0);
2958             if (clen[j] < sstr.str().length())
2959                 clen[j] = sstr.str().length();
2960         }
2961     }
2962     // then all (real) multicolumn cells!
2963     for (int j = 0; j < columns_; ++j) {
2964         for (int i = 0; i < rows_; ++i) {
2965             int cell = GetCellNumber(i, j);
2966             if (!IsMultiColumn(cell, true) || IsPartOfMultiColumn(i, j))
2967                 continue;
2968             ostringstream sstr;
2969             GetCellInset(cell)->Ascii(buf, sstr, 0);
2970             int len = int(sstr.str().length());
2971             int const n = cells_in_multicolumn(cell);
2972             for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2973                 len -= clen[k];
2974             if (len > int(clen[j + n - 1]))
2975                 clen[j + n - 1] = len;
2976         }
2977     }
2978     int cell = 0;
2979     for (int i = 0; i < rows_; ++i) {
2980         AsciiTopHLine(os, i, clen);
2981         for (int j = 0; j < columns_; ++j) {
2982             if (IsPartOfMultiColumn(i,j))
2983                 continue;
2984             ret += AsciiPrintCell(buf, os, cell, i, j, clen);
2985             ++cell;
2986         }
2987         os << endl;
2988         AsciiBottomHLine(os, i, clen);
2989     }
2990     return ret;
2991 }
2992
2993
2994 InsetText * LyXTabular::GetCellInset(int cell) const
2995 {
2996     return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2997 }
2998
2999
3000 InsetText * LyXTabular::GetCellInset(int row, int column) const
3001 {
3002     return GetCellInset(GetCellNumber(row, column));
3003 }
3004
3005
3006 void LyXTabular::Validate(LaTeXFeatures & features) const
3007 {
3008     if (IsLongTabular())
3009         features.longtable = true;
3010     if (NeedRotating())
3011         features.rotating = true;
3012     for (int cell = 0; cell < numberofcells; ++cell) {
3013         if (GetVAlignment(cell) != LYX_VALIGN_TOP)
3014             features.array = true;
3015         GetCellInset(cell)->Validate(features);
3016     }
3017 }
3018
3019
3020 LyXTabular::BoxType LyXTabular::UseParbox(int cell) const
3021 {
3022     LyXParagraph * par = GetCellInset(cell)->par;
3023
3024     for (; par; par = par->next) {
3025         for (int i = 0; i < par->Last(); ++i) {
3026             if (par->GetChar(i) == LyXParagraph::META_NEWLINE)
3027                 return BOX_PARBOX;
3028         }
3029     }
3030     return BOX_NONE;
3031 }