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