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