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