1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 2000-2002 The LyX Team.
8 * @author: Jürgen Vigna
10 * ======================================================
15 // temporary until verified (08/08/2001 Jug)
16 #define SPECIAL_COLUM_HANDLING 1
23 #include "BufferView.h"
24 #include "frontends/Painter.h"
25 #include "LaTeXFeatures.h"
26 #include "insets/insettabular.h"
27 #include "insets/insettext.h"
28 #include "support/lstrings.h"
29 #include "support/lyxmanip.h"
30 #include "support/LAssert.h"
31 #include "frontends/Alert.h"
34 #include "tabular_funcs.h"
48 #ifndef CXX_GLOBAL_CSTD
54 int const WIDTH_OF_LINE = 5;
58 /// Define a few methods for the inner structs
60 LyXTabular::cellstruct::cellstruct(BufferParams const & bg)
65 multicolumn = LyXTabular::CELL_NORMAL;
66 alignment = LYX_ALIGN_CENTER;
67 valignment = LYX_VALIGN_TOP;
77 LyXTabular::rowstruct::rowstruct()
91 LyXTabular::columnstruct::columnstruct()
95 alignment = LYX_ALIGN_CENTER;
96 valignment = LYX_VALIGN_TOP;
101 LyXTabular::ltType::ltType()
110 LyXTabular::LyXTabular(BufferParams const & bp,
111 InsetTabular * inset, int rows_arg, int columns_arg)
115 Init(bp, rows_arg, columns_arg);
119 LyXTabular::LyXTabular(BufferParams const & bp,
120 InsetTabular * inset, LyXTabular const & lt,
125 Init(bp, lt.rows_, lt.columns_, <);
126 // we really should change again to have InsetText as a pointer
127 // and allocate it then we would not have to do this stuff all
130 for (int i = 0; i < rows_; ++i) {
131 for (int j = 0; j < columns_; ++j) {
132 cell_info[i][j].inset.id(lt.cell_info[i][j].inset.id());
133 cell_info[i][j].inset.setParagraphData(lt.cell_info[i][j].inset.paragraphs, true);
139 #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)
146 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
154 LyXTabular & LyXTabular::operator=(LyXTabular const & lt)
157 #warning This whole method should look like this: (Lgb)
162 // If this and lt is not of the same size we have a serious bug
163 // So then it is ok to throw an exception, or for now
165 lyx::Assert(rows_ == lt.rows_ && columns_ == lt.columns_);
167 cell_info = lt.cell_info;
168 row_info = lt.row_info;
169 column_info = lt.column_info;
170 SetLongTabular(lt.is_long_tabular);
179 LyXTabular * LyXTabular::clone(BufferParams const & bp,
180 InsetTabular * inset, bool same_id)
182 LyXTabular * result = new LyXTabular(bp, inset, *this, same_id);
184 // don't know if this is good but I need to Clone also
185 // the text-insets here, this is for the Undo-facility!
186 for (int i = 0; i < rows_; ++i) {
187 for (int j = 0; j < columns_; ++j) {
188 result->cell_info[i][j].inset = cell_info[i][j].inset;
189 result->cell_info[i][j].inset.setOwner(inset);
197 /* activates all lines and sets all widths to 0 */
198 void LyXTabular::Init(BufferParams const & bp,
199 int rows_arg, int columns_arg, LyXTabular const * lt)
202 columns_ = columns_arg;
203 row_info = row_vector(rows_, rowstruct());
204 column_info = column_vector(columns_, columnstruct());
205 cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
213 for (int i = 0; i < rows_; ++i) {
214 for (int j = 0; j < columns_; ++j) {
215 cell_info[i][j].inset.setOwner(owner_);
216 cell_info[i][j].inset.setDrawFrame(0, InsetText::LOCKED);
217 cell_info[i][j].cellno = cellno++;
219 cell_info[i].back().right_line = true;
221 row_info.back().bottom_line = true;
222 row_info.front().bottom_line = true;
224 for (int i = 0; i < columns_; ++i) {
225 calculate_width_of_column(i);
227 column_info.back().right_line = true;
229 calculate_width_of_tabular();
231 rowofcell = vector<int>();
232 columnofcell = vector<int>();
233 set_row_column_number_info();
234 is_long_tabular = false;
239 void LyXTabular::AppendRow(BufferParams const & bp, int cell)
243 int row = row_of_cell(cell);
245 row_vector::iterator rit = row_info.begin() + row;
246 row_info.insert(rit, rowstruct());
247 // now set the values of the row before
248 row_info[row] = row_info[row + 1];
251 cell_vvector::iterator cit = cell_info.begin() + row;
252 cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct(bp)));
254 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
257 for (int i = 0; i <= row; ++i) {
258 for (int j = 0; j < columns_; ++j) {
259 c_info[i][j] = cell_info[i][j];
262 for (int i = row + 1; i < rows_; ++i) {
263 for (int j = 0; j < columns_; ++j) {
264 c_info[i][j] = cell_info[i-1][j];
269 for (int j = 0; j < columns_; ++j) {
270 cell_info[row][j].inset.clear(false);
271 if (bp.tracking_changes)
272 cell_info[row][j].inset.markNew(true);
279 void LyXTabular::DeleteRow(int row)
281 if (rows_ == 1) return; // Not allowed to delete last row
283 row_info.erase(row_info.begin() + row); //&row_info[row]);
284 cell_info.erase(cell_info.begin() + row); //&cell_info[row]);
290 void LyXTabular::AppendColumn(BufferParams const & bp, int cell)
294 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
296 int const column = column_of_cell(cell);
297 column_vector::iterator cit = column_info.begin() + column + 1;
298 column_info.insert(cit, columnstruct());
299 // set the column values of the column before
300 column_info[column + 1] = column_info[column];
302 for (int i = 0; i < rows_; ++i) {
303 for (int j = 0; j <= column; ++j) {
304 c_info[i][j] = cell_info[i][j];
306 for (int j = column + 1; j < columns_; ++j) {
307 c_info[i][j] = cell_info[i][j - 1];
309 // care about multicolumns
310 if (c_info[i][column + 1].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
312 c_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
314 if ((column + 2) >= columns_ ||
315 c_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
317 c_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
322 for (int i = 0; i < rows_; ++i) {
323 cell_info[i][column + 1].inset.clear(false);
324 if (bp.tracking_changes)
325 cell_info[i][column + 1].inset.markNew(true);
331 void LyXTabular::DeleteColumn(int column)
333 // Similar to DeleteRow
334 //if (!(columns_ - 1))
336 if (columns_ == 1) return; // Not allowed to delete last column
338 column_info.erase(column_info.begin() + column);
339 for (int i = 0; i < rows_; ++i) {
340 cell_info[i].erase(cell_info[i].begin() + column);
347 void LyXTabular::reinit()
353 void LyXTabular::Reinit(bool reset_widths)
356 for (int i = 0; i < rows_; ++i) {
357 for (int j = 0; j < columns_; ++j) {
358 cell_info[i][j].width_of_cell = 0;
359 cell_info[i][j].inset.setOwner(owner_);
364 for (int i = 0; i < columns_; ++i) {
365 calculate_width_of_column(i);
367 calculate_width_of_tabular();
369 set_row_column_number_info();
373 void LyXTabular::set_row_column_number_info(bool oldformat)
376 for (int row = 0; row < rows_; ++row) {
377 for (int column = 0; column<columns_; ++column) {
378 if (cell_info[row][column].multicolumn
379 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
381 cell_info[row][column].cellno = numberofcells;
384 ++numberofcells; // because this is one more than as we start from 0
386 rowofcell.resize(numberofcells);
387 columnofcell.resize(numberofcells);
389 for (int row = 0, column = 0, c = 0;
390 c < numberofcells && row < rows_ && column < columns_;) {
392 columnofcell[c] = column;
396 } while (column < columns_ &&
397 cell_info[row][column].multicolumn
398 == LyXTabular::CELL_PART_OF_MULTICOLUMN);
399 if (column == columns_) {
405 for (int row = 0; row < rows_; ++row) {
406 for (int column = 0; column < columns_; ++column) {
407 if (IsPartOfMultiColumn(row,column))
409 // now set the right line of multicolumns right for oldformat read
411 cell_info[row][column].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
413 int cn=cells_in_multicolumn(cell_info[row][column].cellno);
414 cell_info[row][column].right_line =
415 cell_info[row][column+cn-1].right_line;
417 cell_info[row][column].inset.setAutoBreakRows(
418 !GetPWidth(GetCellNumber(row, column)).zero());
424 int LyXTabular::GetNumberOfCells() const
426 return numberofcells;
430 int LyXTabular::NumberOfCellsInRow(int cell) const
432 int const row = row_of_cell(cell);
434 for (int i = 0; i < columns_; ++i) {
435 if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
442 /* returns 1 if there is a topline, returns 0 if not */
443 bool LyXTabular::TopLine(int cell, bool onlycolumn) const
445 int const row = row_of_cell(cell);
447 if (!onlycolumn && IsMultiColumn(cell))
448 return cellinfo_of_cell(cell)->top_line;
449 return row_info[row].top_line;
453 bool LyXTabular::BottomLine(int cell, bool onlycolumn) const
455 // no bottom line underneath non-existent cells if you please
456 // Isn't that a programming error? Is so this should
457 // be an Assert instead. (Lgb)
458 if (cell >= numberofcells)
461 if (!onlycolumn && IsMultiColumn(cell))
462 return cellinfo_of_cell(cell)->bottom_line;
463 return row_info[row_of_cell(cell)].bottom_line;
467 bool LyXTabular::LeftLine(int cell, bool onlycolumn) const
469 if (!onlycolumn && IsMultiColumn(cell) &&
470 (IsFirstCellInRow(cell) || IsMultiColumn(cell-1)))
472 #ifdef SPECIAL_COLUM_HANDLING
473 if (cellinfo_of_cell(cell)->align_special.empty())
474 return cellinfo_of_cell(cell)->left_line;
475 return prefixIs(ltrim(cellinfo_of_cell(cell)->align_special), "|");
477 return cellinfo_of_cell(cell)->left_line;
480 #ifdef SPECIAL_COLUM_HANDLING
481 if (column_info[column_of_cell(cell)].align_special.empty())
482 return column_info[column_of_cell(cell)].left_line;
483 return prefixIs(ltrim(column_info[column_of_cell(cell)].align_special), "|");
485 return column_info[column_of_cell(cell)].left_line;
490 bool LyXTabular::RightLine(int cell, bool onlycolumn) const
492 if (!onlycolumn && IsMultiColumn(cell) &&
493 (IsLastCellInRow(cell) || IsMultiColumn(cell+1)))
495 #ifdef SPECIAL_COLUM_HANDLING
496 if (cellinfo_of_cell(cell)->align_special.empty())
497 return cellinfo_of_cell(cell)->right_line;
498 return suffixIs(rtrim(cellinfo_of_cell(cell)->align_special), "|");
500 return cellinfo_of_cell(cell)->right_line;
503 #ifdef SPECIAL_COLUM_HANDLING
504 if (column_info[column_of_cell(cell)].align_special.empty())
505 return column_info[right_column_of_cell(cell)].right_line;
506 return suffixIs(rtrim(column_info[column_of_cell(cell)].align_special), "|");
508 return column_info[right_column_of_cell(cell)].right_line;
513 bool LyXTabular::topAlreadyDrawn(int cell) const
515 int row = row_of_cell(cell);
516 if ((row > 0) && !GetAdditionalHeight(row)) {
517 int column = column_of_cell(cell);
520 && cell_info[row][column].multicolumn
521 == LyXTabular::CELL_PART_OF_MULTICOLUMN)
523 if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
524 return row_info[row].bottom_line;
526 return cell_info[row][column].bottom_line;
532 bool LyXTabular::leftAlreadyDrawn(int cell) const
534 int column = column_of_cell(cell);
536 int row = row_of_cell(cell);
538 (cell_info[row][column].multicolumn ==
539 LyXTabular::CELL_PART_OF_MULTICOLUMN));
540 if (GetAdditionalWidth(cell_info[row][column].cellno))
542 #ifdef SPECIAL_COLUM_HANDLING
543 return RightLine(cell_info[row][column].cellno);
545 return RightLine(cell_info[row][column].cellno, true);
552 bool LyXTabular::IsLastRow(int cell) const
554 return (row_of_cell(cell) == rows_ - 1);
558 int LyXTabular::GetAdditionalHeight(int row) const
560 if (!row || row >= rows_)
566 for (int column = 0; column < columns_ && bottom; ++column) {
567 switch (cell_info[row - 1][column].multicolumn) {
568 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
569 bottom = cell_info[row - 1][column].bottom_line;
571 case LyXTabular::CELL_NORMAL:
572 bottom = row_info[row - 1].bottom_line;
575 for (int column = 0; column < columns_ && top; ++column) {
576 switch (cell_info[row][column].multicolumn) {
577 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
578 top = cell_info[row][column].top_line;
580 case LyXTabular::CELL_NORMAL:
581 top = row_info[row].top_line;
585 return WIDTH_OF_LINE;
590 int LyXTabular::GetAdditionalWidth(int cell) const
592 // internally already set in SetWidthOfCell
593 // used to get it back in text.C
594 int const col = right_column_of_cell(cell);
595 int const row = row_of_cell(cell);
596 if (col < columns_ - 1 && RightLine(cell) &&
597 LeftLine(cell_info[row][col+1].cellno)) // column_info[col+1].left_line)
599 return WIDTH_OF_LINE;
606 // returns the maximum over all rows
607 int LyXTabular::GetWidthOfColumn(int cell) const
609 int const column1 = column_of_cell(cell);
610 int const column2 = right_column_of_cell(cell);
612 for (int i = column1; i <= column2; ++i) {
613 result += column_info[i].width_of_column;
619 int LyXTabular::GetWidthOfTabular() const
621 return width_of_tabular;
625 /* returns 1 if a complete update is necessary, otherwise 0 */
626 bool LyXTabular::SetWidthOfMulticolCell(int cell, int new_width)
628 if (!IsMultiColumn(cell))
631 int const row = row_of_cell(cell);
632 int const column1 = column_of_cell(cell);
633 int const column2 = right_column_of_cell(cell);
634 int const old_val = cell_info[row][column2].width_of_cell;
636 // first set columns to 0 so we can calculate the right width
637 for (int i = column1; i <= column2; ++i) {
638 cell_info[row][i].width_of_cell = 0;
640 // set the width to MAX_WIDTH until width > 0
641 int width = (new_width + 2 * WIDTH_OF_LINE);
643 for (; i < column2 && width > column_info[i].width_of_column; ++i) {
644 cell_info[row][i].width_of_cell = column_info[i].width_of_column;
645 width -= column_info[i].width_of_column;
648 cell_info[row][i].width_of_cell = width;
650 if (old_val != cell_info[row][column2].width_of_cell) {
651 // in this case we have to recalculate all multicolumn cells which
652 // have this column as one of theirs but not as last one
653 calculate_width_of_column_NMC(i);
654 recalculateMulticolumnsOfColumn(i);
655 calculate_width_of_column(i);
661 void LyXTabular::recalculateMulticolumnsOfColumn(int column)
663 // the last column does not have to be recalculated because all
664 // multicolumns will have here there last multicolumn cell which
665 // always will have the whole rest of the width of the cell.
666 if (column > (columns_ - 2))
668 for(int row = 0; row < rows_; ++row) {
669 int mc = cell_info[row][column].multicolumn;
670 int nmc = cell_info[row][column+1].multicolumn;
671 // we only have to update multicolumns which do not have this
672 // column as their last column!
673 if (mc == CELL_BEGIN_OF_MULTICOLUMN ||
674 ((mc == CELL_PART_OF_MULTICOLUMN) &&
675 (nmc == CELL_PART_OF_MULTICOLUMN)))
677 int const cellno = cell_info[row][column].cellno;
678 SetWidthOfMulticolCell(cellno,
679 GetWidthOfCell(cellno)-(2 * WIDTH_OF_LINE));
685 /* returns 1 if a complete update is necessary, otherwise 0 */
686 bool LyXTabular::SetWidthOfCell(int cell, int new_width)
688 int const row = row_of_cell(cell);
689 int const column1 = column_of_cell(cell);
694 #ifdef SPECIAL_COLUM_HANDLING
695 if (RightLine(cell_info[row][column1].cellno, true) &&
696 (column1 < columns_-1) &&
697 LeftLine(cell_info[row][column1+1].cellno, true))
699 if (column_info[column1].right_line && (column1 < columns_-1) &&
700 column_info[column1+1].left_line) // additional width
704 add_width = WIDTH_OF_LINE;
706 if (GetWidthOfCell(cell) == (new_width+2*WIDTH_OF_LINE+add_width)) {
709 if (IsMultiColumn(cell, true)) {
710 tmp = SetWidthOfMulticolCell(cell, new_width);
712 width = (new_width + 2*WIDTH_OF_LINE + add_width);
713 cell_info[row][column1].width_of_cell = width;
714 tmp = calculate_width_of_column_NMC(column1);
716 recalculateMulticolumnsOfColumn(column1);
719 for (int i = 0; i < columns_; ++i)
720 calculate_width_of_column(i);
721 calculate_width_of_tabular();
728 bool LyXTabular::SetAlignment(int cell, LyXAlignment align, bool onlycolumn)
730 if (!IsMultiColumn(cell) || onlycolumn)
731 column_info[column_of_cell(cell)].alignment = align;
733 cellinfo_of_cell(cell)->alignment = align;
738 bool LyXTabular::SetVAlignment(int cell, VAlignment align, bool onlycolumn)
740 if (!IsMultiColumn(cell) || onlycolumn)
741 column_info[column_of_cell(cell)].valignment = align;
743 cellinfo_of_cell(cell)->valignment = align;
748 bool LyXTabular::SetColumnPWidth(int cell, LyXLength const & width)
750 bool flag = !width.zero();
751 int const j = column_of_cell(cell);
753 column_info[j].p_width = width;
754 // This should not ne necessary anymore
755 // if (flag) // do this only if there is a width
756 // SetAlignment(cell, LYX_ALIGN_LEFT);
757 for (int i = 0; i < rows_; ++i) {
758 int c = GetCellNumber(i, j);
759 flag = !GetPWidth(c).zero(); // because of multicolumns!
760 GetCellInset(c)->setAutoBreakRows(flag);
766 bool LyXTabular::SetMColumnPWidth(int cell, LyXLength const & width)
768 bool const flag = !width.zero();
770 cellinfo_of_cell(cell)->p_width = width;
771 if (IsMultiColumn(cell)) {
772 GetCellInset(cell)->setAutoBreakRows(flag);
779 bool LyXTabular::SetAlignSpecial(int cell, string const & special,
780 LyXTabular::Feature what)
782 if (what == SET_SPECIAL_MULTI)
783 cellinfo_of_cell(cell)->align_special = special;
785 column_info[column_of_cell(cell)].align_special = special;
790 bool LyXTabular::SetAllLines(int cell, bool line)
792 SetTopLine(cell, line);
793 SetBottomLine(cell, line);
794 SetRightLine(cell, line);
795 SetLeftLine(cell, line);
800 bool LyXTabular::SetTopLine(int cell, bool line, bool onlycolumn)
802 int const row = row_of_cell(cell);
804 if (onlycolumn || !IsMultiColumn(cell))
805 row_info[row].top_line = line;
807 cellinfo_of_cell(cell)->top_line = line;
812 bool LyXTabular::SetBottomLine(int cell, bool line, bool onlycolumn)
814 if (onlycolumn || !IsMultiColumn(cell))
815 row_info[row_of_cell(cell)].bottom_line = line;
817 cellinfo_of_cell(cell)->bottom_line = line;
822 bool LyXTabular::SetLeftLine(int cell, bool line, bool onlycolumn)
824 if (onlycolumn || !IsMultiColumn(cell))
825 column_info[column_of_cell(cell)].left_line = line;
827 cellinfo_of_cell(cell)->left_line = line;
832 bool LyXTabular::SetRightLine(int cell, bool line, bool onlycolumn)
834 if (onlycolumn || !IsMultiColumn(cell))
835 column_info[right_column_of_cell(cell)].right_line = line;
837 cellinfo_of_cell(cell)->right_line = line;
842 LyXAlignment LyXTabular::GetAlignment(int cell, bool onlycolumn) const
844 if (!onlycolumn && IsMultiColumn(cell))
845 return cellinfo_of_cell(cell)->alignment;
847 return column_info[column_of_cell(cell)].alignment;
851 LyXTabular::VAlignment
852 LyXTabular::GetVAlignment(int cell, bool onlycolumn) const
854 if (!onlycolumn && IsMultiColumn(cell))
855 return cellinfo_of_cell(cell)->valignment;
857 return column_info[column_of_cell(cell)].valignment;
861 LyXLength const LyXTabular::GetPWidth(int cell) const
863 if (IsMultiColumn(cell))
864 return cellinfo_of_cell(cell)->p_width;
865 return column_info[column_of_cell(cell)].p_width;
869 LyXLength const LyXTabular::GetColumnPWidth(int cell) const
871 return column_info[column_of_cell(cell)].p_width;
875 LyXLength const LyXTabular::GetMColumnPWidth(int cell) const
877 if (IsMultiColumn(cell))
878 return cellinfo_of_cell(cell)->p_width;
883 string const LyXTabular::GetAlignSpecial(int cell, int what) const
885 if (what == SET_SPECIAL_MULTI)
886 return cellinfo_of_cell(cell)->align_special;
887 return column_info[column_of_cell(cell)].align_special;
891 int LyXTabular::GetWidthOfCell(int cell) const
893 int const row = row_of_cell(cell);
894 int const column1 = column_of_cell(cell);
895 int const column2 = right_column_of_cell(cell);
897 for (int i = column1; i <= column2; ++i) {
898 result += cell_info[row][i].width_of_cell;
904 int LyXTabular::GetBeginningOfTextInCell(int cell) const
908 switch (GetAlignment(cell)) {
909 case LYX_ALIGN_CENTER:
910 x += (GetWidthOfColumn(cell) - GetWidthOfCell(cell)) / 2;
912 case LYX_ALIGN_RIGHT:
913 x += GetWidthOfColumn(cell) - GetWidthOfCell(cell);
914 // + GetAdditionalWidth(cell);
916 default: /* LYX_ALIGN_LEFT: nothing :-) */
926 bool LyXTabular::IsFirstCellInRow(int cell) const
928 return column_of_cell(cell) == 0;
932 int LyXTabular::GetFirstCellInRow(int row) const
936 return cell_info[row][0].cellno;
939 bool LyXTabular::IsLastCellInRow(int cell) const
941 return (right_column_of_cell(cell) == (columns_ - 1));
945 int LyXTabular::GetLastCellInRow(int row) const
949 return cell_info[row][columns_-1].cellno;
953 bool LyXTabular::calculate_width_of_column(int column)
955 int const old_column_width = column_info[column].width_of_column;
958 for (int i = 0; i < rows_; ++i) {
959 maximum = max(cell_info[i][column].width_of_cell, maximum);
961 column_info[column].width_of_column = maximum;
962 return (column_info[column].width_of_column != old_column_width);
967 // Calculate the columns regarding ONLY the normal cells and if this
968 // column is inside a multicolumn cell then use it only if its the last
969 // column of this multicolumn cell as this gives an added with to the
970 // column, all the rest should be adapted!
972 bool LyXTabular::calculate_width_of_column_NMC(int column)
974 int const old_column_width = column_info[column].width_of_column;
976 for (int i = 0; i < rows_; ++i) {
977 int cell = GetCellNumber(i, column);
978 bool ismulti = IsMultiColumn(cell, true);
979 if ((!ismulti || (column == right_column_of_cell(cell))) &&
980 (cell_info[i][column].width_of_cell > max))
982 max = cell_info[i][column].width_of_cell;
985 column_info[column].width_of_column = max;
986 return (column_info[column].width_of_column != old_column_width);
990 void LyXTabular::calculate_width_of_tabular()
992 width_of_tabular = 0;
993 for (int i = 0; i < columns_; ++i) {
994 width_of_tabular += column_info[i].width_of_column;
999 int LyXTabular::row_of_cell(int cell) const
1001 if (cell >= numberofcells)
1005 return rowofcell[cell];
1009 int LyXTabular::column_of_cell(int cell) const
1011 if (cell >= numberofcells)
1012 return columns_ - 1;
1015 return columnofcell[cell];
1019 int LyXTabular::right_column_of_cell(int cell) const
1021 int const row = row_of_cell(cell);
1022 int column = column_of_cell(cell);
1023 while (column < (columns_ - 1) &&
1024 cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
1030 void LyXTabular::Write(Buffer const * buf, ostream & os) const
1034 << write_attribute("version", 3)
1035 << write_attribute("rows", rows_)
1036 << write_attribute("columns", columns_)
1038 // global longtable options
1040 << write_attribute("rotate", rotate)
1041 << write_attribute("islongtable", is_long_tabular)
1042 << write_attribute("firstHeadTopDL", endfirsthead.topDL)
1043 << write_attribute("firstHeadBottomDL", endfirsthead.bottomDL)
1044 << write_attribute("firstHeadEmpty", endfirsthead.empty)
1045 << write_attribute("headTopDL", endhead.topDL)
1046 << write_attribute("headBottomDL", endhead.bottomDL)
1047 << write_attribute("footTopDL", endfoot.topDL)
1048 << write_attribute("footBottomDL", endfoot.bottomDL)
1049 << write_attribute("lastFootTopDL", endlastfoot.topDL)
1050 << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
1051 << write_attribute("lastFootEmpty", endlastfoot.empty)
1053 for (int j = 0; j < columns_; ++j) {
1055 << write_attribute("alignment", column_info[j].alignment)
1056 << write_attribute("valignment", column_info[j].valignment)
1057 << write_attribute("leftline", column_info[j].left_line)
1058 << write_attribute("rightline", column_info[j].right_line)
1059 << write_attribute("width", column_info[j].p_width.asString())
1060 << write_attribute("special", column_info[j].align_special)
1063 for (int i = 0; i < rows_; ++i) {
1065 << write_attribute("topline", row_info[i].top_line)
1066 << write_attribute("bottomline", row_info[i].bottom_line)
1067 << write_attribute("endhead", row_info[i].endhead)
1068 << write_attribute("endfirsthead", row_info[i].endfirsthead)
1069 << write_attribute("endfoot", row_info[i].endfoot)
1070 << write_attribute("endlastfoot", row_info[i].endlastfoot)
1071 << write_attribute("newpage", row_info[i].newpage)
1073 for (int j = 0; j < columns_; ++j) {
1075 << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1076 << write_attribute("alignment", cell_info[i][j].alignment)
1077 << write_attribute("valignment", cell_info[i][j].valignment)
1078 << write_attribute("topline", cell_info[i][j].top_line)
1079 << write_attribute("bottomline", cell_info[i][j].bottom_line)
1080 << write_attribute("leftline", cell_info[i][j].left_line)
1081 << write_attribute("rightline", cell_info[i][j].right_line)
1082 << write_attribute("rotate", cell_info[i][j].rotate)
1083 << write_attribute("usebox", cell_info[i][j].usebox)
1084 << write_attribute("width", cell_info[i][j].p_width)
1085 << write_attribute("special", cell_info[i][j].align_special)
1087 os << "\\begin_inset ";
1088 cell_info[i][j].inset.write(buf, os);
1089 os << "\n\\end_inset \n"
1094 os << "</lyxtabular>\n";
1098 void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
1101 istream & is = lex.getStream();
1103 l_getline(is, line);
1104 if (!prefixIs(line, "<lyxtabular ")
1105 && !prefixIs(line, "<LyXTabular ")) {
1111 if (!getTokenValue(line, "version", version))
1113 lyx::Assert(version >= 2);
1114 read(buf, is, lex, line, version);
1117 void LyXTabular::setHeaderFooterRows(int hr, int fhr, int fr, int lfr)
1121 row_info[--hr].endhead = true;
1123 // set firstheader info
1124 if (fhr && (fhr < rows_)) {
1125 if (row_info[fhr].endhead) {
1127 row_info[--fhr].endfirsthead = true;
1128 row_info[fhr].endhead = false;
1130 } else if (row_info[fhr - 1].endhead) {
1131 endfirsthead.empty = true;
1133 while((fhr > 0) && !row_info[--fhr].endhead) {
1134 row_info[fhr].endfirsthead = true;
1139 if (fr && (fr < rows_)) {
1140 if (row_info[fr].endhead && row_info[fr-1].endhead) {
1141 while((fr > 0) && !row_info[--fr].endhead) {
1142 row_info[fr].endfoot = true;
1143 row_info[fr].endhead = false;
1145 } else if (row_info[fr].endfirsthead && row_info[fr-1].endfirsthead) {
1146 while((fr > 0) && !row_info[--fr].endfirsthead) {
1147 row_info[fr].endfoot = true;
1148 row_info[fr].endfirsthead = false;
1150 } else if (!row_info[fr - 1].endhead && !row_info[fr - 1].endfirsthead) {
1151 while((fr > 0) && !row_info[--fr].endhead &&
1152 !row_info[fr].endfirsthead)
1154 row_info[fr].endfoot = true;
1158 // set lastfooter info
1159 if (lfr && (lfr < rows_)) {
1160 if (row_info[lfr].endhead && row_info[lfr - 1].endhead) {
1161 while((lfr > 0) && !row_info[--lfr].endhead) {
1162 row_info[lfr].endlastfoot = true;
1163 row_info[lfr].endhead = false;
1165 } else if (row_info[lfr].endfirsthead &&
1166 row_info[lfr - 1].endfirsthead)
1168 while((lfr > 0) && !row_info[--lfr].endfirsthead) {
1169 row_info[lfr].endlastfoot = true;
1170 row_info[lfr].endfirsthead = false;
1172 } else if (row_info[lfr].endfoot
1173 && row_info[lfr - 1].endfoot) {
1174 while((lfr > 0) && !row_info[--lfr].endfoot) {
1175 row_info[lfr].endlastfoot = true;
1176 row_info[lfr].endfoot = false;
1178 } else if (!row_info[fr - 1].endhead
1179 && !row_info[fr - 1].endfirsthead &&
1180 !row_info[fr - 1].endfoot)
1183 !row_info[--lfr].endhead && !row_info[lfr].endfirsthead &&
1184 !row_info[lfr].endfoot)
1186 row_info[lfr].endlastfoot = true;
1188 } else if (haveLTFoot()) {
1189 endlastfoot.empty = true;
1194 void LyXTabular::read(Buffer const * buf, istream & is,
1195 LyXLex & lex, string const & l, int const version)
1199 if (!getTokenValue(line, "rows", rows_arg))
1202 if (!getTokenValue(line, "columns", columns_arg))
1204 Init(buf->params, rows_arg, columns_arg);
1205 l_getline(is, line);
1206 if (!prefixIs(line, "<features")) {
1207 lyxerr << "Wrong tabular format (expected <features ...> got"
1208 << line << ')' << endl;
1211 getTokenValue(line, "rotate", rotate);
1212 getTokenValue(line, "islongtable", is_long_tabular);
1213 // compatibility read for old longtable options. Now we can make any
1214 // row part of the header/footer type we want before it was strict
1215 // sequential from the first row down (as LaTeX does it!). So now when
1216 // we find a header/footer line we have to go up the rows and set it
1217 // on all preceding rows till the first or one with already a h/f option
1218 // set. If we find a firstheader on the same line as a header or a
1219 // lastfooter on the same line as a footer then this should be set empty.
1227 getTokenValue(line, "endhead", hrow);
1228 getTokenValue(line, "endfirsthead", fhrow);
1229 getTokenValue(line, "endfoot", frow);
1230 getTokenValue(line, "endlastfoot", lfrow);
1231 setHeaderFooterRows(abs(hrow), abs(fhrow), abs(frow), abs(lfrow));
1233 getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
1234 getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
1235 getTokenValue(line, "firstHeadEmpty", endfirsthead.empty);
1236 getTokenValue(line, "headTopDL", endhead.topDL);
1237 getTokenValue(line, "headBottomDL", endhead.bottomDL);
1238 getTokenValue(line, "footTopDL", endfoot.topDL);
1239 getTokenValue(line, "footBottomDL", endfoot.bottomDL);
1240 getTokenValue(line, "lastFootTopDL", endlastfoot.topDL);
1241 getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
1242 getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
1244 for (int j = 0; j < columns_; ++j) {
1246 if (!prefixIs(line,"<column")) {
1247 lyxerr << "Wrong tabular format (expected <column ...> got"
1248 << line << ')' << endl;
1251 getTokenValue(line, "alignment", column_info[j].alignment);
1252 getTokenValue(line, "valignment", column_info[j].valignment);
1253 getTokenValue(line, "leftline", column_info[j].left_line);
1254 getTokenValue(line, "rightline", column_info[j].right_line);
1255 getTokenValue(line, "width", column_info[j].p_width);
1256 getTokenValue(line, "special", column_info[j].align_special);
1259 for (int i = 0; i < rows_; ++i) {
1260 l_getline(is, line);
1261 if (!prefixIs(line, "<row")) {
1262 lyxerr << "Wrong tabular format (expected <row ...> got"
1263 << line << ')' << endl;
1266 getTokenValue(line, "topline", row_info[i].top_line);
1267 getTokenValue(line, "bottomline", row_info[i].bottom_line);
1268 getTokenValue(line, "endfirsthead", row_info[i].endfirsthead);
1269 getTokenValue(line, "endhead", row_info[i].endhead);
1270 getTokenValue(line, "endfoot", row_info[i].endfoot);
1271 getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
1272 getTokenValue(line, "newpage", row_info[i].newpage);
1273 for (int j = 0; j < columns_; ++j) {
1274 l_getline(is, line);
1275 if (!prefixIs(line, "<cell")) {
1276 lyxerr << "Wrong tabular format (expected <cell ...> got"
1277 << line << ')' << endl;
1280 getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1281 getTokenValue(line, "alignment", cell_info[i][j].alignment);
1282 getTokenValue(line, "valignment", cell_info[i][j].valignment);
1283 getTokenValue(line, "topline", cell_info[i][j].top_line);
1284 getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1285 getTokenValue(line, "leftline", cell_info[i][j].left_line);
1286 getTokenValue(line, "rightline", cell_info[i][j].right_line);
1287 getTokenValue(line, "rotate", cell_info[i][j].rotate);
1288 getTokenValue(line, "usebox", cell_info[i][j].usebox);
1289 getTokenValue(line, "width", cell_info[i][j].p_width);
1290 getTokenValue(line, "special", cell_info[i][j].align_special);
1291 l_getline(is, line);
1292 if (prefixIs(line, "\\begin_inset")) {
1293 cell_info[i][j].inset.read(buf, lex);
1294 l_getline(is, line);
1296 if (!prefixIs(line, "</cell>")) {
1297 lyxerr << "Wrong tabular format (expected </cell> got"
1298 << line << ')' << endl;
1302 l_getline(is, line);
1303 if (!prefixIs(line, "</row>")) {
1304 lyxerr << "Wrong tabular format (expected </row> got"
1305 << line << ')' << endl;
1309 while (!prefixIs(line, "</lyxtabular>")) {
1310 l_getline(is, line);
1312 set_row_column_number_info();
1316 bool LyXTabular::IsMultiColumn(int cell, bool real) const
1318 return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
1319 (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
1323 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
1325 int const row = row_of_cell(cell);
1326 int const column = column_of_cell(cell);
1327 return &cell_info[row][column];
1331 void LyXTabular::SetMultiColumn(Buffer * buffer, int cell, int number)
1333 cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1334 cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
1335 cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
1336 cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
1337 cellinfo_of_cell(cell)->right_line = column_info[column_of_cell(cell+number-1)].right_line;
1339 for (int i = 1; i < number; ++i) {
1340 cellinfo_of_cell(cell+i)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1341 cellinfo_of_cell(cell)->inset.appendParagraphs(buffer,
1342 cellinfo_of_cell(cell+i)->inset.paragraphs);
1343 cellinfo_of_cell(cell+i)->inset.clear(false);
1346 for (number--; number > 0; --number) {
1347 cellinfo_of_cell(cell+number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1350 set_row_column_number_info();
1354 int LyXTabular::cells_in_multicolumn(int cell) const
1356 int const row = row_of_cell(cell);
1357 int column = column_of_cell(cell);
1360 while ((column < columns_) &&
1361 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1370 int LyXTabular::UnsetMultiColumn(int cell)
1372 int const row = row_of_cell(cell);
1373 int column = column_of_cell(cell);
1377 if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1378 cell_info[row][column].multicolumn = CELL_NORMAL;
1380 while ((column < columns_) &&
1381 (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
1383 cell_info[row][column].multicolumn = CELL_NORMAL;
1388 set_row_column_number_info();
1393 void LyXTabular::SetLongTabular(bool what)
1395 is_long_tabular = what;
1399 bool LyXTabular::IsLongTabular() const
1401 return is_long_tabular;
1405 void LyXTabular::SetRotateTabular(bool flag)
1411 bool LyXTabular::GetRotateTabular() const
1417 void LyXTabular::SetRotateCell(int cell, bool flag)
1419 cellinfo_of_cell(cell)->rotate = flag;
1423 bool LyXTabular::GetRotateCell(int cell) const
1425 return cellinfo_of_cell(cell)->rotate;
1429 bool LyXTabular::NeedRotating() const
1433 for (int i = 0; i < rows_; ++i) {
1434 for (int j = 0; j < columns_; ++j) {
1435 if (cell_info[i][j].rotate)
1443 bool LyXTabular::IsLastCell(int cell) const
1445 if ((cell + 1) < numberofcells)
1451 int LyXTabular::GetCellAbove(int cell) const
1453 if (row_of_cell(cell) > 0)
1454 return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1459 int LyXTabular::GetCellBelow(int cell) const
1461 if (row_of_cell(cell) + 1 < rows_)
1462 return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1467 int LyXTabular::GetLastCellAbove(int cell) const
1469 if (row_of_cell(cell) <= 0)
1471 if (!IsMultiColumn(cell))
1472 return GetCellAbove(cell);
1473 return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1477 int LyXTabular::GetLastCellBelow(int cell) const
1479 if (row_of_cell(cell) + 1 >= rows_)
1481 if (!IsMultiColumn(cell))
1482 return GetCellBelow(cell);
1483 return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1487 int LyXTabular::GetCellNumber(int row, int column) const
1490 if (column >= columns_)
1491 column = columns_ - 1;
1492 else if (column < 0)
1499 lyx::Assert(column >= 0 || column < columns_ || row >= 0 || row < rows_);
1501 return cell_info[row][column].cellno;
1505 void LyXTabular::SetUsebox(int cell, BoxType type)
1507 cellinfo_of_cell(cell)->usebox = type;
1511 LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
1513 if (column_info[column_of_cell(cell)].p_width.zero() &&
1514 !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.zero()))
1516 if (cellinfo_of_cell(cell)->usebox > 1)
1517 return cellinfo_of_cell(cell)->usebox;
1518 return UseParbox(cell);
1523 // This are functions used for the longtable support
1525 void LyXTabular::SetLTHead(int row, bool flag, ltType const & hd, bool first)
1530 row_info[row].endfirsthead = flag;
1534 row_info[row].endhead = flag;
1539 bool LyXTabular::GetRowOfLTHead(int row, ltType & hd) const
1542 hd.set = haveLTHead();
1543 return row_info[row].endhead;
1547 bool LyXTabular::GetRowOfLTFirstHead(int row, ltType & hd) const
1550 hd.set = haveLTFirstHead();
1551 return row_info[row].endfirsthead;
1555 void LyXTabular::SetLTFoot(int row, bool flag, ltType const & fd, bool last)
1560 row_info[row].endlastfoot = flag;
1564 row_info[row].endfoot = flag;
1569 bool LyXTabular::GetRowOfLTFoot(int row, ltType & fd) const
1572 fd.set = haveLTFoot();
1573 return row_info[row].endfoot;
1577 bool LyXTabular::GetRowOfLTLastFoot(int row, ltType & fd) const
1580 fd.set = haveLTLastFoot();
1581 return row_info[row].endlastfoot;
1585 void LyXTabular::SetLTNewPage(int row, bool what)
1587 row_info[row].newpage = what;
1591 bool LyXTabular::GetLTNewPage(int row) const
1593 return row_info[row].newpage;
1597 bool LyXTabular::haveLTHead() const
1599 for(int i=0; i < rows_; ++i) {
1600 if (row_info[i].endhead)
1607 bool LyXTabular::haveLTFirstHead() const
1609 if (endfirsthead.empty)
1611 for(int i=0; i < rows_; ++i) {
1612 if (row_info[i].endfirsthead)
1619 bool LyXTabular::haveLTFoot() const
1621 for(int i=0; i < rows_; ++i) {
1622 if (row_info[i].endfoot)
1629 bool LyXTabular::haveLTLastFoot() const
1631 if (endlastfoot.empty)
1633 for(int i=0; i < rows_; ++i) {
1634 if (row_info[i].endlastfoot)
1641 // end longtable support functions
1643 bool LyXTabular::SetAscentOfRow(int row, int height)
1645 if ((row >= rows_) || (row_info[row].ascent_of_row == height))
1647 row_info[row].ascent_of_row = height;
1652 bool LyXTabular::SetDescentOfRow(int row, int height)
1654 if ((row >= rows_) || (row_info[row].descent_of_row == height))
1656 row_info[row].descent_of_row = height;
1661 int LyXTabular::GetAscentOfRow(int row) const
1665 return row_info[row].ascent_of_row;
1669 int LyXTabular::GetDescentOfRow(int row) const
1673 return row_info[row].descent_of_row;
1677 int LyXTabular::GetHeightOfTabular() const
1681 for (int row = 0; row < rows_; ++row)
1682 height += GetAscentOfRow(row) + GetDescentOfRow(row) +
1683 GetAdditionalHeight(row);
1688 bool LyXTabular::IsPartOfMultiColumn(int row, int column) const
1690 if ((row >= rows_) || (column >= columns_))
1692 return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
1696 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1698 if ((row < 0) || (row >= rows_))
1701 int const fcell = GetFirstCellInRow(row);
1702 int const n = NumberOfCellsInRow(fcell) + fcell;
1705 for (int i = fcell; i < n; ++i) {
1709 if (tmp == (n - fcell)) {
1712 for (int i = fcell; i < n; ++i) {
1715 << column_of_cell(i) + 1
1717 << right_column_of_cell(i) + 1
1729 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1731 if ((row < 0) || (row >= rows_))
1734 int const fcell = GetFirstCellInRow(row);
1735 int const n = NumberOfCellsInRow(fcell) + fcell;
1738 for (int i = fcell; i < n; ++i) {
1742 if (tmp == (n - fcell)) {
1745 for (int i = fcell; i < n; ++i) {
1746 if (BottomLine(i)) {
1748 << column_of_cell(i) + 1
1750 << right_column_of_cell(i) + 1
1762 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
1766 if (GetRotateCell(cell)) {
1767 os << "\\begin{sideways}\n";
1770 if (IsMultiColumn(cell)) {
1771 os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
1772 if (!cellinfo_of_cell(cell)->align_special.empty()) {
1773 os << cellinfo_of_cell(cell)->align_special << "}{";
1775 if (LeftLine(cell) &&
1776 (IsFirstCellInRow(cell) ||
1777 (!IsMultiColumn(cell-1) && !LeftLine(cell, true) &&
1778 !RightLine(cell-1, true))))
1782 if (!GetPWidth(cell).zero()) {
1783 switch (GetVAlignment(cell)) {
1784 case LYX_VALIGN_TOP:
1787 case LYX_VALIGN_CENTER:
1790 case LYX_VALIGN_BOTTOM:
1795 << GetPWidth(cell).asLatexString()
1798 switch (GetAlignment(cell)) {
1799 case LYX_ALIGN_LEFT:
1802 case LYX_ALIGN_RIGHT:
1810 if (RightLine(cell))
1812 if (((cell + 1) < numberofcells) && !IsFirstCellInRow(cell+1) &&
1818 if (GetUsebox(cell) == BOX_PARBOX) {
1820 switch (GetVAlignment(cell)) {
1821 case LYX_VALIGN_TOP:
1824 case LYX_VALIGN_CENTER:
1827 case LYX_VALIGN_BOTTOM:
1831 os << "]{" << GetPWidth(cell).asLatexString() << "}{";
1832 } else if (GetUsebox(cell) == BOX_MINIPAGE) {
1833 os << "\\begin{minipage}[";
1834 switch (GetVAlignment(cell)) {
1835 case LYX_VALIGN_TOP:
1838 case LYX_VALIGN_CENTER:
1841 case LYX_VALIGN_BOTTOM:
1845 os << "]{" << GetPWidth(cell).asLatexString() << "}\n";
1852 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
1857 if (GetUsebox(cell) == BOX_PARBOX)
1859 else if (GetUsebox(cell) == BOX_MINIPAGE) {
1860 os << "%\n\\end{minipage}";
1863 if (IsMultiColumn(cell)) {
1866 if (GetRotateCell(cell)) {
1867 os << "%\n\\end{sideways}";
1874 int LyXTabular::TeXLongtableHeaderFooter(ostream & os, Buffer const * buf,
1875 bool fragile, bool fp) const
1877 if (!is_long_tabular)
1881 // output header info
1883 if (endhead.topDL) {
1887 for (int i = 0; i < rows_; ++i) {
1888 if (row_info[i].endhead) {
1889 ret += TeXRow(os, i, buf, fragile, fp);
1892 if (endhead.bottomDL) {
1896 os << "\\endhead\n";
1898 if (endfirsthead.empty) {
1899 os << "\\endfirsthead\n";
1903 // output firstheader info
1904 if (haveLTFirstHead()) {
1905 if (endfirsthead.topDL) {
1909 for (int i = 0; i < rows_; ++i) {
1910 if (row_info[i].endfirsthead) {
1911 ret += TeXRow(os, i, buf, fragile, fp);
1914 if (endfirsthead.bottomDL) {
1918 os << "\\endfirsthead\n";
1921 // output footer info
1923 if (endfoot.topDL) {
1927 for (int i = 0; i < rows_; ++i) {
1928 if (row_info[i].endfoot) {
1929 ret += TeXRow(os, i, buf, fragile, fp);
1932 if (endfoot.bottomDL) {
1936 os << "\\endfoot\n";
1938 if (endlastfoot.empty) {
1939 os << "\\endlastfoot\n";
1943 // output lastfooter info
1944 if (haveLTLastFoot()) {
1945 if (endlastfoot.topDL) {
1949 for (int i = 0; i < rows_; ++i) {
1950 if (row_info[i].endlastfoot) {
1951 ret += TeXRow(os, i, buf, fragile, fp);
1954 if (endlastfoot.bottomDL) {
1958 os << "\\endlastfoot\n";
1965 bool LyXTabular::isValidRow(int const row) const
1967 if (!is_long_tabular)
1969 return (!row_info[row].endhead && !row_info[row].endfirsthead &&
1970 !row_info[row].endfoot && !row_info[row].endlastfoot);
1974 int LyXTabular::TeXRow(ostream & os, int const i, Buffer const * buf,
1975 bool fragile, bool fp) const
1978 int cell = GetCellNumber(i, 0);
1980 ret += TeXTopHLine(os, i);
1981 for (int j = 0; j < columns_; ++j) {
1982 if (IsPartOfMultiColumn(i,j))
1984 ret += TeXCellPreamble(os, cell);
1985 InsetText * inset = GetCellInset(cell);
1987 bool rtl = inset->paragraphs.begin()->isRightToLeftPar(buf->params) &&
1988 !inset->paragraphs.begin()->empty() && GetPWidth(cell).zero();
1992 ret += inset->latex(buf, os, fragile, fp);
1996 ret += TeXCellPostamble(os, cell);
1997 if (!IsLastCellInRow(cell)) { // not last cell in row
2003 os << "\\tabularnewline\n";
2005 ret += TeXBottomHLine(os, i);
2010 int LyXTabular::latex(Buffer const * buf,
2011 ostream & os, bool fragile, bool fp) const
2015 //+---------------------------------------------------------------------
2016 //+ first the opening preamble +
2017 //+---------------------------------------------------------------------
2020 os << "\\begin{sideways}\n";
2023 if (is_long_tabular)
2024 os << "\\begin{longtable}{";
2026 os << "\\begin{tabular}{";
2027 for (int i = 0; i < columns_; ++i) {
2028 if (!column_info[i].align_special.empty()) {
2029 os << column_info[i].align_special;
2031 if (column_info[i].left_line)
2033 if (!column_info[i].p_width.zero()) {
2034 switch (column_info[i].alignment) {
2035 case LYX_ALIGN_LEFT:
2036 os << ">{\\raggedright}";
2038 case LYX_ALIGN_RIGHT:
2039 os << ">{\\raggedleft}";
2041 case LYX_ALIGN_CENTER:
2042 os << ">{\\centering}";
2044 case LYX_ALIGN_NONE:
2045 case LYX_ALIGN_BLOCK:
2046 case LYX_ALIGN_LAYOUT:
2047 case LYX_ALIGN_SPECIAL:
2051 switch (column_info[i].valignment) {
2052 case LYX_VALIGN_TOP:
2055 case LYX_VALIGN_CENTER:
2058 case LYX_VALIGN_BOTTOM:
2063 << column_info[i].p_width.asLatexString()
2066 switch (column_info[i].alignment) {
2067 case LYX_ALIGN_LEFT:
2070 case LYX_ALIGN_RIGHT:
2078 if (column_info[i].right_line)
2085 ret += TeXLongtableHeaderFooter(os, buf, fragile, fp);
2087 //+---------------------------------------------------------------------
2088 //+ the single row and columns (cells) +
2089 //+---------------------------------------------------------------------
2091 for (int i = 0; i < rows_; ++i) {
2092 if (isValidRow(i)) {
2093 ret += TeXRow(os, i, buf, fragile, fp);
2094 if (is_long_tabular && row_info[i].newpage) {
2095 os << "\\newpage\n";
2101 //+---------------------------------------------------------------------
2102 //+ the closing of the tabular +
2103 //+---------------------------------------------------------------------
2105 if (is_long_tabular)
2106 os << "\\end{longtable}";
2108 os << "\\end{tabular}";
2110 os << "\n\\end{sideways}";
2118 int LyXTabular::docbookRow(Buffer const * buf, ostream & os, int row) const
2121 int cell = GetFirstCellInRow(row);
2124 for (int j = 0; j < columns_; ++j) {
2125 if (IsPartOfMultiColumn(row, j))
2128 os << "<entry align=\"";
2129 switch (GetAlignment(cell)) {
2130 case LYX_ALIGN_LEFT:
2133 case LYX_ALIGN_RIGHT:
2141 os << "\" valign=\"";
2142 switch (GetVAlignment(cell)) {
2143 case LYX_VALIGN_TOP:
2146 case LYX_VALIGN_BOTTOM:
2149 case LYX_VALIGN_CENTER:
2154 if (IsMultiColumn(cell)) {
2155 os << " namest=\"col" << j << "\" ";
2156 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
2160 ret += GetCellInset(cell)->docbook(buf, os, true);
2169 int LyXTabular::docbook(Buffer const * buf, ostream & os,
2170 bool /*mixcont*/) const
2174 //+---------------------------------------------------------------------
2175 //+ first the opening preamble +
2176 //+---------------------------------------------------------------------
2178 os << "<tgroup cols=\"" << columns_
2179 << "\" colsep=\"1\" rowsep=\"1\">\n";
2181 for (int i = 0; i < columns_; ++i) {
2182 os << "<colspec colname=\"col" << i << "\" align=\"";
2183 switch (column_info[i].alignment) {
2184 case LYX_ALIGN_LEFT:
2187 case LYX_ALIGN_RIGHT:
2198 //+---------------------------------------------------------------------
2199 //+ Long Tabular case +
2200 //+---------------------------------------------------------------------
2202 // output header info
2203 if (haveLTHead() || haveLTFirstHead()) {
2206 for (int i = 0; i < rows_; ++i) {
2207 if (row_info[i].endhead || row_info[i].endfirsthead) {
2208 ret += docbookRow(buf, os, i);
2214 // output footer info
2215 if (haveLTFoot() || haveLTLastFoot()) {
2218 for (int i = 0; i < rows_; ++i) {
2219 if (row_info[i].endfoot || row_info[i].endlastfoot) {
2220 ret += docbookRow(buf, os, i);
2227 //+---------------------------------------------------------------------
2228 //+ the single row and columns (cells) +
2229 //+---------------------------------------------------------------------
2233 for (int i = 0; i < rows_; ++i) {
2234 if (isValidRow(i)) {
2235 ret += docbookRow(buf, os, i);
2240 //+---------------------------------------------------------------------
2241 //+ the closing of the tabular +
2242 //+---------------------------------------------------------------------
2251 // ASCII export function and helpers
2253 int LyXTabular::asciiTopHLine(ostream & os, int row,
2254 vector<unsigned int> const & clen) const
2256 int const fcell = GetFirstCellInRow(row);
2257 int const n = NumberOfCellsInRow(fcell) + fcell;
2260 for (int i = fcell; i < n; ++i) {
2270 for (int i = fcell; i < n; ++i) {
2281 int column = column_of_cell(i);
2282 int len = clen[column];
2283 while (IsPartOfMultiColumn(row, ++column))
2284 len += clen[column] + 4;
2285 os << string(len, ch);
2300 int LyXTabular::asciiBottomHLine(ostream & os, int row,
2301 vector<unsigned int> const & clen) const
2303 int const fcell = GetFirstCellInRow(row);
2304 int const n = NumberOfCellsInRow(fcell) + fcell;
2307 for (int i = fcell; i < n; ++i) {
2308 if (BottomLine(i)) {
2317 for (int i = fcell; i < n; ++i) {
2318 if (BottomLine(i)) {
2328 int column = column_of_cell(i);
2329 int len = clen[column];
2330 while (IsPartOfMultiColumn(row, ++column))
2331 len += clen[column] + 4;
2332 os << string(len, ch);
2333 if (BottomLine(i)) {
2347 int LyXTabular::asciiPrintCell(Buffer const * buf, ostream & os,
2348 int cell, int row, int column,
2349 vector<unsigned int> const & clen,
2350 bool onlydata) const
2353 int ret = GetCellInset(cell)->ascii(buf, sstr, 0);
2365 unsigned int len1 = sstr.str().length();
2366 unsigned int len2 = clen[column];
2367 while (IsPartOfMultiColumn(row, ++column))
2368 len2 += clen[column] + 4;
2371 switch (GetAlignment(cell)) {
2373 case LYX_ALIGN_LEFT:
2376 case LYX_ALIGN_RIGHT:
2380 case LYX_ALIGN_CENTER:
2386 os << string(len1, ' ')
2388 << string(len2, ' ');
2389 if (RightLine(cell))
2398 int LyXTabular::ascii(Buffer const * buf, ostream & os, int const depth,
2399 bool onlydata, unsigned char delim) const
2403 //+---------------------------------------------------------------------
2404 //+ first calculate the width of the single columns +
2405 //+---------------------------------------------------------------------
2406 vector<unsigned int> clen(columns_);
2409 // first all non (real) multicolumn cells!
2410 for (int j = 0; j < columns_; ++j) {
2412 for (int i = 0; i < rows_; ++i) {
2413 int cell = GetCellNumber(i, j);
2414 if (IsMultiColumn(cell, true))
2417 GetCellInset(cell)->ascii(buf, sstr, 0);
2418 if (clen[j] < sstr.str().length())
2419 clen[j] = sstr.str().length();
2422 // then all (real) multicolumn cells!
2423 for (int j = 0; j < columns_; ++j) {
2424 for (int i = 0; i < rows_; ++i) {
2425 int cell = GetCellNumber(i, j);
2426 if (!IsMultiColumn(cell, true) || IsPartOfMultiColumn(i, j))
2429 GetCellInset(cell)->ascii(buf, sstr, 0);
2430 int len = int(sstr.str().length());
2431 int const n = cells_in_multicolumn(cell);
2432 for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2434 if (len > int(clen[j + n - 1]))
2435 clen[j + n - 1] = len;
2440 for (int i = 0; i < rows_; ++i) {
2442 if (asciiTopHLine(os, i, clen)) {
2443 for (int j = 0; j < depth; ++j)
2447 for (int j = 0; j < columns_; ++j) {
2448 if (IsPartOfMultiColumn(i,j))
2450 if (onlydata && j > 0)
2452 ret += asciiPrintCell(buf, os, cell, i, j, clen, onlydata);
2457 for (int j = 0; j < depth; ++j)
2459 if (asciiBottomHLine(os, i, clen)) {
2460 for (int j = 0; j < depth; ++j)
2472 InsetText * LyXTabular::GetCellInset(int cell) const
2475 return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2479 InsetText * LyXTabular::GetCellInset(int row, int column) const
2481 cur_cell = GetCellNumber(row, column);
2482 return & cell_info[row][column].inset;
2486 int LyXTabular::GetCellFromInset(Inset const * inset, int maybe_cell) const
2488 // is this inset part of the tabular?
2489 if (!inset || inset->owner() != owner_) {
2490 lyxerr[Debug::INSETTEXT]
2491 << "this is not a cell of the tabular!" << endl;
2495 const int save_cur_cell = cur_cell;
2496 int cell = cur_cell;
2497 if (GetCellInset(cell) != inset) {
2499 if (cell == -1 || GetCellInset(cell) != inset) {
2505 for (cell = GetNumberOfCells(); cell >= 0; --cell) {
2506 if (GetCellInset(cell) == inset)
2509 lyxerr[Debug::INSETTEXT]
2510 << "LyXTabular::GetCellFromInset: "
2512 << ", cur_cell=" << save_cur_cell
2513 << ", maybe_cell=" << maybe_cell
2515 // We should have found a cell at this point
2517 lyxerr << "LyXTabular::GetCellFromInset: "
2518 << "Cell not found!" << endl;
2526 void LyXTabular::Validate(LaTeXFeatures & features) const
2528 features.require("NeedTabularnewline");
2529 if (IsLongTabular())
2530 features.require("longtable");
2532 features.require("rotating");
2533 for (int cell = 0; cell < numberofcells; ++cell) {
2534 if ( (GetVAlignment(cell) != LYX_VALIGN_TOP) ||
2535 ( !(GetPWidth(cell).zero())&&!(IsMultiColumn(cell)) )
2537 features.require("array");
2538 GetCellInset(cell)->validate(features);
2543 vector<string> const LyXTabular::getLabelList() const
2545 vector<string> label_list;
2546 for (int i = 0; i < rows_; ++i)
2547 for (int j = 0; j < columns_; ++j) {
2548 vector<string> const l =
2549 GetCellInset(i, j)->getLabelList();
2550 label_list.insert(label_list.end(),
2551 l.begin(), l.end());
2557 LyXTabular::BoxType LyXTabular::UseParbox(int cell) const
2559 ParagraphList const & parlist = GetCellInset(cell)->paragraphs;
2560 ParagraphList::iterator cit = parlist.begin();
2561 ParagraphList::iterator end = parlist.end();
2563 for (; cit != end; ++cit) {
2564 for (int i = 0; i < cit->size(); ++i) {
2565 if (cit->isNewline(i))