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