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