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