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