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