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