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