]> git.lyx.org Git - features.git/blob - src/tabular.C
remove some commented code
[features.git] / src / tabular.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 2000 The LyX Team.
7  *
8  *           @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 template<>
947 inline
948 string const tostr(LyXAlignment const & 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 template<>
971 inline
972 string const tostr(LyXTabular::VAlignment const & num)
973 {
974     switch(num) {
975     case LyXTabular::LYX_VALIGN_TOP:
976         return "top";
977     case LyXTabular::LYX_VALIGN_CENTER:
978         return "center";
979     case LyXTabular::LYX_VALIGN_BOTTOM:
980         return "bottom";
981     }
982     return string();
983 }
984
985
986 template<>
987 inline
988 string const tostr(LyXTabular::BoxType const & num)
989 {
990     switch(num) {
991     case LyXTabular::BOX_NONE:
992         return "none";
993     case LyXTabular::BOX_PARBOX:
994         return "parbox";
995     case LyXTabular::BOX_MINIPAGE:
996         return "minipage";
997     }
998     return string();
999 }
1000
1001
1002 void LyXTabular::Write(Buffer const * buf, ostream & os) const
1003 {
1004     // header line
1005     os << "<lyxtabular"
1006        << write_attribute("version", 2)
1007        << write_attribute("rows", rows_)
1008        << write_attribute("columns", columns_)
1009        << ">\n";
1010     // global longtable options
1011     os << "<features"
1012        << write_attribute("rotate", tostr(rotate))
1013        << write_attribute("islongtable", tostr(is_long_tabular))
1014        << write_attribute("endhead", endhead)
1015        << write_attribute("endfirsthead", endfirsthead)
1016        << write_attribute("endfoot", endfoot)
1017        << write_attribute("endlastfoot", endlastfoot)
1018        << ">\n";
1019     for (int j = 0; j < columns_; ++j) {
1020         os << "<column"
1021            << write_attribute("alignment", tostr(column_info[j].alignment))
1022            << write_attribute("valignment", tostr(column_info[j].valignment))
1023            << write_attribute("leftline", tostr(column_info[j].left_line))
1024            << write_attribute("rightline", tostr(column_info[j].right_line))
1025            << write_attribute("width",
1026                               VSpace(column_info[j].p_width)
1027                               .asLyXCommand())
1028            << write_attribute("special", column_info[j].align_special)
1029            << ">\n";
1030     }
1031     for (int i = 0; i < rows_; ++i) {
1032         os << "<row"
1033            << write_attribute("topline", tostr(row_info[i].top_line))
1034            << write_attribute("bottomline", tostr(row_info[i].bottom_line))
1035            << write_attribute("newpage", tostr(row_info[i].newpage))
1036            << ">\n";
1037         for (int j = 0; j < columns_; ++j) {
1038 #if 0
1039             if (!i) {
1040                 os << "<column"
1041                    << write_attribute("alignment", tostr(column_info[j].alignment))
1042                    << write_attribute("valignment", tostr(column_info[j].valignment))
1043                    << write_attribute("leftline", tostr(column_info[j].left_line))
1044                    << write_attribute("rightline", tostr(column_info[j].right_line))
1045                    << write_attribute("width",
1046                                       VSpace(column_info[j].p_width)
1047                                       .asLyXCommand())
1048                    << write_attribute("special", column_info[j].align_special)
1049                    << ">\n";
1050             } else {
1051                 os << "<column>\n";
1052             }
1053 #endif
1054             os << "<cell"
1055                << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1056                << write_attribute("alignment", tostr(cell_info[i][j].alignment))
1057                << write_attribute("valignment", tostr(cell_info[i][j].valignment))
1058                << write_attribute("topline", tostr(cell_info[i][j].top_line))
1059                << write_attribute("bottomline", tostr(cell_info[i][j].bottom_line))
1060                << write_attribute("leftline", tostr(cell_info[i][j].left_line))
1061                << write_attribute("rightline", tostr(cell_info[i][j].right_line))
1062                << write_attribute("rotate", tostr(cell_info[i][j].rotate))
1063                << write_attribute("usebox", tostr(cell_info[i][j].usebox))
1064                << write_attribute("width", cell_info[i][j].p_width)
1065                << write_attribute("special", cell_info[i][j].align_special)
1066                << ">\n";
1067             os << "\\begin_inset ";
1068             cell_info[i][j].inset.Write(buf, os);
1069             os << "\n\\end_inset \n"
1070                << "</cell>\n";
1071 #if 0
1072                << "</column>\n";
1073 #endif
1074         }
1075         os << "</row>\n";
1076     }
1077     os << "</lyxtabular>\n";
1078 }
1079
1080
1081 // I would have liked a fromstr template a lot better. (Lgb)
1082
1083 static inline
1084 bool string2type(string const str, LyXAlignment & num)
1085 {
1086     if (str == "none")
1087         num = LYX_ALIGN_NONE;
1088     else if (str == "block")
1089         num = LYX_ALIGN_BLOCK;
1090     else if (str == "left")
1091         num = LYX_ALIGN_LEFT;
1092     else if (str == "center")
1093         num = LYX_ALIGN_CENTER;
1094     else if (str == "right")
1095         num = LYX_ALIGN_RIGHT;
1096     else
1097         return false;
1098     return true;
1099 }
1100
1101
1102 static inline
1103 bool string2type(string const str, LyXTabular::VAlignment & num)
1104 {
1105     if (str == "top")
1106         num = LyXTabular::LYX_VALIGN_TOP;
1107     else if (str == "center")
1108         num = LyXTabular::LYX_VALIGN_CENTER;
1109     else if (str == "bottom")
1110         num = LyXTabular::LYX_VALIGN_BOTTOM;
1111     else
1112         return false;
1113     return true;
1114 }
1115
1116
1117 static inline
1118 bool string2type(string const str, LyXTabular::BoxType & num)
1119 {
1120     if (str == "none")
1121         num = LyXTabular::BOX_NONE;
1122     else if (str == "parbox")
1123         num = LyXTabular::BOX_PARBOX;
1124     else if (str == "minipage")
1125         num = LyXTabular::BOX_MINIPAGE;
1126     else
1127         return false;
1128     return true;
1129 }
1130
1131
1132 static inline
1133 bool string2type(string const str, bool & num)
1134 {
1135     if (str == "true")
1136         num = true;
1137     else if (str == "false")
1138         num = false;
1139     else
1140         return false;
1141     return true;
1142 }
1143
1144
1145 static
1146 bool getTokenValue(string const & str, const char * token, string & ret)
1147 {
1148     size_t token_length = strlen(token);
1149     string::size_type pos = str.find(token);
1150
1151     if (pos == string::npos || pos+token_length+1 >= str.length()
1152         || str[pos+token_length] != '=')
1153         return false;
1154     ret.erase();
1155     pos += token_length + 1;
1156     char ch = str[pos];
1157     if ((ch != '"') && (ch != '\'')) { // only read till next space
1158         ret += ch;
1159         ch = ' ';
1160     }
1161     while((pos < str.length() - 1) && (str[++pos] != ch))
1162         ret += str[pos];
1163
1164     return true;
1165 }
1166
1167
1168 static
1169 bool getTokenValue(string const & str, const char * token, int & num)
1170 {
1171     string tmp;
1172     if (!getTokenValue(str, token, tmp))
1173         return false;
1174     num = strToInt(tmp);
1175     return true;
1176 }
1177
1178
1179 static
1180 bool getTokenValue(string const & str, const char * token, LyXAlignment & num)
1181 {
1182     string tmp;
1183     if (!getTokenValue(str, token, tmp))
1184         return false;
1185     return string2type(tmp, num);
1186 }
1187
1188
1189 static
1190 bool getTokenValue(string const & str, const char * token,
1191                    LyXTabular::VAlignment & num)
1192 {
1193     string tmp;
1194     if (!getTokenValue(str, token, tmp))
1195         return false;
1196     return string2type(tmp, num);
1197 }
1198
1199
1200 static
1201 bool getTokenValue(string const & str, const char * token,
1202                    LyXTabular::BoxType & num)
1203 {
1204     string tmp;
1205     if (!getTokenValue(str, token, tmp))
1206         return false;
1207     return string2type(tmp, num);
1208 }
1209
1210
1211 static
1212 bool getTokenValue(string const & str, const char * token, bool & flag)
1213 {
1214     string tmp;
1215     if (!getTokenValue(str, token, tmp))
1216         return false;
1217     return string2type(tmp, flag);
1218 }    
1219
1220
1221 static inline
1222 void l_getline(istream & is, string & str)
1223 {
1224     getline(is, str);
1225     while(str.empty())
1226         getline(is, str);
1227 }
1228
1229
1230 void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
1231 {
1232         string line;
1233         istream & is = lex.getStream();
1234
1235         l_getline(is, line);
1236         if (!prefixIs(line, "<lyxtabular ")
1237             && !prefixIs(line, "<LyXTabular ")) {
1238                 OldFormatRead(lex, line);
1239                 return;
1240         }
1241
1242         int version;
1243         if (!getTokenValue(line, "version", version))
1244                 return;
1245         if (version == 1)
1246                 ReadOld(buf, is, lex, line);
1247         else if (version == 2)
1248                 ReadNew(buf, is, lex, line);
1249 }
1250
1251
1252 void LyXTabular::ReadNew(Buffer const * buf, istream & is,
1253                          LyXLex & lex, string const & l)
1254 {
1255     string line(l);
1256     int rows_arg;
1257     if (!getTokenValue(line, "rows", rows_arg))
1258         return;
1259     int columns_arg;
1260     if (!getTokenValue(line, "columns", columns_arg))
1261         return;
1262     Init(rows_arg, columns_arg);
1263     l_getline(is, line);
1264     if (!prefixIs(line, "<features")) {
1265         lyxerr << "Wrong tabular format (expected <features ...> got" <<
1266             line << ")" << endl;
1267         return;
1268     }
1269     getTokenValue(line, "rotate", rotate);
1270     getTokenValue(line, "islongtable", is_long_tabular);
1271     getTokenValue(line, "endhead", endhead);
1272     getTokenValue(line, "endfirsthead", endfirsthead);
1273     getTokenValue(line, "endfoot", endfoot);
1274     getTokenValue(line, "endlastfoot", endlastfoot);
1275
1276     for (int j = 0; j < columns_; ++j) {
1277         l_getline(is,line);
1278         if (!prefixIs(line,"<column")) {
1279             lyxerr << "Wrong tabular format (expected <column ...> got" <<
1280                 line << ")" << endl;
1281             return;
1282         }
1283         getTokenValue(line, "alignment", column_info[j].alignment);
1284         getTokenValue(line, "valignment", column_info[j].valignment);
1285         getTokenValue(line, "leftline", column_info[j].left_line);
1286         getTokenValue(line, "rightline", column_info[j].right_line);
1287         getTokenValue(line, "width", column_info[j].p_width);
1288         getTokenValue(line, "special", column_info[j].align_special);
1289     }
1290
1291     for (int i = 0; i < rows_; ++i) {
1292         l_getline(is, line);
1293         if (!prefixIs(line, "<row")) {
1294             lyxerr << "Wrong tabular format (expected <row ...> got" <<
1295                 line << ")" << endl;
1296             return;
1297         }
1298         getTokenValue(line, "topline", row_info[i].top_line);
1299         getTokenValue(line, "bottomline", row_info[i].bottom_line);
1300         getTokenValue(line, "newpage", row_info[i].newpage);
1301         for (int j = 0; j < columns_; ++j) {
1302             l_getline(is, line);
1303             if (!prefixIs(line, "<cell")) {
1304                 lyxerr << "Wrong tabular format (expected <cell ...> got" <<
1305                     line << ")" << endl;
1306                 return;
1307             }
1308             getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1309             getTokenValue(line, "alignment", cell_info[i][j].alignment);
1310             getTokenValue(line, "valignment", cell_info[i][j].valignment);
1311             getTokenValue(line, "topline", cell_info[i][j].top_line);
1312             getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1313             getTokenValue(line, "leftline", cell_info[i][j].left_line);
1314             getTokenValue(line, "rightline", cell_info[i][j].right_line);
1315             getTokenValue(line, "rotate", cell_info[i][j].rotate);
1316             getTokenValue(line, "usebox", cell_info[i][j].usebox);
1317             getTokenValue(line, "width", cell_info[i][j].p_width);
1318             getTokenValue(line, "special", cell_info[i][j].align_special);
1319             l_getline(is, line);
1320             if (prefixIs(line, "\\begin_inset")) {
1321                 cell_info[i][j].inset.Read(buf, lex);
1322                 l_getline(is, line);
1323             }
1324             if (line != "</cell>") {
1325                 lyxerr << "Wrong tabular format (expected </cell> got" <<
1326                     line << ")" << endl;
1327                 return;
1328             }
1329         }
1330         l_getline(is, line);
1331         if (line != "</row>") {
1332             lyxerr << "Wrong tabular format (expected </row> got" <<
1333                 line << ")" << endl;
1334             return;
1335         }
1336     }
1337     while (line != "</lyxtabular>") {
1338         l_getline(is, line);
1339     }
1340     set_row_column_number_info();
1341 }
1342
1343
1344 void LyXTabular::OldFormatRead(LyXLex & lex, string const & fl)
1345 {
1346     int version;
1347     int i, j;
1348     int rows_arg = 0;
1349     int columns_arg = 0;
1350     int is_long_tabular_arg = false;
1351     int rotate_arg = false;
1352     int a = -1;
1353     int b = -1;
1354     int c = -1;
1355     int d = -1;
1356     int e = 0;
1357     int f = 0;
1358     int g = 0;
1359         
1360     istream & is = lex.getStream();
1361     string s(fl);
1362     if (s.length() > 8)
1363         version = lyx::atoi(s.substr(8, string::npos));
1364     else
1365         version = 1;
1366
1367     vector<int> cont_row_info;
1368
1369     if (version < 5) {
1370         lyxerr << "Tabular format < 5 is not supported anymore\n"
1371             "Get an older version of LyX (< 1.1.x) for conversion!"
1372                << endl;
1373         WriteAlert(_("Warning:"),
1374                    _("Tabular format < 5 is not supported anymore\n"),
1375                    _("Get an older version of LyX (< 1.1.x) for conversion!"));
1376         if (version > 2) {
1377             is >> rows_arg >> columns_arg >> is_long_tabular_arg
1378                >> rotate_arg >> a >> b >> c >> d;
1379         } else
1380             is >> rows_arg >> columns_arg;
1381         Init(rows_arg, columns_arg);
1382         cont_row_info = vector<int>(rows_arg);
1383         SetLongTabular(is_long_tabular_arg);
1384         SetRotateTabular(rotate_arg);
1385         string tmp;
1386         for (i = 0; i < rows_; ++i) {
1387             getline(is, tmp);
1388             cont_row_info[i] = false;
1389         }
1390         for (i = 0; i < columns_; ++i) {
1391             getline(is, tmp);
1392         }
1393         for (i = 0; i < rows_; ++i) {
1394             for (j = 0; j < columns_; ++j) {
1395                 getline(is, tmp);
1396             }
1397         }
1398     } else {
1399         is >> rows_arg >> columns_arg >> is_long_tabular_arg
1400            >> rotate_arg >> a >> b >> c >> d;
1401         Init(rows_arg, columns_arg);
1402         cont_row_info = vector<int>(rows_arg);
1403         SetLongTabular(is_long_tabular_arg);
1404         SetRotateTabular(rotate_arg);
1405         endhead = a + 1;
1406         endfirsthead = b + 1;
1407         endfoot = c + 1;
1408         endlastfoot = d + 1;
1409         for (i = 0; i < rows_; ++i) {
1410             a = b = c = d = e = f = g = 0;
1411             is >> a >> b >> c >> d;
1412             row_info[i].top_line = a;
1413             row_info[i].bottom_line = b;
1414             cont_row_info[i] = c;
1415             row_info[i].newpage = d;
1416         }
1417         for (i = 0; i < columns_; ++i) {
1418             string s1;
1419             string s2;
1420             is >> a >> b >> c;
1421 #if 1
1422             char ch; // skip '"'
1423             is >> ch;
1424 #else
1425             // ignore is buggy but we will use it later (Lgb)
1426             is.ignore(); // skip '"'
1427 #endif    
1428             getline(is, s1, '"');
1429 #if 1
1430             is >> ch; // skip '"'
1431 #else
1432             // ignore is buggy but we will use it later (Lgb)
1433             is.ignore(); // skip '"'
1434 #endif
1435             getline(is, s2, '"');
1436             column_info[i].alignment = static_cast<LyXAlignment>(a);
1437             column_info[i].left_line = b;
1438             column_info[i].right_line = c;
1439             column_info[i].p_width = s1;
1440             column_info[i].align_special = s2;
1441         }
1442         for (i = 0; i < rows_; ++i) {
1443             for (j = 0; j < columns_; ++j) {
1444                 string s1;
1445                 string s2;
1446                 is >> a >> b >> c >> d >> e >> f >> g;
1447 #if 1
1448                 char ch;
1449                 is >> ch; // skip '"'
1450 #else
1451                 // ignore is buggy but we will use it later (Lgb)
1452                 is.ignore(); // skip '"'
1453 #endif
1454                 getline(is, s1, '"');
1455 #if 1
1456                 is >> ch; // skip '"'
1457 #else
1458                 // ignore is buggy but we will use it later (Lgb)
1459                 is.ignore(); // skip '"'
1460 #endif
1461                 getline(is, s2, '"');
1462                 cell_info[i][j].multicolumn = static_cast<char>(a);
1463                 cell_info[i][j].alignment = static_cast<LyXAlignment>(b);
1464                 cell_info[i][j].top_line = static_cast<char>(c);
1465                 cell_info[i][j].bottom_line = static_cast<char>(d);
1466                 cell_info[i][j].left_line = column_info[j].left_line;
1467                 cell_info[i][j].right_line = column_info[j].right_line;
1468                 cell_info[i][j].rotate = static_cast<bool>(f);
1469                 cell_info[i][j].usebox = static_cast<BoxType>(g);
1470                 cell_info[i][j].align_special = s1;
1471                 cell_info[i][j].p_width = s2;
1472             }
1473         }
1474     }
1475     set_row_column_number_info(true);
1476
1477     LyXParagraph * par = new LyXParagraph;
1478     LyXParagraph * return_par = 0;
1479 #ifndef NEW_INSETS
1480     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
1481     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
1482 #endif
1483     string tmptok;
1484     int pos = 0;
1485     char depth = 0;
1486     LyXFont font(LyXFont::ALL_INHERIT);
1487     font.setLanguage(owner_->BufferOwner()->GetLanguage());
1488
1489     while (lex.IsOK()) {
1490         lex.nextToken();
1491         string const token = lex.GetString();
1492         if (token.empty())
1493             continue;
1494         if (token == "\\layout"
1495             || token == "\\end_float"
1496             || token == "\\end_deeper") {
1497             lex.pushToken(token);
1498             break;
1499         }
1500         if (owner_->BufferOwner()->parseSingleLyXformat2Token(lex, par,
1501                                                               return_par,
1502                                                               token, pos,
1503                                                               depth, font
1504 #ifndef NEW_INSETS
1505                                                               ,
1506                                                               footnoteflag,
1507                                                               footnotekind
1508 #endif
1509                 ))
1510         {
1511             // the_end read
1512             lex.pushToken(token);
1513             break;
1514         }
1515         if (return_par) {
1516             lex.printError("New Paragraph allocated! This should not happen!");
1517             lex.pushToken(token);
1518             delete par;
1519             par = return_par;
1520             break;
1521         }
1522     }
1523     // now we have the par we should fill the insets with this!
1524     int cell = 0;
1525     InsetText * inset = GetCellInset(cell);
1526     int row;
1527
1528     for (int i = 0; i < par->Last(); ++i) {
1529         if (par->IsNewline(i)) {
1530             ++cell;
1531             if (cell > GetNumberOfCells()) {
1532                 lyxerr << "Some error in reading old table format occured!" <<
1533                     endl << "Terminating when reading cell[" << cell << "]!" <<
1534                     endl;
1535                 delete par;
1536                 return;
1537             }
1538             row = row_of_cell(cell);
1539             if (cont_row_info[row]) {
1540                 DeleteRow(row);
1541                 cont_row_info.erase(cont_row_info.begin() + row); //&cont_row_info[row]);
1542                 while(!IsFirstCellInRow(--cell));
1543             } else {
1544                 inset = GetCellInset(cell);
1545                 continue;
1546             }
1547             inset = GetCellInset(cell);
1548             row = row_of_cell(cell);
1549             if (!cell_info[row_of_cell(cell)][column_of_cell(cell)].usebox)
1550             {
1551                 // insert a space instead
1552                 par->Erase(i);
1553                 par->InsertChar(i, ' ');
1554             }
1555         }
1556         par->CopyIntoMinibuffer(*owner_->BufferOwner(), i);
1557         inset->par->InsertFromMinibuffer(inset->par->Last());
1558     }
1559     delete par;
1560     Reinit();
1561 }
1562
1563
1564 string const LyXTabular::GetDocBookAlign(int cell, bool isColumn) const
1565 {
1566     int const i = isColumn ? cell : column_of_cell(cell);
1567         
1568     if (!isColumn && IsMultiColumn(cell)) {
1569        if (!cellinfo_of_cell(cell)->align_special.empty()) {
1570            return cellinfo_of_cell(cell)->align_special;
1571        } else {
1572            switch (GetAlignment(cell)) {
1573            case LYX_ALIGN_LEFT:
1574                return "left";
1575            case LYX_ALIGN_RIGHT:
1576                return "right";
1577            default:
1578                return "center";
1579            }
1580        }
1581     } else {
1582        if (!column_info[i].align_special.empty()) {
1583            return column_info[i].align_special;
1584        }
1585 #ifdef IGNORE_THIS_FOR_NOW
1586        else if (!column_info[i].p_width.empty()) {
1587            file += "p{";
1588            file += column_info[i].p_width;
1589            file += '}';
1590        }
1591 #endif
1592        else {
1593            switch (column_info[i].alignment) {
1594            case LYX_ALIGN_LEFT:
1595                return "left";
1596            case LYX_ALIGN_RIGHT:
1597                return "right";
1598            default:
1599                return "center";
1600            }
1601        }
1602     }
1603 }
1604
1605
1606 // cell <0 will tex the preamble
1607 // returns the number of printed newlines
1608 int LyXTabular::DocBookEndOfCell(ostream & os, int cell, int & depth) const
1609 {
1610     int ret = 0;
1611     if (IsLastCell(cell)) {
1612             os << newlineAndDepth(--depth)
1613                << "</ENTRY>"
1614                << newlineAndDepth(--depth)
1615                << "</ROW>"
1616                << newlineAndDepth(--depth)
1617                << "</TBODY>"
1618                << newlineAndDepth(--depth);
1619         if (is_long_tabular)
1620                 os << "</TGROUP>";
1621         else
1622                 os << "</TGROUP>"
1623                    << newlineAndDepth(--depth);
1624         ret += 4;
1625     } else {
1626         if (cell < 0) {
1627             // preamble
1628             if (is_long_tabular)
1629                     os << "<TGROUP ";
1630             else
1631                     os << "<TGROUP ";
1632             os << "COLS='"
1633                << columns_
1634                << "' COLSEP='1' ROWSEP='1'>"
1635                << newlineAndDepth(++depth);
1636             ++ret;
1637             for (int i = 0; i < columns_; ++i) {
1638                     os << "<COLSPEC ALIGN='"
1639                        << GetDocBookAlign(i, true)
1640                        << "' COLNAME='col"
1641                        << i + 1
1642                        << "' COLNUM='"
1643                        << i + 1
1644                        << "' COLSEP='";
1645                if (i == (columns_-1)) {
1646                        os << '1';
1647                } else {
1648                    if (column_info[i].right_line ||
1649                        column_info[i+1].left_line)
1650                            os << '1';
1651                    else
1652                            os << '0';
1653                }
1654                os << "'>"
1655                   << newlineAndDepth(depth);
1656                 ++ret;
1657 #ifdef NOT_HANDLED_YET_AS_I_DONT_KNOW_HOW
1658                 if (column_info[i].left_line)
1659                         os << '|';
1660 #endif
1661             }
1662             os << "<TBODY>"
1663                << newlineAndDepth(++depth)
1664                << "<ROW>"
1665                << newlineAndDepth(++depth)
1666                << "<ENTRY ALIGN='"
1667                << GetDocBookAlign(0)
1668                << "'";
1669            if (IsMultiColumn(0)) {
1670                    os << " NAMEST='col1' NAMEEND='col"
1671                       << cells_in_multicolumn(0)
1672                       << "'";
1673            }
1674            os << ">"
1675               << newlineAndDepth(++depth);
1676             ret += 3;
1677         } else {
1678             if (IsLastCellInRow(cell)) {
1679                     os << newlineAndDepth(--depth)
1680                        << "</ENTRY>"
1681                        << newlineAndDepth(--depth)
1682                        << "</ROW>"
1683                        << newlineAndDepth(depth)
1684                        << "<ROW>"
1685                        << newlineAndDepth(++depth)
1686                        << "<ENTRY ALIGN='"
1687                        << GetDocBookAlign(cell + 1)
1688                        << "' VALIGN='middle'";
1689                if (IsMultiColumn(cell + 1)) {
1690                        os << " NAMEST='col"
1691                           << column_of_cell(cell + 1) + 1
1692                           << "' NAMEEND='col"
1693                           << column_of_cell(cell + 1) +
1694                                cells_in_multicolumn(cell + 1)
1695                           << "'";
1696                }
1697                os << ">"
1698                   << newlineAndDepth(++depth);
1699                 ret += 4;
1700             } else {
1701                     os << newlineAndDepth(--depth)
1702                        << "</ENTRY>"
1703                        << newlineAndDepth(depth)
1704                        << "<ENTRY ALIGN='"
1705                        << GetDocBookAlign(cell + 1)
1706                        << "' VALIGN='middle'";
1707                if (IsMultiColumn(cell + 1)) {
1708                        os << " NAMEST='col"
1709                           << column_of_cell(cell + 1) + 1
1710                           << "' NAMEEND='col"
1711                           << column_of_cell(cell + 1) +
1712                                cells_in_multicolumn(cell + 1)
1713                           << "'";
1714                }
1715                os << ">"
1716                   << newlineAndDepth(++depth);
1717                 ret += 3;
1718             }
1719         }
1720     }
1721     return ret;
1722 }
1723
1724
1725 bool LyXTabular::IsMultiColumn(int cell, bool real) const
1726 {
1727     return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
1728         (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
1729 }
1730
1731
1732 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
1733 {
1734     int const row = row_of_cell(cell);
1735     int const column = column_of_cell(cell);
1736     return  &cell_info[row][column];
1737 }
1738
1739
1740 void LyXTabular::SetMultiColumn(int cell, int number)
1741 {
1742     cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1743     cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
1744     cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
1745     cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
1746     for (number--; number > 0; --number) {
1747         cellinfo_of_cell(cell+number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1748     }
1749     set_row_column_number_info();
1750 }
1751
1752
1753 int LyXTabular::cells_in_multicolumn(int cell) const
1754 {
1755     int const row = row_of_cell(cell);
1756     int column = column_of_cell(cell);
1757     int result = 1;
1758     ++column;
1759     while ((column < columns_) &&
1760            cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1761     {
1762         ++result;
1763         ++column;
1764     }
1765     return result;
1766 }
1767
1768
1769 int LyXTabular::UnsetMultiColumn(int cell)
1770 {
1771     int const row = row_of_cell(cell);
1772     int column = column_of_cell(cell);
1773     
1774     int result = 0;
1775     
1776     if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1777         cell_info[row][column].multicolumn = CELL_NORMAL;
1778         ++column;
1779         while ((column < columns_) &&
1780                (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
1781         {
1782             cell_info[row][column].multicolumn = CELL_NORMAL;
1783             ++column;
1784             ++result;
1785         }
1786     }
1787     set_row_column_number_info();
1788     return result;
1789 }
1790
1791
1792 void LyXTabular::SetLongTabular(bool what)
1793 {
1794     is_long_tabular = what;
1795 }
1796
1797
1798 bool LyXTabular::IsLongTabular() const
1799 {
1800     return is_long_tabular;
1801 }
1802
1803
1804 void LyXTabular::SetRotateTabular(bool flag)
1805 {
1806     rotate = flag;
1807 }
1808
1809
1810 bool LyXTabular::GetRotateTabular() const
1811 {
1812     return rotate;
1813 }
1814
1815
1816 void LyXTabular::SetRotateCell(int cell, bool flag)
1817 {
1818     cellinfo_of_cell(cell)->rotate = flag;
1819 }
1820
1821
1822 bool LyXTabular::GetRotateCell(int cell) const
1823 {
1824     return cellinfo_of_cell(cell)->rotate;
1825 }
1826
1827
1828 bool LyXTabular::NeedRotating() const
1829 {
1830     if (rotate)
1831         return true;
1832     for (int i = 0; i < rows_; ++i) {
1833         for (int j = 0; j < columns_; ++j) {
1834             if (cell_info[i][j].rotate)
1835                 return true;
1836         }
1837     }
1838     return false;
1839 }
1840
1841
1842 bool LyXTabular::IsLastCell(int cell) const
1843 {
1844     if ((cell + 1) < GetNumberOfCells())
1845         return false;
1846     return true;
1847 }
1848
1849
1850 int LyXTabular::GetCellAbove(int cell) const
1851 {
1852     if (row_of_cell(cell) > 0)
1853         return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1854     return cell;
1855 }
1856
1857
1858 int LyXTabular::GetCellBelow(int cell) const
1859 {
1860     if (row_of_cell(cell) + 1 < rows_)
1861         return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1862     return cell;
1863 }
1864
1865
1866 int LyXTabular::GetLastCellAbove(int cell) const
1867 {
1868     if (row_of_cell(cell) <= 0)
1869         return cell;
1870     if (!IsMultiColumn(cell))
1871         return GetCellAbove(cell);
1872     return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1873 }
1874
1875
1876 int LyXTabular::GetLastCellBelow(int cell) const
1877 {
1878     if (row_of_cell(cell) + 1 >= rows_)
1879         return cell;
1880     if (!IsMultiColumn(cell))
1881         return GetCellBelow(cell);
1882     return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1883 }
1884
1885
1886 int LyXTabular::GetCellNumber(int row, int column) const
1887 {
1888     if (column >= columns_)
1889         column = columns_ - 1;
1890     else if (column < 0)
1891         column = 0;
1892     if (row >= rows_)
1893         row = rows_ - 1;
1894     else if (row < 0)
1895         row = 0;
1896     
1897     return cell_info[row][column].cellno;
1898 }
1899
1900
1901 void LyXTabular::SetUsebox(int cell, BoxType type)
1902 {
1903     cellinfo_of_cell(cell)->usebox = type;
1904 }
1905
1906
1907 LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
1908 {
1909     if (column_info[column_of_cell(cell)].p_width.empty() &&
1910         !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.empty()))
1911         return BOX_NONE;
1912     if (cellinfo_of_cell(cell)->usebox > 1)
1913         return cellinfo_of_cell(cell)->usebox;
1914     return UseParbox(cell);
1915 }
1916
1917
1918 void LyXTabular::SetLTHead(int cell, bool first)
1919 {
1920     int const row = row_of_cell(cell);
1921     int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
1922
1923     if (first) {
1924         if (endfirsthead == val)
1925             endfirsthead = 0;
1926         else
1927             endfirsthead = val;
1928     } else {
1929         if (endhead == val)
1930             endhead = 0;
1931         else
1932             endhead = val;
1933     }
1934 }
1935
1936
1937 bool LyXTabular::GetRowOfLTHead(int cell, int & row) const
1938 {
1939     row = endhead;
1940     if (abs(endhead) > rows_)
1941         return false;
1942     return (row_of_cell(cell) == abs(endhead) - 1);
1943 }
1944
1945
1946 bool LyXTabular::GetRowOfLTFirstHead(int cell, int & row) const
1947 {
1948     row = endfirsthead;
1949     if (abs(endfirsthead) > rows_)
1950         return false;
1951     return (row_of_cell(cell) == abs(endfirsthead) - 1);
1952 }
1953
1954
1955 void LyXTabular::SetLTFoot(int cell, bool last)
1956 {
1957     int const row = row_of_cell(cell);
1958     int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
1959
1960     if (last) {
1961         if (endlastfoot == val)
1962             endlastfoot = 0;
1963         else
1964             endlastfoot = val;
1965     } else {
1966         if (endfoot == val)
1967             endfoot = 0;
1968         else
1969             endfoot = val;
1970     }
1971 }
1972
1973
1974 bool LyXTabular::GetRowOfLTFoot(int cell, int & row) const
1975 {
1976     row = endfoot;
1977     if ((endfoot + 1) > rows_)
1978         return false;
1979     return (row_of_cell(cell) == abs(endfoot) - 1);
1980 }
1981
1982
1983 bool LyXTabular::GetRowOfLTLastFoot(int cell, int & row) const
1984 {
1985     row = endlastfoot;
1986     if (abs(endlastfoot) > rows_)
1987         return false;
1988     return (row_of_cell(cell) == (abs(endlastfoot)-1));
1989 }
1990
1991
1992 void LyXTabular::SetLTNewPage(int cell, bool what)
1993 {
1994     row_info[row_of_cell(cell)].newpage = what;
1995 }
1996
1997
1998 bool LyXTabular::GetLTNewPage(int cell) const
1999 {
2000     return row_info[row_of_cell(cell)].newpage;
2001 }
2002
2003
2004 bool LyXTabular::SetAscentOfRow(int row, int height)
2005 {
2006     if ((row >= rows_) || (row_info[row].ascent_of_row == height))
2007         return false;
2008     row_info[row].ascent_of_row = height;
2009     return true;
2010 }
2011
2012
2013 bool LyXTabular::SetDescentOfRow(int row, int height)
2014 {
2015     if ((row >= rows_) || (row_info[row].descent_of_row == height))
2016         return false;
2017     row_info[row].descent_of_row = height;
2018     return true;
2019 }
2020
2021
2022 int LyXTabular::GetAscentOfRow(int row) const
2023 {
2024     if (row >= rows_)
2025         return 0;
2026     return row_info[row].ascent_of_row;
2027 }
2028
2029
2030 int LyXTabular::GetDescentOfRow(int row) const
2031 {
2032     if (row >= rows_)
2033         return 0;
2034     return row_info[row].descent_of_row;
2035 }
2036
2037
2038 int LyXTabular::GetHeightOfTabular() const
2039 {
2040     int height = 0;
2041
2042     for (int row = 0; row < rows_; ++row)
2043         height += GetAscentOfRow(row) + GetDescentOfRow(row) +
2044             GetAdditionalHeight(GetCellNumber(row, 0));
2045     return height;
2046 }
2047
2048
2049 bool LyXTabular::IsPartOfMultiColumn(int row, int column) const
2050 {
2051     if ((row >= rows_) || (column >= columns_))
2052         return false;
2053     return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
2054 }
2055
2056
2057 int LyXTabular::TeXTopHLine(ostream & os, int row) const
2058 {
2059     if ((row < 0) || (row >= rows_))
2060         return 0;
2061
2062     int const fcell = GetFirstCellInRow(row);
2063     int const n = NumberOfCellsInRow(fcell) + fcell;
2064     int tmp = 0;
2065
2066     for (int i = fcell; i < n; ++i) {
2067         if (TopLine(i))
2068             ++tmp;
2069     }
2070     if (tmp == (n - fcell)){
2071         os << "\\hline ";
2072     } else if (tmp) {
2073         for (int i = fcell; i < n; ++i) {
2074             if (TopLine(i)) {
2075                 os << "\\cline{"
2076                    << column_of_cell(i) + 1
2077                    << '-'
2078                    << right_column_of_cell(i) + 1
2079                    << "} ";
2080             }
2081         }
2082     } else {
2083         return 0;
2084     }
2085     os << "\n";
2086     return 1;
2087 }
2088
2089
2090 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
2091 {
2092     if ((row < 0) || (row >= rows_))
2093         return 0;
2094
2095     int const fcell = GetFirstCellInRow(row);
2096     int const n = NumberOfCellsInRow(fcell) + fcell;
2097     int tmp = 0;
2098
2099     for (int i = fcell; i < n; ++i) {
2100         if (BottomLine(i))
2101             ++tmp;
2102     }
2103     if (tmp == (n-fcell)){
2104         os << "\\hline";
2105     } else if (tmp) {
2106         for (int i = fcell; i < n; ++i) {
2107             if (BottomLine(i)) {
2108                 os << "\\cline{"
2109                    << column_of_cell(i) + 1
2110                    << '-'
2111                    << right_column_of_cell(i) + 1
2112                    << "} ";
2113             }
2114         }
2115     } else {
2116         return 0;
2117     }
2118     os << "\n";
2119     return 1;
2120 }
2121
2122
2123 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
2124 {
2125     int ret = 0;
2126
2127     if (GetRotateCell(cell)) {
2128         os << "\\begin{sideways}\n";
2129         ++ret;
2130     }
2131     if (IsMultiColumn(cell)) {
2132         os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
2133         if (!cellinfo_of_cell(cell)->align_special.empty()) {
2134             os << cellinfo_of_cell(cell)->align_special << "}{";
2135         } else {
2136             if (LeftLine(cell))
2137                 os << '|';
2138             if (!GetPWidth(cell).empty()) {
2139                 switch (GetVAlignment(cell)) {
2140                 case LYX_VALIGN_TOP:
2141                     os << "p";
2142                     break;
2143                 case LYX_VALIGN_CENTER:
2144                     os << "m";
2145                     break;
2146                 case LYX_VALIGN_BOTTOM:
2147                     os << "b";
2148                     break;
2149                 }
2150                 os << "{" << GetPWidth(cell) << '}';
2151             } else {
2152                 switch (GetAlignment(cell)) {
2153                 case LYX_ALIGN_LEFT:
2154                     os << 'l';
2155                     break;
2156                 case LYX_ALIGN_RIGHT:
2157                     os << 'r';
2158                     break;
2159                 default:
2160                     os << 'c';
2161                     break;
2162                 }
2163             }
2164             if (RightLine(cell))
2165                 os << '|';
2166             if (((cell + 1) < numberofcells) && !IsFirstCellInRow(cell+1) &&
2167                 LeftLine(cell+1))
2168                 os << '|';
2169             os << "}{";
2170         }
2171     }
2172     if (GetUsebox(cell) == BOX_PARBOX) {
2173         os << "\\parbox[";
2174         switch (GetVAlignment(cell)) {
2175         case LYX_VALIGN_TOP:
2176             os << "t";
2177             break;
2178         case LYX_VALIGN_CENTER:
2179             os << "c";
2180             break;
2181         case LYX_VALIGN_BOTTOM:
2182             os << "b";
2183             break;
2184         }
2185         os << "]{" << GetPWidth(cell) << "}{";
2186     } else if (GetUsebox(cell) == BOX_MINIPAGE) {
2187         os << "\\begin{minipage}[";
2188         switch (GetVAlignment(cell)) {
2189         case LYX_VALIGN_TOP:
2190             os << "t";
2191             break;
2192         case LYX_VALIGN_CENTER:
2193             os << "m";
2194             break;
2195         case LYX_VALIGN_BOTTOM:
2196             os << "b";
2197             break;
2198         }
2199         os << "]{" << GetPWidth(cell) << "}\n";
2200         ++ret;
2201     }
2202     return ret;
2203 }
2204
2205
2206 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
2207 {
2208     int ret = 0;
2209
2210     // usual cells
2211     if (GetUsebox(cell) == BOX_PARBOX)
2212         os << "}";
2213     else if (GetUsebox(cell) == BOX_MINIPAGE) {
2214         os << "%\n\\end{minipage}";
2215         ret += 2;
2216     }
2217     if (IsMultiColumn(cell)){
2218         os << '}';
2219     }
2220     if (GetRotateCell(cell)) {
2221         os << "%\n\\end{sideways}";
2222         ++ret;
2223     }
2224     return ret;
2225 }
2226
2227
2228 int LyXTabular::Latex(Buffer const * buf,
2229                       ostream & os, bool fragile, bool fp) const
2230 {
2231     int ret = 0;
2232     int cell = 0;
2233
2234     //+---------------------------------------------------------------------
2235     //+                      first the opening preamble                    +
2236     //+---------------------------------------------------------------------
2237
2238     if (rotate) {
2239         os << "\\begin{sideways}\n";
2240         ++ret;
2241     }
2242     if (is_long_tabular)
2243         os << "\\begin{longtable}{";
2244     else
2245         os << "\\begin{tabular}{";
2246     for (int i = 0; i < columns_; ++i) {
2247         if (column_info[i].left_line)
2248             os << '|';
2249         if (!column_info[i].align_special.empty()) {
2250             os << column_info[i].align_special;
2251         } else if (!column_info[i].p_width.empty()) {
2252             switch (column_info[i].valignment) {
2253             case LYX_VALIGN_TOP:
2254                 os << "p";
2255                 break;
2256             case LYX_VALIGN_CENTER:
2257                 os << "m";
2258                 break;
2259             case LYX_VALIGN_BOTTOM:
2260                 os << "b";
2261                 break;
2262             }
2263             os << "{"
2264                << column_info[i].p_width
2265                << '}';
2266         } else {
2267             switch (column_info[i].alignment) {
2268             case LYX_ALIGN_LEFT:
2269                 os << 'l';
2270                 break;
2271             case LYX_ALIGN_RIGHT:
2272                 os << 'r';
2273                 break;
2274             default:
2275                 os << 'c';
2276                 break;
2277             }
2278         }
2279         if (column_info[i].right_line)
2280             os << '|';
2281     }
2282     os << "}\n";
2283     ++ret;
2284
2285     //+---------------------------------------------------------------------
2286     //+                      the single row and columns (cells)            +
2287     //+---------------------------------------------------------------------
2288
2289     for (int i = 0; i < rows_; ++i) {
2290         ret += TeXTopHLine(os, i);
2291         int bret = ret;
2292         if (IsLongTabular()) {
2293             if ((endhead < 0) && (i == (abs(endhead)-1))) {
2294                 os << "\\endhead\n";
2295                 ++ret;
2296             }
2297             if ((endfirsthead < 0) && (i == (abs(endfirsthead)-1))) {
2298                 os << "\\endfirsthead\n";
2299                 ++ret;
2300             }
2301             if ((endfoot < 0) && (i == (abs(endfoot)-1))) {
2302                 os << "\\endfoot\n";
2303                 ++ret;
2304             }
2305             if ((endlastfoot < 0) && (i == (abs(endlastfoot)-1))) {
2306                 os << "\\endlastfoot\n";
2307                 ++ret;
2308             }
2309         }
2310         if (ret > bret) {
2311             ret += TeXBottomHLine(os, i-1);
2312             ret += TeXTopHLine(os, i);
2313         }
2314         for (int j = 0; j < columns_; ++j) {
2315             if (IsPartOfMultiColumn(i,j))
2316                 continue;
2317             ret += TeXCellPreamble(os, cell);
2318             InsetText * inset = GetCellInset(cell);
2319
2320             bool rtl = inset->par->isRightToLeftPar(buf->params) &&
2321                     inset->par->Last() > 0 && GetPWidth(cell).empty();
2322             if (rtl)
2323                 os << "\\R{";
2324             ret += inset->Latex(buf, os, fragile, fp);
2325             if (rtl)
2326                 os << "}";
2327
2328             ret += TeXCellPostamble(os, cell);
2329             if (!IsLastCellInRow(cell)) { // not last cell in row
2330                 os << "&\n";
2331                 ++ret;
2332             }
2333             ++cell;
2334         }
2335         os << "\\\\\n";
2336         ret += TeXBottomHLine(os, i);
2337         bret = ret;
2338         if (IsLongTabular()) {
2339             if ((endhead > 0) && (i == (endhead - 1))) {
2340                 os << "\\endhead\n";
2341                 ++ret;
2342             }
2343             if ((endfirsthead > 0) && (i == (endfirsthead - 1))) {
2344                 os << "\\endfirsthead\n";
2345                 ++ret;
2346             }
2347             if ((endfoot > 0) && (i == (endfoot - 1))) {
2348                 os << "\\endfoot\n";
2349                 ++ret;
2350             }
2351             if ((endlastfoot > 0) && (i == (endlastfoot - 1))) {
2352                 os << "\\endlastfoot\n";
2353                 ++ret;
2354             }
2355 //          if (ret > bret)
2356 //              ret += TeXBottomHLine(os, i);
2357             if (row_info[i].newpage) {
2358                 os << "\\newpage\n";
2359                 ++ret;
2360             }
2361         }
2362     }
2363
2364     //+---------------------------------------------------------------------
2365     //+                      the closing of the tabular                    +
2366     //+---------------------------------------------------------------------
2367
2368     if (is_long_tabular)
2369         os << "\\end{longtable}";
2370     else
2371         os << "\\end{tabular}";
2372     if (rotate) {
2373         os << "\n\\end{sideways}";
2374         ++ret;
2375     }
2376
2377     return ret;
2378 }
2379
2380
2381 int LyXTabular::DocBook(Buffer const * buf, ostream & os) const
2382 {
2383     int ret = 0;
2384
2385     //+---------------------------------------------------------------------
2386     //+                      first the opening preamble                    +
2387     //+---------------------------------------------------------------------
2388
2389     os << "<tgroup cols=\"" << columns_
2390        << "\" colsep=\"1\" rowsep=\"1\">\n";
2391     
2392     for (int i = 0; i < columns_; ++i) {
2393         os << "<colspec colname=\"col" << i << "\" align=\"";
2394         switch (column_info[i].alignment) {
2395         case LYX_ALIGN_LEFT:
2396             os << "left";
2397             break;
2398         case LYX_ALIGN_RIGHT:
2399             os << "right";
2400             break;
2401         default:
2402             os << "center";
2403             break;
2404         }
2405         os << "\"/>\n";
2406         ++ret;
2407     }
2408
2409     //+---------------------------------------------------------------------
2410     //+                      the single row and columns (cells)            +
2411     //+---------------------------------------------------------------------
2412
2413     int cell = 0;
2414     os << "<tbody>\n";
2415     for (int i = 0; i < rows_; ++i) {
2416         os << "<row>\n";
2417         for (int j = 0; j < columns_; ++j) {
2418             if (IsPartOfMultiColumn(i, j))
2419                 continue;
2420             
2421             os << "<entry align=\"";
2422             switch (GetAlignment(cell)) {
2423             case LYX_ALIGN_LEFT:
2424                 os << "left";
2425                 break;
2426             case LYX_ALIGN_RIGHT:
2427                 os << "right";
2428                 break;
2429             default:
2430                 os << "center";
2431                 break;
2432             }
2433             
2434             os << "\" valign=\"";
2435             switch (GetVAlignment(cell)) {
2436             case LYX_VALIGN_TOP:
2437                 os << "top";
2438                 break;
2439             case LYX_VALIGN_BOTTOM:
2440                 os << "bottom";
2441                 break;
2442             case LYX_VALIGN_CENTER:
2443                 os << "middle";
2444             }
2445             os << "\"";
2446             
2447             if (IsMultiColumn(cell)) {
2448                 os << " namest=\"col" << j << "\" ";
2449                 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< "\"";
2450             }
2451             
2452             os << ">";
2453             ret += GetCellInset(cell)->DocBook(buf, os);
2454             os << "</entry>";
2455             ++cell;
2456         }
2457         os << "</row>\n";
2458     }
2459     os << "</tbody>\n";
2460     //+---------------------------------------------------------------------
2461     //+                      the closing of the tabular                    +
2462     //+---------------------------------------------------------------------
2463
2464     os << "</tgroup>";
2465     ++ret;
2466
2467     return ret;
2468 }
2469
2470
2471 static
2472 inline
2473 void print_n_chars(ostream & os, unsigned char ch, int n)
2474 {
2475         os << string(n, ch);
2476 }
2477
2478
2479 int LyXTabular::AsciiTopHLine(ostream & os, int row,
2480                               vector<unsigned int> const & clen) const
2481 {
2482     int const fcell = GetFirstCellInRow(row);
2483     int const n = NumberOfCellsInRow(fcell) + fcell;
2484     int tmp = 0;
2485
2486     for (int i = fcell; i < n; ++i) {
2487         if (TopLine(i)) {
2488             ++tmp;
2489             break;
2490         }
2491     }
2492     if (!tmp)
2493         return 0;
2494
2495     unsigned char ch;
2496     for (int i = fcell; i < n; ++i) {
2497         if (TopLine(i)) {
2498             if (LeftLine(i))
2499                 os << "+-";
2500             else
2501                 os << "--";
2502             ch = '-';
2503         } else {
2504             os << "  ";
2505             ch = ' ';
2506         }
2507         int column = column_of_cell(i);
2508         int len = clen[column];
2509         while(IsPartOfMultiColumn(row, ++column))
2510             len += clen[column] + 4;
2511         print_n_chars(os, ch, len);
2512         if (TopLine(i)) {
2513             if (RightLine(i))
2514                 os << "-+";
2515             else
2516                 os << "--";
2517         } else {
2518             os << "  ";
2519         }
2520     }
2521     os << endl;
2522     return 1;
2523 }
2524
2525
2526 int LyXTabular::AsciiBottomHLine(ostream & os, int row,
2527                                  vector<unsigned int> const & clen) const
2528 {
2529     int const fcell = GetFirstCellInRow(row);
2530     int const n = NumberOfCellsInRow(fcell) + fcell;
2531     int tmp = 0;
2532
2533     for (int i = fcell; i < n; ++i) {
2534         if (BottomLine(i)) {
2535             ++tmp;
2536             break;
2537         }
2538     }
2539     if (!tmp)
2540         return 0;
2541
2542     unsigned char ch;
2543     for (int i = fcell; i < n; ++i) {
2544         if (BottomLine(i)) {
2545             if (LeftLine(i))
2546                 os << "+-";
2547             else
2548                 os << "--";
2549             ch = '-';
2550         } else {
2551             os << "  ";
2552             ch = ' ';
2553         }
2554         int column = column_of_cell(i);
2555         int len = clen[column];
2556         while(IsPartOfMultiColumn(row, ++column))
2557             len += clen[column] + 4;
2558         print_n_chars(os, ch, len);
2559         if (BottomLine(i)) {
2560             if (RightLine(i))
2561                 os << "-+";
2562             else
2563                 os << "--";
2564         } else {
2565             os << "  ";
2566         }
2567     }
2568     os << endl;
2569     return 1;
2570 }
2571
2572
2573 int LyXTabular::AsciiPrintCell(Buffer const * buf, ostream & os,
2574                                int cell, int row, int column,
2575                                vector<unsigned int> const & clen) const
2576 {
2577     ostringstream sstr;
2578     int ret = GetCellInset(cell)->Ascii(buf, sstr, 0);
2579
2580     if (LeftLine(cell))
2581         os << "| ";
2582     else
2583         os << "  ";
2584
2585     unsigned int len1 = sstr.str().length();
2586     unsigned int len2 = clen[column];
2587     while(IsPartOfMultiColumn(row, ++column))
2588         len2 += clen[column] + 4;
2589     len2 -= len1;
2590
2591     switch (GetAlignment(cell)) {
2592     default:
2593     case LYX_ALIGN_LEFT:
2594         len1 = 0;
2595         break;
2596     case LYX_ALIGN_RIGHT:
2597         len1 = len2;
2598         len2 = 0;
2599         break;
2600     case LYX_ALIGN_CENTER:
2601         len1 = len2 / 2;
2602         len2 -= len1;
2603         break;
2604     }
2605
2606     for (unsigned int i = 0; i < len1; ++i)
2607         os << " ";
2608     os << sstr.str();
2609     for (unsigned int i = 0; i < len2; ++i)
2610         os << " ";
2611     if (RightLine(cell))
2612         os << " |";
2613     else
2614         os << "  ";
2615
2616 #warning What is this supposed to do? (Lgb)
2617     return ret * 0; // eh? (Lgb)
2618 }
2619
2620
2621 int LyXTabular::Ascii(Buffer const * buf, ostream & os) const
2622 {
2623     int ret = 0;
2624
2625     //+---------------------------------------------------------------------
2626     //+           first calculate the width of the single columns          +
2627     //+---------------------------------------------------------------------
2628     vector<unsigned int> clen(columns_);
2629
2630     // first all non (real) multicolumn cells!
2631     for (int j = 0; j < columns_; ++j) {
2632         clen[j] = 0;
2633         for (int i = 0; i < rows_; ++i) {
2634             int cell = GetCellNumber(i, j);
2635             if (IsMultiColumn(cell, true))
2636                 continue;
2637             ostringstream sstr;
2638             GetCellInset(cell)->Ascii(buf, sstr, 0);
2639             if (clen[j] < sstr.str().length())
2640                 clen[j] = sstr.str().length();
2641         }
2642     }
2643     // then all (real) multicolumn cells!
2644     for (int j = 0; j < columns_; ++j) {
2645         for (int i = 0; i < rows_; ++i) {
2646             int cell = GetCellNumber(i, j);
2647             if (!IsMultiColumn(cell, true) || IsPartOfMultiColumn(i, j))
2648                 continue;
2649             ostringstream sstr;
2650             GetCellInset(cell)->Ascii(buf, sstr, 0);
2651             int len = int(sstr.str().length());
2652             int const n = cells_in_multicolumn(cell);
2653             for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2654                 len -= clen[k];
2655             if (len > int(clen[j + n - 1]))
2656                 clen[j + n - 1] = len;
2657         }
2658     }
2659     int cell = 0;
2660     for (int i = 0; i < rows_; ++i) {
2661         AsciiTopHLine(os, i, clen);
2662         for (int j = 0; j < columns_; ++j) {
2663             if (IsPartOfMultiColumn(i,j))
2664                 continue;
2665             ret += AsciiPrintCell(buf, os, cell, i, j, clen);
2666             ++cell;
2667         }
2668         os << endl;
2669         AsciiBottomHLine(os, i, clen);
2670     }
2671     return ret;
2672 }
2673
2674
2675 InsetText * LyXTabular::GetCellInset(int cell) const
2676 {
2677     return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2678 }
2679
2680
2681 InsetText * LyXTabular::GetCellInset(int row, int column) const
2682 {
2683     return GetCellInset(GetCellNumber(row, column));
2684 }
2685
2686
2687 void LyXTabular::Validate(LaTeXFeatures & features) const
2688 {
2689     if (IsLongTabular())
2690         features.longtable = true;
2691     if (NeedRotating())
2692         features.rotating = true;
2693     for (int cell = 0; cell < numberofcells; ++cell) {
2694         if (GetVAlignment(cell) != LYX_VALIGN_TOP)
2695             features.array = true;
2696         GetCellInset(cell)->Validate(features);
2697     }
2698 }
2699
2700
2701 LyXTabular::BoxType LyXTabular::UseParbox(int cell) const
2702 {
2703     LyXParagraph * par = GetCellInset(cell)->par;
2704
2705     for (; par; par = par->next) {
2706         for (int i = 0; i < par->Last(); ++i) {
2707             if (par->GetChar(i) == LyXParagraph::META_NEWLINE)
2708                 return BOX_PARBOX;
2709         }
2710     }
2711     return BOX_NONE;
2712 }