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