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