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