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