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