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