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