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