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