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