]> git.lyx.org Git - lyx.git/blob - src/tabular.C
The 'bformat' introduction
[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 // temporary until verified (08/08/2001 Jug)
16 #define SPECIAL_COLUM_HANDLING 1
17
18 #include "tabular.h"
19 #include "debug.h"
20 #include "vspace.h"
21 #include "layout.h"
22 #include "buffer.h"
23 #include "BufferView.h"
24 #include "frontends/Painter.h"
25 #include "LaTeXFeatures.h"
26 #include "insets/insettabular.h"
27 #include "insets/insettext.h"
28 #include "support/lstrings.h"
29 #include "support/lyxmanip.h"
30 #include "support/LAssert.h"
31 #include "frontends/Alert.h"
32 #include "gettext.h"
33 #include "Lsstream.h"
34 #include "tabular_funcs.h"
35 #include "lyxlex.h"
36
37 #include <algorithm>
38 #include <cstdlib>
39
40 using std::abs;
41 using std::ostream;
42 using std::istream;
43 using std::getline;
44 using std::max;
45 using std::endl;
46 using std::vector;
47
48 #ifndef CXX_GLOBAL_CSTD
49 using std::strlen;
50 #endif
51
52 namespace {
53
54         int const WIDTH_OF_LINE = 5;
55
56 } // namespace
57
58 /// Define a few methods for the inner structs
59
60 LyXTabular::cellstruct::cellstruct(BufferParams const & bg)
61         : inset(bg)
62 {
63         cellno = 0;
64         width_of_cell = 0;
65         multicolumn = LyXTabular::CELL_NORMAL;
66         alignment = LYX_ALIGN_CENTER;
67         valignment = LYX_VALIGN_TOP;
68         top_line = true;
69         bottom_line = false;
70         left_line = true;
71         right_line = false;
72         usebox = BOX_NONE;
73         rotate = false;
74 }
75
76
77 LyXTabular::rowstruct::rowstruct()
78 {
79         top_line = true;
80         bottom_line = false;
81         ascent_of_row = 0;
82         descent_of_row = 0;
83         endhead = false;
84         endfirsthead = false;
85         endfoot = false;
86         endlastfoot = false;
87         newpage = false;
88 }
89
90
91 LyXTabular::columnstruct::columnstruct()
92 {
93         left_line = true;
94         right_line = false;
95         alignment = LYX_ALIGN_CENTER;
96         valignment = LYX_VALIGN_TOP;
97         width_of_column = 0;
98 }
99
100
101 LyXTabular::ltType::ltType()
102 {
103         topDL = false;
104         bottomDL = false;
105         empty = false;
106 }
107
108
109 /* konstruktor */
110 LyXTabular::LyXTabular(BufferParams const & bp,
111                        InsetTabular * inset, int rows_arg, int columns_arg)
112 {
113         owner_ = inset;
114         cur_cell = -1;
115         Init(bp, rows_arg, columns_arg);
116 }
117
118
119 LyXTabular::LyXTabular(BufferParams const & bp,
120                        InsetTabular * inset, LyXTabular const & lt,
121                        bool same_id)
122 {
123         owner_ = inset;
124         cur_cell = -1;
125         Init(bp, lt.rows_, lt.columns_, &lt);
126         // we really should change again to have InsetText as a pointer
127         // and allocate it then we would not have to do this stuff all
128         // double!
129         if (same_id) {
130                 for (int i = 0; i < rows_; ++i) {
131                         for (int j = 0; j < columns_; ++j) {
132                                 cell_info[i][j].inset.id(lt.cell_info[i][j].inset.id());
133                                 cell_info[i][j].inset.setParagraphData(lt.cell_info[i][j].inset.paragraphs, true);
134                         }
135                 }
136         }
137 #if 0
138 #ifdef WITH_WARNINGS
139 #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)
140 #endif
141         operator=(lt);
142 #endif
143 }
144
145
146 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
147 {
148         owner_ = inset;
149         cur_cell = -1;
150         Read(buf, lex);
151 }
152
153
154 LyXTabular & LyXTabular::operator=(LyXTabular const & lt)
155 {
156 #if 0
157 #warning This whole method should look like this: (Lgb)
158
159                 LyXTabular tmp(lt);
160                 tmp.swap(*this);
161 #else
162         // If this and lt is not of the same size we have a serious bug
163         // So then it is ok to throw an exception, or for now
164         // call abort()
165         lyx::Assert(rows_ == lt.rows_ && columns_ == lt.columns_);
166         cur_cell = -1;
167         cell_info = lt.cell_info;
168         row_info = lt.row_info;
169         column_info = lt.column_info;
170         SetLongTabular(lt.is_long_tabular);
171         rotate = lt.rotate;
172
173         Reinit();
174 #endif
175         return *this;
176 }
177
178
179 LyXTabular * LyXTabular::clone(BufferParams const & bp,
180                                InsetTabular * inset, bool same_id)
181 {
182         LyXTabular * result = new LyXTabular(bp, inset, *this, same_id);
183 #if 0
184         // don't know if this is good but I need to Clone also
185         // the text-insets here, this is for the Undo-facility!
186         for (int i = 0; i < rows_; ++i) {
187                 for (int j = 0; j < columns_; ++j) {
188                         result->cell_info[i][j].inset = cell_info[i][j].inset;
189                         result->cell_info[i][j].inset.setOwner(inset);
190                 }
191         }
192 #endif
193         return result;
194 }
195
196
197 /* activates all lines and sets all widths to 0 */
198 void LyXTabular::Init(BufferParams const & bp,
199                       int rows_arg, int columns_arg, LyXTabular const * lt)
200 {
201         rows_ = rows_arg;
202         columns_ = columns_arg;
203         row_info = row_vector(rows_, rowstruct());
204         column_info = column_vector(columns_, columnstruct());
205         cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
206
207         if (lt) {
208                 operator=(*lt);
209                 return;
210         }
211
212         int cellno = 0;
213         for (int i = 0; i < rows_; ++i) {
214                 for (int j = 0; j < columns_; ++j) {
215                         cell_info[i][j].inset.setOwner(owner_);
216                         cell_info[i][j].inset.setDrawFrame(0, InsetText::LOCKED);
217                         cell_info[i][j].cellno = cellno++;
218                 }
219                 cell_info[i].back().right_line = true;
220         }
221         row_info.back().bottom_line = true;
222         row_info.front().bottom_line = true;
223
224         for (int i = 0; i < columns_; ++i) {
225                 calculate_width_of_column(i);
226         }
227         column_info.back().right_line = true;
228
229         calculate_width_of_tabular();
230
231         rowofcell = vector<int>();
232         columnofcell = vector<int>();
233         set_row_column_number_info();
234         is_long_tabular = false;
235         rotate = false;
236 }
237
238
239 void LyXTabular::AppendRow(BufferParams const & bp, int cell)
240 {
241         ++rows_;
242
243         int row = row_of_cell(cell);
244
245         row_vector::iterator rit = row_info.begin() + row;
246         row_info.insert(rit, rowstruct());
247         // now set the values of the row before
248         row_info[row] = row_info[row + 1];
249
250 #if 0
251         cell_vvector::iterator cit = cell_info.begin() + row;
252         cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct(bp)));
253 #else
254         cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
255                                                               cellstruct(bp)));
256
257         for (int i = 0; i <= row; ++i) {
258                 for (int j = 0; j < columns_; ++j) {
259                         c_info[i][j] = cell_info[i][j];
260                 }
261         }
262         for (int i = row + 1; i < rows_; ++i) {
263                 for (int j = 0; j < columns_; ++j) {
264                         c_info[i][j] = cell_info[i-1][j];
265                 }
266         }
267         cell_info = c_info;
268         ++row;
269         for (int j = 0; j < columns_; ++j) {
270                 cell_info[row][j].inset.clear(false);
271                 if (bp.tracking_changes)
272                         cell_info[row][j].inset.markNew(true);
273         }
274 #endif
275         Reinit();
276 }
277
278
279 void LyXTabular::DeleteRow(int row)
280 {
281         if (rows_ == 1) return; // Not allowed to delete last row
282
283         row_info.erase(row_info.begin() + row); //&row_info[row]);
284         cell_info.erase(cell_info.begin() + row); //&cell_info[row]);
285         --rows_;
286         Reinit();
287 }
288
289
290 void LyXTabular::AppendColumn(BufferParams const & bp, int cell)
291 {
292         ++columns_;
293
294         cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
295                                                               cellstruct(bp)));
296         int const column = column_of_cell(cell);
297         column_vector::iterator cit = column_info.begin() + column + 1;
298         column_info.insert(cit, columnstruct());
299         // set the column values of the column before
300         column_info[column + 1] = column_info[column];
301
302         for (int i = 0; i < rows_; ++i) {
303                 for (int j = 0; j <= column; ++j) {
304                         c_info[i][j] = cell_info[i][j];
305                 }
306                 for (int j = column + 1; j < columns_; ++j) {
307                         c_info[i][j] = cell_info[i][j - 1];
308                 }
309                 // care about multicolumns
310                 if (c_info[i][column + 1].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
311                 {
312                         c_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
313                 }
314                 if ((column + 2) >= columns_ ||
315                         c_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
316                 {
317                         c_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
318                 }
319         }
320         cell_info = c_info;
321         //++column;
322         for (int i = 0; i < rows_; ++i) {
323                 cell_info[i][column + 1].inset.clear(false);
324                 if (bp.tracking_changes)
325                         cell_info[i][column + 1].inset.markNew(true);
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::topAlreadyDrawn(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::leftAlreadyDrawn(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                 lyx::Assert(false);
1107                 return;
1108         }
1109
1110         int version;
1111         if (!getTokenValue(line, "version", version))
1112                 return;
1113         lyx::Assert(version >= 2);
1114         read(buf, is, lex, line, version);
1115 }
1116
1117 void LyXTabular::setHeaderFooterRows(int hr, int fhr, int fr, int lfr)
1118 {
1119         // set header info
1120         while(hr > 0) {
1121                 row_info[--hr].endhead = true;
1122         }
1123         // set firstheader info
1124         if (fhr && (fhr < rows_)) {
1125                 if (row_info[fhr].endhead) {
1126                         while(fhr > 0) {
1127                                 row_info[--fhr].endfirsthead = true;
1128                                 row_info[fhr].endhead = false;
1129                         }
1130                 } else if (row_info[fhr - 1].endhead) {
1131                         endfirsthead.empty = true;
1132                 } else {
1133                         while((fhr > 0) && !row_info[--fhr].endhead) {
1134                                 row_info[fhr].endfirsthead = true;
1135                         }
1136                 }
1137         }
1138         // set footer info
1139         if (fr && (fr < rows_)) {
1140                 if (row_info[fr].endhead && row_info[fr-1].endhead) {
1141                         while((fr > 0) && !row_info[--fr].endhead) {
1142                                 row_info[fr].endfoot = true;
1143                                 row_info[fr].endhead = false;
1144                         }
1145                 } else if (row_info[fr].endfirsthead && row_info[fr-1].endfirsthead) {
1146                         while((fr > 0) && !row_info[--fr].endfirsthead) {
1147                                 row_info[fr].endfoot = true;
1148                                 row_info[fr].endfirsthead = false;
1149                         }
1150                 } else if (!row_info[fr - 1].endhead && !row_info[fr - 1].endfirsthead) {
1151                         while((fr > 0) && !row_info[--fr].endhead &&
1152                                   !row_info[fr].endfirsthead)
1153                         {
1154                                 row_info[fr].endfoot = true;
1155                         }
1156                 }
1157         }
1158         // set lastfooter info
1159         if (lfr && (lfr < rows_)) {
1160                 if (row_info[lfr].endhead && row_info[lfr - 1].endhead) {
1161                         while((lfr > 0) && !row_info[--lfr].endhead) {
1162                                 row_info[lfr].endlastfoot = true;
1163                                 row_info[lfr].endhead = false;
1164                         }
1165                 } else if (row_info[lfr].endfirsthead &&
1166                                    row_info[lfr - 1].endfirsthead)
1167                 {
1168                         while((lfr > 0) && !row_info[--lfr].endfirsthead) {
1169                                 row_info[lfr].endlastfoot = true;
1170                                 row_info[lfr].endfirsthead = false;
1171                         }
1172                 } else if (row_info[lfr].endfoot
1173                            && row_info[lfr - 1].endfoot) {
1174                         while((lfr > 0) && !row_info[--lfr].endfoot) {
1175                                 row_info[lfr].endlastfoot = true;
1176                                 row_info[lfr].endfoot = false;
1177                         }
1178                 } else if (!row_info[fr - 1].endhead
1179                            && !row_info[fr - 1].endfirsthead &&
1180                                    !row_info[fr - 1].endfoot)
1181                 {
1182                         while((lfr > 0) &&
1183                                   !row_info[--lfr].endhead && !row_info[lfr].endfirsthead &&
1184                                   !row_info[lfr].endfoot)
1185                         {
1186                                 row_info[lfr].endlastfoot = true;
1187                         }
1188                 } else if (haveLTFoot()) {
1189                         endlastfoot.empty = true;
1190                 }
1191         }
1192 }
1193
1194 void LyXTabular::read(Buffer const * buf, istream & is,
1195                       LyXLex & lex, string const & l, int const version)
1196 {
1197         string line(l);
1198         int rows_arg;
1199         if (!getTokenValue(line, "rows", rows_arg))
1200                 return;
1201         int columns_arg;
1202         if (!getTokenValue(line, "columns", columns_arg))
1203                 return;
1204         Init(buf->params, rows_arg, columns_arg);
1205         l_getline(is, line);
1206         if (!prefixIs(line, "<features")) {
1207                 lyxerr << "Wrong tabular format (expected <features ...> got"
1208                        << line << ')' << endl;
1209                 return;
1210         }
1211         getTokenValue(line, "rotate", rotate);
1212         getTokenValue(line, "islongtable", is_long_tabular);
1213         // compatibility read for old longtable options. Now we can make any
1214         // row part of the header/footer type we want before it was strict
1215         // sequential from the first row down (as LaTeX does it!). So now when
1216         // we find a header/footer line we have to go up the rows and set it
1217         // on all preceding rows till the first or one with already a h/f option
1218         // set. If we find a firstheader on the same line as a header or a
1219         // lastfooter on the same line as a footer then this should be set empty.
1220         // (Jug 20011220)
1221         if (version < 3) {
1222                 int hrow;
1223                 int fhrow;
1224                 int frow;
1225                 int lfrow;
1226
1227                 getTokenValue(line, "endhead", hrow);
1228                 getTokenValue(line, "endfirsthead", fhrow);
1229                 getTokenValue(line, "endfoot", frow);
1230                 getTokenValue(line, "endlastfoot", lfrow);
1231                 setHeaderFooterRows(abs(hrow), abs(fhrow), abs(frow), abs(lfrow));
1232         } else {
1233            getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
1234            getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
1235            getTokenValue(line, "firstHeadEmpty", endfirsthead.empty);
1236            getTokenValue(line, "headTopDL", endhead.topDL);
1237            getTokenValue(line, "headBottomDL", endhead.bottomDL);
1238            getTokenValue(line, "footTopDL", endfoot.topDL);
1239            getTokenValue(line, "footBottomDL", endfoot.bottomDL);
1240            getTokenValue(line, "lastFootTopDL", endlastfoot.topDL);
1241            getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
1242            getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
1243         }
1244         for (int j = 0; j < columns_; ++j) {
1245                 l_getline(is,line);
1246                 if (!prefixIs(line,"<column")) {
1247                         lyxerr << "Wrong tabular format (expected <column ...> got"
1248                                << line << ')' << endl;
1249                         return;
1250                 }
1251                 getTokenValue(line, "alignment", column_info[j].alignment);
1252                 getTokenValue(line, "valignment", column_info[j].valignment);
1253                 getTokenValue(line, "leftline", column_info[j].left_line);
1254                 getTokenValue(line, "rightline", column_info[j].right_line);
1255                 getTokenValue(line, "width", column_info[j].p_width);
1256                 getTokenValue(line, "special", column_info[j].align_special);
1257         }
1258
1259         for (int i = 0; i < rows_; ++i) {
1260                 l_getline(is, line);
1261                 if (!prefixIs(line, "<row")) {
1262                         lyxerr << "Wrong tabular format (expected <row ...> got"
1263                                << line << ')' << endl;
1264                         return;
1265                 }
1266                 getTokenValue(line, "topline", row_info[i].top_line);
1267                 getTokenValue(line, "bottomline", row_info[i].bottom_line);
1268                 getTokenValue(line, "endfirsthead", row_info[i].endfirsthead);
1269                 getTokenValue(line, "endhead", row_info[i].endhead);
1270                 getTokenValue(line, "endfoot", row_info[i].endfoot);
1271                 getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
1272                 getTokenValue(line, "newpage", row_info[i].newpage);
1273                 for (int j = 0; j < columns_; ++j) {
1274                         l_getline(is, line);
1275                         if (!prefixIs(line, "<cell")) {
1276                                 lyxerr << "Wrong tabular format (expected <cell ...> got"
1277                                        << line << ')' << endl;
1278                                 return;
1279                         }
1280                         getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1281                         getTokenValue(line, "alignment", cell_info[i][j].alignment);
1282                         getTokenValue(line, "valignment", cell_info[i][j].valignment);
1283                         getTokenValue(line, "topline", cell_info[i][j].top_line);
1284                         getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1285                         getTokenValue(line, "leftline", cell_info[i][j].left_line);
1286                         getTokenValue(line, "rightline", cell_info[i][j].right_line);
1287                         getTokenValue(line, "rotate", cell_info[i][j].rotate);
1288                         getTokenValue(line, "usebox", cell_info[i][j].usebox);
1289                         getTokenValue(line, "width", cell_info[i][j].p_width);
1290                         getTokenValue(line, "special", cell_info[i][j].align_special);
1291                         l_getline(is, line);
1292                         if (prefixIs(line, "\\begin_inset")) {
1293                                 cell_info[i][j].inset.read(buf, lex);
1294                                 l_getline(is, line);
1295                         }
1296                         if (!prefixIs(line, "</cell>")) {
1297                                 lyxerr << "Wrong tabular format (expected </cell> got"
1298                                        << line << ')' << endl;
1299                                 return;
1300                         }
1301                 }
1302                 l_getline(is, line);
1303                 if (!prefixIs(line, "</row>")) {
1304                         lyxerr << "Wrong tabular format (expected </row> got"
1305                                << line << ')' << endl;
1306                         return;
1307                 }
1308         }
1309         while (!prefixIs(line, "</lyxtabular>")) {
1310                 l_getline(is, line);
1311         }
1312         set_row_column_number_info();
1313 }
1314
1315
1316 bool LyXTabular::IsMultiColumn(int cell, bool real) const
1317 {
1318         return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
1319                         (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
1320 }
1321
1322
1323 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
1324 {
1325         int const row = row_of_cell(cell);
1326         int const column = column_of_cell(cell);
1327         return  &cell_info[row][column];
1328 }
1329
1330
1331 void LyXTabular::SetMultiColumn(Buffer * buffer, int cell, int number)
1332 {
1333         cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1334         cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
1335         cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
1336         cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
1337         cellinfo_of_cell(cell)->right_line = column_info[column_of_cell(cell+number-1)].right_line;
1338 #if 1
1339         for (int i = 1; i < number; ++i) {
1340                 cellinfo_of_cell(cell+i)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1341                 cellinfo_of_cell(cell)->inset.appendParagraphs(buffer,
1342                         cellinfo_of_cell(cell+i)->inset.paragraphs);
1343                 cellinfo_of_cell(cell+i)->inset.clear(false);
1344         }
1345 #else
1346         for (number--; number > 0; --number) {
1347                 cellinfo_of_cell(cell+number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1348         }
1349 #endif
1350         set_row_column_number_info();
1351 }
1352
1353
1354 int LyXTabular::cells_in_multicolumn(int cell) const
1355 {
1356         int const row = row_of_cell(cell);
1357         int column = column_of_cell(cell);
1358         int result = 1;
1359         ++column;
1360         while ((column < columns_) &&
1361                    cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1362         {
1363                 ++result;
1364                 ++column;
1365         }
1366         return result;
1367 }
1368
1369
1370 int LyXTabular::UnsetMultiColumn(int cell)
1371 {
1372         int const row = row_of_cell(cell);
1373         int column = column_of_cell(cell);
1374
1375         int result = 0;
1376
1377         if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1378                 cell_info[row][column].multicolumn = CELL_NORMAL;
1379                 ++column;
1380                 while ((column < columns_) &&
1381                            (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
1382                 {
1383                         cell_info[row][column].multicolumn = CELL_NORMAL;
1384                         ++column;
1385                         ++result;
1386                 }
1387         }
1388         set_row_column_number_info();
1389         return result;
1390 }
1391
1392
1393 void LyXTabular::SetLongTabular(bool what)
1394 {
1395         is_long_tabular = what;
1396 }
1397
1398
1399 bool LyXTabular::IsLongTabular() const
1400 {
1401         return is_long_tabular;
1402 }
1403
1404
1405 void LyXTabular::SetRotateTabular(bool flag)
1406 {
1407         rotate = flag;
1408 }
1409
1410
1411 bool LyXTabular::GetRotateTabular() const
1412 {
1413         return rotate;
1414 }
1415
1416
1417 void LyXTabular::SetRotateCell(int cell, bool flag)
1418 {
1419         cellinfo_of_cell(cell)->rotate = flag;
1420 }
1421
1422
1423 bool LyXTabular::GetRotateCell(int cell) const
1424 {
1425         return cellinfo_of_cell(cell)->rotate;
1426 }
1427
1428
1429 bool LyXTabular::NeedRotating() const
1430 {
1431         if (rotate)
1432                 return true;
1433         for (int i = 0; i < rows_; ++i) {
1434                 for (int j = 0; j < columns_; ++j) {
1435                         if (cell_info[i][j].rotate)
1436                                 return true;
1437                 }
1438         }
1439         return false;
1440 }
1441
1442
1443 bool LyXTabular::IsLastCell(int cell) const
1444 {
1445         if ((cell + 1) < numberofcells)
1446                 return false;
1447         return true;
1448 }
1449
1450
1451 int LyXTabular::GetCellAbove(int cell) const
1452 {
1453         if (row_of_cell(cell) > 0)
1454                 return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1455         return cell;
1456 }
1457
1458
1459 int LyXTabular::GetCellBelow(int cell) const
1460 {
1461         if (row_of_cell(cell) + 1 < rows_)
1462                 return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1463         return cell;
1464 }
1465
1466
1467 int LyXTabular::GetLastCellAbove(int cell) const
1468 {
1469         if (row_of_cell(cell) <= 0)
1470                 return cell;
1471         if (!IsMultiColumn(cell))
1472                 return GetCellAbove(cell);
1473         return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1474 }
1475
1476
1477 int LyXTabular::GetLastCellBelow(int cell) const
1478 {
1479         if (row_of_cell(cell) + 1 >= rows_)
1480                 return cell;
1481         if (!IsMultiColumn(cell))
1482                 return GetCellBelow(cell);
1483         return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1484 }
1485
1486
1487 int LyXTabular::GetCellNumber(int row, int column) const
1488 {
1489 #if 0
1490         if (column >= columns_)
1491                 column = columns_ - 1;
1492         else if (column < 0)
1493                 column = 0;
1494         if (row >= rows_)
1495                 row = rows_ - 1;
1496         else if (row < 0)
1497                 row = 0;
1498 #else
1499         lyx::Assert(column >= 0 || column < columns_ || row >= 0 || row < rows_);
1500 #endif
1501         return cell_info[row][column].cellno;
1502 }
1503
1504
1505 void LyXTabular::SetUsebox(int cell, BoxType type)
1506 {
1507         cellinfo_of_cell(cell)->usebox = type;
1508 }
1509
1510
1511 LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
1512 {
1513         if (column_info[column_of_cell(cell)].p_width.zero() &&
1514                 !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.zero()))
1515                 return BOX_NONE;
1516         if (cellinfo_of_cell(cell)->usebox > 1)
1517                 return cellinfo_of_cell(cell)->usebox;
1518         return UseParbox(cell);
1519 }
1520
1521
1522 ///
1523 //  This are functions used for the longtable support
1524 ///
1525 void LyXTabular::SetLTHead(int row, bool flag, ltType const & hd, bool first)
1526 {
1527         if (first) {
1528                 endfirsthead = hd;
1529                 if (hd.set)
1530                         row_info[row].endfirsthead = flag;
1531         } else {
1532                 endhead = hd;
1533                 if (hd.set)
1534                         row_info[row].endhead = flag;
1535         }
1536 }
1537
1538
1539 bool LyXTabular::GetRowOfLTHead(int row, ltType & hd) const
1540 {
1541         hd = endhead;
1542         hd.set = haveLTHead();
1543         return row_info[row].endhead;
1544 }
1545
1546
1547 bool LyXTabular::GetRowOfLTFirstHead(int row, ltType & hd) const
1548 {
1549         hd = endfirsthead;
1550         hd.set = haveLTFirstHead();
1551         return row_info[row].endfirsthead;
1552 }
1553
1554
1555 void LyXTabular::SetLTFoot(int row, bool flag, ltType const & fd, bool last)
1556 {
1557         if (last) {
1558                 endlastfoot = fd;
1559                 if (fd.set)
1560                         row_info[row].endlastfoot = flag;
1561         } else {
1562                 endfoot = fd;
1563                 if (fd.set)
1564                         row_info[row].endfoot = flag;
1565         }
1566 }
1567
1568
1569 bool LyXTabular::GetRowOfLTFoot(int row, ltType & fd) const
1570 {
1571         fd = endfoot;
1572         fd.set = haveLTFoot();
1573         return row_info[row].endfoot;
1574 }
1575
1576
1577 bool LyXTabular::GetRowOfLTLastFoot(int row, ltType & fd) const
1578 {
1579         fd = endlastfoot;
1580         fd.set = haveLTLastFoot();
1581         return row_info[row].endlastfoot;
1582 }
1583
1584
1585 void LyXTabular::SetLTNewPage(int row, bool what)
1586 {
1587         row_info[row].newpage = what;
1588 }
1589
1590
1591 bool LyXTabular::GetLTNewPage(int row) const
1592 {
1593         return row_info[row].newpage;
1594 }
1595
1596
1597 bool LyXTabular::haveLTHead() const
1598 {
1599         for(int i=0; i < rows_; ++i) {
1600                 if (row_info[i].endhead)
1601                         return true;
1602         }
1603         return false;
1604 }
1605
1606
1607 bool LyXTabular::haveLTFirstHead() const
1608 {
1609         if (endfirsthead.empty)
1610                 return false;
1611         for(int i=0; i < rows_; ++i) {
1612                 if (row_info[i].endfirsthead)
1613                         return true;
1614         }
1615         return false;
1616 }
1617
1618
1619 bool LyXTabular::haveLTFoot() const
1620 {
1621         for(int i=0; i < rows_; ++i) {
1622                 if (row_info[i].endfoot)
1623                         return true;
1624         }
1625         return false;
1626 }
1627
1628
1629 bool LyXTabular::haveLTLastFoot() const
1630 {
1631         if (endlastfoot.empty)
1632                 return false;
1633         for(int i=0; i < rows_; ++i) {
1634                 if (row_info[i].endlastfoot)
1635                         return true;
1636         }
1637         return false;
1638 }
1639
1640
1641 // end longtable support functions
1642
1643 bool LyXTabular::SetAscentOfRow(int row, int height)
1644 {
1645         if ((row >= rows_) || (row_info[row].ascent_of_row == height))
1646                 return false;
1647         row_info[row].ascent_of_row = height;
1648         return true;
1649 }
1650
1651
1652 bool LyXTabular::SetDescentOfRow(int row, int height)
1653 {
1654         if ((row >= rows_) || (row_info[row].descent_of_row == height))
1655                 return false;
1656         row_info[row].descent_of_row = height;
1657         return true;
1658 }
1659
1660
1661 int LyXTabular::GetAscentOfRow(int row) const
1662 {
1663         if (row >= rows_)
1664                 return 0;
1665         return row_info[row].ascent_of_row;
1666 }
1667
1668
1669 int LyXTabular::GetDescentOfRow(int row) const
1670 {
1671         if (row >= rows_)
1672                 return 0;
1673         return row_info[row].descent_of_row;
1674 }
1675
1676
1677 int LyXTabular::GetHeightOfTabular() const
1678 {
1679         int height = 0;
1680
1681         for (int row = 0; row < rows_; ++row)
1682                 height += GetAscentOfRow(row) + GetDescentOfRow(row) +
1683                         GetAdditionalHeight(row);
1684         return height;
1685 }
1686
1687
1688 bool LyXTabular::IsPartOfMultiColumn(int row, int column) const
1689 {
1690         if ((row >= rows_) || (column >= columns_))
1691                 return false;
1692         return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
1693 }
1694
1695
1696 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1697 {
1698         if ((row < 0) || (row >= rows_))
1699                 return 0;
1700
1701         int const fcell = GetFirstCellInRow(row);
1702         int const n = NumberOfCellsInRow(fcell) + fcell;
1703         int tmp = 0;
1704
1705         for (int i = fcell; i < n; ++i) {
1706                 if (TopLine(i))
1707                         ++tmp;
1708         }
1709         if (tmp == (n - fcell)) {
1710                 os << "\\hline ";
1711         } else if (tmp) {
1712                 for (int i = fcell; i < n; ++i) {
1713                         if (TopLine(i)) {
1714                                 os << "\\cline{"
1715                                    << column_of_cell(i) + 1
1716                                    << '-'
1717                                    << right_column_of_cell(i) + 1
1718                                    << "} ";
1719                         }
1720                 }
1721         } else {
1722                 return 0;
1723         }
1724         os << "\n";
1725         return 1;
1726 }
1727
1728
1729 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1730 {
1731         if ((row < 0) || (row >= rows_))
1732                 return 0;
1733
1734         int const fcell = GetFirstCellInRow(row);
1735         int const n = NumberOfCellsInRow(fcell) + fcell;
1736         int tmp = 0;
1737
1738         for (int i = fcell; i < n; ++i) {
1739                 if (BottomLine(i))
1740                         ++tmp;
1741         }
1742         if (tmp == (n - fcell)) {
1743                 os << "\\hline";
1744         } else if (tmp) {
1745                 for (int i = fcell; i < n; ++i) {
1746                         if (BottomLine(i)) {
1747                                 os << "\\cline{"
1748                                    << column_of_cell(i) + 1
1749                                    << '-'
1750                                    << right_column_of_cell(i) + 1
1751                                    << "} ";
1752                         }
1753                 }
1754         } else {
1755                 return 0;
1756         }
1757         os << "\n";
1758         return 1;
1759 }
1760
1761
1762 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
1763 {
1764         int ret = 0;
1765
1766         if (GetRotateCell(cell)) {
1767                 os << "\\begin{sideways}\n";
1768                 ++ret;
1769         }
1770         if (IsMultiColumn(cell)) {
1771                 os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
1772                 if (!cellinfo_of_cell(cell)->align_special.empty()) {
1773                         os << cellinfo_of_cell(cell)->align_special << "}{";
1774                 } else {
1775                         if (LeftLine(cell) &&
1776                                 (IsFirstCellInRow(cell) ||
1777                                  (!IsMultiColumn(cell-1) && !LeftLine(cell, true) &&
1778                                   !RightLine(cell-1, true))))
1779                         {
1780                                 os << '|';
1781                         }
1782                         if (!GetPWidth(cell).zero()) {
1783                                 switch (GetVAlignment(cell)) {
1784                                 case LYX_VALIGN_TOP:
1785                                         os << 'p';
1786                                         break;
1787                                 case LYX_VALIGN_CENTER:
1788                                         os << 'm';
1789                                         break;
1790                                 case LYX_VALIGN_BOTTOM:
1791                                         os << 'b';
1792                                         break;
1793                                 }
1794                                 os << '{'
1795                                    << GetPWidth(cell).asLatexString()
1796                                    << '}';
1797                         } else {
1798                                 switch (GetAlignment(cell)) {
1799                                 case LYX_ALIGN_LEFT:
1800                                         os << 'l';
1801                                         break;
1802                                 case LYX_ALIGN_RIGHT:
1803                                         os << 'r';
1804                                         break;
1805                                 default:
1806                                         os << 'c';
1807                                         break;
1808                                 }
1809                         }
1810                         if (RightLine(cell))
1811                                 os << '|';
1812                         if (((cell + 1) < numberofcells) && !IsFirstCellInRow(cell+1) &&
1813                                 LeftLine(cell+1))
1814                                 os << '|';
1815                         os << "}{";
1816                 }
1817         }
1818         if (GetUsebox(cell) == BOX_PARBOX) {
1819                 os << "\\parbox[";
1820                 switch (GetVAlignment(cell)) {
1821                 case LYX_VALIGN_TOP:
1822                         os << 't';
1823                         break;
1824                 case LYX_VALIGN_CENTER:
1825                         os << 'c';
1826                         break;
1827                 case LYX_VALIGN_BOTTOM:
1828                         os << 'b';
1829                         break;
1830                 }
1831                 os << "]{" << GetPWidth(cell).asLatexString() << "}{";
1832         } else if (GetUsebox(cell) == BOX_MINIPAGE) {
1833                 os << "\\begin{minipage}[";
1834                 switch (GetVAlignment(cell)) {
1835                 case LYX_VALIGN_TOP:
1836                         os << 't';
1837                         break;
1838                 case LYX_VALIGN_CENTER:
1839                         os << 'm';
1840                         break;
1841                 case LYX_VALIGN_BOTTOM:
1842                         os << 'b';
1843                         break;
1844                 }
1845                 os << "]{" << GetPWidth(cell).asLatexString() << "}\n";
1846                 ++ret;
1847         }
1848         return ret;
1849 }
1850
1851
1852 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
1853 {
1854         int ret = 0;
1855
1856         // usual cells
1857         if (GetUsebox(cell) == BOX_PARBOX)
1858                 os << '}';
1859         else if (GetUsebox(cell) == BOX_MINIPAGE) {
1860                 os << "%\n\\end{minipage}";
1861                 ret += 2;
1862         }
1863         if (IsMultiColumn(cell)) {
1864                 os << '}';
1865         }
1866         if (GetRotateCell(cell)) {
1867                 os << "%\n\\end{sideways}";
1868                 ++ret;
1869         }
1870         return ret;
1871 }
1872
1873
1874 int LyXTabular::TeXLongtableHeaderFooter(ostream & os, Buffer const * buf,
1875                                          bool fragile, bool fp) const
1876 {
1877         if (!is_long_tabular)
1878                 return 0;
1879
1880         int ret = 0;
1881         // output header info
1882         if (haveLTHead()) {
1883                 if (endhead.topDL) {
1884                         os << "\\hline\n";
1885                         ++ret;
1886                 }
1887                 for (int i = 0; i < rows_; ++i) {
1888                         if (row_info[i].endhead) {
1889                                 ret += TeXRow(os, i, buf, fragile, fp);
1890                         }
1891                 }
1892                 if (endhead.bottomDL) {
1893                         os << "\\hline\n";
1894                         ++ret;
1895                 }
1896                 os << "\\endhead\n";
1897                 ++ret;
1898                 if (endfirsthead.empty) {
1899                         os << "\\endfirsthead\n";
1900                         ++ret;
1901                 }
1902         }
1903         // output firstheader info
1904         if (haveLTFirstHead()) {
1905                 if (endfirsthead.topDL) {
1906                         os << "\\hline\n";
1907                         ++ret;
1908                 }
1909                 for (int i = 0; i < rows_; ++i) {
1910                         if (row_info[i].endfirsthead) {
1911                                 ret += TeXRow(os, i, buf, fragile, fp);
1912                         }
1913                 }
1914                 if (endfirsthead.bottomDL) {
1915                         os << "\\hline\n";
1916                         ++ret;
1917                 }
1918                 os << "\\endfirsthead\n";
1919                 ++ret;
1920         }
1921         // output footer info
1922         if (haveLTFoot()) {
1923                 if (endfoot.topDL) {
1924                         os << "\\hline\n";
1925                         ++ret;
1926                 }
1927                 for (int i = 0; i < rows_; ++i) {
1928                         if (row_info[i].endfoot) {
1929                                 ret += TeXRow(os, i, buf, fragile, fp);
1930                         }
1931                 }
1932                 if (endfoot.bottomDL) {
1933                         os << "\\hline\n";
1934                         ++ret;
1935                 }
1936                 os << "\\endfoot\n";
1937                 ++ret;
1938                 if (endlastfoot.empty) {
1939                         os << "\\endlastfoot\n";
1940                         ++ret;
1941                 }
1942         }
1943         // output lastfooter info
1944         if (haveLTLastFoot()) {
1945                 if (endlastfoot.topDL) {
1946                         os << "\\hline\n";
1947                         ++ret;
1948                 }
1949                 for (int i = 0; i < rows_; ++i) {
1950                         if (row_info[i].endlastfoot) {
1951                                 ret += TeXRow(os, i, buf, fragile, fp);
1952                         }
1953                 }
1954                 if (endlastfoot.bottomDL) {
1955                         os << "\\hline\n";
1956                         ++ret;
1957                 }
1958                 os << "\\endlastfoot\n";
1959                 ++ret;
1960         }
1961         return ret;
1962 }
1963
1964
1965 bool LyXTabular::isValidRow(int const row) const
1966 {
1967         if (!is_long_tabular)
1968                 return true;
1969         return (!row_info[row].endhead && !row_info[row].endfirsthead &&
1970                         !row_info[row].endfoot && !row_info[row].endlastfoot);
1971 }
1972
1973
1974 int LyXTabular::TeXRow(ostream & os, int const i, Buffer const * buf,
1975                        bool fragile, bool fp) const
1976 {
1977         int ret = 0;
1978         int cell = GetCellNumber(i, 0);
1979
1980         ret += TeXTopHLine(os, i);
1981         for (int j = 0; j < columns_; ++j) {
1982                 if (IsPartOfMultiColumn(i,j))
1983                         continue;
1984                 ret += TeXCellPreamble(os, cell);
1985                 InsetText * inset = GetCellInset(cell);
1986
1987                 bool rtl = inset->paragraphs.begin()->isRightToLeftPar(buf->params) &&
1988                         !inset->paragraphs.begin()->empty() && GetPWidth(cell).zero();
1989
1990                 if (rtl)
1991                         os << "\\R{";
1992                 ret += inset->latex(buf, os, fragile, fp);
1993                 if (rtl)
1994                         os << '}';
1995
1996                 ret += TeXCellPostamble(os, cell);
1997                 if (!IsLastCellInRow(cell)) { // not last cell in row
1998                         os << "&\n";
1999                         ++ret;
2000                 }
2001                 ++cell;
2002         }
2003         os << "\\tabularnewline\n";
2004         ++ret;
2005         ret += TeXBottomHLine(os, i);
2006         return ret;
2007 }
2008
2009
2010 int LyXTabular::latex(Buffer const * buf,
2011                                           ostream & os, bool fragile, bool fp) const
2012 {
2013         int ret = 0;
2014
2015         //+---------------------------------------------------------------------
2016         //+                      first the opening preamble                    +
2017         //+---------------------------------------------------------------------
2018
2019         if (rotate) {
2020                 os << "\\begin{sideways}\n";
2021                 ++ret;
2022         }
2023         if (is_long_tabular)
2024                 os << "\\begin{longtable}{";
2025         else
2026                 os << "\\begin{tabular}{";
2027         for (int i = 0; i < columns_; ++i) {
2028                 if (!column_info[i].align_special.empty()) {
2029                         os << column_info[i].align_special;
2030                 } else {
2031                         if (column_info[i].left_line)
2032                                 os << '|';
2033                         if (!column_info[i].p_width.zero()) {
2034                                 switch (column_info[i].alignment) {
2035                                 case LYX_ALIGN_LEFT:
2036                                         os << ">{\\raggedright}";
2037                                         break;
2038                                 case LYX_ALIGN_RIGHT:
2039                                         os << ">{\\raggedleft}";
2040                                         break;
2041                                 case LYX_ALIGN_CENTER:
2042                                         os << ">{\\centering}";
2043                                         break;
2044                                 case LYX_ALIGN_NONE:
2045                                 case LYX_ALIGN_BLOCK:
2046                                 case LYX_ALIGN_LAYOUT:
2047                                 case LYX_ALIGN_SPECIAL:
2048                                         break;
2049                                 }
2050
2051                                 switch (column_info[i].valignment) {
2052                                 case LYX_VALIGN_TOP:
2053                                         os << 'p';
2054                                         break;
2055                                 case LYX_VALIGN_CENTER:
2056                                         os << 'm';
2057                                         break;
2058                                 case LYX_VALIGN_BOTTOM:
2059                                         os << 'b';
2060                                         break;
2061                         }
2062                                 os << '{'
2063                                    << column_info[i].p_width.asLatexString()
2064                                    << '}';
2065                         } else {
2066                                 switch (column_info[i].alignment) {
2067                                 case LYX_ALIGN_LEFT:
2068                                         os << 'l';
2069                                         break;
2070                                 case LYX_ALIGN_RIGHT:
2071                                         os << 'r';
2072                                         break;
2073                                 default:
2074                                         os << 'c';
2075                                         break;
2076                                 }
2077                         }
2078                         if (column_info[i].right_line)
2079                                 os << '|';
2080                 }
2081         }
2082         os << "}\n";
2083         ++ret;
2084
2085         ret += TeXLongtableHeaderFooter(os, buf, fragile, fp);
2086
2087         //+---------------------------------------------------------------------
2088         //+                      the single row and columns (cells)            +
2089         //+---------------------------------------------------------------------
2090
2091         for (int i = 0; i < rows_; ++i) {
2092                 if (isValidRow(i)) {
2093                         ret += TeXRow(os, i, buf, fragile, fp);
2094                         if (is_long_tabular && row_info[i].newpage) {
2095                                 os << "\\newpage\n";
2096                                 ++ret;
2097                         }
2098                 }
2099         }
2100
2101         //+---------------------------------------------------------------------
2102         //+                      the closing of the tabular                    +
2103         //+---------------------------------------------------------------------
2104
2105         if (is_long_tabular)
2106                 os << "\\end{longtable}";
2107         else
2108                 os << "\\end{tabular}";
2109         if (rotate) {
2110                 os << "\n\\end{sideways}";
2111                 ++ret;
2112         }
2113
2114         return ret;
2115 }
2116
2117
2118 int LyXTabular::docbookRow(Buffer const * buf, ostream & os, int row) const
2119 {
2120         int ret = 0;
2121         int cell = GetFirstCellInRow(row);
2122
2123         os << "<row>\n";
2124         for (int j = 0; j < columns_; ++j) {
2125                 if (IsPartOfMultiColumn(row, j))
2126                         continue;
2127
2128                 os << "<entry align=\"";
2129                 switch (GetAlignment(cell)) {
2130                 case LYX_ALIGN_LEFT:
2131                         os << "left";
2132                         break;
2133                 case LYX_ALIGN_RIGHT:
2134                         os << "right";
2135                         break;
2136                 default:
2137                         os << "center";
2138                         break;
2139                 }
2140
2141                 os << "\" valign=\"";
2142                 switch (GetVAlignment(cell)) {
2143                 case LYX_VALIGN_TOP:
2144                         os << "top";
2145                         break;
2146                 case LYX_VALIGN_BOTTOM:
2147                         os << "bottom";
2148                         break;
2149                 case LYX_VALIGN_CENTER:
2150                         os << "middle";
2151                 }
2152                 os << '"';
2153
2154                 if (IsMultiColumn(cell)) {
2155                         os << " namest=\"col" << j << "\" ";
2156                         os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
2157                 }
2158
2159                 os << '>';
2160                 ret += GetCellInset(cell)->docbook(buf, os, true);
2161                 os << "</entry>\n";
2162                 ++cell;
2163         }
2164         os << "</row>\n";
2165         return ret;
2166 }
2167
2168
2169 int LyXTabular::docbook(Buffer const * buf, ostream & os,
2170                         bool /*mixcont*/) const
2171 {
2172         int ret = 0;
2173
2174         //+---------------------------------------------------------------------
2175         //+                      first the opening preamble                    +
2176         //+---------------------------------------------------------------------
2177
2178         os << "<tgroup cols=\"" << columns_
2179            << "\" colsep=\"1\" rowsep=\"1\">\n";
2180
2181         for (int i = 0; i < columns_; ++i) {
2182                 os << "<colspec colname=\"col" << i << "\" align=\"";
2183                 switch (column_info[i].alignment) {
2184                 case LYX_ALIGN_LEFT:
2185                         os << "left";
2186                         break;
2187                 case LYX_ALIGN_RIGHT:
2188                         os << "right";
2189                         break;
2190                 default:
2191                         os << "center";
2192                         break;
2193                 }
2194                 os << "\">\n";
2195                 ++ret;
2196         }
2197
2198         //+---------------------------------------------------------------------
2199         //+                      Long Tabular case                             +
2200         //+---------------------------------------------------------------------
2201
2202         // output header info
2203         if (haveLTHead() || haveLTFirstHead()) {
2204                 os << "<thead>\n";
2205                 ++ret;
2206                 for (int i = 0; i < rows_; ++i) {
2207                         if (row_info[i].endhead || row_info[i].endfirsthead) {
2208                                 ret += docbookRow(buf, os, i);
2209                         }
2210                 }
2211                 os << "</thead>\n";
2212                 ++ret;
2213         }
2214         // output footer info
2215         if (haveLTFoot() || haveLTLastFoot()) {
2216                 os << "<tfoot>\n";
2217                 ++ret;
2218                 for (int i = 0; i < rows_; ++i) {
2219                         if (row_info[i].endfoot || row_info[i].endlastfoot) {
2220                                 ret += docbookRow(buf, os, i);
2221                         }
2222                 }
2223                 os << "</tfoot>\n";
2224                 ++ret;
2225         }
2226
2227         //+---------------------------------------------------------------------
2228         //+                      the single row and columns (cells)            +
2229         //+---------------------------------------------------------------------
2230
2231         os << "<tbody>\n";
2232         ++ret;
2233         for (int i = 0; i < rows_; ++i) {
2234                 if (isValidRow(i)) {
2235                         ret += docbookRow(buf, os, i);
2236                 }
2237         }
2238         os << "</tbody>\n";
2239         ++ret;
2240         //+---------------------------------------------------------------------
2241         //+                      the closing of the tabular                    +
2242         //+---------------------------------------------------------------------
2243
2244         os << "</tgroup>";
2245         ++ret;
2246
2247         return ret;
2248 }
2249
2250 //--
2251 // ASCII export function and helpers
2252 //--
2253 int LyXTabular::asciiTopHLine(ostream & os, int row,
2254                               vector<unsigned int> const & clen) const
2255 {
2256         int const fcell = GetFirstCellInRow(row);
2257         int const n = NumberOfCellsInRow(fcell) + fcell;
2258         int tmp = 0;
2259
2260         for (int i = fcell; i < n; ++i) {
2261                 if (TopLine(i)) {
2262                         ++tmp;
2263                         break;
2264                 }
2265         }
2266         if (!tmp)
2267                 return 0;
2268
2269         unsigned char ch;
2270         for (int i = fcell; i < n; ++i) {
2271                 if (TopLine(i)) {
2272                         if (LeftLine(i))
2273                                 os << "+-";
2274                         else
2275                                 os << "--";
2276                         ch = '-';
2277                 } else {
2278                         os << "  ";
2279                         ch = ' ';
2280                 }
2281                 int column = column_of_cell(i);
2282                 int len = clen[column];
2283                 while (IsPartOfMultiColumn(row, ++column))
2284                         len += clen[column] + 4;
2285                 os << string(len, ch);
2286                 if (TopLine(i)) {
2287                         if (RightLine(i))
2288                                 os << "-+";
2289                         else
2290                                 os << "--";
2291                 } else {
2292                         os << "  ";
2293                 }
2294         }
2295         os << endl;
2296         return 1;
2297 }
2298
2299
2300 int LyXTabular::asciiBottomHLine(ostream & os, int row,
2301                                  vector<unsigned int> const & clen) const
2302 {
2303         int const fcell = GetFirstCellInRow(row);
2304         int const n = NumberOfCellsInRow(fcell) + fcell;
2305         int tmp = 0;
2306
2307         for (int i = fcell; i < n; ++i) {
2308                 if (BottomLine(i)) {
2309                         ++tmp;
2310                         break;
2311                 }
2312         }
2313         if (!tmp)
2314                 return 0;
2315
2316         unsigned char ch;
2317         for (int i = fcell; i < n; ++i) {
2318                 if (BottomLine(i)) {
2319                         if (LeftLine(i))
2320                                 os << "+-";
2321                         else
2322                                 os << "--";
2323                         ch = '-';
2324                 } else {
2325                         os << "  ";
2326                         ch = ' ';
2327                 }
2328                 int column = column_of_cell(i);
2329                 int len = clen[column];
2330                 while (IsPartOfMultiColumn(row, ++column))
2331                         len += clen[column] + 4;
2332                 os << string(len, ch);
2333                 if (BottomLine(i)) {
2334                         if (RightLine(i))
2335                                 os << "-+";
2336                         else
2337                                 os << "--";
2338                 } else {
2339                         os << "  ";
2340                 }
2341         }
2342         os << endl;
2343         return 1;
2344 }
2345
2346
2347 int LyXTabular::asciiPrintCell(Buffer const * buf, ostream & os,
2348                                int cell, int row, int column,
2349                                vector<unsigned int> const & clen,
2350                                bool onlydata) const
2351 {
2352         ostringstream sstr;
2353         int ret = GetCellInset(cell)->ascii(buf, sstr, 0);
2354
2355         if (onlydata) {
2356                 os << sstr.str();
2357                 return ret;
2358         }
2359
2360         if (LeftLine(cell))
2361                 os << "| ";
2362         else
2363                 os << "  ";
2364
2365         unsigned int len1 = sstr.str().length();
2366         unsigned int len2 = clen[column];
2367         while (IsPartOfMultiColumn(row, ++column))
2368                 len2 += clen[column] + 4;
2369         len2 -= len1;
2370
2371         switch (GetAlignment(cell)) {
2372         default:
2373         case LYX_ALIGN_LEFT:
2374                 len1 = 0;
2375                 break;
2376         case LYX_ALIGN_RIGHT:
2377                 len1 = len2;
2378                 len2 = 0;
2379                 break;
2380         case LYX_ALIGN_CENTER:
2381                 len1 = len2 / 2;
2382                 len2 -= len1;
2383                 break;
2384         }
2385
2386         os << string(len1, ' ')
2387            << sstr.str()
2388            << string(len2, ' ');
2389         if (RightLine(cell))
2390                 os << " |";
2391         else
2392                 os << "  ";
2393
2394         return ret;
2395 }
2396
2397
2398 int LyXTabular::ascii(Buffer const * buf, ostream & os, int const depth,
2399                                           bool onlydata, unsigned char delim) const
2400 {
2401         int ret = 0;
2402
2403         //+---------------------------------------------------------------------
2404         //+           first calculate the width of the single columns          +
2405         //+---------------------------------------------------------------------
2406         vector<unsigned int> clen(columns_);
2407
2408         if (!onlydata) {
2409                 // first all non (real) multicolumn cells!
2410                 for (int j = 0; j < columns_; ++j) {
2411                         clen[j] = 0;
2412                         for (int i = 0; i < rows_; ++i) {
2413                                 int cell = GetCellNumber(i, j);
2414                                 if (IsMultiColumn(cell, true))
2415                                         continue;
2416                                 ostringstream sstr;
2417                                 GetCellInset(cell)->ascii(buf, sstr, 0);
2418                                 if (clen[j] < sstr.str().length())
2419                                         clen[j] = sstr.str().length();
2420                         }
2421                 }
2422                 // then all (real) multicolumn cells!
2423                 for (int j = 0; j < columns_; ++j) {
2424                         for (int i = 0; i < rows_; ++i) {
2425                                 int cell = GetCellNumber(i, j);
2426                                 if (!IsMultiColumn(cell, true) || IsPartOfMultiColumn(i, j))
2427                                         continue;
2428                                 ostringstream sstr;
2429                                 GetCellInset(cell)->ascii(buf, sstr, 0);
2430                                 int len = int(sstr.str().length());
2431                                 int const n = cells_in_multicolumn(cell);
2432                                 for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2433                                         len -= clen[k];
2434                                 if (len > int(clen[j + n - 1]))
2435                                         clen[j + n - 1] = len;
2436                         }
2437                 }
2438         }
2439         int cell = 0;
2440         for (int i = 0; i < rows_; ++i) {
2441                 if (!onlydata) {
2442                         if (asciiTopHLine(os, i, clen)) {
2443                                 for (int j = 0; j < depth; ++j)
2444                                         os << "  ";
2445                         }
2446                 }
2447                 for (int j = 0; j < columns_; ++j) {
2448                         if (IsPartOfMultiColumn(i,j))
2449                                 continue;
2450                         if (onlydata && j > 0)
2451                                 os << delim;
2452                         ret += asciiPrintCell(buf, os, cell, i, j, clen, onlydata);
2453                         ++cell;
2454                 }
2455                 os << endl;
2456                 if (!onlydata) {
2457                         for (int j = 0; j < depth; ++j)
2458                                 os << "  ";
2459                         if (asciiBottomHLine(os, i, clen)) {
2460                                 for (int j = 0; j < depth; ++j)
2461                                         os << "  ";
2462                         }
2463                 }
2464         }
2465         return ret;
2466 }
2467 //--
2468 // end ascii export
2469 //--
2470
2471
2472 InsetText * LyXTabular::GetCellInset(int cell) const
2473 {
2474         cur_cell = cell;
2475         return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2476 }
2477
2478
2479 InsetText * LyXTabular::GetCellInset(int row, int column) const
2480 {
2481         cur_cell = GetCellNumber(row, column);
2482         return & cell_info[row][column].inset;
2483 }
2484
2485
2486 int LyXTabular::GetCellFromInset(Inset const * inset, int maybe_cell) const
2487 {
2488         // is this inset part of the tabular?
2489         if (!inset || inset->owner() != owner_) {
2490                 lyxerr[Debug::INSETTEXT]
2491                         << "this is not a cell of the tabular!" << endl;
2492                 return -1;
2493         }
2494
2495         const int save_cur_cell = cur_cell;
2496         int cell = cur_cell;
2497         if (GetCellInset(cell) != inset) {
2498                 cell = maybe_cell;
2499                 if (cell == -1 || GetCellInset(cell) != inset) {
2500                         cell = -1;
2501                 }
2502         }
2503
2504         if (cell == -1) {
2505                 for (cell = GetNumberOfCells(); cell >= 0; --cell) {
2506                         if (GetCellInset(cell) == inset)
2507                                 break;
2508                 }
2509                 lyxerr[Debug::INSETTEXT]
2510                          << "LyXTabular::GetCellFromInset: "
2511                                     << "cell=" << cell
2512                                     << ", cur_cell=" << save_cur_cell
2513                                     << ", maybe_cell=" << maybe_cell
2514                                     << endl;
2515                 // We should have found a cell at this point
2516                 if (cell == -1) {
2517                         lyxerr << "LyXTabular::GetCellFromInset: "
2518                                << "Cell not found!" << endl;
2519                 }
2520         }
2521
2522         return cell;
2523 }
2524
2525
2526 void LyXTabular::Validate(LaTeXFeatures & features) const
2527 {
2528         features.require("NeedTabularnewline");
2529         if (IsLongTabular())
2530                 features.require("longtable");
2531         if (NeedRotating())
2532                 features.require("rotating");
2533         for (int cell = 0; cell < numberofcells; ++cell) {
2534                 if ( (GetVAlignment(cell) != LYX_VALIGN_TOP) ||
2535                      ( !(GetPWidth(cell).zero())&&!(IsMultiColumn(cell)) )
2536                    )
2537                         features.require("array");
2538                 GetCellInset(cell)->validate(features);
2539         }
2540 }
2541
2542
2543 vector<string> const LyXTabular::getLabelList() const
2544 {
2545         vector<string> label_list;
2546         for (int i = 0; i < rows_; ++i)
2547                 for (int j = 0; j < columns_; ++j) {
2548                         vector<string> const l =
2549                                 GetCellInset(i, j)->getLabelList();
2550                         label_list.insert(label_list.end(),
2551                                           l.begin(), l.end());
2552                 }
2553         return label_list;
2554 }
2555
2556
2557 LyXTabular::BoxType LyXTabular::UseParbox(int cell) const
2558 {
2559         ParagraphList const & parlist = GetCellInset(cell)->paragraphs;
2560         ParagraphList::iterator cit = parlist.begin();
2561         ParagraphList::iterator end = parlist.end();
2562
2563         for (; cit != end; ++cit) {
2564                 for (int i = 0; i < cit->size(); ++i) {
2565                         if (cit->isNewline(i))
2566                                 return BOX_PARBOX;
2567                 }
2568         }
2569         return BOX_NONE;
2570 }