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