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