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)
124 Init(bp, lt.rows_, lt.columns_, <);
127 #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)
134 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
142 LyXTabular & LyXTabular::operator=(LyXTabular const & lt)
145 #warning This whole method should look like this: (Lgb)
150 // If this and lt is not of the same size we have a serious bug
151 // So then it is ok to throw an exception, or for now
153 lyx::Assert(rows_ == lt.rows_ && columns_ == lt.columns_);
155 cell_info = lt.cell_info;
156 row_info = lt.row_info;
157 column_info = lt.column_info;
158 SetLongTabular(lt.is_long_tabular);
167 LyXTabular * LyXTabular::clone(BufferParams const & bp,
168 InsetTabular * inset)
170 LyXTabular * result = new LyXTabular(bp, inset, *this);
172 // don't know if this is good but I need to Clone also
173 // the text-insets here, this is for the Undo-facility!
174 for (int i = 0; i < rows_; ++i) {
175 for (int j = 0; j < columns_; ++j) {
176 result->cell_info[i][j].inset = cell_info[i][j].inset;
177 result->cell_info[i][j].inset.setOwner(inset);
185 /* activates all lines and sets all widths to 0 */
186 void LyXTabular::Init(BufferParams const & bp,
187 int rows_arg, int columns_arg, LyXTabular const * lt)
190 columns_ = columns_arg;
191 row_info = row_vector(rows_, rowstruct());
192 column_info = column_vector(columns_, columnstruct());
193 cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
201 for (int i = 0; i < rows_; ++i) {
202 for (int j = 0; j < columns_; ++j) {
203 cell_info[i][j].inset.setOwner(owner_);
204 cell_info[i][j].inset.setDrawFrame(0, InsetText::LOCKED);
205 cell_info[i][j].cellno = cellno++;
207 cell_info[i].back().right_line = true;
209 row_info.back().bottom_line = true;
210 row_info.front().bottom_line = true;
212 for (int i = 0; i < columns_; ++i) {
213 calculate_width_of_column(i);
215 column_info.back().right_line = true;
217 calculate_width_of_tabular();
219 rowofcell = vector<int>();
220 columnofcell = vector<int>();
221 set_row_column_number_info();
222 is_long_tabular = false;
227 void LyXTabular::AppendRow(BufferParams const & bp, int cell)
231 int row = row_of_cell(cell);
233 row_vector::iterator rit = row_info.begin() + row;
234 row_info.insert(rit, rowstruct());
235 // now set the values of the row before
236 row_info[row] = row_info[row + 1];
239 cell_vvector::iterator cit = cell_info.begin() + row;
240 cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct(bp)));
242 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
245 for (int i = 0; i <= row; ++i) {
246 for (int j = 0; j < columns_; ++j) {
247 c_info[i][j] = cell_info[i][j];
250 for (int i = row + 1; i < rows_; ++i) {
251 for (int j = 0; j < columns_; ++j) {
252 c_info[i][j] = cell_info[i-1][j];
257 for (int j = 0; j < columns_; ++j) {
258 cell_info[row][j].inset.clear(false);
259 if (bp.tracking_changes)
260 cell_info[row][j].inset.markNew(true);
267 void LyXTabular::DeleteRow(int row)
269 if (rows_ == 1) return; // Not allowed to delete last row
271 row_info.erase(row_info.begin() + row); //&row_info[row]);
272 cell_info.erase(cell_info.begin() + row); //&cell_info[row]);
278 void LyXTabular::AppendColumn(BufferParams const & bp, int cell)
282 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
284 int const column = column_of_cell(cell);
285 column_vector::iterator cit = column_info.begin() + column + 1;
286 column_info.insert(cit, columnstruct());
287 // set the column values of the column before
288 column_info[column + 1] = column_info[column];
290 for (int i = 0; i < rows_; ++i) {
291 for (int j = 0; j <= column; ++j) {
292 c_info[i][j] = cell_info[i][j];
294 for (int j = column + 1; j < columns_; ++j) {
295 c_info[i][j] = cell_info[i][j - 1];
297 // care about multicolumns
298 if (c_info[i][column + 1].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
300 c_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
302 if ((column + 2) >= columns_ ||
303 c_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
305 c_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
310 for (int i = 0; i < rows_; ++i) {
311 cell_info[i][column + 1].inset.clear(false);
312 if (bp.tracking_changes)
313 cell_info[i][column + 1].inset.markNew(true);
319 void LyXTabular::DeleteColumn(int column)
321 // Similar to DeleteRow
322 //if (!(columns_ - 1))
324 if (columns_ == 1) return; // Not allowed to delete last column
326 column_info.erase(column_info.begin() + column);
327 for (int i = 0; i < rows_; ++i) {
328 cell_info[i].erase(cell_info[i].begin() + column);
335 void LyXTabular::reinit()
341 void LyXTabular::Reinit(bool reset_widths)
344 for (int i = 0; i < rows_; ++i) {
345 for (int j = 0; j < columns_; ++j) {
346 cell_info[i][j].width_of_cell = 0;
347 cell_info[i][j].inset.setOwner(owner_);
352 for (int i = 0; i < columns_; ++i) {
353 calculate_width_of_column(i);
355 calculate_width_of_tabular();
357 set_row_column_number_info();
361 void LyXTabular::set_row_column_number_info(bool oldformat)
364 for (int row = 0; row < rows_; ++row) {
365 for (int column = 0; column<columns_; ++column) {
366 if (cell_info[row][column].multicolumn
367 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
369 cell_info[row][column].cellno = numberofcells;
372 ++numberofcells; // because this is one more than as we start from 0
374 rowofcell.resize(numberofcells);
375 columnofcell.resize(numberofcells);
377 for (int row = 0, column = 0, c = 0;
378 c < numberofcells && row < rows_ && column < columns_;) {
380 columnofcell[c] = column;
384 } while (column < columns_ &&
385 cell_info[row][column].multicolumn
386 == LyXTabular::CELL_PART_OF_MULTICOLUMN);
387 if (column == columns_) {
393 for (int row = 0; row < rows_; ++row) {
394 for (int column = 0; column < columns_; ++column) {
395 if (IsPartOfMultiColumn(row,column))
397 // now set the right line of multicolumns right for oldformat read
399 cell_info[row][column].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
401 int cn=cells_in_multicolumn(cell_info[row][column].cellno);
402 cell_info[row][column].right_line =
403 cell_info[row][column+cn-1].right_line;
405 cell_info[row][column].inset.setAutoBreakRows(
406 !GetPWidth(GetCellNumber(row, column)).zero());
412 int LyXTabular::GetNumberOfCells() const
414 return numberofcells;
418 int LyXTabular::NumberOfCellsInRow(int cell) const
420 int const row = row_of_cell(cell);
422 for (int i = 0; i < columns_; ++i) {
423 if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
430 /* returns 1 if there is a topline, returns 0 if not */
431 bool LyXTabular::TopLine(int cell, bool onlycolumn) const
433 int const row = row_of_cell(cell);
435 if (!onlycolumn && IsMultiColumn(cell))
436 return cellinfo_of_cell(cell)->top_line;
437 return row_info[row].top_line;
441 bool LyXTabular::BottomLine(int cell, bool onlycolumn) const
443 // no bottom line underneath non-existent cells if you please
444 // Isn't that a programming error? Is so this should
445 // be an Assert instead. (Lgb)
446 if (cell >= numberofcells)
449 if (!onlycolumn && IsMultiColumn(cell))
450 return cellinfo_of_cell(cell)->bottom_line;
451 return row_info[row_of_cell(cell)].bottom_line;
455 bool LyXTabular::LeftLine(int cell, bool onlycolumn) const
457 if (!onlycolumn && IsMultiColumn(cell) &&
458 (IsFirstCellInRow(cell) || IsMultiColumn(cell-1)))
460 #ifdef SPECIAL_COLUM_HANDLING
461 if (cellinfo_of_cell(cell)->align_special.empty())
462 return cellinfo_of_cell(cell)->left_line;
463 return prefixIs(ltrim(cellinfo_of_cell(cell)->align_special), "|");
465 return cellinfo_of_cell(cell)->left_line;
468 #ifdef SPECIAL_COLUM_HANDLING
469 if (column_info[column_of_cell(cell)].align_special.empty())
470 return column_info[column_of_cell(cell)].left_line;
471 return prefixIs(ltrim(column_info[column_of_cell(cell)].align_special), "|");
473 return column_info[column_of_cell(cell)].left_line;
478 bool LyXTabular::RightLine(int cell, bool onlycolumn) const
480 if (!onlycolumn && IsMultiColumn(cell) &&
481 (IsLastCellInRow(cell) || IsMultiColumn(cell+1)))
483 #ifdef SPECIAL_COLUM_HANDLING
484 if (cellinfo_of_cell(cell)->align_special.empty())
485 return cellinfo_of_cell(cell)->right_line;
486 return suffixIs(rtrim(cellinfo_of_cell(cell)->align_special), "|");
488 return cellinfo_of_cell(cell)->right_line;
491 #ifdef SPECIAL_COLUM_HANDLING
492 if (column_info[column_of_cell(cell)].align_special.empty())
493 return column_info[right_column_of_cell(cell)].right_line;
494 return suffixIs(rtrim(column_info[column_of_cell(cell)].align_special), "|");
496 return column_info[right_column_of_cell(cell)].right_line;
501 bool LyXTabular::topAlreadyDrawn(int cell) const
503 int row = row_of_cell(cell);
504 if ((row > 0) && !GetAdditionalHeight(row)) {
505 int column = column_of_cell(cell);
508 && cell_info[row][column].multicolumn
509 == LyXTabular::CELL_PART_OF_MULTICOLUMN)
511 if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
512 return row_info[row].bottom_line;
514 return cell_info[row][column].bottom_line;
520 bool LyXTabular::leftAlreadyDrawn(int cell) const
522 int column = column_of_cell(cell);
524 int row = row_of_cell(cell);
526 (cell_info[row][column].multicolumn ==
527 LyXTabular::CELL_PART_OF_MULTICOLUMN));
528 if (GetAdditionalWidth(cell_info[row][column].cellno))
530 #ifdef SPECIAL_COLUM_HANDLING
531 return RightLine(cell_info[row][column].cellno);
533 return RightLine(cell_info[row][column].cellno, true);
540 bool LyXTabular::IsLastRow(int cell) const
542 return (row_of_cell(cell) == rows_ - 1);
546 int LyXTabular::GetAdditionalHeight(int row) const
548 if (!row || row >= rows_)
554 for (int column = 0; column < columns_ && bottom; ++column) {
555 switch (cell_info[row - 1][column].multicolumn) {
556 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
557 bottom = cell_info[row - 1][column].bottom_line;
559 case LyXTabular::CELL_NORMAL:
560 bottom = row_info[row - 1].bottom_line;
563 for (int column = 0; column < columns_ && top; ++column) {
564 switch (cell_info[row][column].multicolumn) {
565 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
566 top = cell_info[row][column].top_line;
568 case LyXTabular::CELL_NORMAL:
569 top = row_info[row].top_line;
573 return WIDTH_OF_LINE;
578 int LyXTabular::GetAdditionalWidth(int cell) const
580 // internally already set in SetWidthOfCell
581 // used to get it back in text.C
582 int const col = right_column_of_cell(cell);
583 int const row = row_of_cell(cell);
584 if (col < columns_ - 1 && RightLine(cell) &&
585 LeftLine(cell_info[row][col+1].cellno)) // column_info[col+1].left_line)
587 return WIDTH_OF_LINE;
594 // returns the maximum over all rows
595 int LyXTabular::GetWidthOfColumn(int cell) const
597 int const column1 = column_of_cell(cell);
598 int const column2 = right_column_of_cell(cell);
600 for (int i = column1; i <= column2; ++i) {
601 result += column_info[i].width_of_column;
607 int LyXTabular::GetWidthOfTabular() const
609 return width_of_tabular;
613 /* returns 1 if a complete update is necessary, otherwise 0 */
614 bool LyXTabular::SetWidthOfMulticolCell(int cell, int new_width)
616 if (!IsMultiColumn(cell))
619 int const row = row_of_cell(cell);
620 int const column1 = column_of_cell(cell);
621 int const column2 = right_column_of_cell(cell);
622 int const old_val = cell_info[row][column2].width_of_cell;
624 // first set columns to 0 so we can calculate the right width
625 for (int i = column1; i <= column2; ++i) {
626 cell_info[row][i].width_of_cell = 0;
628 // set the width to MAX_WIDTH until width > 0
629 int width = (new_width + 2 * WIDTH_OF_LINE);
631 for (; i < column2 && width > column_info[i].width_of_column; ++i) {
632 cell_info[row][i].width_of_cell = column_info[i].width_of_column;
633 width -= column_info[i].width_of_column;
636 cell_info[row][i].width_of_cell = width;
638 if (old_val != cell_info[row][column2].width_of_cell) {
639 // in this case we have to recalculate all multicolumn cells which
640 // have this column as one of theirs but not as last one
641 calculate_width_of_column_NMC(i);
642 recalculateMulticolumnsOfColumn(i);
643 calculate_width_of_column(i);
649 void LyXTabular::recalculateMulticolumnsOfColumn(int column)
651 // the last column does not have to be recalculated because all
652 // multicolumns will have here there last multicolumn cell which
653 // always will have the whole rest of the width of the cell.
654 if (column > (columns_ - 2))
656 for(int row = 0; row < rows_; ++row) {
657 int mc = cell_info[row][column].multicolumn;
658 int nmc = cell_info[row][column+1].multicolumn;
659 // we only have to update multicolumns which do not have this
660 // column as their last column!
661 if (mc == CELL_BEGIN_OF_MULTICOLUMN ||
662 ((mc == CELL_PART_OF_MULTICOLUMN) &&
663 (nmc == CELL_PART_OF_MULTICOLUMN)))
665 int const cellno = cell_info[row][column].cellno;
666 SetWidthOfMulticolCell(cellno,
667 GetWidthOfCell(cellno)-(2 * WIDTH_OF_LINE));
673 /* returns 1 if a complete update is necessary, otherwise 0 */
674 bool LyXTabular::SetWidthOfCell(int cell, int new_width)
676 int const row = row_of_cell(cell);
677 int const column1 = column_of_cell(cell);
682 #ifdef SPECIAL_COLUM_HANDLING
683 if (RightLine(cell_info[row][column1].cellno, true) &&
684 (column1 < columns_-1) &&
685 LeftLine(cell_info[row][column1+1].cellno, true))
687 if (column_info[column1].right_line && (column1 < columns_-1) &&
688 column_info[column1+1].left_line) // additional width
692 add_width = WIDTH_OF_LINE;
694 if (GetWidthOfCell(cell) == (new_width+2*WIDTH_OF_LINE+add_width)) {
697 if (IsMultiColumn(cell, true)) {
698 tmp = SetWidthOfMulticolCell(cell, new_width);
700 width = (new_width + 2*WIDTH_OF_LINE + add_width);
701 cell_info[row][column1].width_of_cell = width;
702 tmp = calculate_width_of_column_NMC(column1);
704 recalculateMulticolumnsOfColumn(column1);
707 for (int i = 0; i < columns_; ++i)
708 calculate_width_of_column(i);
709 calculate_width_of_tabular();
716 bool LyXTabular::SetAlignment(int cell, LyXAlignment align, bool onlycolumn)
718 if (!IsMultiColumn(cell) || onlycolumn)
719 column_info[column_of_cell(cell)].alignment = align;
721 cellinfo_of_cell(cell)->alignment = align;
726 bool LyXTabular::SetVAlignment(int cell, VAlignment align, bool onlycolumn)
728 if (!IsMultiColumn(cell) || onlycolumn)
729 column_info[column_of_cell(cell)].valignment = align;
731 cellinfo_of_cell(cell)->valignment = align;
736 bool LyXTabular::SetColumnPWidth(int cell, LyXLength const & width)
738 bool flag = !width.zero();
739 int const j = column_of_cell(cell);
741 column_info[j].p_width = width;
742 // This should not ne necessary anymore
743 // if (flag) // do this only if there is a width
744 // SetAlignment(cell, LYX_ALIGN_LEFT);
745 for (int i = 0; i < rows_; ++i) {
746 int c = GetCellNumber(i, j);
747 flag = !GetPWidth(c).zero(); // because of multicolumns!
748 GetCellInset(c)->setAutoBreakRows(flag);
754 bool LyXTabular::SetMColumnPWidth(int cell, LyXLength const & width)
756 bool const flag = !width.zero();
758 cellinfo_of_cell(cell)->p_width = width;
759 if (IsMultiColumn(cell)) {
760 GetCellInset(cell)->setAutoBreakRows(flag);
767 bool LyXTabular::SetAlignSpecial(int cell, string const & special,
768 LyXTabular::Feature what)
770 if (what == SET_SPECIAL_MULTI)
771 cellinfo_of_cell(cell)->align_special = special;
773 column_info[column_of_cell(cell)].align_special = special;
778 bool LyXTabular::SetAllLines(int cell, bool line)
780 SetTopLine(cell, line);
781 SetBottomLine(cell, line);
782 SetRightLine(cell, line);
783 SetLeftLine(cell, line);
788 bool LyXTabular::SetTopLine(int cell, bool line, bool onlycolumn)
790 int const row = row_of_cell(cell);
792 if (onlycolumn || !IsMultiColumn(cell))
793 row_info[row].top_line = line;
795 cellinfo_of_cell(cell)->top_line = line;
800 bool LyXTabular::SetBottomLine(int cell, bool line, bool onlycolumn)
802 if (onlycolumn || !IsMultiColumn(cell))
803 row_info[row_of_cell(cell)].bottom_line = line;
805 cellinfo_of_cell(cell)->bottom_line = line;
810 bool LyXTabular::SetLeftLine(int cell, bool line, bool onlycolumn)
812 if (onlycolumn || !IsMultiColumn(cell))
813 column_info[column_of_cell(cell)].left_line = line;
815 cellinfo_of_cell(cell)->left_line = line;
820 bool LyXTabular::SetRightLine(int cell, bool line, bool onlycolumn)
822 if (onlycolumn || !IsMultiColumn(cell))
823 column_info[right_column_of_cell(cell)].right_line = line;
825 cellinfo_of_cell(cell)->right_line = line;
830 LyXAlignment LyXTabular::GetAlignment(int cell, bool onlycolumn) const
832 if (!onlycolumn && IsMultiColumn(cell))
833 return cellinfo_of_cell(cell)->alignment;
835 return column_info[column_of_cell(cell)].alignment;
839 LyXTabular::VAlignment
840 LyXTabular::GetVAlignment(int cell, bool onlycolumn) const
842 if (!onlycolumn && IsMultiColumn(cell))
843 return cellinfo_of_cell(cell)->valignment;
845 return column_info[column_of_cell(cell)].valignment;
849 LyXLength const LyXTabular::GetPWidth(int cell) const
851 if (IsMultiColumn(cell))
852 return cellinfo_of_cell(cell)->p_width;
853 return column_info[column_of_cell(cell)].p_width;
857 LyXLength const LyXTabular::GetColumnPWidth(int cell) const
859 return column_info[column_of_cell(cell)].p_width;
863 LyXLength const LyXTabular::GetMColumnPWidth(int cell) const
865 if (IsMultiColumn(cell))
866 return cellinfo_of_cell(cell)->p_width;
871 string const LyXTabular::GetAlignSpecial(int cell, int what) const
873 if (what == SET_SPECIAL_MULTI)
874 return cellinfo_of_cell(cell)->align_special;
875 return column_info[column_of_cell(cell)].align_special;
879 int LyXTabular::GetWidthOfCell(int cell) const
881 int const row = row_of_cell(cell);
882 int const column1 = column_of_cell(cell);
883 int const column2 = right_column_of_cell(cell);
885 for (int i = column1; i <= column2; ++i) {
886 result += cell_info[row][i].width_of_cell;
892 int LyXTabular::GetBeginningOfTextInCell(int cell) const
896 switch (GetAlignment(cell)) {
897 case LYX_ALIGN_CENTER:
898 x += (GetWidthOfColumn(cell) - GetWidthOfCell(cell)) / 2;
900 case LYX_ALIGN_RIGHT:
901 x += GetWidthOfColumn(cell) - GetWidthOfCell(cell);
902 // + GetAdditionalWidth(cell);
904 default: /* LYX_ALIGN_LEFT: nothing :-) */
914 bool LyXTabular::IsFirstCellInRow(int cell) const
916 return column_of_cell(cell) == 0;
920 int LyXTabular::GetFirstCellInRow(int row) const
924 return cell_info[row][0].cellno;
927 bool LyXTabular::IsLastCellInRow(int cell) const
929 return (right_column_of_cell(cell) == (columns_ - 1));
933 int LyXTabular::GetLastCellInRow(int row) const
937 return cell_info[row][columns_-1].cellno;
941 bool LyXTabular::calculate_width_of_column(int column)
943 int const old_column_width = column_info[column].width_of_column;
946 for (int i = 0; i < rows_; ++i) {
947 maximum = max(cell_info[i][column].width_of_cell, maximum);
949 column_info[column].width_of_column = maximum;
950 return (column_info[column].width_of_column != old_column_width);
955 // Calculate the columns regarding ONLY the normal cells and if this
956 // column is inside a multicolumn cell then use it only if its the last
957 // column of this multicolumn cell as this gives an added with to the
958 // column, all the rest should be adapted!
960 bool LyXTabular::calculate_width_of_column_NMC(int column)
962 int const old_column_width = column_info[column].width_of_column;
964 for (int i = 0; i < rows_; ++i) {
965 int cell = GetCellNumber(i, column);
966 bool ismulti = IsMultiColumn(cell, true);
967 if ((!ismulti || (column == right_column_of_cell(cell))) &&
968 (cell_info[i][column].width_of_cell > max))
970 max = cell_info[i][column].width_of_cell;
973 column_info[column].width_of_column = max;
974 return (column_info[column].width_of_column != old_column_width);
978 void LyXTabular::calculate_width_of_tabular()
980 width_of_tabular = 0;
981 for (int i = 0; i < columns_; ++i) {
982 width_of_tabular += column_info[i].width_of_column;
987 int LyXTabular::row_of_cell(int cell) const
989 if (cell >= numberofcells)
993 return rowofcell[cell];
997 int LyXTabular::column_of_cell(int cell) const
999 if (cell >= numberofcells)
1000 return columns_ - 1;
1003 return columnofcell[cell];
1007 int LyXTabular::right_column_of_cell(int cell) const
1009 int const row = row_of_cell(cell);
1010 int column = column_of_cell(cell);
1011 while (column < (columns_ - 1) &&
1012 cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
1018 void LyXTabular::Write(Buffer const * buf, ostream & os) const
1022 << write_attribute("version", 3)
1023 << write_attribute("rows", rows_)
1024 << write_attribute("columns", columns_)
1026 // global longtable options
1028 << write_attribute("rotate", rotate)
1029 << write_attribute("islongtable", is_long_tabular)
1030 << write_attribute("firstHeadTopDL", endfirsthead.topDL)
1031 << write_attribute("firstHeadBottomDL", endfirsthead.bottomDL)
1032 << write_attribute("firstHeadEmpty", endfirsthead.empty)
1033 << write_attribute("headTopDL", endhead.topDL)
1034 << write_attribute("headBottomDL", endhead.bottomDL)
1035 << write_attribute("footTopDL", endfoot.topDL)
1036 << write_attribute("footBottomDL", endfoot.bottomDL)
1037 << write_attribute("lastFootTopDL", endlastfoot.topDL)
1038 << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
1039 << write_attribute("lastFootEmpty", endlastfoot.empty)
1041 for (int j = 0; j < columns_; ++j) {
1043 << write_attribute("alignment", column_info[j].alignment)
1044 << write_attribute("valignment", column_info[j].valignment)
1045 << write_attribute("leftline", column_info[j].left_line)
1046 << write_attribute("rightline", column_info[j].right_line)
1047 << write_attribute("width", column_info[j].p_width.asString())
1048 << write_attribute("special", column_info[j].align_special)
1051 for (int i = 0; i < rows_; ++i) {
1053 << write_attribute("topline", row_info[i].top_line)
1054 << write_attribute("bottomline", row_info[i].bottom_line)
1055 << write_attribute("endhead", row_info[i].endhead)
1056 << write_attribute("endfirsthead", row_info[i].endfirsthead)
1057 << write_attribute("endfoot", row_info[i].endfoot)
1058 << write_attribute("endlastfoot", row_info[i].endlastfoot)
1059 << write_attribute("newpage", row_info[i].newpage)
1061 for (int j = 0; j < columns_; ++j) {
1063 << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1064 << write_attribute("alignment", cell_info[i][j].alignment)
1065 << write_attribute("valignment", cell_info[i][j].valignment)
1066 << write_attribute("topline", cell_info[i][j].top_line)
1067 << write_attribute("bottomline", cell_info[i][j].bottom_line)
1068 << write_attribute("leftline", cell_info[i][j].left_line)
1069 << write_attribute("rightline", cell_info[i][j].right_line)
1070 << write_attribute("rotate", cell_info[i][j].rotate)
1071 << write_attribute("usebox", cell_info[i][j].usebox)
1072 << write_attribute("width", cell_info[i][j].p_width)
1073 << write_attribute("special", cell_info[i][j].align_special)
1075 os << "\\begin_inset ";
1076 cell_info[i][j].inset.write(buf, os);
1077 os << "\n\\end_inset \n"
1082 os << "</lyxtabular>\n";
1086 void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
1089 istream & is = lex.getStream();
1091 l_getline(is, line);
1092 if (!prefixIs(line, "<lyxtabular ")
1093 && !prefixIs(line, "<LyXTabular ")) {
1099 if (!getTokenValue(line, "version", version))
1101 lyx::Assert(version >= 2);
1102 read(buf, is, lex, line, version);
1105 void LyXTabular::setHeaderFooterRows(int hr, int fhr, int fr, int lfr)
1109 row_info[--hr].endhead = true;
1111 // set firstheader info
1112 if (fhr && (fhr < rows_)) {
1113 if (row_info[fhr].endhead) {
1115 row_info[--fhr].endfirsthead = true;
1116 row_info[fhr].endhead = false;
1118 } else if (row_info[fhr - 1].endhead) {
1119 endfirsthead.empty = true;
1121 while((fhr > 0) && !row_info[--fhr].endhead) {
1122 row_info[fhr].endfirsthead = true;
1127 if (fr && (fr < rows_)) {
1128 if (row_info[fr].endhead && row_info[fr-1].endhead) {
1129 while((fr > 0) && !row_info[--fr].endhead) {
1130 row_info[fr].endfoot = true;
1131 row_info[fr].endhead = false;
1133 } else if (row_info[fr].endfirsthead && row_info[fr-1].endfirsthead) {
1134 while((fr > 0) && !row_info[--fr].endfirsthead) {
1135 row_info[fr].endfoot = true;
1136 row_info[fr].endfirsthead = false;
1138 } else if (!row_info[fr - 1].endhead && !row_info[fr - 1].endfirsthead) {
1139 while((fr > 0) && !row_info[--fr].endhead &&
1140 !row_info[fr].endfirsthead)
1142 row_info[fr].endfoot = true;
1146 // set lastfooter info
1147 if (lfr && (lfr < rows_)) {
1148 if (row_info[lfr].endhead && row_info[lfr - 1].endhead) {
1149 while((lfr > 0) && !row_info[--lfr].endhead) {
1150 row_info[lfr].endlastfoot = true;
1151 row_info[lfr].endhead = false;
1153 } else if (row_info[lfr].endfirsthead &&
1154 row_info[lfr - 1].endfirsthead)
1156 while((lfr > 0) && !row_info[--lfr].endfirsthead) {
1157 row_info[lfr].endlastfoot = true;
1158 row_info[lfr].endfirsthead = false;
1160 } else if (row_info[lfr].endfoot
1161 && row_info[lfr - 1].endfoot) {
1162 while((lfr > 0) && !row_info[--lfr].endfoot) {
1163 row_info[lfr].endlastfoot = true;
1164 row_info[lfr].endfoot = false;
1166 } else if (!row_info[fr - 1].endhead
1167 && !row_info[fr - 1].endfirsthead &&
1168 !row_info[fr - 1].endfoot)
1171 !row_info[--lfr].endhead && !row_info[lfr].endfirsthead &&
1172 !row_info[lfr].endfoot)
1174 row_info[lfr].endlastfoot = true;
1176 } else if (haveLTFoot()) {
1177 endlastfoot.empty = true;
1182 void LyXTabular::read(Buffer const * buf, istream & is,
1183 LyXLex & lex, string const & l, int const version)
1187 if (!getTokenValue(line, "rows", rows_arg))
1190 if (!getTokenValue(line, "columns", columns_arg))
1192 Init(buf->params, rows_arg, columns_arg);
1193 l_getline(is, line);
1194 if (!prefixIs(line, "<features")) {
1195 lyxerr << "Wrong tabular format (expected <features ...> got"
1196 << line << ')' << endl;
1199 getTokenValue(line, "rotate", rotate);
1200 getTokenValue(line, "islongtable", is_long_tabular);
1201 // compatibility read for old longtable options. Now we can make any
1202 // row part of the header/footer type we want before it was strict
1203 // sequential from the first row down (as LaTeX does it!). So now when
1204 // we find a header/footer line we have to go up the rows and set it
1205 // on all preceding rows till the first or one with already a h/f option
1206 // set. If we find a firstheader on the same line as a header or a
1207 // lastfooter on the same line as a footer then this should be set empty.
1215 getTokenValue(line, "endhead", hrow);
1216 getTokenValue(line, "endfirsthead", fhrow);
1217 getTokenValue(line, "endfoot", frow);
1218 getTokenValue(line, "endlastfoot", lfrow);
1219 setHeaderFooterRows(abs(hrow), abs(fhrow), abs(frow), abs(lfrow));
1221 getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
1222 getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
1223 getTokenValue(line, "firstHeadEmpty", endfirsthead.empty);
1224 getTokenValue(line, "headTopDL", endhead.topDL);
1225 getTokenValue(line, "headBottomDL", endhead.bottomDL);
1226 getTokenValue(line, "footTopDL", endfoot.topDL);
1227 getTokenValue(line, "footBottomDL", endfoot.bottomDL);
1228 getTokenValue(line, "lastFootTopDL", endlastfoot.topDL);
1229 getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
1230 getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
1232 for (int j = 0; j < columns_; ++j) {
1234 if (!prefixIs(line,"<column")) {
1235 lyxerr << "Wrong tabular format (expected <column ...> got"
1236 << line << ')' << endl;
1239 getTokenValue(line, "alignment", column_info[j].alignment);
1240 getTokenValue(line, "valignment", column_info[j].valignment);
1241 getTokenValue(line, "leftline", column_info[j].left_line);
1242 getTokenValue(line, "rightline", column_info[j].right_line);
1243 getTokenValue(line, "width", column_info[j].p_width);
1244 getTokenValue(line, "special", column_info[j].align_special);
1247 for (int i = 0; i < rows_; ++i) {
1248 l_getline(is, line);
1249 if (!prefixIs(line, "<row")) {
1250 lyxerr << "Wrong tabular format (expected <row ...> got"
1251 << line << ')' << endl;
1254 getTokenValue(line, "topline", row_info[i].top_line);
1255 getTokenValue(line, "bottomline", row_info[i].bottom_line);
1256 getTokenValue(line, "endfirsthead", row_info[i].endfirsthead);
1257 getTokenValue(line, "endhead", row_info[i].endhead);
1258 getTokenValue(line, "endfoot", row_info[i].endfoot);
1259 getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
1260 getTokenValue(line, "newpage", row_info[i].newpage);
1261 for (int j = 0; j < columns_; ++j) {
1262 l_getline(is, line);
1263 if (!prefixIs(line, "<cell")) {
1264 lyxerr << "Wrong tabular format (expected <cell ...> got"
1265 << line << ')' << endl;
1268 getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1269 getTokenValue(line, "alignment", cell_info[i][j].alignment);
1270 getTokenValue(line, "valignment", cell_info[i][j].valignment);
1271 getTokenValue(line, "topline", cell_info[i][j].top_line);
1272 getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1273 getTokenValue(line, "leftline", cell_info[i][j].left_line);
1274 getTokenValue(line, "rightline", cell_info[i][j].right_line);
1275 getTokenValue(line, "rotate", cell_info[i][j].rotate);
1276 getTokenValue(line, "usebox", cell_info[i][j].usebox);
1277 getTokenValue(line, "width", cell_info[i][j].p_width);
1278 getTokenValue(line, "special", cell_info[i][j].align_special);
1279 l_getline(is, line);
1280 if (prefixIs(line, "\\begin_inset")) {
1281 cell_info[i][j].inset.read(buf, lex);
1282 l_getline(is, line);
1284 if (!prefixIs(line, "</cell>")) {
1285 lyxerr << "Wrong tabular format (expected </cell> got"
1286 << line << ')' << endl;
1290 l_getline(is, line);
1291 if (!prefixIs(line, "</row>")) {
1292 lyxerr << "Wrong tabular format (expected </row> got"
1293 << line << ')' << endl;
1297 while (!prefixIs(line, "</lyxtabular>")) {
1298 l_getline(is, line);
1300 set_row_column_number_info();
1304 bool LyXTabular::IsMultiColumn(int cell, bool real) const
1306 return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
1307 (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
1311 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
1313 int const row = row_of_cell(cell);
1314 int const column = column_of_cell(cell);
1315 return &cell_info[row][column];
1319 void LyXTabular::SetMultiColumn(Buffer * buffer, int cell, int number)
1321 cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1322 cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
1323 cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
1324 cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
1325 cellinfo_of_cell(cell)->right_line = column_info[column_of_cell(cell+number-1)].right_line;
1327 for (int i = 1; i < number; ++i) {
1328 cellinfo_of_cell(cell + i)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1329 cellinfo_of_cell(cell)->inset.appendParagraphs(buffer,
1330 cellinfo_of_cell(cell+i)->inset.paragraphs);
1331 cellinfo_of_cell(cell + i)->inset.clear(false);
1334 for (number--; number > 0; --number) {
1335 cellinfo_of_cell(cell + number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1338 set_row_column_number_info();
1342 int LyXTabular::cells_in_multicolumn(int cell) const
1344 int const row = row_of_cell(cell);
1345 int column = column_of_cell(cell);
1348 while ((column < columns_) &&
1349 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1358 int LyXTabular::UnsetMultiColumn(int cell)
1360 int const row = row_of_cell(cell);
1361 int column = column_of_cell(cell);
1365 if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1366 cell_info[row][column].multicolumn = CELL_NORMAL;
1368 while ((column < columns_) &&
1369 (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
1371 cell_info[row][column].multicolumn = CELL_NORMAL;
1376 set_row_column_number_info();
1381 void LyXTabular::SetLongTabular(bool what)
1383 is_long_tabular = what;
1387 bool LyXTabular::IsLongTabular() const
1389 return is_long_tabular;
1393 void LyXTabular::SetRotateTabular(bool flag)
1399 bool LyXTabular::GetRotateTabular() const
1405 void LyXTabular::SetRotateCell(int cell, bool flag)
1407 cellinfo_of_cell(cell)->rotate = flag;
1411 bool LyXTabular::GetRotateCell(int cell) const
1413 return cellinfo_of_cell(cell)->rotate;
1417 bool LyXTabular::NeedRotating() const
1421 for (int i = 0; i < rows_; ++i) {
1422 for (int j = 0; j < columns_; ++j) {
1423 if (cell_info[i][j].rotate)
1431 bool LyXTabular::IsLastCell(int cell) const
1433 if ((cell + 1) < numberofcells)
1439 int LyXTabular::GetCellAbove(int cell) const
1441 if (row_of_cell(cell) > 0)
1442 return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1447 int LyXTabular::GetCellBelow(int cell) const
1449 if (row_of_cell(cell) + 1 < rows_)
1450 return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1455 int LyXTabular::GetLastCellAbove(int cell) const
1457 if (row_of_cell(cell) <= 0)
1459 if (!IsMultiColumn(cell))
1460 return GetCellAbove(cell);
1461 return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1465 int LyXTabular::GetLastCellBelow(int cell) const
1467 if (row_of_cell(cell) + 1 >= rows_)
1469 if (!IsMultiColumn(cell))
1470 return GetCellBelow(cell);
1471 return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1475 int LyXTabular::GetCellNumber(int row, int column) const
1478 if (column >= columns_)
1479 column = columns_ - 1;
1480 else if (column < 0)
1487 lyx::Assert(column >= 0 || column < columns_ || row >= 0 || row < rows_);
1489 return cell_info[row][column].cellno;
1493 void LyXTabular::SetUsebox(int cell, BoxType type)
1495 cellinfo_of_cell(cell)->usebox = type;
1499 LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
1501 if (column_info[column_of_cell(cell)].p_width.zero() &&
1502 !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.zero()))
1504 if (cellinfo_of_cell(cell)->usebox > 1)
1505 return cellinfo_of_cell(cell)->usebox;
1506 return UseParbox(cell);
1511 // This are functions used for the longtable support
1513 void LyXTabular::SetLTHead(int row, bool flag, ltType const & hd, bool first)
1518 row_info[row].endfirsthead = flag;
1522 row_info[row].endhead = flag;
1527 bool LyXTabular::GetRowOfLTHead(int row, ltType & hd) const
1530 hd.set = haveLTHead();
1531 return row_info[row].endhead;
1535 bool LyXTabular::GetRowOfLTFirstHead(int row, ltType & hd) const
1538 hd.set = haveLTFirstHead();
1539 return row_info[row].endfirsthead;
1543 void LyXTabular::SetLTFoot(int row, bool flag, ltType const & fd, bool last)
1548 row_info[row].endlastfoot = flag;
1552 row_info[row].endfoot = flag;
1557 bool LyXTabular::GetRowOfLTFoot(int row, ltType & fd) const
1560 fd.set = haveLTFoot();
1561 return row_info[row].endfoot;
1565 bool LyXTabular::GetRowOfLTLastFoot(int row, ltType & fd) const
1568 fd.set = haveLTLastFoot();
1569 return row_info[row].endlastfoot;
1573 void LyXTabular::SetLTNewPage(int row, bool what)
1575 row_info[row].newpage = what;
1579 bool LyXTabular::GetLTNewPage(int row) const
1581 return row_info[row].newpage;
1585 bool LyXTabular::haveLTHead() const
1587 for(int i=0; i < rows_; ++i) {
1588 if (row_info[i].endhead)
1595 bool LyXTabular::haveLTFirstHead() const
1597 if (endfirsthead.empty)
1599 for(int i=0; i < rows_; ++i) {
1600 if (row_info[i].endfirsthead)
1607 bool LyXTabular::haveLTFoot() const
1609 for(int i=0; i < rows_; ++i) {
1610 if (row_info[i].endfoot)
1617 bool LyXTabular::haveLTLastFoot() const
1619 if (endlastfoot.empty)
1621 for(int i=0; i < rows_; ++i) {
1622 if (row_info[i].endlastfoot)
1629 // end longtable support functions
1631 bool LyXTabular::SetAscentOfRow(int row, int height)
1633 if ((row >= rows_) || (row_info[row].ascent_of_row == height))
1635 row_info[row].ascent_of_row = height;
1640 bool LyXTabular::SetDescentOfRow(int row, int height)
1642 if ((row >= rows_) || (row_info[row].descent_of_row == height))
1644 row_info[row].descent_of_row = height;
1649 int LyXTabular::GetAscentOfRow(int row) const
1653 return row_info[row].ascent_of_row;
1657 int LyXTabular::GetDescentOfRow(int row) const
1661 return row_info[row].descent_of_row;
1665 int LyXTabular::GetHeightOfTabular() const
1669 for (int row = 0; row < rows_; ++row)
1670 height += GetAscentOfRow(row) + GetDescentOfRow(row) +
1671 GetAdditionalHeight(row);
1676 bool LyXTabular::IsPartOfMultiColumn(int row, int column) const
1678 if ((row >= rows_) || (column >= columns_))
1680 return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
1684 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1686 if ((row < 0) || (row >= rows_))
1689 int const fcell = GetFirstCellInRow(row);
1690 int const n = NumberOfCellsInRow(fcell) + fcell;
1693 for (int i = fcell; i < n; ++i) {
1697 if (tmp == (n - fcell)) {
1700 for (int i = fcell; i < n; ++i) {
1703 << column_of_cell(i) + 1
1705 << right_column_of_cell(i) + 1
1717 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1719 if ((row < 0) || (row >= rows_))
1722 int const fcell = GetFirstCellInRow(row);
1723 int const n = NumberOfCellsInRow(fcell) + fcell;
1726 for (int i = fcell; i < n; ++i) {
1730 if (tmp == (n - fcell)) {
1733 for (int i = fcell; i < n; ++i) {
1734 if (BottomLine(i)) {
1736 << column_of_cell(i) + 1
1738 << right_column_of_cell(i) + 1
1750 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
1754 if (GetRotateCell(cell)) {
1755 os << "\\begin{sideways}\n";
1758 if (IsMultiColumn(cell)) {
1759 os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
1760 if (!cellinfo_of_cell(cell)->align_special.empty()) {
1761 os << cellinfo_of_cell(cell)->align_special << "}{";
1763 if (LeftLine(cell) &&
1764 (IsFirstCellInRow(cell) ||
1765 (!IsMultiColumn(cell-1) && !LeftLine(cell, true) &&
1766 !RightLine(cell-1, true))))
1770 if (!GetPWidth(cell).zero()) {
1771 switch (GetVAlignment(cell)) {
1772 case LYX_VALIGN_TOP:
1775 case LYX_VALIGN_CENTER:
1778 case LYX_VALIGN_BOTTOM:
1783 << GetPWidth(cell).asLatexString()
1786 switch (GetAlignment(cell)) {
1787 case LYX_ALIGN_LEFT:
1790 case LYX_ALIGN_RIGHT:
1798 if (RightLine(cell))
1800 if (((cell + 1) < numberofcells) && !IsFirstCellInRow(cell+1) &&
1806 if (GetUsebox(cell) == BOX_PARBOX) {
1808 switch (GetVAlignment(cell)) {
1809 case LYX_VALIGN_TOP:
1812 case LYX_VALIGN_CENTER:
1815 case LYX_VALIGN_BOTTOM:
1819 os << "]{" << GetPWidth(cell).asLatexString() << "}{";
1820 } else if (GetUsebox(cell) == BOX_MINIPAGE) {
1821 os << "\\begin{minipage}[";
1822 switch (GetVAlignment(cell)) {
1823 case LYX_VALIGN_TOP:
1826 case LYX_VALIGN_CENTER:
1829 case LYX_VALIGN_BOTTOM:
1833 os << "]{" << GetPWidth(cell).asLatexString() << "}\n";
1840 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
1845 if (GetUsebox(cell) == BOX_PARBOX)
1847 else if (GetUsebox(cell) == BOX_MINIPAGE) {
1848 os << "%\n\\end{minipage}";
1851 if (IsMultiColumn(cell)) {
1854 if (GetRotateCell(cell)) {
1855 os << "%\n\\end{sideways}";
1862 int LyXTabular::TeXLongtableHeaderFooter(ostream & os, Buffer const * buf,
1863 LatexRunParams const & runparams) const
1865 if (!is_long_tabular)
1869 // output header info
1871 if (endhead.topDL) {
1875 for (int i = 0; i < rows_; ++i) {
1876 if (row_info[i].endhead) {
1877 ret += TeXRow(os, i, buf, runparams);
1880 if (endhead.bottomDL) {
1884 os << "\\endhead\n";
1886 if (endfirsthead.empty) {
1887 os << "\\endfirsthead\n";
1891 // output firstheader info
1892 if (haveLTFirstHead()) {
1893 if (endfirsthead.topDL) {
1897 for (int i = 0; i < rows_; ++i) {
1898 if (row_info[i].endfirsthead) {
1899 ret += TeXRow(os, i, buf, runparams);
1902 if (endfirsthead.bottomDL) {
1906 os << "\\endfirsthead\n";
1909 // output footer info
1911 if (endfoot.topDL) {
1915 for (int i = 0; i < rows_; ++i) {
1916 if (row_info[i].endfoot) {
1917 ret += TeXRow(os, i, buf, runparams);
1920 if (endfoot.bottomDL) {
1924 os << "\\endfoot\n";
1926 if (endlastfoot.empty) {
1927 os << "\\endlastfoot\n";
1931 // output lastfooter info
1932 if (haveLTLastFoot()) {
1933 if (endlastfoot.topDL) {
1937 for (int i = 0; i < rows_; ++i) {
1938 if (row_info[i].endlastfoot) {
1939 ret += TeXRow(os, i, buf, runparams);
1942 if (endlastfoot.bottomDL) {
1946 os << "\\endlastfoot\n";
1953 bool LyXTabular::isValidRow(int const row) const
1955 if (!is_long_tabular)
1957 return (!row_info[row].endhead && !row_info[row].endfirsthead &&
1958 !row_info[row].endfoot && !row_info[row].endlastfoot);
1962 int LyXTabular::TeXRow(ostream & os, int const i, Buffer const * buf,
1963 LatexRunParams const & runparams) const
1966 int cell = GetCellNumber(i, 0);
1968 ret += TeXTopHLine(os, i);
1969 for (int j = 0; j < columns_; ++j) {
1970 if (IsPartOfMultiColumn(i,j))
1972 ret += TeXCellPreamble(os, cell);
1973 InsetText * inset = GetCellInset(cell);
1975 bool rtl = inset->paragraphs.begin()->isRightToLeftPar(buf->params) &&
1976 !inset->paragraphs.begin()->empty() && GetPWidth(cell).zero();
1980 ret += inset->latex(buf, os, runparams);
1984 ret += TeXCellPostamble(os, cell);
1985 if (!IsLastCellInRow(cell)) { // not last cell in row
1991 os << "\\tabularnewline\n";
1993 ret += TeXBottomHLine(os, i);
1998 int LyXTabular::latex(Buffer const * buf, ostream & os,
1999 LatexRunParams const & runparams) const
2003 //+---------------------------------------------------------------------
2004 //+ first the opening preamble +
2005 //+---------------------------------------------------------------------
2008 os << "\\begin{sideways}\n";
2011 if (is_long_tabular)
2012 os << "\\begin{longtable}{";
2014 os << "\\begin{tabular}{";
2015 for (int i = 0; i < columns_; ++i) {
2016 if (!column_info[i].align_special.empty()) {
2017 os << column_info[i].align_special;
2019 if (column_info[i].left_line)
2021 if (!column_info[i].p_width.zero()) {
2022 switch (column_info[i].alignment) {
2023 case LYX_ALIGN_LEFT:
2024 os << ">{\\raggedright}";
2026 case LYX_ALIGN_RIGHT:
2027 os << ">{\\raggedleft}";
2029 case LYX_ALIGN_CENTER:
2030 os << ">{\\centering}";
2032 case LYX_ALIGN_NONE:
2033 case LYX_ALIGN_BLOCK:
2034 case LYX_ALIGN_LAYOUT:
2035 case LYX_ALIGN_SPECIAL:
2039 switch (column_info[i].valignment) {
2040 case LYX_VALIGN_TOP:
2043 case LYX_VALIGN_CENTER:
2046 case LYX_VALIGN_BOTTOM:
2051 << column_info[i].p_width.asLatexString()
2054 switch (column_info[i].alignment) {
2055 case LYX_ALIGN_LEFT:
2058 case LYX_ALIGN_RIGHT:
2066 if (column_info[i].right_line)
2073 ret += TeXLongtableHeaderFooter(os, buf, runparams);
2075 //+---------------------------------------------------------------------
2076 //+ the single row and columns (cells) +
2077 //+---------------------------------------------------------------------
2079 for (int i = 0; i < rows_; ++i) {
2080 if (isValidRow(i)) {
2081 ret += TeXRow(os, i, buf, runparams);
2082 if (is_long_tabular && row_info[i].newpage) {
2083 os << "\\newpage\n";
2089 //+---------------------------------------------------------------------
2090 //+ the closing of the tabular +
2091 //+---------------------------------------------------------------------
2093 if (is_long_tabular)
2094 os << "\\end{longtable}";
2096 os << "\\end{tabular}";
2098 os << "\n\\end{sideways}";
2106 int LyXTabular::docbookRow(Buffer const * buf, ostream & os, int row) const
2109 int cell = GetFirstCellInRow(row);
2112 for (int j = 0; j < columns_; ++j) {
2113 if (IsPartOfMultiColumn(row, j))
2116 os << "<entry align=\"";
2117 switch (GetAlignment(cell)) {
2118 case LYX_ALIGN_LEFT:
2121 case LYX_ALIGN_RIGHT:
2129 os << "\" valign=\"";
2130 switch (GetVAlignment(cell)) {
2131 case LYX_VALIGN_TOP:
2134 case LYX_VALIGN_BOTTOM:
2137 case LYX_VALIGN_CENTER:
2142 if (IsMultiColumn(cell)) {
2143 os << " namest=\"col" << j << "\" ";
2144 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
2148 ret += GetCellInset(cell)->docbook(buf, os, true);
2157 int LyXTabular::docbook(Buffer const * buf, ostream & os,
2158 bool /*mixcont*/) const
2162 //+---------------------------------------------------------------------
2163 //+ first the opening preamble +
2164 //+---------------------------------------------------------------------
2166 os << "<tgroup cols=\"" << columns_
2167 << "\" colsep=\"1\" rowsep=\"1\">\n";
2169 for (int i = 0; i < columns_; ++i) {
2170 os << "<colspec colname=\"col" << i << "\" align=\"";
2171 switch (column_info[i].alignment) {
2172 case LYX_ALIGN_LEFT:
2175 case LYX_ALIGN_RIGHT:
2186 //+---------------------------------------------------------------------
2187 //+ Long Tabular case +
2188 //+---------------------------------------------------------------------
2190 // output header info
2191 if (haveLTHead() || haveLTFirstHead()) {
2194 for (int i = 0; i < rows_; ++i) {
2195 if (row_info[i].endhead || row_info[i].endfirsthead) {
2196 ret += docbookRow(buf, os, i);
2202 // output footer info
2203 if (haveLTFoot() || haveLTLastFoot()) {
2206 for (int i = 0; i < rows_; ++i) {
2207 if (row_info[i].endfoot || row_info[i].endlastfoot) {
2208 ret += docbookRow(buf, os, i);
2215 //+---------------------------------------------------------------------
2216 //+ the single row and columns (cells) +
2217 //+---------------------------------------------------------------------
2221 for (int i = 0; i < rows_; ++i) {
2222 if (isValidRow(i)) {
2223 ret += docbookRow(buf, os, i);
2228 //+---------------------------------------------------------------------
2229 //+ the closing of the tabular +
2230 //+---------------------------------------------------------------------
2239 // ASCII export function and helpers
2241 int LyXTabular::asciiTopHLine(ostream & os, int row,
2242 vector<unsigned int> const & clen) const
2244 int const fcell = GetFirstCellInRow(row);
2245 int const n = NumberOfCellsInRow(fcell) + fcell;
2248 for (int i = fcell; i < n; ++i) {
2258 for (int i = fcell; i < n; ++i) {
2269 int column = column_of_cell(i);
2270 int len = clen[column];
2271 while (IsPartOfMultiColumn(row, ++column))
2272 len += clen[column] + 4;
2273 os << string(len, ch);
2288 int LyXTabular::asciiBottomHLine(ostream & os, int row,
2289 vector<unsigned int> const & clen) const
2291 int const fcell = GetFirstCellInRow(row);
2292 int const n = NumberOfCellsInRow(fcell) + fcell;
2295 for (int i = fcell; i < n; ++i) {
2296 if (BottomLine(i)) {
2305 for (int i = fcell; i < n; ++i) {
2306 if (BottomLine(i)) {
2316 int column = column_of_cell(i);
2317 int len = clen[column];
2318 while (IsPartOfMultiColumn(row, ++column))
2319 len += clen[column] + 4;
2320 os << string(len, ch);
2321 if (BottomLine(i)) {
2335 int LyXTabular::asciiPrintCell(Buffer const * buf, ostream & os,
2336 int cell, int row, int column,
2337 vector<unsigned int> const & clen,
2338 bool onlydata) const
2341 int ret = GetCellInset(cell)->ascii(buf, sstr, 0);
2353 unsigned int len1 = sstr.str().length();
2354 unsigned int len2 = clen[column];
2355 while (IsPartOfMultiColumn(row, ++column))
2356 len2 += clen[column] + 4;
2359 switch (GetAlignment(cell)) {
2361 case LYX_ALIGN_LEFT:
2364 case LYX_ALIGN_RIGHT:
2368 case LYX_ALIGN_CENTER:
2374 os << string(len1, ' ') << sstr.str() << string(len2, ' ');
2376 if (RightLine(cell))
2385 int LyXTabular::ascii(Buffer const * buf, ostream & os, int const depth,
2386 bool onlydata, unsigned char delim) const
2390 // first calculate the width of the single columns
2391 vector<unsigned int> clen(columns_);
2394 // first all non (real) multicolumn cells!
2395 for (int j = 0; j < columns_; ++j) {
2397 for (int i = 0; i < rows_; ++i) {
2398 int cell = GetCellNumber(i, j);
2399 if (IsMultiColumn(cell, true))
2402 GetCellInset(cell)->ascii(buf, sstr, 0);
2403 if (clen[j] < sstr.str().length())
2404 clen[j] = sstr.str().length();
2407 // then all (real) multicolumn cells!
2408 for (int j = 0; j < columns_; ++j) {
2409 for (int i = 0; i < rows_; ++i) {
2410 int cell = GetCellNumber(i, j);
2411 if (!IsMultiColumn(cell, true) || IsPartOfMultiColumn(i, j))
2414 GetCellInset(cell)->ascii(buf, sstr, 0);
2415 int len = int(sstr.str().length());
2416 int const n = cells_in_multicolumn(cell);
2417 for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2419 if (len > int(clen[j + n - 1]))
2420 clen[j + n - 1] = len;
2425 for (int i = 0; i < rows_; ++i) {
2427 if (asciiTopHLine(os, i, clen)) {
2428 for (int j = 0; j < depth; ++j)
2432 for (int j = 0; j < columns_; ++j) {
2433 if (IsPartOfMultiColumn(i,j))
2435 if (onlydata && j > 0)
2437 ret += asciiPrintCell(buf, os, cell, i, j, clen, onlydata);
2442 for (int j = 0; j < depth; ++j)
2444 if (asciiBottomHLine(os, i, clen)) {
2445 for (int j = 0; j < depth; ++j)
2457 InsetText * LyXTabular::GetCellInset(int cell) const
2460 return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2464 InsetText * LyXTabular::GetCellInset(int row, int column) const
2466 cur_cell = GetCellNumber(row, column);
2467 return & cell_info[row][column].inset;
2471 int LyXTabular::GetCellFromInset(Inset const * inset, int maybe_cell) const
2473 // is this inset part of the tabular?
2474 if (!inset || inset->owner() != owner_) {
2475 lyxerr[Debug::INSETTEXT]
2476 << "this is not a cell of the tabular!" << endl;
2480 const int save_cur_cell = cur_cell;
2481 int cell = cur_cell;
2482 if (GetCellInset(cell) != inset) {
2484 if (cell == -1 || GetCellInset(cell) != inset) {
2490 for (cell = GetNumberOfCells(); cell >= 0; --cell) {
2491 if (GetCellInset(cell) == inset)
2494 lyxerr[Debug::INSETTEXT]
2495 << "LyXTabular::GetCellFromInset: "
2497 << ", cur_cell=" << save_cur_cell
2498 << ", maybe_cell=" << maybe_cell
2500 // We should have found a cell at this point
2502 lyxerr << "LyXTabular::GetCellFromInset: "
2503 << "Cell not found!" << endl;
2511 void LyXTabular::Validate(LaTeXFeatures & features) const
2513 features.require("NeedTabularnewline");
2514 if (IsLongTabular())
2515 features.require("longtable");
2517 features.require("rotating");
2518 for (int cell = 0; cell < numberofcells; ++cell) {
2519 if ((GetVAlignment(cell) != LYX_VALIGN_TOP) ||
2520 (!(GetPWidth(cell).zero())&&!(IsMultiColumn(cell))))
2521 features.require("array");
2522 GetCellInset(cell)->validate(features);
2527 vector<string> const LyXTabular::getLabelList() const
2529 vector<string> label_list;
2530 for (int i = 0; i < rows_; ++i)
2531 for (int j = 0; j < columns_; ++j) {
2532 vector<string> const l =
2533 GetCellInset(i, j)->getLabelList();
2534 label_list.insert(label_list.end(),
2535 l.begin(), l.end());
2541 LyXTabular::BoxType LyXTabular::UseParbox(int cell) const
2543 ParagraphList const & parlist = GetCellInset(cell)->paragraphs;
2544 ParagraphList::const_iterator cit = parlist.begin();
2545 ParagraphList::const_iterator end = parlist.end();
2547 for (; cit != end; ++cit) {
2548 for (int i = 0; i < cit->size(); ++i) {
2549 if (cit->isNewline(i))