]> git.lyx.org Git - features.git/blob - src/tabular.C
some formatting changes some simplifications and removal of dead code
[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  *           @author: Jürgen Vigna
9  *
10  * ====================================================== 
11  */
12
13 #include <config.h>
14
15 #ifdef __GNUG__
16 #pragma implementation
17 #endif
18
19 #include <algorithm>
20 #include <cstdlib>
21
22 #include "tabular.h"
23 #include "debug.h"
24 #include "vspace.h"
25 #include "layout.h"
26 #include "lyx_gui_misc.h"
27 #include "buffer.h"
28 #include "BufferView.h"
29 #include "Painter.h"
30 #include "LaTeXFeatures.h"
31 #include "support/lstrings.h"
32 #include "support/lyxmanip.h"
33 #include "insets/insettabular.h"
34 #include "insets/insettext.h"
35
36 using std::ostream;
37 using std::istream;
38 using std::getline;
39 using std::max;
40 using std::endl;
41 using std::vector;
42
43 static int const WIDTH_OF_LINE = 5;
44
45 /// Define a few methods for the inner structs
46
47 LyXTabular::cellstruct::cellstruct() 
48 {
49     cellno = 0;
50     width_of_cell = 0;
51     multicolumn = LyXTabular::CELL_NORMAL;
52     alignment = LYX_ALIGN_CENTER;
53     valignment = LYX_VALIGN_TOP;
54     top_line = true;
55     bottom_line = false;
56     left_line = true;
57     right_line = false;
58     usebox = BOX_NONE;
59     rotate = false;
60 }
61
62
63 LyXTabular::rowstruct::rowstruct() 
64 {
65     top_line = true;
66     bottom_line = false;
67     ascent_of_row = 0;
68     descent_of_row = 0;
69     newpage = false;
70 }
71
72
73 LyXTabular::columnstruct::columnstruct() 
74 {
75     left_line = true;
76     right_line = false;
77     alignment = LYX_ALIGN_CENTER;
78     valignment = LYX_VALIGN_TOP;
79     width_of_column = 0;
80 }
81
82
83 /* konstruktor */
84 LyXTabular::LyXTabular(InsetTabular * inset, int rows_arg, int columns_arg)
85 {
86     owner_ = inset;
87     Init(rows_arg, columns_arg);
88 }
89
90
91 LyXTabular::LyXTabular(InsetTabular * inset, LyXTabular const & lt)
92 {
93     owner_ = inset;
94     Init(lt.rows_, lt.columns_);
95 #warning Jürgen, can you make it the other way round. So that copy assignment depends on the copy constructor and not the other way. (Lgb)
96     operator=(lt);
97 }
98
99
100 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
101 {
102     owner_ = inset;
103     Read(buf, lex);
104 }
105
106
107 LyXTabular & LyXTabular::operator=(LyXTabular const & lt)
108 {
109     // If this and lt is not of the same size we have a serious bug
110     // So then it is ok to throw an exception, or for now
111     // call abort()
112     Assert(rows_ == lt.rows_ && columns_ == lt.columns_);
113
114     cell_info = lt.cell_info;
115     row_info = lt.row_info;
116     column_info = lt.column_info;
117
118     // long tabular stuff
119     SetLongTabular(lt.is_long_tabular);
120     endhead = lt.endhead;
121     endfoot = lt.endfoot;
122     endfirsthead = lt.endfirsthead;
123     endlastfoot = lt.endlastfoot;
124
125     rotate = lt.rotate;
126
127     Reinit();
128     
129     return *this;
130 }
131
132
133 LyXTabular * LyXTabular::Clone(InsetTabular * inset)
134 {
135     LyXTabular * result = new LyXTabular(inset, *this);
136     // don't know if this is good but I need to Clone also
137     // the text-insets here, this is for the Undo-facility!
138     for (int i = 0; i < rows_; ++i) {
139         for (int j = 0; j < columns_; ++j) {
140             result->cell_info[i][j].inset = cell_info[i][j].inset;
141             result->cell_info[i][j].inset.setOwner(inset);
142         }
143     }
144     return result;
145 }
146
147
148 /* activates all lines and sets all widths to 0 */ 
149 void LyXTabular::Init(int rows_arg, int columns_arg)
150 {
151     rows_ = rows_arg;
152     columns_ = columns_arg;
153     row_info = row_vector(rows_, rowstruct());
154     column_info = column_vector(columns_, columnstruct());
155     cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct()));
156
157     int cellno = 0;
158     for (int i = 0; i < rows_; ++i) {
159         for (int j = 0; j < columns_; ++j) {
160             cell_info[i][j].inset.setOwner(owner_);
161             cell_info[i][j].inset.SetDrawFrame(0, InsetText::LOCKED);
162             cell_info[i][j].cellno = cellno++;
163         }
164         cell_info[i].back().right_line = true;
165     }
166     row_info.back().bottom_line = true;
167     row_info.front().bottom_line = true;
168
169     for (int i = 0; i < columns_; ++i) {
170         calculate_width_of_column(i);
171     }
172     column_info.back().right_line = true;
173    
174     calculate_width_of_tabular();
175
176     rowofcell = vector<int>();
177     columnofcell = vector<int>();
178     set_row_column_number_info();
179     is_long_tabular = false;
180     rotate = false;
181     endhead = 0;
182     endfirsthead = 0;
183     endfoot = 0;
184     endlastfoot = 0;
185 }
186
187
188 void LyXTabular::AppendRow(int cell)
189 {
190     ++rows_;
191    
192     int row = row_of_cell(cell);
193
194     row_vector::iterator rit = row_info.begin() + row;
195     row_info.insert(rit, rowstruct());
196
197 #if 0
198     cell_vvector::iterator cit = cell_info.begin() + row;
199     cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct()));
200 #else
201     cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
202                                                           cellstruct()));
203
204     for (int i = 0; i <= row; ++i) {
205         for (int j = 0; j < columns_; ++j) {
206             c_info[i][j] = cell_info[i][j];
207         }
208     }
209     for (int i = row + 1; i < rows_; ++i) {
210         for (int j = 0; j < columns_; ++j) {
211             c_info[i][j] = cell_info[i-1][j];
212         }
213     }
214     cell_info = c_info;
215     ++row;
216     for (int j = 0; j < columns_; ++j) {
217         cell_info[row][j].inset.clear();
218     }
219 #endif
220     Reinit();
221 }
222
223
224 void LyXTabular::DeleteRow(int row)
225 {
226     // Why make it so hard? (Lgb)
227     //if (!(rows_ - 1))
228     //return;
229     if (rows_ == 1) return; // Not allowed to delete last row
230         
231     row_info.erase(row_info.begin() + row); //&row_info[row]);
232     cell_info.erase(cell_info.begin() + row); //&cell_info[row]);
233     --rows_;
234     Reinit();
235 }
236
237
238 void LyXTabular::AppendColumn(int cell)
239 {
240     ++columns_;
241    
242     cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
243                                                           cellstruct()));
244     int const column = column_of_cell(cell);
245     column_vector::iterator cit = column_info.begin() + column + 1;
246     column_info.insert(cit, columnstruct());
247
248     for (int i = 0; i < rows_; ++i) {
249         for (int j = 0; j <= column; ++j) {
250             c_info[i][j] = cell_info[i][j];
251         }
252         for (int j = column + 1; j < columns_; ++j) {
253             c_info[i][j] = cell_info[i][j - 1];
254         }
255         // care about multicolumns
256         if (cell_info[i][column + 1].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
257             cell_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
258         }
259         if ((column + 1) == columns_ ||
260             cell_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN) {
261             cell_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
262         }
263     }
264     cell_info = c_info;
265     //++column;
266     for (int i = 0; i < rows_; ++i) {
267         //cell_info[i][column].inset.clear();
268         cell_info[i][column + 1].inset.clear();
269     }
270     Reinit();
271 }
272
273
274 void LyXTabular::DeleteColumn(int column)
275 {
276     // Similar to DeleteRow
277     //if (!(columns_ - 1))
278     //return;
279     if (columns_ == 1) return; // Not allowed to delete last column
280          
281     column_info.erase(column_info.begin() + column);
282     for (int i = 0; i < rows_; ++i) {
283         cell_info[i].erase(cell_info[i].begin() + column);
284     }
285     --columns_;
286     Reinit();
287 }
288
289
290 void LyXTabular::Reinit()
291 {   
292     for (int i = 0; i < rows_; ++i) {
293         for (int j = 0; j < columns_; ++j) {
294             cell_info[i][j].width_of_cell = 0;
295             cell_info[i][j].inset.setOwner(owner_);
296         }
297     }
298   
299     for (int i = 0; i < columns_; ++i) {
300         calculate_width_of_column(i);
301     }
302     calculate_width_of_tabular();
303
304     set_row_column_number_info();
305 }
306
307
308 void LyXTabular::set_row_column_number_info(bool oldformat)
309 {
310     numberofcells = -1;
311     for (int row = 0; row < rows_; ++row) {
312         for (int column = 0; column<columns_; ++column) {
313             if (cell_info[row][column].multicolumn
314                 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
315                 ++numberofcells;
316             cell_info[row][column].cellno = numberofcells;
317         }
318     }
319     ++numberofcells; // because this is one more than as we start from 0
320
321     rowofcell.resize(numberofcells);
322     columnofcell.resize(numberofcells);
323
324 #if 0
325     int row = 0;
326     int column = 0;
327     int c = 0;
328     
329     while (c < numberofcells && row < rows_ && column < columns_) {
330         rowofcell[c] = row;
331         columnofcell[c] = column;
332         ++c;
333         do {
334             ++column;
335         } while (column < columns_ &&
336                  cell_info[row][column].multicolumn
337                  == LyXTabular::CELL_PART_OF_MULTICOLUMN);
338         if (column == columns_) {
339             column = 0;
340             ++row;
341         }
342     }
343 #else
344     // Isn't this the same as the while above? (Lgb)
345     for (int row = 0, column = 0, c = 0;
346          c < numberofcells && row < rows_ && column < columns_;) {
347         rowofcell[c] = row;
348         columnofcell[c] = column;
349         ++c;
350         do {
351             ++column;
352         } while (column < columns_ &&
353                  cell_info[row][column].multicolumn
354                  == LyXTabular::CELL_PART_OF_MULTICOLUMN);
355         if (column == columns_) {
356             column = 0;
357             ++row;
358         }
359     }
360 #endif
361
362     for (int row = 0; row < rows_; ++row) {
363         for (int column = 0; column < columns_; ++column) {
364             if (IsPartOfMultiColumn(row,column))
365                 continue;
366             // now set the right line of multicolumns right for oldformat read
367             if (oldformat &&
368                 cell_info[row][column].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
369             {
370                 int cn=cells_in_multicolumn(cell_info[row][column].cellno);
371                 cell_info[row][column].right_line =
372                     cell_info[row][column+cn-1].right_line;
373             }
374             cell_info[row][column].inset.SetAutoBreakRows(
375                 !GetPWidth(GetCellNumber(row, column)).empty());
376         }
377     }
378 }
379
380
381 int LyXTabular::GetNumberOfCells() const
382 {
383     return numberofcells;
384 }
385
386
387 int LyXTabular::NumberOfCellsInRow(int cell) const
388 {
389     int const row = row_of_cell(cell);
390     int result = 0;
391     for (int i = 0; i < columns_; ++i) {
392         if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
393             ++result;
394     }
395     return result;
396 }
397
398
399 /* returns 1 if there is a topline, returns 0 if not */ 
400 bool LyXTabular::TopLine(int cell, bool onlycolumn) const
401 {
402     int const row = row_of_cell(cell);
403     
404     if (!onlycolumn && IsMultiColumn(cell))
405         return cellinfo_of_cell(cell)->top_line;
406     return row_info[row].top_line;
407 }
408
409
410 bool LyXTabular::BottomLine(int cell, bool onlycolumn) const
411 {
412     // no bottom line underneath non-existent cells if you please
413     // Isn't that a programming error? Is so this should
414     // be an Assert instead. (Lgb)
415     if (cell >= numberofcells)
416         return false;
417
418     if (!onlycolumn && IsMultiColumn(cell))
419         return cellinfo_of_cell(cell)->bottom_line;
420     return row_info[row_of_cell(cell)].bottom_line;
421 }
422
423
424 bool LyXTabular::LeftLine(int cell, bool onlycolumn) const
425 {
426     if (!onlycolumn && IsMultiColumn(cell))
427         return cellinfo_of_cell(cell)->left_line;
428     return column_info[column_of_cell(cell)].left_line;
429 }
430
431
432 bool LyXTabular::RightLine(int cell, bool onlycolumn) const
433 {
434     if (!onlycolumn && IsMultiColumn(cell))
435         return cellinfo_of_cell(cell)->right_line;
436     return column_info[right_column_of_cell(cell)].right_line;
437 }
438
439
440 bool LyXTabular::TopAlreadyDrawed(int cell) const
441 {
442     if (GetAdditionalHeight(cell))
443         return false;
444     int row = row_of_cell(cell);
445     if (row > 0) {
446         int column = column_of_cell(cell);
447         --row;
448         while (column
449                && cell_info[row][column].multicolumn
450                == LyXTabular::CELL_PART_OF_MULTICOLUMN)
451             --column;
452         if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
453             return row_info[row].bottom_line;
454         else
455             return cell_info[row][column].bottom_line;
456     }
457     return false;
458 }
459
460
461 bool LyXTabular::LeftAlreadyDrawed(int cell) const
462 {
463     int column = column_of_cell(cell);
464     if (column > 0) {
465         int row = row_of_cell(cell);
466         while (--column &&
467                (cell_info[row][column].multicolumn ==
468                 LyXTabular::CELL_PART_OF_MULTICOLUMN));
469         if (GetAdditionalWidth(cell_info[row][column].cellno))
470             return false;
471         return column_info[column].right_line;
472     }
473     return false;
474 }
475
476
477 bool LyXTabular::IsLastRow(int cell) const
478 {
479     return (row_of_cell(cell) == rows_ - 1);
480 }
481
482
483 int LyXTabular::GetAdditionalHeight(int cell) const
484 {
485     int const row = row_of_cell(cell);
486     if (!row) return 0;
487
488     bool top = true;
489     bool bottom = true;
490
491     for (int column = 0; column < columns_ - 1 && bottom; ++column) {
492         switch (cell_info[row - 1][column].multicolumn) {
493         case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
494             bottom = cell_info[row - 1][column].bottom_line;
495             break;
496         case LyXTabular::CELL_NORMAL:
497             bottom = row_info[row - 1].bottom_line;
498         }
499     }
500     for (int column = 0; column < columns_ - 1 && top; ++column) {
501         switch (cell_info[row][column].multicolumn){
502         case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
503             top = cell_info[row][column].top_line;
504             break;
505         case LyXTabular::CELL_NORMAL:
506             top = row_info[row].top_line;
507         }
508     }
509     if (top && bottom)
510         return WIDTH_OF_LINE;
511     return 0;
512 }
513
514
515 int LyXTabular::GetAdditionalWidth(int cell) const
516 {
517     // internally already set in SetWidthOfCell
518     // used to get it back in text.C
519     int const col = right_column_of_cell(cell);
520     if (col < columns_ - 1 && column_info[col].right_line &&
521         column_info[col+1].left_line)
522         return WIDTH_OF_LINE;
523     else
524         return 0;
525 }
526
527
528 // returns the maximum over all rows 
529 int LyXTabular::GetWidthOfColumn(int cell) const
530 {
531     int const column1 = column_of_cell(cell);
532     int const column2 = right_column_of_cell(cell);
533     int result = 0;
534     for (int i = column1; i <= column2; ++i) {
535         result += column_info[i].width_of_column;
536     }
537     return result;
538 }
539
540
541 int LyXTabular::GetWidthOfTabular() const
542 {
543     return width_of_tabular;
544 }
545
546
547 /* returns 1 if a complete update is necessary, otherwise 0 */ 
548 bool LyXTabular::SetWidthOfMulticolCell(int cell, int new_width)
549 {
550     if (!IsMultiColumn(cell))
551         return false;
552     
553     int const row = row_of_cell(cell);
554     int const column1 = column_of_cell(cell);
555     int const column2 = right_column_of_cell(cell);
556
557     // first set columns to 0 so we can calculate the right width
558     for (int i = column1; i <= column2; ++i) {
559         cell_info[row][i].width_of_cell = 0;
560     }
561     // set the width to MAX_WIDTH until width > 0
562     int width = (new_width + 2 * WIDTH_OF_LINE);
563
564     int i = column1;
565     for (; i < column2 && width > column_info[i].width_of_column; ++i) {
566         cell_info[row][i].width_of_cell = column_info[i].width_of_column;
567         width -= column_info[i].width_of_column;
568     }
569     if (width > 0) {
570         cell_info[row][i].width_of_cell = width;
571     }
572     return true;
573 }
574
575
576 void LyXTabular::recalculateMulticolCells(int cell, int new_width)
577 {
578     int const row = row_of_cell(cell);
579     int const column1 = column_of_cell(cell);
580     int const column2 = right_column_of_cell(cell);
581
582     // first set columns to 0 so we can calculate the right width
583     int i = column1;
584     for (; i <= column2; ++i)
585         cell_info[row][i].width_of_cell = 0;
586     for (i = cell + 1; (i < numberofcells) && (!IsMultiColumn(i)); ++i)
587         ;
588     if (i < numberofcells)
589         recalculateMulticolCells(i, GetWidthOfCell(i) - (2 * WIDTH_OF_LINE));
590     SetWidthOfMulticolCell(cell, new_width);
591 }
592
593
594 /* returns 1 if a complete update is necessary, otherwise 0 */ 
595 bool LyXTabular::SetWidthOfCell(int cell, int new_width)
596 {
597     int const row = row_of_cell(cell);
598     int const column1 = column_of_cell(cell);
599     bool tmp = false;
600     int width = 0;
601
602     if (GetWidthOfCell(cell) == (new_width+2*WIDTH_OF_LINE))
603         return false;
604     if (IsMultiColumn(cell, true)) {
605         tmp = SetWidthOfMulticolCell(cell, new_width);
606     } else {
607         width = (new_width + 2*WIDTH_OF_LINE);
608         cell_info[row][column1].width_of_cell = width;
609         if (column_info[column1].right_line && (column1 < columns_-1) &&
610             column_info[column1+1].left_line) // additional width
611             cell_info[row][column1].width_of_cell += WIDTH_OF_LINE;
612         tmp = calculate_width_of_column_NMC(column1);
613     }
614     if (tmp) {
615         int i = 0;
616         for (; i<columns_; ++i)
617             calculate_width_of_column_NMC(i);
618         for (i = 0; (i < numberofcells) && !IsMultiColumn(i); ++i)
619             ;
620         if (i < numberofcells)
621             recalculateMulticolCells(i, GetWidthOfCell(i)-(2 * WIDTH_OF_LINE));
622         for (i = 0; i < columns_; ++i)
623             calculate_width_of_column(i);
624         calculate_width_of_tabular();
625         return true;
626     }
627     return false;
628 }
629
630
631 bool LyXTabular::SetAlignment(int cell, LyXAlignment align, bool onlycolumn)
632 {
633     if (!IsMultiColumn(cell) || onlycolumn)
634         column_info[column_of_cell(cell)].alignment = align;
635     if (!onlycolumn)
636         cellinfo_of_cell(cell)->alignment = align;
637     return true;
638 }
639
640
641 bool LyXTabular::SetVAlignment(int cell, VAlignment align, bool onlycolumn)
642 {
643     if (!IsMultiColumn(cell) || onlycolumn)
644         column_info[column_of_cell(cell)].valignment = align;
645     if (!onlycolumn)
646         cellinfo_of_cell(cell)->valignment = align;
647     return true;
648 }
649
650
651 bool LyXTabular::SetColumnPWidth(int cell, string const & width)
652 {
653     bool flag = !width.empty();
654     int const j = column_of_cell(cell);
655
656     column_info[j].p_width = width;
657     if (flag) // do this only if there is a width
658         SetAlignment(cell, LYX_ALIGN_LEFT);
659     for (int i = 0; i < rows_; ++i) {
660         int c = GetCellNumber(i, j);
661         flag = !GetPWidth(c).empty(); // because of multicolumns!
662         GetCellInset(c)->SetAutoBreakRows(flag);
663     }
664     return true;
665 }
666
667
668 bool LyXTabular::SetMColumnPWidth(int cell, string const & width)
669 {
670     bool const flag = !width.empty();
671
672     cellinfo_of_cell(cell)->p_width = width;
673     if (IsMultiColumn(cell)) {
674         GetCellInset(cell)->SetAutoBreakRows(flag);
675         return true;
676     }
677     return false;
678 }
679
680
681 bool LyXTabular::SetAlignSpecial(int cell, string const & special,
682                                  LyXTabular::Feature what)
683 {
684     if (what == SET_SPECIAL_MULTI)
685         cellinfo_of_cell(cell)->align_special = special;
686     else
687         column_info[column_of_cell(cell)].align_special = special;
688     return true;
689 }
690
691
692 bool LyXTabular::SetAllLines(int cell, bool line)
693 {
694     SetTopLine(cell, line);
695     SetBottomLine(cell, line);
696     SetRightLine(cell, line);
697     SetLeftLine(cell, line);
698     return true;
699 }
700
701
702 bool LyXTabular::SetTopLine(int cell, bool line, bool onlycolumn)
703 {
704     int const row = row_of_cell(cell);
705
706     if (onlycolumn || !IsMultiColumn(cell))
707         row_info[row].top_line = line;
708     else
709         cellinfo_of_cell(cell)->top_line = line;
710     return true;
711 }
712
713
714 bool LyXTabular::SetBottomLine(int cell, bool line, bool onlycolumn)
715 {
716     if (onlycolumn || !IsMultiColumn(cell))
717         row_info[row_of_cell(cell)].bottom_line = line;
718     else
719         cellinfo_of_cell(cell)->bottom_line = line;
720     return true;
721 }
722
723
724 bool LyXTabular::SetLeftLine(int cell, bool line, bool onlycolumn)
725 {
726     if (onlycolumn || !IsMultiColumn(cell))
727         column_info[column_of_cell(cell)].left_line = line;
728     else
729         cellinfo_of_cell(cell)->left_line = line;
730     return true;
731 }
732
733
734 bool LyXTabular::SetRightLine(int cell, bool line, bool onlycolumn)
735 {
736     if (onlycolumn || !IsMultiColumn(cell))
737         column_info[right_column_of_cell(cell)].right_line = line;
738     else
739         cellinfo_of_cell(cell)->right_line = line;
740     return true;
741 }
742
743
744 LyXAlignment LyXTabular::GetAlignment(int cell, bool onlycolumn) const
745 {
746     if (!onlycolumn && IsMultiColumn(cell))
747         return cellinfo_of_cell(cell)->alignment;
748     else
749         return column_info[column_of_cell(cell)].alignment;
750 }
751
752
753 LyXTabular::VAlignment
754 LyXTabular::GetVAlignment(int cell, bool onlycolumn) const
755 {
756     if (!onlycolumn && IsMultiColumn(cell))
757         return cellinfo_of_cell(cell)->valignment;
758     else
759         return column_info[column_of_cell(cell)].valignment;
760 }
761
762
763 string const LyXTabular::GetPWidth(int cell) const
764 {
765     if (IsMultiColumn(cell))
766         return cellinfo_of_cell(cell)->p_width;
767     return column_info[column_of_cell(cell)].p_width;
768 }
769
770
771 string const LyXTabular::GetColumnPWidth(int cell) const
772 {
773     return column_info[column_of_cell(cell)].p_width;
774 }
775
776
777 string const LyXTabular::GetMColumnPWidth(int cell) const
778 {
779     if (IsMultiColumn(cell))
780         return cellinfo_of_cell(cell)->p_width;
781     return string();
782 }
783
784
785 string const LyXTabular::GetAlignSpecial(int cell, int what) const
786 {
787     if (what == SET_SPECIAL_MULTI)
788         return cellinfo_of_cell(cell)->align_special;
789     return column_info[column_of_cell(cell)].align_special;
790 }
791
792
793 int LyXTabular::GetWidthOfCell(int cell) const
794 {
795     int const row = row_of_cell(cell);
796     int const column1 = column_of_cell(cell);
797     int const column2 = right_column_of_cell(cell);
798     int result = 0;
799     for (int i = column1; i <= column2; ++i) {
800         result += cell_info[row][i].width_of_cell;
801     }
802     return result;
803 }
804
805
806 int LyXTabular::GetBeginningOfTextInCell(int cell) const
807 {
808     int x = 0;
809    
810     switch (GetAlignment(cell)){
811     case LYX_ALIGN_CENTER:
812         x += (GetWidthOfColumn(cell) - GetWidthOfCell(cell)) / 2;
813         break;
814     case LYX_ALIGN_RIGHT:
815         x += GetWidthOfColumn(cell) - GetWidthOfCell(cell);
816         // + GetAdditionalWidth(cell);
817         break;
818     default: /* LYX_ALIGN_LEFT: nothing :-) */ 
819         break;
820     }
821     
822     // the LaTeX Way :-(
823     x += WIDTH_OF_LINE;
824     return x;
825 }
826
827
828 bool LyXTabular::IsFirstCellInRow(int cell) const
829 {
830     return column_of_cell(cell) == 0;
831 }
832
833
834 int LyXTabular::GetFirstCellInRow(int row) const
835 {
836     if (row > (rows_-1))
837         row = rows_ - 1;
838     return cell_info[row][0].cellno;
839 }
840
841 bool LyXTabular::IsLastCellInRow(int cell) const
842 {
843     return (right_column_of_cell(cell) == (columns_ - 1));
844 }
845
846
847 int LyXTabular::GetLastCellInRow(int row) const
848 {
849     if (row > (rows_-1))
850         row = rows_ - 1;
851     return cell_info[row][columns_-1].cellno;
852 }
853
854
855 bool LyXTabular::calculate_width_of_column(int column)
856 {
857     int const old_column_width = column_info[column].width_of_column;
858     int maximum = 0;
859     
860     for (int i = 0; i < rows_; ++i) {
861         maximum = max(cell_info[i][column].width_of_cell, maximum);
862     }
863     column_info[column].width_of_column = maximum;
864     return (column_info[column].width_of_column != old_column_width);
865 }
866
867
868 //
869 // calculate the with of the column without regarding REAL MultiColumn
870 // cells. This means MultiColumn-cells spanning more than 1 column.
871 //
872 bool LyXTabular::calculate_width_of_column_NMC(int column)
873 {
874     int const old_column_width = column_info[column].width_of_column;
875     int max = 0;
876     for (int i = 0; i < rows_; ++i) {
877         if (!IsMultiColumn(GetCellNumber(i, column), true) &&
878             (cell_info[i][column].width_of_cell > max)) {
879             max = cell_info[i][column].width_of_cell;
880         }
881     }
882     column_info[column].width_of_column = max;
883     return (column_info[column].width_of_column != old_column_width);
884 }
885
886
887 void LyXTabular::calculate_width_of_tabular()
888 {
889     width_of_tabular = 0;
890     for (int i = 0; i < columns_; ++i) {
891         width_of_tabular += column_info[i].width_of_column;
892     }
893 }
894
895
896 int LyXTabular::row_of_cell(int cell) const
897 {
898     if (cell >= numberofcells)
899         return rows_ - 1;
900     else if (cell < 0)
901         return 0;
902     return rowofcell[cell];
903 }
904
905
906 int LyXTabular::column_of_cell(int cell) const
907 {
908     if (cell >= numberofcells)
909         return columns_ - 1;
910     else if (cell < 0)
911         return 0;
912     return columnofcell[cell];
913 }
914
915
916 int LyXTabular::right_column_of_cell(int cell) const
917 {
918     int const row = row_of_cell(cell);
919     int column = column_of_cell(cell);
920     while (column < (columns_ - 1) &&
921            cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
922         ++column;
923     return column;
924 }
925
926
927 // Perfect case for a template... (Lgb)
928 #if 1
929 template<class T>
930 string const write_attribute(string const & name, T const & t)
931 {
932      string str = " " + name + "=\"" + tostr(t) + "\"";
933      return str;
934 }
935
936 template <>
937 string const write_attribute(string const & name, bool const & b)
938 {
939         return write_attribute(name, int(b));
940 }
941
942 #else
943
944 string const write_attribute(string const & name, int value)
945 {
946     string str = " " + name + "=\"" + tostr(value) + "\"";
947     return str;
948 }
949
950
951 string const write_attribute(string const & name, string const & value)
952 {
953     string str = " " + name + "=\"" + value + "\"";
954     return str;
955 }
956
957
958 string const write_attribute(string const & name, bool value)
959 {
960     string str = " " + name + "=\"" + tostr(static_cast<int>(value)) + "\"";
961     return str;
962 }
963 #endif
964
965
966 void LyXTabular::Write(Buffer const * buf, ostream & os) const
967 {
968     // header line
969     os << "<LyXTabular"
970        << write_attribute("version", 1)
971        << write_attribute("rows", rows_)
972        << write_attribute("columns", columns_)
973        << ">\n";
974     // global longtable options
975     os << "<Features"
976        << write_attribute("rotate", rotate)
977        << write_attribute("islongtable", is_long_tabular)
978        << write_attribute("endhead", endhead)
979        << write_attribute("endfirsthead", endfirsthead)
980        << write_attribute("endfoot", endfoot)
981        << write_attribute("endlastfoot", endlastfoot)
982        << ">\n\n";
983     for (int i = 0; i < rows_; ++i) {
984         os << "<Row"
985            << write_attribute("topline", row_info[i].top_line)
986            << write_attribute("bottomline", row_info[i].bottom_line)
987            << write_attribute("newpage", row_info[i].newpage)
988            << ">\n";
989         for (int j = 0; j < columns_; ++j) {
990             if (!i) {
991                 os << "<Column"
992                    << write_attribute("alignment", column_info[j].alignment)
993                    << write_attribute("valignment", column_info[j].valignment)
994                    << write_attribute("leftline", column_info[j].left_line)
995                    << write_attribute("rightline", column_info[j].right_line)
996                    << write_attribute("width",
997                                       VSpace(column_info[j].p_width)
998                                       .asLyXCommand())
999                    << write_attribute("special", column_info[j].align_special)
1000                    << ">\n";
1001             } else {
1002                 os << "<Column>\n";
1003             }
1004             os << "<Cell"
1005                << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1006                << write_attribute("alignment", cell_info[i][j].alignment)
1007                << write_attribute("valignment", cell_info[i][j].valignment)
1008                << write_attribute("topline", cell_info[i][j].top_line)
1009                << write_attribute("bottomline", cell_info[i][j].bottom_line)
1010                << write_attribute("leftline", cell_info[i][j].left_line)
1011                << write_attribute("rightline", cell_info[i][j].right_line)
1012                << write_attribute("rotate", cell_info[i][j].rotate)
1013                << write_attribute("usebox", cell_info[i][j].usebox)
1014                << write_attribute("width", cell_info[i][j].p_width)
1015                << write_attribute("special", cell_info[i][j].align_special)
1016                << ">\n";
1017             os << "\\begin_inset ";
1018             cell_info[i][j].inset.Write(buf, os);
1019             os << "\n\\end_inset \n"
1020                << "</Cell>\n"
1021                << "</Column>\n";
1022         }
1023         os << "</Row>\n";
1024     }
1025     os << "</LyXTabular>\n";
1026 }
1027
1028
1029 static
1030 bool getTokenValue(string const & str, const char * token, string & ret)
1031 {
1032     string::size_type pos = str.find(token);
1033     char ch = str[pos + strlen(token)];
1034
1035     if ((pos == string::npos) || (ch != '='))
1036         return false;
1037     ret.erase();
1038     pos += strlen(token) + 1;
1039     ch = str[pos];
1040     if ((ch != '"') && (ch != '\'')) { // only read till next space
1041         ret += ch;
1042         ch = ' ';
1043     }
1044     while((pos < str.length() - 1) && (str[++pos] != ch))
1045         ret += str[pos];
1046
1047     return true;
1048 }
1049
1050
1051 static
1052 bool getTokenValue(string const & str, const char * token, int & num)
1053 {
1054     string::size_type pos = str.find(token);
1055     char ch = str[pos + strlen(token)];
1056
1057     if ((pos == string::npos) || (ch != '='))
1058         return false;
1059     string ret;
1060     pos += strlen(token) + 1;
1061     ch = str[pos];
1062     if ((ch != '"') && (ch != '\'')) { // only read till next space
1063         if (!isdigit(ch))
1064             return false;
1065         ret += ch;
1066     }
1067     ++pos;
1068     while((pos < str.length() - 1) && isdigit(str[pos]))
1069         ret += str[pos++];
1070
1071     num = strToInt(ret);
1072     return true;
1073 }
1074
1075
1076 static
1077 bool getTokenValue(string const & str, const char * token, LyXAlignment & num)
1078 {
1079     int tmp;
1080     bool const ret = getTokenValue(str, token, tmp);
1081     num = static_cast<LyXAlignment>(tmp);
1082     return ret;
1083 }
1084
1085
1086 static
1087 bool getTokenValue(string const & str, const char * token,
1088                    LyXTabular::VAlignment & num)
1089 {
1090     int tmp;
1091     bool const ret = getTokenValue(str, token, tmp);
1092     num = static_cast<LyXTabular::VAlignment>(tmp);
1093     return ret;
1094 }
1095
1096
1097 static
1098 bool getTokenValue(string const & str, const char * token,
1099                    LyXTabular::BoxType & num)
1100 {
1101     int tmp;
1102     bool ret = getTokenValue(str, token, tmp);
1103     num = static_cast<LyXTabular::BoxType>(tmp);
1104     return ret;
1105 }
1106
1107
1108 static
1109 bool getTokenValue(string const & str, const char * token, bool & flag)
1110 {
1111     string::size_type pos = str.find(token);
1112     char ch = str[pos + strlen(token)];
1113
1114     if ((pos == string::npos) || (ch != '='))
1115         return false;
1116     string ret;
1117     pos += strlen(token) + 1;
1118     ch = str[pos];
1119     if ((ch != '"') && (ch != '\'')) { // only read till next space
1120         if (!isdigit(ch))
1121             return false;
1122         ret += ch;
1123     }
1124     ++pos;
1125     while((pos < str.length() - 1) && isdigit(str[pos]))
1126         ret += str[pos++];
1127
1128     flag = strToInt(ret);
1129     return true;
1130 }
1131
1132
1133 static inline
1134 void l_getline(istream & is, string & str)
1135 {
1136     getline(is, str);
1137     while(str.empty())
1138         getline(is, str);
1139 }
1140
1141
1142 void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
1143 {
1144     string line;
1145     istream & is = lex.getStream();
1146
1147     l_getline(is, line);
1148     if (!prefixIs(line, "<LyXTabular ")) {
1149         OldFormatRead(lex, line);
1150         return;
1151     }
1152
1153     int version;
1154     int rows_arg;
1155     int columns_arg;
1156     if (!getTokenValue(line, "version", version))
1157         return;
1158     if (!getTokenValue(line, "rows", rows_arg))
1159         return;
1160     if (!getTokenValue(line, "columns", columns_arg))
1161         return;
1162     Init(rows_arg, columns_arg);
1163     l_getline(is, line);
1164     if (!prefixIs(line, "<Features ")) {
1165         lyxerr << "Wrong tabular format (expected <Feture ...> got" <<
1166             line << ")" << endl;
1167         return;
1168     }
1169     getTokenValue(line, "islongtable", is_long_tabular);
1170     getTokenValue(line, "endhead", endhead);
1171     getTokenValue(line, "endfirsthead", endfirsthead);
1172     getTokenValue(line, "endfoot", endfoot);
1173     getTokenValue(line, "endlastfoot", endlastfoot);
1174
1175     for (int i = 0; i < rows_; ++i) {
1176         l_getline(is, line);
1177         if (!prefixIs(line, "<Row ")) {
1178             lyxerr << "Wrong tabular format (expected <Row ...> got" <<
1179                 line << ")" << endl;
1180             return;
1181         }
1182         getTokenValue(line, "topline", row_info[i].top_line);
1183         getTokenValue(line, "bottomline", row_info[i].bottom_line);
1184         getTokenValue(line, "newpage", row_info[i].newpage);
1185         for (int j = 0; j < columns_; ++j) {
1186             l_getline(is,line);
1187             if (!prefixIs(line,"<Column")) {
1188                 lyxerr << "Wrong tabular format (expected <Column ...> got" <<
1189                     line << ")" << endl;
1190                 return;
1191             }
1192             if (!i) {
1193                 getTokenValue(line, "alignment", column_info[j].alignment);
1194                 getTokenValue(line, "valignment", column_info[j].valignment);
1195                 getTokenValue(line, "leftline", column_info[j].left_line);
1196                 getTokenValue(line, "rightline", column_info[j].right_line);
1197                 getTokenValue(line, "width", column_info[j].p_width);
1198                 getTokenValue(line, "special", column_info[j].align_special);
1199             }
1200             l_getline(is, line);
1201             if (!prefixIs(line, "<Cell")) {
1202                 lyxerr << "Wrong tabular format (expected <Cell ...> got" <<
1203                     line << ")" << endl;
1204                 return;
1205             }
1206             getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1207             getTokenValue(line, "alignment", cell_info[i][j].alignment);
1208             getTokenValue(line, "valignment", cell_info[i][j].valignment);
1209             getTokenValue(line, "topline", cell_info[i][j].top_line);
1210             getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1211             getTokenValue(line, "leftline", cell_info[i][j].left_line);
1212             getTokenValue(line, "rightline", cell_info[i][j].right_line);
1213             getTokenValue(line, "rotate", cell_info[i][j].rotate);
1214             getTokenValue(line, "usebox", cell_info[i][j].usebox);
1215             getTokenValue(line, "width", cell_info[i][j].p_width);
1216             getTokenValue(line, "special", cell_info[i][j].align_special);
1217             l_getline(is, line);
1218             if (prefixIs(line, "\\begin_inset")) {
1219                 cell_info[i][j].inset.Read(buf, lex);
1220                 l_getline(is, line);
1221             }
1222             if (line != "</Cell>") {
1223                 lyxerr << "Wrong tabular format (expected </Cell> got" <<
1224                     line << ")" << endl;
1225                 return;
1226             }
1227             l_getline(is, line);
1228             if (line != "</Column>") {
1229                 lyxerr << "Wrong tabular format (expected </Column> got" <<
1230                     line << ")" << endl;
1231                 return;
1232             }
1233         }
1234         l_getline(is, line);
1235         if (line != "</Row>") {
1236             lyxerr << "Wrong tabular format (expected </Row> got" <<
1237                 line << ")" << endl;
1238             return;
1239         }
1240     }
1241     while (line != "</LyXTabular>") {
1242         l_getline(is, line);
1243     }
1244     set_row_column_number_info();
1245 }
1246
1247
1248 void LyXTabular::OldFormatRead(LyXLex & lex, string const & fl)
1249 {
1250     int version;
1251     int i, j;
1252     int rows_arg = 0;
1253     int columns_arg = 0;
1254     int is_long_tabular_arg = false;
1255     int rotate_arg = false;
1256     int a = -1;
1257     int b = -1;
1258     int c = -1;
1259     int d = -1;
1260     int e = 0;
1261     int f = 0;
1262     int g = 0;
1263     int h = 0;
1264         
1265     istream & is = lex.getStream();
1266     string s(fl);
1267     if (s.length() > 8)
1268         version = lyx::atoi(s.substr(8, string::npos));
1269     else
1270         version = 1;
1271
1272     vector<int> cont_row_info;
1273
1274     if (version < 5) {
1275         lyxerr << "Tabular format < 5 is not supported anymore\n"
1276             "Get an older version of LyX (< 1.1.x) for conversion!"
1277                << endl;
1278         WriteAlert(_("Warning:"),
1279                    _("Tabular format < 5 is not supported anymore\n"),
1280                    _("Get an older version of LyX (< 1.1.x) for conversion!"));
1281         if (version > 2) {
1282             is >> rows_arg >> columns_arg >> is_long_tabular_arg
1283                >> rotate_arg >> a >> b >> c >> d;
1284         } else
1285             is >> rows_arg >> columns_arg;
1286         Init(rows_arg, columns_arg);
1287         cont_row_info = vector<int>(rows_arg);
1288         SetLongTabular(is_long_tabular_arg);
1289         SetRotateTabular(rotate_arg);
1290         string tmp;
1291         for (i = 0; i < rows_; ++i) {
1292             getline(is, tmp);
1293             cont_row_info[i] = false;
1294         }
1295         for (i = 0; i < columns_; ++i) {
1296             getline(is, tmp);
1297         }
1298         for (i = 0; i < rows_; ++i) {
1299             for (j = 0; j < columns_; ++j) {
1300                 getline(is, tmp);
1301             }
1302         }
1303     } else {
1304         is >> rows_arg >> columns_arg >> is_long_tabular_arg
1305            >> rotate_arg >> a >> b >> c >> d;
1306         Init(rows_arg, columns_arg);
1307         cont_row_info = vector<int>(rows_arg);
1308         SetLongTabular(is_long_tabular_arg);
1309         SetRotateTabular(rotate_arg);
1310         endhead = a;
1311         endfirsthead = b;
1312         endfoot = c;
1313         endlastfoot = d;
1314         for (i = 0; i < rows_; ++i) {
1315             a = b = c = d = e = f = g = h = 0;
1316             is >> a >> b >> c >> d;
1317             row_info[i].top_line = a;
1318             row_info[i].bottom_line = b;
1319             cont_row_info[i] = c;
1320             row_info[i].newpage = d;
1321         }
1322         for (i = 0; i < columns_; ++i) {
1323             string s1;
1324             string s2;
1325             is >> a >> b >> c;
1326 #if 1
1327             char ch; // skip '"'
1328             is >> ch;
1329 #else
1330             // ignore is buggy but we will use it later (Lgb)
1331             is.ignore(); // skip '"'
1332 #endif    
1333             getline(is, s1, '"');
1334 #if 1
1335             is >> ch; // skip '"'
1336 #else
1337             // ignore is buggy but we will use it later (Lgb)
1338             is.ignore(); // skip '"'
1339 #endif
1340             getline(is, s2, '"');
1341             column_info[i].alignment = static_cast<LyXAlignment>(a);
1342             column_info[i].left_line = b;
1343             column_info[i].right_line = c;
1344             column_info[i].p_width = s1;
1345             column_info[i].align_special = s2;
1346         }
1347         for (i = 0; i < rows_; ++i) {
1348             for (j = 0; j < columns_; ++j) {
1349                 string s1;
1350                 string s2;
1351                 is >> a >> b >> c >> d >> e >> f >> g;
1352 #if 1
1353                 char ch;
1354                 is >> ch; // skip '"'
1355 #else
1356                 // ignore is buggy but we will use it later (Lgb)
1357                 is.ignore(); // skip '"'
1358 #endif
1359                 getline(is, s1, '"');
1360 #if 1
1361                 is >> ch; // skip '"'
1362 #else
1363                 // ignore is buggy but we will use it later (Lgb)
1364                 is.ignore(); // skip '"'
1365 #endif
1366                 getline(is, s2, '"');
1367                 cell_info[i][j].multicolumn = static_cast<char>(a);
1368                 cell_info[i][j].alignment = static_cast<LyXAlignment>(b);
1369                 cell_info[i][j].top_line = static_cast<char>(c);
1370                 cell_info[i][j].bottom_line = static_cast<char>(d);
1371                 cell_info[i][j].left_line = column_info[j].left_line;
1372                 cell_info[i][j].right_line = column_info[j].right_line;
1373                 cell_info[i][j].rotate = static_cast<bool>(f);
1374                 cell_info[i][j].usebox = static_cast<BoxType>(g);
1375                 cell_info[i][j].align_special = s1;
1376                 cell_info[i][j].p_width = s2;
1377             }
1378         }
1379     }
1380     set_row_column_number_info(true);
1381
1382     LyXParagraph * par = new LyXParagraph;
1383     LyXParagraph * return_par = 0;
1384 #ifndef NEW_INSETS
1385     LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
1386     LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
1387 #endif
1388     string tmptok;
1389     int pos = 0;
1390     char depth = 0;
1391     LyXFont font(LyXFont::ALL_SANE);
1392     font.setLanguage(owner_->BufferOwner()->GetLanguage());
1393
1394     while (lex.IsOK()) {
1395         lex.nextToken();
1396         string const token = lex.GetString();
1397         if (token.empty())
1398             continue;
1399         if (token == "\\layout"
1400             || token == "\\end_float"
1401             || token == "\\end_deeper") {
1402             lex.pushToken(token);
1403             break;
1404         }
1405         if (owner_->BufferOwner()->parseSingleLyXformat2Token(lex, par,
1406                                                               return_par,
1407                                                               token, pos,
1408                                                               depth, font
1409 #ifndef NEW_INSETS
1410                                                               ,
1411                                                               footnoteflag,
1412                                                               footnotekind
1413 #endif
1414                 ))
1415         {
1416             // the_end read
1417             lex.pushToken(token);
1418             break;
1419         }
1420         if (return_par) {
1421             lex.printError("New Paragraph allocated! This should not happen!");
1422             lex.pushToken(token);
1423             delete par;
1424             par = return_par;
1425             break;
1426         }
1427     }
1428     // now we have the par we should fill the insets with this!
1429     int cell = 0;
1430     InsetText * inset = GetCellInset(cell);
1431     int row;
1432
1433     for (int i = 0; i < par->Last(); ++i) {
1434         if (par->IsNewline(i)) {
1435             ++cell;
1436             if (cell > GetNumberOfCells()) {
1437                 lyxerr << "Some error in reading old table format occured!" <<
1438                     endl << "Terminating when reading cell[" << cell << "]!" <<
1439                     endl;
1440                 delete par;
1441                 return;
1442             }
1443             row = row_of_cell(cell);
1444             if (cont_row_info[row]) {
1445                 DeleteRow(row);
1446                 cont_row_info.erase(cont_row_info.begin() + row); //&cont_row_info[row]);
1447                 while(!IsFirstCellInRow(--cell));
1448             } else {
1449                 inset = GetCellInset(cell);
1450                 continue;
1451             }
1452             inset = GetCellInset(cell);
1453             row = row_of_cell(cell);
1454             if (!cell_info[row_of_cell(cell)][column_of_cell(cell)].usebox)
1455             {
1456                 // insert a space instead
1457                 par->Erase(i);
1458                 par->InsertChar(i, ' ');
1459             }
1460         }
1461         par->CopyIntoMinibuffer(owner_->BufferOwner()->params, i);
1462         inset->par->InsertFromMinibuffer(inset->par->Last());
1463     }
1464     delete par;
1465     Reinit();
1466 }
1467
1468
1469 string const LyXTabular::GetDocBookAlign(int cell, bool isColumn) const
1470 {
1471     int const i = isColumn ? cell : column_of_cell(cell);
1472         
1473     if (!isColumn && IsMultiColumn(cell)) {
1474        if (!cellinfo_of_cell(cell)->align_special.empty()) {
1475            return cellinfo_of_cell(cell)->align_special;
1476        } else {
1477            switch (GetAlignment(cell)) {
1478            case LYX_ALIGN_LEFT:
1479                return "left";
1480            case LYX_ALIGN_RIGHT:
1481                return "right";
1482            default:
1483                return "center";
1484            }
1485        }
1486     } else {
1487        if (!column_info[i].align_special.empty()) {
1488            return column_info[i].align_special;
1489        }
1490 #ifdef IGNORE_THIS_FOR_NOW
1491        else if (!column_info[i].p_width.empty()) {
1492            file += "p{";
1493            file += column_info[i].p_width;
1494            file += '}';
1495        }
1496 #endif
1497        else {
1498            switch (column_info[i].alignment) {
1499            case LYX_ALIGN_LEFT:
1500                return "left";
1501            case LYX_ALIGN_RIGHT:
1502                return "right";
1503            default:
1504                return "center";
1505            }
1506        }
1507     }
1508 }
1509
1510
1511 // cell <0 will tex the preamble
1512 // returns the number of printed newlines
1513 int LyXTabular::DocBookEndOfCell(ostream & os, int cell, int & depth) const
1514 {
1515     int ret = 0;
1516     if (IsLastCell(cell)) {
1517             os << newlineAndDepth(--depth)
1518                << "</ENTRY>"
1519                << newlineAndDepth(--depth)
1520                << "</ROW>"
1521                << newlineAndDepth(--depth)
1522                << "</TBODY>"
1523                << newlineAndDepth(--depth);
1524         if (is_long_tabular)
1525                 os << "</TGROUP>";
1526         else
1527                 os << "</TGROUP>"
1528                    << newlineAndDepth(--depth);
1529         ret += 4;
1530     } else {
1531         if (cell < 0) {
1532             // preamble
1533             if (is_long_tabular)
1534                     os << "<TGROUP ";
1535             else
1536                     os << "<TGROUP ";
1537             os << "COLS='"
1538                << columns_
1539                << "' COLSEP='1' ROWSEP='1'>"
1540                << newlineAndDepth(++depth);
1541             ++ret;
1542             for (int i = 0; i < columns_; ++i) {
1543                     os << "<COLSPEC ALIGN='"
1544                        << GetDocBookAlign(i, true)
1545                        << "' COLNAME='col"
1546                        << i + 1
1547                        << "' COLNUM='"
1548                        << i + 1
1549                        << "' COLSEP='";
1550                if (i == (columns_-1)) {
1551                        os << '1';
1552                } else {
1553                    if (column_info[i].right_line ||
1554                        column_info[i+1].left_line)
1555                            os << '1';
1556                    else
1557                            os << '0';
1558                }
1559                os << "'>"
1560                   << newlineAndDepth(depth);
1561                 ++ret;
1562 #ifdef NOT_HANDLED_YET_AS_I_DONT_KNOW_HOW
1563                 if (column_info[i].left_line)
1564                         os << '|';
1565 #endif
1566             }
1567             os << "<TBODY>"
1568                << newlineAndDepth(++depth)
1569                << "<ROW>"
1570                << newlineAndDepth(++depth)
1571                << "<ENTRY ALIGN='"
1572                << GetDocBookAlign(0)
1573                << "'";
1574            if (IsMultiColumn(0)) {
1575                    os << " NAMEST='col1' NAMEEND='col"
1576                       << cells_in_multicolumn(0)
1577                       << "'";
1578            }
1579            os << ">"
1580               << newlineAndDepth(++depth);
1581             ret += 3;
1582         } else {
1583             if (IsLastCellInRow(cell)) {
1584                     os << newlineAndDepth(--depth)
1585                        << "</ENTRY>"
1586                        << newlineAndDepth(--depth)
1587                        << "</ROW>"
1588                        << newlineAndDepth(depth)
1589                        << "<ROW>"
1590                        << newlineAndDepth(++depth)
1591                        << "<ENTRY ALIGN='"
1592                        << GetDocBookAlign(cell + 1)
1593                        << "' VALIGN='middle'";
1594                if (IsMultiColumn(cell + 1)) {
1595                        os << " NAMEST='col"
1596                           << column_of_cell(cell + 1) + 1
1597                           << "' NAMEEND='col"
1598                           << column_of_cell(cell + 1) +
1599                                cells_in_multicolumn(cell + 1)
1600                           << "'";
1601                }
1602                os << ">"
1603                   << newlineAndDepth(++depth);
1604                 ret += 4;
1605             } else {
1606                     os << newlineAndDepth(--depth)
1607                        << "</ENTRY>"
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 += 3;
1623             }
1624         }
1625     }
1626     return ret;
1627 }
1628
1629
1630 bool LyXTabular::IsMultiColumn(int cell, bool real) const
1631 {
1632     return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
1633         (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
1634 }
1635
1636
1637 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
1638 {
1639     int const row = row_of_cell(cell);
1640     int const column = column_of_cell(cell);
1641     return  &cell_info[row][column];
1642 }
1643
1644
1645 void LyXTabular::SetMultiColumn(int cell, int number)
1646 {
1647     cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1648     cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
1649     cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
1650     cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
1651     for (number--; number > 0; --number) {
1652         cellinfo_of_cell(cell+number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1653     }
1654     set_row_column_number_info();
1655 }
1656
1657
1658 int LyXTabular::cells_in_multicolumn(int cell) const
1659 {
1660     int const row = row_of_cell(cell);
1661     int column = column_of_cell(cell);
1662     int result = 1;
1663     ++column;
1664     while ((column < columns_) &&
1665            cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1666     {
1667         ++result;
1668         ++column;
1669     }
1670     return result;
1671 }
1672
1673
1674 int LyXTabular::UnsetMultiColumn(int cell)
1675 {
1676     int const row = row_of_cell(cell);
1677     int column = column_of_cell(cell);
1678     
1679     int result = 0;
1680     
1681     if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1682         cell_info[row][column].multicolumn = CELL_NORMAL;
1683         ++column;
1684         while ((column < columns_) &&
1685                (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
1686         {
1687             cell_info[row][column].multicolumn = CELL_NORMAL;
1688             ++column;
1689             ++result;
1690         }
1691     }
1692     set_row_column_number_info();
1693     return result;
1694 }
1695
1696
1697 void LyXTabular::SetLongTabular(bool what)
1698 {
1699     is_long_tabular = what;
1700 }
1701
1702
1703 bool LyXTabular::IsLongTabular() const
1704 {
1705     return is_long_tabular;
1706 }
1707
1708
1709 void LyXTabular::SetRotateTabular(bool flag)
1710 {
1711     rotate = flag;
1712 }
1713
1714
1715 bool LyXTabular::GetRotateTabular() const
1716 {
1717     return rotate;
1718 }
1719
1720
1721 void LyXTabular::SetRotateCell(int cell, bool flag)
1722 {
1723     cellinfo_of_cell(cell)->rotate = flag;
1724 }
1725
1726
1727 bool LyXTabular::GetRotateCell(int cell) const
1728 {
1729     return cellinfo_of_cell(cell)->rotate;
1730 }
1731
1732
1733 bool LyXTabular::NeedRotating() const
1734 {
1735     if (rotate)
1736         return true;
1737     for (int i = 0; i < rows_; ++i) {
1738         for (int j = 0; j < columns_; ++j) {
1739             if (cell_info[i][j].rotate)
1740                 return true;
1741         }
1742     }
1743     return false;
1744 }
1745
1746
1747 bool LyXTabular::IsLastCell(int cell) const
1748 {
1749     if ((cell + 1) < GetNumberOfCells())
1750         return false;
1751     return true;
1752 }
1753
1754
1755 int LyXTabular::GetCellAbove(int cell) const
1756 {
1757     if (row_of_cell(cell) > 0)
1758         return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1759     return cell;
1760 }
1761
1762
1763 int LyXTabular::GetCellBelow(int cell) const
1764 {
1765     if (row_of_cell(cell) + 1 < rows_)
1766         return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1767     return cell;
1768 }
1769
1770
1771 int LyXTabular::GetLastCellAbove(int cell) const
1772 {
1773     if (row_of_cell(cell) <= 0)
1774         return cell;
1775     if (!IsMultiColumn(cell))
1776         return GetCellAbove(cell);
1777     return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1778 }
1779
1780
1781 int LyXTabular::GetLastCellBelow(int cell) const
1782 {
1783     if (row_of_cell(cell) + 1 >= rows_)
1784         return cell;
1785     if (!IsMultiColumn(cell))
1786         return GetCellBelow(cell);
1787     return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1788 }
1789
1790
1791 int LyXTabular::GetCellNumber(int row, int column) const
1792 {
1793     if (column >= columns_)
1794         column = columns_ - 1;
1795     else if (column < 0)
1796         column = 0;
1797     if (row >= rows_)
1798         row = rows_ - 1;
1799     else if (row < 0)
1800         row = 0;
1801     
1802     return cell_info[row][column].cellno;
1803 }
1804
1805
1806 void LyXTabular::SetUsebox(int cell, BoxType type)
1807 {
1808     cellinfo_of_cell(cell)->usebox = type;
1809 }
1810
1811
1812 LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
1813 {
1814     if (column_info[column_of_cell(cell)].p_width.empty() &&
1815         !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.empty()))
1816         return BOX_NONE;
1817     if (cellinfo_of_cell(cell)->usebox > 1)
1818         return cellinfo_of_cell(cell)->usebox;
1819     return UseParbox(cell);
1820 }
1821
1822
1823 void LyXTabular::SetLTHead(int cell, bool first)
1824 {
1825     int const row = row_of_cell(cell);
1826     int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
1827
1828     if (first) {
1829         if (endfirsthead == val)
1830             endfirsthead = 0;
1831         else
1832             endfirsthead = val;
1833     } else {
1834         if (endhead == val)
1835             endhead = 0;
1836         else
1837             endhead = val;
1838     }
1839 }
1840
1841
1842 bool LyXTabular::GetRowOfLTHead(int cell, int & row) const
1843 {
1844     row = endhead;
1845     if (abs(endhead) > rows_)
1846         return false;
1847     return (row_of_cell(cell) == abs(endhead) - 1);
1848 }
1849
1850
1851 bool LyXTabular::GetRowOfLTFirstHead(int cell, int & row) const
1852 {
1853     row = endfirsthead;
1854     if (abs(endfirsthead) > rows_)
1855         return false;
1856     return (row_of_cell(cell) == abs(endfirsthead) - 1);
1857 }
1858
1859
1860 void LyXTabular::SetLTFoot(int cell, bool last)
1861 {
1862     int const row = row_of_cell(cell);
1863     int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
1864
1865     if (last) {
1866         if (endlastfoot == val)
1867             endlastfoot = 0;
1868         else
1869             endlastfoot = val;
1870     } else {
1871         if (endfoot == val)
1872             endfoot = 0;
1873         else
1874             endfoot = val;
1875     }
1876 }
1877
1878
1879 bool LyXTabular::GetRowOfLTFoot(int cell, int & row) const
1880 {
1881     row = endfoot;
1882     if ((endfoot + 1) > rows_)
1883         return false;
1884     return (row_of_cell(cell) == abs(endfoot) - 1);
1885 }
1886
1887
1888 bool LyXTabular::GetRowOfLTLastFoot(int cell, int & row) const
1889 {
1890     row = endlastfoot;
1891     if (abs(endlastfoot) > rows_)
1892         return false;
1893     return (row_of_cell(cell) == (abs(endlastfoot)-1));
1894 }
1895
1896
1897 void LyXTabular::SetLTNewPage(int cell, bool what)
1898 {
1899     row_info[row_of_cell(cell)].newpage = what;
1900 }
1901
1902
1903 bool LyXTabular::GetLTNewPage(int cell) const
1904 {
1905     return row_info[row_of_cell(cell)].newpage;
1906 }
1907
1908
1909 bool LyXTabular::SetAscentOfRow(int row, int height)
1910 {
1911     if ((row >= rows_) || (row_info[row].ascent_of_row == height))
1912         return false;
1913     row_info[row].ascent_of_row = height;
1914     return true;
1915 }
1916
1917
1918 bool LyXTabular::SetDescentOfRow(int row, int height)
1919 {
1920     if ((row >= rows_) || (row_info[row].descent_of_row == height))
1921         return false;
1922     row_info[row].descent_of_row = height;
1923     return true;
1924 }
1925
1926
1927 int LyXTabular::GetAscentOfRow(int row) const
1928 {
1929     if (row >= rows_)
1930         return 0;
1931     return row_info[row].ascent_of_row;
1932 }
1933
1934
1935 int LyXTabular::GetDescentOfRow(int row) const
1936 {
1937     if (row >= rows_)
1938         return 0;
1939     return row_info[row].descent_of_row;
1940 }
1941
1942
1943 int LyXTabular::GetHeightOfTabular() const
1944 {
1945     int height = 0;
1946
1947     for (int row = 0; row < rows_; ++row)
1948         height += GetAscentOfRow(row) + GetDescentOfRow(row) +
1949             GetAdditionalHeight(GetCellNumber(row, 0));
1950     return height;
1951 }
1952
1953
1954 bool LyXTabular::IsPartOfMultiColumn(int row, int column) const
1955 {
1956     if ((row >= rows_) || (column >= columns_))
1957         return false;
1958     return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
1959 }
1960
1961
1962 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1963 {
1964     int const fcell = GetFirstCellInRow(row);
1965     int const n = NumberOfCellsInRow(fcell) + fcell;
1966     int tmp = 0;
1967
1968     for (int i = fcell; i < n; ++i) {
1969         if (TopLine(i))
1970             ++tmp;
1971     }
1972     if (tmp == (n - fcell)){
1973         os << "\\hline ";
1974     } else if (tmp) {
1975         for (int i = fcell; i < n; ++i) {
1976             if (TopLine(i)) {
1977                 os << "\\cline{"
1978                    << column_of_cell(i) + 1
1979                    << '-'
1980                    << right_column_of_cell(i) + 1
1981                    << "} ";
1982             }
1983         }
1984     } else {
1985         return 0;
1986     }
1987     os << "\n";
1988     return 1;
1989 }
1990
1991
1992 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1993 {
1994     int const fcell = GetFirstCellInRow(row);
1995     int const n = NumberOfCellsInRow(fcell) + fcell;
1996     int tmp = 0;
1997
1998     for (int i = fcell; i < n; ++i) {
1999         if (BottomLine(i))
2000             ++tmp;
2001     }
2002     if (tmp == (n-fcell)){
2003         os << "\\hline";
2004     } else if (tmp) {
2005         for (int i = fcell; i < n; ++i) {
2006             if (BottomLine(i)) {
2007                 os << "\\cline{"
2008                    << column_of_cell(i) + 1
2009                    << '-'
2010                    << right_column_of_cell(i) + 1
2011                    << "} ";
2012             }
2013         }
2014     } else {
2015         return 0;
2016     }
2017     os << "\n";
2018     return 1;
2019 }
2020
2021
2022 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
2023 {
2024     int ret = 0;
2025
2026     if (GetRotateCell(cell)) {
2027         os << "\\begin{sideways}\n";
2028         ++ret;
2029     }
2030     if (IsMultiColumn(cell)) {
2031         os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
2032         if (!cellinfo_of_cell(cell+1)->align_special.empty()) {
2033             os << cellinfo_of_cell(cell+1)->align_special << "}{";
2034         } else {
2035             if (LeftLine(cell))
2036                 os << '|';
2037             if (!GetPWidth(cell).empty()) {
2038                 switch (GetVAlignment(cell)) {
2039                 case LYX_VALIGN_TOP:
2040                     os << "p";
2041                     break;
2042                 case LYX_VALIGN_CENTER:
2043                     os << "m";
2044                     break;
2045                 case LYX_VALIGN_BOTTOM:
2046                     os << "b";
2047                     break;
2048                 }
2049                 os << "{" << GetPWidth(cell) << '}';
2050             } else {
2051                 switch (GetAlignment(cell)) {
2052                 case LYX_ALIGN_LEFT:
2053                     os << 'l';
2054                     break;
2055                 case LYX_ALIGN_RIGHT:
2056                     os << 'r';
2057                     break;
2058                 default:
2059                     os << 'c';
2060                     break;
2061                 }
2062             }
2063             if (RightLine(cell))
2064                 os << '|';
2065             if (((cell + 1) < numberofcells) && !IsFirstCellInRow(cell+1) &&
2066                 LeftLine(cell+1))
2067                 os << '|';
2068             os << "}{";
2069         }
2070     }
2071     if (GetUsebox(cell) == BOX_PARBOX) {
2072         os << "\\parbox[";
2073         switch (GetVAlignment(cell)) {
2074         case LYX_VALIGN_TOP:
2075             os << "t";
2076             break;
2077         case LYX_VALIGN_CENTER:
2078             os << "c";
2079             break;
2080         case LYX_VALIGN_BOTTOM:
2081             os << "b";
2082             break;
2083         }
2084         os << "]{" << GetPWidth(cell) << "}{";
2085     } else if (GetUsebox(cell) == BOX_MINIPAGE) {
2086         os << "\\begin{minipage}[";
2087         switch (GetVAlignment(cell)) {
2088         case LYX_VALIGN_TOP:
2089             os << "t";
2090             break;
2091         case LYX_VALIGN_CENTER:
2092             os << "m";
2093             break;
2094         case LYX_VALIGN_BOTTOM:
2095             os << "b";
2096             break;
2097         }
2098         os << "]{" << GetPWidth(cell) << "}\n";
2099         ++ret;
2100     }
2101     return ret;
2102 }
2103
2104
2105 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
2106 {
2107     int ret = 0;
2108
2109     // usual cells
2110     if (GetUsebox(cell) == BOX_PARBOX)
2111         os << "}";
2112     else if (GetUsebox(cell) == BOX_MINIPAGE) {
2113         os << "%\n\\end{minipage}";
2114         ret += 2;
2115     }
2116     if (IsMultiColumn(cell)){
2117         os << '}';
2118     }
2119     if (GetRotateCell(cell)) {
2120         os << "%\n\\end{sideways}";
2121         ++ret;
2122     }
2123     return ret;
2124 }
2125
2126
2127 int LyXTabular::Latex(Buffer const * buf,
2128                       ostream & os, bool fragile, bool fp) const
2129 {
2130     int ret = 0;
2131     int cell = 0;
2132
2133     //+---------------------------------------------------------------------
2134     //+                      first the opening preamble                    +
2135     //+---------------------------------------------------------------------
2136
2137     if (rotate) {
2138         os << "\\begin{sideways}\n";
2139         ++ret;
2140     }
2141     if (is_long_tabular)
2142         os << "\\begin{longtable}{";
2143     else
2144         os << "\\begin{tabular}{";
2145     for (int i = 0; i < columns_; ++i) {
2146         if (column_info[i].left_line)
2147             os << '|';
2148         if (!column_info[i].align_special.empty()) {
2149             os << column_info[i].align_special;
2150         } else if (!column_info[i].p_width.empty()) {
2151             switch (column_info[i].valignment) {
2152             case LYX_VALIGN_TOP:
2153                 os << "p";
2154                 break;
2155             case LYX_VALIGN_CENTER:
2156                 os << "m";
2157                 break;
2158             case LYX_VALIGN_BOTTOM:
2159                 os << "b";
2160                 break;
2161             }
2162             os << "{"
2163                << column_info[i].p_width
2164                << '}';
2165         } else {
2166             switch (column_info[i].alignment) {
2167             case LYX_ALIGN_LEFT:
2168                 os << 'l';
2169                 break;
2170             case LYX_ALIGN_RIGHT:
2171                 os << 'r';
2172                 break;
2173             default:
2174                 os << 'c';
2175                 break;
2176             }
2177         }
2178         if (column_info[i].right_line)
2179             os << '|';
2180     }
2181     os << "}\n";
2182     ++ret;
2183
2184     //+---------------------------------------------------------------------
2185     //+                      the single row and columns (cells)            +
2186     //+---------------------------------------------------------------------
2187
2188     //int bret;
2189     for (int i = 0; i < rows_; ++i) {
2190         ret += TeXTopHLine(os, i);
2191         int bret = ret;
2192         if (IsLongTabular()) {
2193             if ((endhead < 0) && (i == (abs(endhead)-1))) {
2194                 os << "\\endhead\n";
2195                 ++ret;
2196             }
2197             if ((endfirsthead < 0) && (i == (abs(endfirsthead)-1))) {
2198                 os << "\\endfirsthead\n";
2199                 ++ret;
2200             }
2201             if ((endfoot < 0) && (i == (abs(endfoot)-1))) {
2202                 os << "\\endfoot\n";
2203                 ++ret;
2204             }
2205             if ((endlastfoot < 0) && (i == (abs(endlastfoot)-1))) {
2206                 os << "\\endlastfoot\n";
2207                 ++ret;
2208             }
2209         }
2210         if (ret > bret) {
2211             if (i > 0)
2212                 ret += TeXBottomHLine(os, i-1);
2213             ret += TeXTopHLine(os, i);
2214         }
2215         for (int j = 0; j < columns_; ++j) {
2216             if (IsPartOfMultiColumn(i,j))
2217                 continue;
2218             ret += TeXCellPreamble(os, cell);
2219             ret += GetCellInset(cell)->Latex(buf, os, fragile, fp);
2220             ret += TeXCellPostamble(os, cell);
2221             if (!IsLastCellInRow(cell)) { // not last cell in row
2222                 os << "&\n";
2223                 ++ret;
2224             }
2225             ++cell;
2226         }
2227         os << "\\\\\n";
2228         ret += TeXBottomHLine(os, i);
2229         bret = ret;
2230         if (IsLongTabular()) {
2231             if ((endhead > 0) && (i == (endhead - 1))) {
2232                 os << "\\endhead\n";
2233                 ++ret;
2234             }
2235             if ((endfirsthead > 0) && (i == (endfirsthead - 1))) {
2236                 os << "\\endfirsthead\n";
2237                 ++ret;
2238             }
2239             if ((endfoot > 0) && (i == (endfoot - 1))) {
2240                 os << "\\endfoot\n";
2241                 ++ret;
2242             }
2243             if ((endlastfoot > 0) && (i == (endlastfoot - 1))) {
2244                 os << "\\endlastfoot\n";
2245                 ++ret;
2246             }
2247             if (ret > bret)
2248                 ret += TeXBottomHLine(os, i);
2249             if (row_info[i].newpage) {
2250                 os << "\\newpage\n";
2251                 ++ret;
2252             }
2253         }
2254     }
2255
2256     //+---------------------------------------------------------------------
2257     //+                      the closing of the tabular                    +
2258     //+---------------------------------------------------------------------
2259
2260     if (is_long_tabular)
2261         os << "\\end{longtable}";
2262     else
2263         os << "\\end{tabular}";
2264     if (rotate) {
2265         os << "\n\\end{sideways}";
2266         ++ret;
2267     }
2268
2269     return ret;
2270 }
2271
2272
2273 int LyXTabular::DocBook(Buffer const * buf, ostream & os) const
2274 {
2275     int ret = 0;
2276
2277     //+---------------------------------------------------------------------
2278     //+                      first the opening preamble                    +
2279     //+---------------------------------------------------------------------
2280
2281     os << "<tgroup cols=\"" << columns_
2282        << "\" colsep=\"1\" rowsep=\"1\">\n";
2283     
2284     for (int i = 0; i < columns_; ++i) {
2285         os << "<colspec colname=\"col" << i << "\" align=\"";
2286         switch (column_info[i].alignment) {
2287         case LYX_ALIGN_LEFT:
2288             os << "left";
2289             break;
2290         case LYX_ALIGN_RIGHT:
2291             os << "right";
2292             break;
2293         default:
2294             os << "center";
2295             break;
2296         }
2297         os << "\"/>\n";
2298         ++ret;
2299     }
2300
2301     //+---------------------------------------------------------------------
2302     //+                      the single row and columns (cells)            +
2303     //+---------------------------------------------------------------------
2304
2305     int cell = 0;
2306     os << "<tbody>\n";
2307     for (int i = 0; i < rows_; ++i) {
2308         os << "<row>\n";
2309         for (int j = 0; j < columns_; ++j) {
2310             if (IsPartOfMultiColumn(i, j))
2311                 continue;
2312             
2313             os << "<entry align=\"";
2314             switch (GetAlignment(cell)) {
2315             case LYX_ALIGN_LEFT:
2316                 os << "left";
2317                 break;
2318             case LYX_ALIGN_RIGHT:
2319                 os << "right";
2320                 break;
2321             default:
2322                 os << "center";
2323                 break;
2324             }
2325             
2326             os << "\" valign=\"";
2327             switch (GetVAlignment(cell)) {
2328             case LYX_VALIGN_TOP:
2329                 os << "top";
2330                 break;
2331             case LYX_VALIGN_BOTTOM:
2332                 os << "bottom";
2333                 break;
2334             case LYX_VALIGN_CENTER:
2335                 os << "middle";
2336             }
2337             os << "\"";
2338             
2339             if (IsMultiColumn(cell)) {
2340                 os << " namest=\"col" << j << "\" ";
2341                 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< "\"";
2342             }
2343             
2344             os << ">";
2345             ret += GetCellInset(cell)->DocBook(buf, os);
2346             os << "</entry>";
2347             ++cell;
2348         }
2349         os << "</row>\n";
2350     }
2351     os << "</tbody>\n";
2352     //+---------------------------------------------------------------------
2353     //+                      the closing of the tabular                    +
2354     //+---------------------------------------------------------------------
2355
2356     os << "</tgroup>";
2357     ++ret;
2358
2359     return ret;
2360 }
2361
2362
2363 static
2364 inline
2365 void print_n_chars(ostream & os, unsigned char ch, int n)
2366 {
2367 #if 0
2368         for (int i = 0; i < n; ++i)
2369                 os << ch;
2370 #else
2371         os << string(n, ch);
2372 #endif
2373 }
2374
2375
2376 int LyXTabular::AsciiTopHLine(ostream & os, int row,
2377                               vector<unsigned int> const & clen) const
2378 {
2379     int const fcell = GetFirstCellInRow(row);
2380     int const n = NumberOfCellsInRow(fcell) + fcell;
2381
2382 #if 0
2383     int tmp = 0;
2384
2385     for (int i = fcell; i < n; ++i) {
2386         if (TopLine(i))
2387             ++tmp;
2388     }
2389     if (!tmp)
2390         return 0;
2391 #else
2392     // Isn't this equivalent? (Lgb)
2393     for (int i = fcell; i < n; ++i) {
2394             if (TopLine(i))
2395                     return 0;
2396     }
2397 #endif
2398
2399     unsigned char ch;
2400     for (int i = fcell; i < n; ++i) {
2401         if (TopLine(i)) {
2402             if (LeftLine(i))
2403                 os << "+-";
2404             else
2405                 os << "--";
2406             ch = '-';
2407         } else {
2408             os << "  ";
2409             ch = ' ';
2410         }
2411         int column = column_of_cell(i);
2412         int len = clen[column];
2413         while(IsPartOfMultiColumn(row, ++column))
2414             len += clen[column] + 4;
2415         print_n_chars(os, ch, len);
2416         if (TopLine(i)) {
2417             if (RightLine(i))
2418                 os << "-+";
2419             else
2420                 os << "--";
2421         } else {
2422             os << "  ";
2423         }
2424     }
2425     os << endl;
2426     return 1;
2427 }
2428
2429
2430 int LyXTabular::AsciiBottomHLine(ostream & os, int row,
2431                                  vector<unsigned int> const & clen) const
2432 {
2433     int const fcell = GetFirstCellInRow(row);
2434     int const n = NumberOfCellsInRow(fcell) + fcell;
2435
2436 #if 0
2437     int tmp = 0;
2438
2439     for (int i = fcell; i < n; ++i) {
2440         if (BottomLine(i))
2441             ++tmp;
2442     }
2443     if (!tmp)
2444         return 0;
2445 #else
2446     // Isn't this equivalent? (Lgb)
2447     for (int i = fcell; i < n; ++i) {
2448         if (BottomLine(i))
2449             return 0;
2450     }
2451 #endif
2452     unsigned char ch;
2453     for (int i = fcell; i < n; ++i) {
2454         if (BottomLine(i)) {
2455             if (LeftLine(i))
2456                 os << "+-";
2457             else
2458                 os << "--";
2459             ch = '-';
2460         } else {
2461             os << "  ";
2462             ch = ' ';
2463         }
2464         int column = column_of_cell(i);
2465         int len = clen[column];
2466         while(IsPartOfMultiColumn(row, ++column))
2467             len += clen[column] + 4;
2468         print_n_chars(os, ch, len);
2469         if (BottomLine(i)) {
2470             if (RightLine(i))
2471                 os << "-+";
2472             else
2473                 os << "--";
2474         } else {
2475             os << "  ";
2476         }
2477     }
2478     os << endl;
2479     return 1;
2480 }
2481
2482
2483 int LyXTabular::AsciiPrintCell(Buffer const * buf, ostream & os,
2484                                int cell, int row, int column,
2485                                vector<unsigned int> const & clen) const
2486 {
2487     ostringstream sstr;
2488     int ret = GetCellInset(cell)->Ascii(buf, sstr, 0);
2489
2490     if (LeftLine(cell))
2491         os << "| ";
2492     else
2493         os << "  ";
2494
2495     unsigned int len1 = sstr.str().length();
2496     unsigned int len2 = clen[column];
2497     while(IsPartOfMultiColumn(row, ++column))
2498         len2 += clen[column] + 4;
2499     len2 -= len1;
2500
2501     switch (GetAlignment(cell)) {
2502     default:
2503     case LYX_ALIGN_LEFT:
2504         len1 = 0;
2505         break;
2506     case LYX_ALIGN_RIGHT:
2507         len1 = len2;
2508         len2 = 0;
2509         break;
2510     case LYX_ALIGN_CENTER:
2511         len1 = len2 / 2;
2512         len2 -= len1;
2513         break;
2514     }
2515
2516     for (unsigned int i = 0; i < len1; ++i)
2517         os << " ";
2518     os << sstr.str();
2519     for (unsigned int i = 0; i < len2; ++i)
2520         os << " ";
2521     if (RightLine(cell))
2522         os << " |";
2523     else
2524         os << "  ";
2525
2526     return ret * 0; // eh? (Lgb)
2527 }
2528
2529
2530 int LyXTabular::Ascii(Buffer const * buf, ostream & os) const
2531 {
2532     int ret = 0;
2533
2534     //+---------------------------------------------------------------------
2535     //+           first calculate the width of the single columns          +
2536     //+---------------------------------------------------------------------
2537     vector<unsigned int> clen(columns_);
2538
2539     // first all non (real) multicolumn cells!
2540     for (int j = 0; j < columns_; ++j) {
2541         clen[j] = 0;
2542         for (int i = 0; i < rows_; ++i) {
2543             int cell = GetCellNumber(i, j);
2544             if (IsMultiColumn(cell, true))
2545                 continue;
2546             ostringstream sstr;
2547             GetCellInset(cell)->Ascii(buf, sstr, 0);
2548             if (clen[j] < sstr.str().length())
2549                 clen[j] = sstr.str().length();
2550         }
2551     }
2552     // then all (real) multicolumn cells!
2553     for (int j = 0; j < columns_; ++j) {
2554         for (int i = 0; i < rows_; ++i) {
2555             int cell = GetCellNumber(i, j);
2556             if (!IsMultiColumn(cell, true) || IsPartOfMultiColumn(i, j))
2557                 continue;
2558             ostringstream sstr;
2559             GetCellInset(cell)->Ascii(buf, sstr, 0);
2560             int len = int(sstr.str().length());
2561             int const n = cells_in_multicolumn(cell);
2562             for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2563                 len -= clen[k];
2564             if (len > int(clen[j + n - 1]))
2565                 clen[j + n - 1] = len;
2566         }
2567     }
2568     int cell = 0;
2569     for (int i = 0; i < rows_; ++i) {
2570         AsciiTopHLine(os, i, clen);
2571         for (int j = 0; j < columns_; ++j) {
2572             if (IsPartOfMultiColumn(i,j))
2573                 continue;
2574             ret += AsciiPrintCell(buf, os, cell, i, j, clen);
2575             ++cell;
2576         }
2577         os << endl;
2578         AsciiBottomHLine(os, i, clen);
2579     }
2580     return ret;
2581 }
2582
2583
2584 InsetText * LyXTabular::GetCellInset(int cell) const
2585 {
2586     return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2587 }
2588
2589
2590 void LyXTabular::Validate(LaTeXFeatures & features) const
2591 {
2592     if (IsLongTabular())
2593         features.longtable = true;
2594     if (NeedRotating())
2595         features.rotating = true;
2596     for (int cell = 0; cell < numberofcells; ++cell) {
2597         if (GetVAlignment(cell) != LYX_VALIGN_TOP)
2598             features.array = true;
2599         GetCellInset(cell)->Validate(features);
2600     }
2601 }
2602
2603
2604 LyXTabular::BoxType LyXTabular::UseParbox(int cell) const
2605 {
2606     LyXParagraph * par = GetCellInset(cell)->par;
2607
2608     for (; par; par = par->next) {
2609         for (int i = 0; i < par->Last(); ++i) {
2610             if (par->GetChar(i) == LyXParagraph::META_NEWLINE)
2611                 return BOX_PARBOX;
2612         }
2613     }
2614     return BOX_NONE;
2615 }