3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Matthias Ettrich
9 * \author Jean-Marc Lasgouttes
10 * \author Angus Leeming
12 * \author André Pönitz
13 * \author Jürgen Vigna
15 * Full author contact details are available in file CREDITS.
23 #include "bufferparams.h"
25 #include "LaTeXFeatures.h"
27 #include "outputparams.h"
28 #include "paragraph.h"
30 #include "insets/insettabular.h"
32 #include "support/lstrings.h"
33 #include "support/tostr.h"
37 using lyx::support::ltrim;
38 using lyx::support::prefixIs;
39 using lyx::support::rtrim;
40 using lyx::support::strToInt;
41 using lyx::support::suffixIs;
43 using boost::shared_ptr;
44 using boost::dynamic_pointer_cast;
53 using std::ostringstream;
57 #ifndef CXX_GLOBAL_CSTD
64 int const WIDTH_OF_LINE = 5;
67 string const write_attribute(string const & name, T const & t)
69 string const s = tostr(t);
70 return s.empty() ? s : " " + name + "=\"" + s + "\"";
73 string const write_attribute(string const & name, string const & t)
75 return t.empty() ? t : " " + name + "=\"" + t + "\"";
79 string const write_attribute(string const & name, bool const & b)
81 // we write only true attribute values so we remove a bit of the
82 // file format bloat for tabulars.
83 return b ? write_attribute(name, tostr(b)) : string();
87 string const write_attribute(string const & name, int const & i)
89 // we write only true attribute values so we remove a bit of the
90 // file format bloat for tabulars.
91 return i ? write_attribute(name, tostr(i)) : string();
95 string const write_attribute(string const & name, LyXLength const & value)
97 // we write only the value if we really have one same reson as above.
98 return value.zero() ? string() : write_attribute(name, value.asString());
102 string const tostr(LyXAlignment const & num)
107 case LYX_ALIGN_BLOCK:
111 case LYX_ALIGN_CENTER:
113 case LYX_ALIGN_RIGHT:
115 case LYX_ALIGN_LAYOUT:
117 case LYX_ALIGN_SPECIAL:
124 string const tostr(LyXTabular::VAlignment const & num)
127 case LyXTabular::LYX_VALIGN_TOP:
129 case LyXTabular::LYX_VALIGN_MIDDLE:
131 case LyXTabular::LYX_VALIGN_BOTTOM:
138 string const tostr(LyXTabular::BoxType const & num)
141 case LyXTabular::BOX_NONE:
143 case LyXTabular::BOX_PARBOX:
145 case LyXTabular::BOX_MINIPAGE:
152 // I would have liked a fromstr template a lot better. (Lgb)
153 bool string2type(string const str, LyXAlignment & num)
156 num = LYX_ALIGN_NONE;
157 else if (str == "block")
158 num = LYX_ALIGN_BLOCK;
159 else if (str == "left")
160 num = LYX_ALIGN_LEFT;
161 else if (str == "center")
162 num = LYX_ALIGN_CENTER;
163 else if (str == "right")
164 num = LYX_ALIGN_RIGHT;
171 bool string2type(string const str, LyXTabular::VAlignment & num)
174 num = LyXTabular::LYX_VALIGN_TOP;
175 else if (str == "middle" )
176 num = LyXTabular::LYX_VALIGN_MIDDLE;
177 else if (str == "bottom")
178 num = LyXTabular::LYX_VALIGN_BOTTOM;
185 bool string2type(string const str, LyXTabular::BoxType & num)
188 num = LyXTabular::BOX_NONE;
189 else if (str == "parbox")
190 num = LyXTabular::BOX_PARBOX;
191 else if (str == "minipage")
192 num = LyXTabular::BOX_MINIPAGE;
199 bool string2type(string const str, bool & num)
203 else if (str == "false")
211 bool getTokenValue(string const & str, char const * token, string & ret)
214 size_t token_length = strlen(token);
215 string::size_type pos = str.find(token);
217 if (pos == string::npos || pos + token_length + 1 >= str.length()
218 || str[pos + token_length] != '=')
220 pos += token_length + 1;
222 if (ch != '"' && ch != '\'') { // only read till next space
226 while (pos < str.length() - 1 && str[++pos] != ch)
233 bool getTokenValue(string const & str, char const * token, int & num)
237 if (!getTokenValue(str, token, tmp))
244 bool getTokenValue(string const & str, char const * token, LyXAlignment & num)
247 return getTokenValue(str, token, tmp) && string2type(tmp, num);
251 bool getTokenValue(string const & str, char const * token,
252 LyXTabular::VAlignment & num)
255 return getTokenValue(str, token, tmp) && string2type(tmp, num);
259 bool getTokenValue(string const & str, char const * token,
260 LyXTabular::BoxType & num)
263 return getTokenValue(str, token, tmp) && string2type(tmp, num);
267 bool getTokenValue(string const & str, char const * token, bool & flag)
269 // set the flag always to false as this should be the default for bools
270 // not in the file-format.
273 return getTokenValue(str, token, tmp) && string2type(tmp, flag);
277 bool getTokenValue(string const & str, char const * token, LyXLength & len)
279 // set the lenght to be zero() as default as this it should be if not
280 // in the file format.
283 return getTokenValue(str, token, tmp) && isValidLength(tmp, &len);
287 void l_getline(istream & is, string & str)
290 while (str.empty()) {
292 if (!str.empty() && str[str.length() - 1] == '\r')
293 str.erase(str.length() - 1);
299 /// Define a few methods for the inner structs
301 LyXTabular::cellstruct::cellstruct(BufferParams const & bp)
304 multicolumn(LyXTabular::CELL_NORMAL),
305 alignment(LYX_ALIGN_CENTER),
306 valignment(LYX_VALIGN_TOP),
313 inset(new InsetText(bp))
317 LyXTabular::cellstruct::cellstruct(cellstruct const & cs)
319 width_of_cell(cs.width_of_cell),
320 multicolumn(cs.multicolumn),
321 alignment(cs.alignment),
322 valignment(cs.valignment),
323 top_line(cs.top_line),
324 bottom_line(cs.bottom_line),
325 left_line(cs.left_line),
326 right_line(cs.right_line),
329 align_special(cs.align_special),
331 inset(dynamic_cast<InsetText*>(cs.inset->clone().release()))
335 LyXTabular::cellstruct &
336 LyXTabular::cellstruct::operator=(cellstruct cs)
344 LyXTabular::cellstruct::swap(cellstruct & rhs)
346 std::swap(cellno, rhs.cellno);
347 std::swap(width_of_cell, rhs.width_of_cell);
348 std::swap(multicolumn, rhs.multicolumn);
349 std::swap(alignment, rhs.alignment);
350 std::swap(valignment, rhs.valignment);
351 std::swap(top_line, rhs.top_line);
352 std::swap(bottom_line, rhs.bottom_line);
353 std::swap(left_line, rhs.left_line);
354 std::swap(right_line, rhs.right_line);
355 std::swap(usebox, rhs.usebox);
356 std::swap(rotate, rhs.rotate);
357 std::swap(align_special, rhs.align_special);
358 p_width.swap(rhs.p_width);
359 inset.swap(rhs.inset);
363 LyXTabular::rowstruct::rowstruct()
376 LyXTabular::columnstruct::columnstruct()
377 : alignment(LYX_ALIGN_CENTER),
378 valignment(LYX_VALIGN_TOP),
386 LyXTabular::ltType::ltType()
393 LyXTabular::LyXTabular(BufferParams const & bp, int rows_arg, int columns_arg)
395 init(bp, rows_arg, columns_arg);
399 // activates all lines and sets all widths to 0
400 void LyXTabular::init(BufferParams const & bp, int rows_arg, int columns_arg)
403 columns_ = columns_arg;
404 row_info = row_vector(rows_);
405 column_info = column_vector(columns_);
406 cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
407 row_info.reserve(10);
408 column_info.reserve(10);
409 cell_info.reserve(100);
411 for (int i = 0; i < rows_; ++i)
412 cell_info[i].back().right_line = true;
413 row_info.back().bottom_line = true;
414 row_info.front().bottom_line = true;
415 column_info.back().right_line = true;
416 is_long_tabular = false;
421 void LyXTabular::fixCellNums()
424 for (int i = 0; i < rows_; ++i) {
425 for (int j = 0; j < columns_; ++j) {
426 // When debugging it can be nice to set
428 cell_info[i][j].inset->setDrawFrame(false);
429 cell_info[i][j].cellno = cellno++;
431 cell_info[i].back().right_line = true;
434 set_row_column_number_info();
438 void LyXTabular::appendRow(BufferParams const & bp, int const cell)
442 int const row = row_of_cell(cell);
444 row_vector::iterator rit = row_info.begin() + row;
445 row_info.insert(rit, rowstruct());
446 // now set the values of the row before
447 row_info[row] = row_info[row + 1];
449 cell_vvector old(rows_ - 1);
450 for (int i = 0; i < rows_ - 1; ++i)
451 swap(cell_info[i], old[i]);
453 cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
455 for (int i = 0; i <= row; ++i)
456 swap(cell_info[i], old[i]);
457 for (int i = row + 2; i < rows_; ++i)
458 swap(cell_info[i], old[i - 1]);
460 if (bp.tracking_changes)
461 for (int j = 0; j < columns_; ++j)
462 cell_info[row + 1][j].inset->markNew(true);
464 set_row_column_number_info();
468 void LyXTabular::deleteRow(int const row)
470 // Not allowed to delete last row
474 row_info.erase(row_info.begin() + row);
475 cell_info.erase(cell_info.begin() + row);
481 void LyXTabular::appendColumn(BufferParams const & bp, int const cell)
485 int const column = column_of_cell(cell);
486 column_vector::iterator cit = column_info.begin() + column + 1;
487 column_info.insert(cit, columnstruct());
488 // set the column values of the column before
489 column_info[column + 1] = column_info[column];
491 for (int i = 0; i < rows_; ++i) {
492 cell_info[i].insert(cell_info[i].begin() + column + 1, cellstruct(bp));
494 // care about multicolumns
495 if (cell_info[i][column + 1].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
496 cell_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
498 if (column + 2 >= columns_
499 || cell_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
500 cell_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
503 for (int i = 0; i < rows_; ++i) {
504 cell_info[i][column + 1].inset->clear(false);
505 if (bp.tracking_changes)
506 cell_info[i][column + 1].inset->markNew(true);
512 void LyXTabular::deleteColumn(int const column)
514 // Not allowed to delete last column
518 column_info.erase(column_info.begin() + column);
519 for (int i = 0; i < rows_; ++i)
520 cell_info[i].erase(cell_info[i].begin() + column);
526 void LyXTabular::set_row_column_number_info()
529 for (int row = 0; row < rows_; ++row) {
530 for (int column = 0; column < columns_; ++column) {
531 if (cell_info[row][column].multicolumn
532 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
534 cell_info[row][column].cellno = numberofcells;
537 ++numberofcells; // because this is one more than as we start from 0
539 rowofcell.resize(numberofcells);
540 columnofcell.resize(numberofcells);
542 for (int row = 0, column = 0, c = 0;
543 c < numberofcells && row < rows_ && column < columns_;) {
545 columnofcell[c] = column;
549 } while (column < columns_ &&
550 cell_info[row][column].multicolumn
551 == LyXTabular::CELL_PART_OF_MULTICOLUMN);
553 if (column == columns_) {
559 for (int row = 0; row < rows_; ++row) {
560 for (int column = 0; column < columns_; ++column) {
561 if (isPartOfMultiColumn(row,column))
563 cell_info[row][column].inset->setAutoBreakRows(
564 !getPWidth(getCellNumber(row, column)).zero());
570 int LyXTabular::getNumberOfCells() const
572 return numberofcells;
576 int LyXTabular::numberOfCellsInRow(int const cell) const
578 int const row = row_of_cell(cell);
580 for (int i = 0; i < columns_; ++i)
581 if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
587 // returns 1 if there is a topline, returns 0 if not
588 bool LyXTabular::topLine(int const cell, bool const onlycolumn) const
590 if (!onlycolumn && isMultiColumn(cell))
591 return cellinfo_of_cell(cell).top_line;
592 return row_info[row_of_cell(cell)].top_line;
596 bool LyXTabular::bottomLine(int cell, bool onlycolumn) const
598 if (!onlycolumn && isMultiColumn(cell))
599 return cellinfo_of_cell(cell).bottom_line;
600 return row_info[row_of_cell(cell)].bottom_line;
604 bool LyXTabular::leftLine(int cell, bool onlycolumn) const
606 if (!onlycolumn && isMultiColumn(cell) &&
607 (isFirstCellInRow(cell) || isMultiColumn(cell-1)))
609 if (cellinfo_of_cell(cell).align_special.empty())
610 return cellinfo_of_cell(cell).left_line;
611 return prefixIs(ltrim(cellinfo_of_cell(cell).align_special), "|");
613 if (column_info[column_of_cell(cell)].align_special.empty())
614 return column_info[column_of_cell(cell)].left_line;
615 return prefixIs(ltrim(column_info[column_of_cell(cell)].align_special), "|");
619 bool LyXTabular::rightLine(int cell, bool onlycolumn) const
621 if (!onlycolumn && isMultiColumn(cell) &&
622 (isLastCellInRow(cell) || isMultiColumn(cell + 1)))
624 if (cellinfo_of_cell(cell).align_special.empty())
625 return cellinfo_of_cell(cell).right_line;
626 return suffixIs(rtrim(cellinfo_of_cell(cell).align_special), "|");
628 if (column_info[column_of_cell(cell)].align_special.empty())
629 return column_info[right_column_of_cell(cell)].right_line;
630 return suffixIs(rtrim(column_info[column_of_cell(cell)].align_special), "|");
634 bool LyXTabular::topAlreadyDrawn(int cell) const
636 int row = row_of_cell(cell);
637 if (row > 0 && !getAdditionalHeight(row)) {
638 int column = column_of_cell(cell);
641 && cell_info[row][column].multicolumn
642 == LyXTabular::CELL_PART_OF_MULTICOLUMN)
644 if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
645 return row_info[row].bottom_line;
647 return cell_info[row][column].bottom_line;
653 bool LyXTabular::leftAlreadyDrawn(int cell) const
655 int column = column_of_cell(cell);
657 int row = row_of_cell(cell);
659 (cell_info[row][column].multicolumn ==
660 LyXTabular::CELL_PART_OF_MULTICOLUMN));
661 if (getAdditionalWidth(cell_info[row][column].cellno))
663 return rightLine(cell_info[row][column].cellno);
669 bool LyXTabular::isLastRow(int cell) const
671 return row_of_cell(cell) == rows_ - 1;
675 int LyXTabular::getAdditionalHeight(int row) const
677 if (!row || row >= rows_)
683 for (int column = 0; column < columns_ && bottom; ++column) {
684 switch (cell_info[row - 1][column].multicolumn) {
685 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
686 bottom = cell_info[row - 1][column].bottom_line;
688 case LyXTabular::CELL_NORMAL:
689 bottom = row_info[row - 1].bottom_line;
692 for (int column = 0; column < columns_ && top; ++column) {
693 switch (cell_info[row][column].multicolumn) {
694 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
695 top = cell_info[row][column].top_line;
697 case LyXTabular::CELL_NORMAL:
698 top = row_info[row].top_line;
702 return WIDTH_OF_LINE;
707 int LyXTabular::getAdditionalWidth(int cell) const
709 // internally already set in setWidthOfCell
710 // used to get it back in text.C
711 int const col = right_column_of_cell(cell);
712 int const row = row_of_cell(cell);
713 if (col < columns_ - 1 && rightLine(cell) &&
714 leftLine(cell_info[row][col+1].cellno)) // column_info[col+1].left_line)
716 return WIDTH_OF_LINE;
722 // returns the maximum over all rows
723 int LyXTabular::getWidthOfColumn(int cell) const
725 int const column1 = column_of_cell(cell);
726 int const column2 = right_column_of_cell(cell);
728 for (int i = column1; i <= column2; ++i)
729 result += column_info[i].width_of_column;
734 int LyXTabular::getWidthOfTabular() const
736 return width_of_tabular;
740 // returns true if a complete update is necessary, otherwise false
741 bool LyXTabular::setWidthOfMulticolCell(int cell, int new_width)
743 if (!isMultiColumn(cell))
746 int const row = row_of_cell(cell);
747 int const column1 = column_of_cell(cell);
748 int const column2 = right_column_of_cell(cell);
749 int const old_val = cell_info[row][column2].width_of_cell;
751 // first set columns to 0 so we can calculate the right width
752 for (int i = column1; i <= column2; ++i) {
753 cell_info[row][i].width_of_cell = 0;
755 // set the width to MAX_WIDTH until width > 0
756 int width = new_width + 2 * WIDTH_OF_LINE;
758 for (; i < column2 && width > column_info[i].width_of_column; ++i) {
759 cell_info[row][i].width_of_cell = column_info[i].width_of_column;
760 width -= column_info[i].width_of_column;
763 cell_info[row][i].width_of_cell = width;
765 if (old_val != cell_info[row][column2].width_of_cell) {
766 // in this case we have to recalculate all multicolumn cells which
767 // have this column as one of theirs but not as last one
768 calculate_width_of_column_NMC(i);
769 recalculateMulticolumnsOfColumn(i);
770 calculate_width_of_column(i);
776 void LyXTabular::recalculateMulticolumnsOfColumn(int column)
778 // the last column does not have to be recalculated because all
779 // multicolumns will have here there last multicolumn cell which
780 // always will have the whole rest of the width of the cell.
781 if (column > (columns_ - 2))
783 for(int row = 0; row < rows_; ++row) {
784 int mc = cell_info[row][column].multicolumn;
785 int nmc = cell_info[row][column+1].multicolumn;
786 // we only have to update multicolumns which do not have this
787 // column as their last column!
788 if (mc == CELL_BEGIN_OF_MULTICOLUMN ||
789 (mc == CELL_PART_OF_MULTICOLUMN &&
790 nmc == CELL_PART_OF_MULTICOLUMN))
792 int const cellno = cell_info[row][column].cellno;
793 setWidthOfMulticolCell(cellno,
794 getWidthOfCell(cellno) - 2 * WIDTH_OF_LINE);
800 // returns 1 if a complete update is necessary, otherwise 0
801 void LyXTabular::setWidthOfCell(int cell, int new_width)
803 int const row = row_of_cell(cell);
804 int const column1 = column_of_cell(cell);
809 if (rightLine(cell_info[row][column1].cellno, true) &&
810 column1 < columns_ - 1 &&
811 leftLine(cell_info[row][column1+1].cellno, true))
813 add_width = WIDTH_OF_LINE;
816 if (getWidthOfCell(cell) == new_width + 2 * WIDTH_OF_LINE + add_width)
819 if (isMultiColumnReal(cell)) {
820 tmp = setWidthOfMulticolCell(cell, new_width);
822 width = new_width + 2 * WIDTH_OF_LINE + add_width;
823 cell_info[row][column1].width_of_cell = width;
824 tmp = calculate_width_of_column_NMC(column1);
826 recalculateMulticolumnsOfColumn(column1);
829 for (int i = 0; i < columns_; ++i)
830 calculate_width_of_column(i);
831 calculate_width_of_tabular();
836 void LyXTabular::setAlignment(int cell, LyXAlignment align, bool onlycolumn)
838 if (!isMultiColumn(cell) || onlycolumn)
839 column_info[column_of_cell(cell)].alignment = align;
841 cellinfo_of_cell(cell).alignment = align;
845 void LyXTabular::setVAlignment(int cell, VAlignment align, bool onlycolumn)
847 if (!isMultiColumn(cell) || onlycolumn)
848 column_info[column_of_cell(cell)].valignment = align;
850 cellinfo_of_cell(cell).valignment = align;
854 void LyXTabular::setColumnPWidth(int cell, LyXLength const & width)
856 int const j = column_of_cell(cell);
858 column_info[j].p_width = width;
859 for (int i = 0; i < rows_; ++i) {
860 int const cell = getCellNumber(i, j);
861 // because of multicolumns
862 getCellInset(cell)->setAutoBreakRows(!getPWidth(cell).zero());
867 bool LyXTabular::setMColumnPWidth(int cell, LyXLength const & width)
869 if (!isMultiColumn(cell))
872 cellinfo_of_cell(cell).p_width = width;
873 getCellInset(cell)->setAutoBreakRows(!width.zero());
878 void LyXTabular::setAlignSpecial(int cell, string const & special,
879 LyXTabular::Feature what)
881 if (what == SET_SPECIAL_MULTI)
882 cellinfo_of_cell(cell).align_special = special;
884 column_info[column_of_cell(cell)].align_special = special;
888 void LyXTabular::setAllLines(int cell, bool line)
890 setTopLine(cell, line);
891 setBottomLine(cell, line);
892 setRightLine(cell, line);
893 setLeftLine(cell, line);
897 void LyXTabular::setTopLine(int cell, bool line, bool onlycolumn)
899 int const row = row_of_cell(cell);
900 if (onlycolumn || !isMultiColumn(cell))
901 row_info[row].top_line = line;
903 cellinfo_of_cell(cell).top_line = line;
907 void LyXTabular::setBottomLine(int cell, bool line, bool onlycolumn)
909 if (onlycolumn || !isMultiColumn(cell))
910 row_info[row_of_cell(cell)].bottom_line = line;
912 cellinfo_of_cell(cell).bottom_line = line;
916 void LyXTabular::setLeftLine(int cell, bool line, bool onlycolumn)
918 if (onlycolumn || !isMultiColumn(cell))
919 column_info[column_of_cell(cell)].left_line = line;
921 cellinfo_of_cell(cell).left_line = line;
925 void LyXTabular::setRightLine(int cell, bool line, bool onlycolumn)
927 if (onlycolumn || !isMultiColumn(cell))
928 column_info[right_column_of_cell(cell)].right_line = line;
930 cellinfo_of_cell(cell).right_line = line;
934 LyXAlignment LyXTabular::getAlignment(int cell, bool onlycolumn) const
936 if (!onlycolumn && isMultiColumn(cell))
937 return cellinfo_of_cell(cell).alignment;
938 return column_info[column_of_cell(cell)].alignment;
942 LyXTabular::VAlignment
943 LyXTabular::getVAlignment(int cell, bool onlycolumn) const
945 if (!onlycolumn && isMultiColumn(cell))
946 return cellinfo_of_cell(cell).valignment;
947 return column_info[column_of_cell(cell)].valignment;
951 LyXLength const LyXTabular::getPWidth(int cell) const
953 if (isMultiColumn(cell))
954 return cellinfo_of_cell(cell).p_width;
955 return column_info[column_of_cell(cell)].p_width;
959 LyXLength const LyXTabular::getColumnPWidth(int cell) const
961 return column_info[column_of_cell(cell)].p_width;
965 LyXLength const LyXTabular::getMColumnPWidth(int cell) const
967 if (isMultiColumn(cell))
968 return cellinfo_of_cell(cell).p_width;
973 string const LyXTabular::getAlignSpecial(int cell, int what) const
975 if (what == SET_SPECIAL_MULTI)
976 return cellinfo_of_cell(cell).align_special;
977 return column_info[column_of_cell(cell)].align_special;
981 int LyXTabular::getWidthOfCell(int cell) const
983 int const row = row_of_cell(cell);
984 int const column1 = column_of_cell(cell);
985 int const column2 = right_column_of_cell(cell);
987 for (int i = column1; i <= column2; ++i)
988 result += cell_info[row][i].width_of_cell;
993 int LyXTabular::getBeginningOfTextInCell(int cell) const
997 switch (getAlignment(cell)) {
998 case LYX_ALIGN_CENTER:
999 x += (getWidthOfColumn(cell) - getWidthOfCell(cell)) / 2;
1001 case LYX_ALIGN_RIGHT:
1002 x += getWidthOfColumn(cell) - getWidthOfCell(cell);
1003 // + getAdditionalWidth(cell);
1006 // LYX_ALIGN_LEFT: nothing :-)
1010 // the LaTeX Way :-(
1016 bool LyXTabular::isFirstCellInRow(int cell) const
1018 return column_of_cell(cell) == 0;
1022 int LyXTabular::getFirstCellInRow(int row) const
1024 if (row > rows_ - 1)
1026 return cell_info[row][0].cellno;
1030 bool LyXTabular::isLastCellInRow(int cell) const
1032 return right_column_of_cell(cell) == columns_ - 1;
1036 int LyXTabular::getLastCellInRow(int row) const
1038 if (row > rows_ - 1)
1040 return cell_info[row][columns_-1].cellno;
1044 void LyXTabular::calculate_width_of_column(int column)
1047 for (int i = 0; i < rows_; ++i)
1048 maximum = max(cell_info[i][column].width_of_cell, maximum);
1049 column_info[column].width_of_column = maximum;
1054 // Calculate the columns regarding ONLY the normal cells and if this
1055 // column is inside a multicolumn cell then use it only if its the last
1056 // column of this multicolumn cell as this gives an added width to the
1057 // column, all the rest should be adapted!
1059 bool LyXTabular::calculate_width_of_column_NMC(int column)
1061 int const old_column_width = column_info[column].width_of_column;
1063 for (int i = 0; i < rows_; ++i) {
1064 int cell = getCellNumber(i, column);
1065 bool ismulti = isMultiColumnReal(cell);
1066 if ((!ismulti || column == right_column_of_cell(cell)) &&
1067 cell_info[i][column].width_of_cell > max)
1069 max = cell_info[i][column].width_of_cell;
1072 column_info[column].width_of_column = max;
1073 return column_info[column].width_of_column != old_column_width;
1077 void LyXTabular::calculate_width_of_tabular()
1079 width_of_tabular = 0;
1080 for (int i = 0; i < columns_; ++i)
1081 width_of_tabular += column_info[i].width_of_column;
1085 int LyXTabular::row_of_cell(int cell) const
1087 if (cell >= numberofcells)
1091 return rowofcell[cell];
1095 int LyXTabular::column_of_cell(int cell) const
1097 if (cell >= numberofcells)
1098 return columns_ - 1;
1101 return columnofcell[cell];
1105 int LyXTabular::right_column_of_cell(int cell) const
1107 int const row = row_of_cell(cell);
1108 int column = column_of_cell(cell);
1109 while (column < columns_ - 1 &&
1110 cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
1116 void LyXTabular::write(Buffer const & buf, ostream & os) const
1120 << write_attribute("version", 3)
1121 << write_attribute("rows", rows_)
1122 << write_attribute("columns", columns_)
1124 // global longtable options
1126 << write_attribute("rotate", rotate)
1127 << write_attribute("islongtable", is_long_tabular)
1128 << write_attribute("firstHeadTopDL", endfirsthead.topDL)
1129 << write_attribute("firstHeadBottomDL", endfirsthead.bottomDL)
1130 << write_attribute("firstHeadEmpty", endfirsthead.empty)
1131 << write_attribute("headTopDL", endhead.topDL)
1132 << write_attribute("headBottomDL", endhead.bottomDL)
1133 << write_attribute("footTopDL", endfoot.topDL)
1134 << write_attribute("footBottomDL", endfoot.bottomDL)
1135 << write_attribute("lastFootTopDL", endlastfoot.topDL)
1136 << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
1137 << write_attribute("lastFootEmpty", endlastfoot.empty)
1139 for (int j = 0; j < columns_; ++j) {
1141 << write_attribute("alignment", column_info[j].alignment)
1142 << write_attribute("valignment", column_info[j].valignment)
1143 << write_attribute("leftline", column_info[j].left_line)
1144 << write_attribute("rightline", column_info[j].right_line)
1145 << write_attribute("width", column_info[j].p_width.asString())
1146 << write_attribute("special", column_info[j].align_special)
1149 for (int i = 0; i < rows_; ++i) {
1151 << write_attribute("topline", row_info[i].top_line)
1152 << write_attribute("bottomline", row_info[i].bottom_line)
1153 << write_attribute("endhead", row_info[i].endhead)
1154 << write_attribute("endfirsthead", row_info[i].endfirsthead)
1155 << write_attribute("endfoot", row_info[i].endfoot)
1156 << write_attribute("endlastfoot", row_info[i].endlastfoot)
1157 << write_attribute("newpage", row_info[i].newpage)
1159 for (int j = 0; j < columns_; ++j) {
1161 << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1162 << write_attribute("alignment", cell_info[i][j].alignment)
1163 << write_attribute("valignment", cell_info[i][j].valignment)
1164 << write_attribute("topline", cell_info[i][j].top_line)
1165 << write_attribute("bottomline", cell_info[i][j].bottom_line)
1166 << write_attribute("leftline", cell_info[i][j].left_line)
1167 << write_attribute("rightline", cell_info[i][j].right_line)
1168 << write_attribute("rotate", cell_info[i][j].rotate)
1169 << write_attribute("usebox", cell_info[i][j].usebox)
1170 << write_attribute("width", cell_info[i][j].p_width)
1171 << write_attribute("special", cell_info[i][j].align_special)
1173 os << "\\begin_inset ";
1174 cell_info[i][j].inset->write(buf, os);
1175 os << "\n\\end_inset\n"
1180 os << "</lyxtabular>\n";
1184 void LyXTabular::setHeaderFooterRows(int hr, int fhr, int fr, int lfr)
1188 row_info[--hr].endhead = true;
1190 // set firstheader info
1191 if (fhr && fhr < rows_) {
1192 if (row_info[fhr].endhead) {
1194 row_info[--fhr].endfirsthead = true;
1195 row_info[fhr].endhead = false;
1197 } else if (row_info[fhr - 1].endhead) {
1198 endfirsthead.empty = true;
1200 while (fhr > 0 && !row_info[--fhr].endhead) {
1201 row_info[fhr].endfirsthead = true;
1206 if (fr && fr < rows_) {
1207 if (row_info[fr].endhead && row_info[fr-1].endhead) {
1208 while (fr > 0 && !row_info[--fr].endhead) {
1209 row_info[fr].endfoot = true;
1210 row_info[fr].endhead = false;
1212 } else if (row_info[fr].endfirsthead && row_info[fr-1].endfirsthead) {
1213 while (fr > 0 && !row_info[--fr].endfirsthead) {
1214 row_info[fr].endfoot = true;
1215 row_info[fr].endfirsthead = false;
1217 } else if (!row_info[fr - 1].endhead && !row_info[fr - 1].endfirsthead) {
1218 while (fr > 0 && !row_info[--fr].endhead &&
1219 !row_info[fr].endfirsthead)
1221 row_info[fr].endfoot = true;
1225 // set lastfooter info
1226 if (lfr && lfr < rows_) {
1227 if (row_info[lfr].endhead && row_info[lfr - 1].endhead) {
1228 while (lfr > 0 && !row_info[--lfr].endhead) {
1229 row_info[lfr].endlastfoot = true;
1230 row_info[lfr].endhead = false;
1232 } else if (row_info[lfr].endfirsthead &&
1233 row_info[lfr - 1].endfirsthead)
1235 while (lfr > 0 && !row_info[--lfr].endfirsthead) {
1236 row_info[lfr].endlastfoot = true;
1237 row_info[lfr].endfirsthead = false;
1239 } else if (row_info[lfr].endfoot
1240 && row_info[lfr - 1].endfoot) {
1241 while (lfr > 0 && !row_info[--lfr].endfoot) {
1242 row_info[lfr].endlastfoot = true;
1243 row_info[lfr].endfoot = false;
1245 } else if (!row_info[fr - 1].endhead
1246 && !row_info[fr - 1].endfirsthead &&
1247 !row_info[fr - 1].endfoot)
1250 !row_info[--lfr].endhead && !row_info[lfr].endfirsthead &&
1251 !row_info[lfr].endfoot)
1253 row_info[lfr].endlastfoot = true;
1255 } else if (haveLTFoot()) {
1256 endlastfoot.empty = true;
1262 void LyXTabular::read(Buffer const & buf, LyXLex & lex)
1265 istream & is = lex.getStream();
1267 l_getline(is, line);
1268 if (!prefixIs(line, "<lyxtabular ")
1269 && !prefixIs(line, "<LyXTabular ")) {
1270 BOOST_ASSERT(false);
1275 if (!getTokenValue(line, "version", version))
1277 BOOST_ASSERT(version >= 2);
1280 if (!getTokenValue(line, "rows", rows_arg))
1283 if (!getTokenValue(line, "columns", columns_arg))
1285 init(buf.params(), rows_arg, columns_arg);
1286 l_getline(is, line);
1287 if (!prefixIs(line, "<features")) {
1288 lyxerr << "Wrong tabular format (expected <features ...> got"
1289 << line << ')' << endl;
1292 getTokenValue(line, "rotate", rotate);
1293 getTokenValue(line, "islongtable", is_long_tabular);
1294 // compatibility read for old longtable options. Now we can make any
1295 // row part of the header/footer type we want before it was strict
1296 // sequential from the first row down (as LaTeX does it!). So now when
1297 // we find a header/footer line we have to go up the rows and set it
1298 // on all preceding rows till the first or one with already a h/f option
1299 // set. If we find a firstheader on the same line as a header or a
1300 // lastfooter on the same line as a footer then this should be set empty.
1308 getTokenValue(line, "endhead", hrow);
1309 getTokenValue(line, "endfirsthead", fhrow);
1310 getTokenValue(line, "endfoot", frow);
1311 getTokenValue(line, "endlastfoot", lfrow);
1312 setHeaderFooterRows(abs(hrow), abs(fhrow), abs(frow), abs(lfrow));
1314 getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
1315 getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
1316 getTokenValue(line, "firstHeadEmpty", endfirsthead.empty);
1317 getTokenValue(line, "headTopDL", endhead.topDL);
1318 getTokenValue(line, "headBottomDL", endhead.bottomDL);
1319 getTokenValue(line, "footTopDL", endfoot.topDL);
1320 getTokenValue(line, "footBottomDL", endfoot.bottomDL);
1321 getTokenValue(line, "lastFootTopDL", endlastfoot.topDL);
1322 getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
1323 getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
1325 for (int j = 0; j < columns_; ++j) {
1327 if (!prefixIs(line,"<column")) {
1328 lyxerr << "Wrong tabular format (expected <column ...> got"
1329 << line << ')' << endl;
1332 getTokenValue(line, "alignment", column_info[j].alignment);
1333 getTokenValue(line, "valignment", column_info[j].valignment);
1334 getTokenValue(line, "leftline", column_info[j].left_line);
1335 getTokenValue(line, "rightline", column_info[j].right_line);
1336 getTokenValue(line, "width", column_info[j].p_width);
1337 getTokenValue(line, "special", column_info[j].align_special);
1340 for (int i = 0; i < rows_; ++i) {
1341 l_getline(is, line);
1342 if (!prefixIs(line, "<row")) {
1343 lyxerr << "Wrong tabular format (expected <row ...> got"
1344 << line << ')' << endl;
1347 getTokenValue(line, "topline", row_info[i].top_line);
1348 getTokenValue(line, "bottomline", row_info[i].bottom_line);
1349 getTokenValue(line, "endfirsthead", row_info[i].endfirsthead);
1350 getTokenValue(line, "endhead", row_info[i].endhead);
1351 getTokenValue(line, "endfoot", row_info[i].endfoot);
1352 getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
1353 getTokenValue(line, "newpage", row_info[i].newpage);
1354 for (int j = 0; j < columns_; ++j) {
1355 l_getline(is, line);
1356 if (!prefixIs(line, "<cell")) {
1357 lyxerr << "Wrong tabular format (expected <cell ...> got"
1358 << line << ')' << endl;
1361 getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1362 getTokenValue(line, "alignment", cell_info[i][j].alignment);
1363 getTokenValue(line, "valignment", cell_info[i][j].valignment);
1364 getTokenValue(line, "topline", cell_info[i][j].top_line);
1365 getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1366 getTokenValue(line, "leftline", cell_info[i][j].left_line);
1367 getTokenValue(line, "rightline", cell_info[i][j].right_line);
1368 getTokenValue(line, "rotate", cell_info[i][j].rotate);
1369 getTokenValue(line, "usebox", cell_info[i][j].usebox);
1370 getTokenValue(line, "width", cell_info[i][j].p_width);
1371 getTokenValue(line, "special", cell_info[i][j].align_special);
1372 l_getline(is, line);
1373 if (prefixIs(line, "\\begin_inset")) {
1374 cell_info[i][j].inset->read(buf, lex);
1375 l_getline(is, line);
1377 if (!prefixIs(line, "</cell>")) {
1378 lyxerr << "Wrong tabular format (expected </cell> got"
1379 << line << ')' << endl;
1383 l_getline(is, line);
1384 if (!prefixIs(line, "</row>")) {
1385 lyxerr << "Wrong tabular format (expected </row> got"
1386 << line << ')' << endl;
1390 while (!prefixIs(line, "</lyxtabular>")) {
1391 l_getline(is, line);
1393 set_row_column_number_info();
1397 bool LyXTabular::isMultiColumn(int cell) const
1399 return cellinfo_of_cell(cell).multicolumn != LyXTabular::CELL_NORMAL;
1403 bool LyXTabular::isMultiColumnReal(int cell) const
1405 return column_of_cell(cell) != right_column_of_cell(cell) &&
1406 cellinfo_of_cell(cell).multicolumn != LyXTabular::CELL_NORMAL;
1410 LyXTabular::cellstruct & LyXTabular::cellinfo_of_cell(int cell) const
1412 return cell_info[row_of_cell(cell)][column_of_cell(cell)];
1416 void LyXTabular::setMultiColumn(Buffer * buffer, int cell, int number)
1418 cellstruct & cs = cellinfo_of_cell(cell);
1419 cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1420 cs.alignment = column_info[column_of_cell(cell)].alignment;
1421 cs.top_line = row_info[row_of_cell(cell)].top_line;
1422 cs.bottom_line = row_info[row_of_cell(cell)].bottom_line;
1423 cs.right_line = column_info[column_of_cell(cell+number-1)].right_line;
1424 for (int i = 1; i < number; ++i) {
1425 cellstruct & cs1 = cellinfo_of_cell(cell + i);
1426 cs1.multicolumn = CELL_PART_OF_MULTICOLUMN;
1427 cs.inset->appendParagraphs(buffer, cs1.inset->paragraphs());
1428 cs1.inset->clear(false);
1430 set_row_column_number_info();
1434 int LyXTabular::cells_in_multicolumn(int cell) const
1436 int const row = row_of_cell(cell);
1437 int column = column_of_cell(cell);
1440 while (column < columns_ &&
1441 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1450 int LyXTabular::unsetMultiColumn(int cell)
1452 int const row = row_of_cell(cell);
1453 int column = column_of_cell(cell);
1457 if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1458 cell_info[row][column].multicolumn = CELL_NORMAL;
1460 while (column < columns_ &&
1461 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1463 cell_info[row][column].multicolumn = CELL_NORMAL;
1468 set_row_column_number_info();
1473 void LyXTabular::setLongTabular(bool what)
1475 is_long_tabular = what;
1479 bool LyXTabular::isLongTabular() const
1481 return is_long_tabular;
1485 void LyXTabular::setRotateTabular(bool flag)
1491 bool LyXTabular::getRotateTabular() const
1497 void LyXTabular::setRotateCell(int cell, bool flag)
1499 cellinfo_of_cell(cell).rotate = flag;
1503 bool LyXTabular::getRotateCell(int cell) const
1505 return cellinfo_of_cell(cell).rotate;
1509 bool LyXTabular::needRotating() const
1513 for (int i = 0; i < rows_; ++i)
1514 for (int j = 0; j < columns_; ++j)
1515 if (cell_info[i][j].rotate)
1521 bool LyXTabular::isLastCell(int cell) const
1523 if (cell + 1 < numberofcells)
1529 int LyXTabular::getCellAbove(int cell) const
1531 if (row_of_cell(cell) > 0)
1532 return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1537 int LyXTabular::getCellBelow(int cell) const
1539 if (row_of_cell(cell) + 1 < rows_)
1540 return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1545 int LyXTabular::getLastCellAbove(int cell) const
1547 if (row_of_cell(cell) <= 0)
1549 if (!isMultiColumn(cell))
1550 return getCellAbove(cell);
1551 return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1555 int LyXTabular::getLastCellBelow(int cell) const
1557 if (row_of_cell(cell) + 1 >= rows_)
1559 if (!isMultiColumn(cell))
1560 return getCellBelow(cell);
1561 return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1565 int LyXTabular::getCellNumber(int row, int column) const
1567 BOOST_ASSERT(column >= 0 || column < columns_ || row >= 0 || row < rows_);
1568 return cell_info[row][column].cellno;
1572 void LyXTabular::setUsebox(int cell, BoxType type)
1574 cellinfo_of_cell(cell).usebox = type;
1578 LyXTabular::BoxType LyXTabular::getUsebox(int cell) const
1580 if (column_info[column_of_cell(cell)].p_width.zero() &&
1581 !(isMultiColumn(cell) && !cellinfo_of_cell(cell).p_width.zero()))
1583 if (cellinfo_of_cell(cell).usebox > 1)
1584 return cellinfo_of_cell(cell).usebox;
1585 return useParbox(cell);
1590 // This are functions used for the longtable support
1592 void LyXTabular::setLTHead(int row, bool flag, ltType const & hd, bool first)
1597 row_info[row].endfirsthead = flag;
1601 row_info[row].endhead = flag;
1606 bool LyXTabular::getRowOfLTHead(int row, ltType & hd) const
1609 hd.set = haveLTHead();
1610 return row_info[row].endhead;
1614 bool LyXTabular::getRowOfLTFirstHead(int row, ltType & hd) const
1617 hd.set = haveLTFirstHead();
1618 return row_info[row].endfirsthead;
1622 void LyXTabular::setLTFoot(int row, bool flag, ltType const & fd, bool last)
1627 row_info[row].endlastfoot = flag;
1631 row_info[row].endfoot = flag;
1636 bool LyXTabular::getRowOfLTFoot(int row, ltType & fd) const
1639 fd.set = haveLTFoot();
1640 return row_info[row].endfoot;
1644 bool LyXTabular::getRowOfLTLastFoot(int row, ltType & fd) const
1647 fd.set = haveLTLastFoot();
1648 return row_info[row].endlastfoot;
1652 void LyXTabular::setLTNewPage(int row, bool what)
1654 row_info[row].newpage = what;
1658 bool LyXTabular::getLTNewPage(int row) const
1660 return row_info[row].newpage;
1664 bool LyXTabular::haveLTHead() const
1666 for (int i = 0; i < rows_; ++i)
1667 if (row_info[i].endhead)
1673 bool LyXTabular::haveLTFirstHead() const
1675 if (endfirsthead.empty)
1677 for (int i = 0; i < rows_; ++i)
1678 if (row_info[i].endfirsthead)
1684 bool LyXTabular::haveLTFoot() const
1686 for (int i = 0; i < rows_; ++i)
1687 if (row_info[i].endfoot)
1693 bool LyXTabular::haveLTLastFoot() const
1695 if (endlastfoot.empty)
1697 for (int i = 0; i < rows_; ++i)
1698 if (row_info[i].endlastfoot)
1704 // end longtable support functions
1706 void LyXTabular::setAscentOfRow(int row, int height)
1708 if (row >= rows_ || row_info[row].ascent_of_row == height)
1710 row_info[row].ascent_of_row = height;
1714 void LyXTabular::setDescentOfRow(int row, int height)
1716 if (row >= rows_ || row_info[row].descent_of_row == height)
1718 row_info[row].descent_of_row = height;
1722 int LyXTabular::getAscentOfRow(int row) const
1726 return row_info[row].ascent_of_row;
1730 int LyXTabular::getDescentOfRow(int row) const
1732 BOOST_ASSERT(row < rows_);
1733 return row_info[row].descent_of_row;
1737 int LyXTabular::getHeightOfTabular() const
1740 for (int row = 0; row < rows_; ++row)
1741 height += getAscentOfRow(row) + getDescentOfRow(row) +
1742 getAdditionalHeight(row);
1747 bool LyXTabular::isPartOfMultiColumn(int row, int column) const
1749 BOOST_ASSERT(row < rows_);
1750 BOOST_ASSERT(column < columns_);
1751 return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN;
1755 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1757 BOOST_ASSERT(row >= 0);
1758 BOOST_ASSERT(row < rows_);
1760 int const fcell = getFirstCellInRow(row);
1761 int const n = numberOfCellsInRow(fcell) + fcell;
1764 for (int i = fcell; i < n; ++i) {
1768 if (tmp == n - fcell) {
1771 for (int i = fcell; i < n; ++i) {
1774 << column_of_cell(i) + 1
1776 << right_column_of_cell(i) + 1
1788 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1790 if (row < 0 || row >= rows_)
1793 int const fcell = getFirstCellInRow(row);
1794 int const n = numberOfCellsInRow(fcell) + fcell;
1797 for (int i = fcell; i < n; ++i) {
1801 if (tmp == n - fcell) {
1804 for (int i = fcell; i < n; ++i) {
1805 if (bottomLine(i)) {
1807 << column_of_cell(i) + 1
1809 << right_column_of_cell(i) + 1
1821 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
1825 if (getRotateCell(cell)) {
1826 os << "\\begin{sideways}\n";
1829 if (isMultiColumn(cell)) {
1830 os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
1831 if (!cellinfo_of_cell(cell).align_special.empty()) {
1832 os << cellinfo_of_cell(cell).align_special << "}{";
1834 if (leftLine(cell) &&
1835 (isFirstCellInRow(cell) ||
1836 (!isMultiColumn(cell - 1) && !leftLine(cell, true) &&
1837 !rightLine(cell - 1, true))))
1841 if (!getPWidth(cell).zero()) {
1842 switch (getVAlignment(cell)) {
1843 case LYX_VALIGN_TOP:
1846 case LYX_VALIGN_MIDDLE:
1849 case LYX_VALIGN_BOTTOM:
1854 << getPWidth(cell).asLatexString()
1857 switch (getAlignment(cell)) {
1858 case LYX_ALIGN_LEFT:
1861 case LYX_ALIGN_RIGHT:
1869 if (rightLine(cell))
1871 if (((cell + 1) < numberofcells) && !isFirstCellInRow(cell+1) &&
1877 if (getUsebox(cell) == BOX_PARBOX) {
1879 switch (getVAlignment(cell)) {
1880 case LYX_VALIGN_TOP:
1883 case LYX_VALIGN_MIDDLE:
1886 case LYX_VALIGN_BOTTOM:
1890 os << "]{" << getPWidth(cell).asLatexString() << "}{";
1891 } else if (getUsebox(cell) == BOX_MINIPAGE) {
1892 os << "\\begin{minipage}[";
1893 switch (getVAlignment(cell)) {
1894 case LYX_VALIGN_TOP:
1897 case LYX_VALIGN_MIDDLE:
1900 case LYX_VALIGN_BOTTOM:
1904 os << "]{" << getPWidth(cell).asLatexString() << "}\n";
1911 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
1916 if (getUsebox(cell) == BOX_PARBOX)
1918 else if (getUsebox(cell) == BOX_MINIPAGE) {
1919 os << "%\n\\end{minipage}";
1922 if (isMultiColumn(cell)) {
1925 if (getRotateCell(cell)) {
1926 os << "%\n\\end{sideways}";
1933 int LyXTabular::TeXLongtableHeaderFooter(ostream & os, Buffer const & buf,
1934 OutputParams const & runparams) const
1936 if (!is_long_tabular)
1940 // output header info
1942 if (endhead.topDL) {
1946 for (int i = 0; i < rows_; ++i) {
1947 if (row_info[i].endhead) {
1948 ret += TeXRow(os, i, buf, runparams);
1951 if (endhead.bottomDL) {
1955 os << "\\endhead\n";
1957 if (endfirsthead.empty) {
1958 os << "\\endfirsthead\n";
1962 // output firstheader info
1963 if (haveLTFirstHead()) {
1964 if (endfirsthead.topDL) {
1968 for (int i = 0; i < rows_; ++i) {
1969 if (row_info[i].endfirsthead) {
1970 ret += TeXRow(os, i, buf, runparams);
1973 if (endfirsthead.bottomDL) {
1977 os << "\\endfirsthead\n";
1980 // output footer info
1982 if (endfoot.topDL) {
1986 for (int i = 0; i < rows_; ++i) {
1987 if (row_info[i].endfoot) {
1988 ret += TeXRow(os, i, buf, runparams);
1991 if (endfoot.bottomDL) {
1995 os << "\\endfoot\n";
1997 if (endlastfoot.empty) {
1998 os << "\\endlastfoot\n";
2002 // output lastfooter info
2003 if (haveLTLastFoot()) {
2004 if (endlastfoot.topDL) {
2008 for (int i = 0; i < rows_; ++i) {
2009 if (row_info[i].endlastfoot) {
2010 ret += TeXRow(os, i, buf, runparams);
2013 if (endlastfoot.bottomDL) {
2017 os << "\\endlastfoot\n";
2024 bool LyXTabular::isValidRow(int row) const
2026 if (!is_long_tabular)
2028 return !row_info[row].endhead && !row_info[row].endfirsthead &&
2029 !row_info[row].endfoot && !row_info[row].endlastfoot;
2033 int LyXTabular::TeXRow(ostream & os, int i, Buffer const & buf,
2034 OutputParams const & runparams) const
2036 int cell = getCellNumber(i, 0);
2038 int ret = TeXTopHLine(os, i);
2039 for (int j = 0; j < columns_; ++j) {
2040 if (isPartOfMultiColumn(i, j))
2042 ret += TeXCellPreamble(os, cell);
2043 shared_ptr<InsetText> inset = getCellInset(cell);
2045 Paragraph const & par = inset->paragraphs().front();
2046 bool rtl = par.isRightToLeftPar(buf.params())
2048 && getPWidth(cell).zero();
2052 ret += inset->latex(buf, os, runparams);
2056 ret += TeXCellPostamble(os, cell);
2057 if (!isLastCellInRow(cell)) { // not last cell in row
2063 os << "\\tabularnewline\n";
2065 ret += TeXBottomHLine(os, i);
2070 int LyXTabular::latex(Buffer const & buf, ostream & os,
2071 OutputParams const & runparams) const
2075 //+---------------------------------------------------------------------
2076 //+ first the opening preamble +
2077 //+---------------------------------------------------------------------
2080 os << "\\begin{sideways}\n";
2083 if (is_long_tabular)
2084 os << "\\begin{longtable}{";
2086 os << "\\begin{tabular}{";
2087 for (int i = 0; i < columns_; ++i) {
2088 if (!column_info[i].align_special.empty()) {
2089 os << column_info[i].align_special;
2091 if (column_info[i].left_line)
2093 if (!column_info[i].p_width.zero()) {
2094 switch (column_info[i].alignment) {
2095 case LYX_ALIGN_LEFT:
2096 os << ">{\\raggedright}";
2098 case LYX_ALIGN_RIGHT:
2099 os << ">{\\raggedleft}";
2101 case LYX_ALIGN_CENTER:
2102 os << ">{\\centering}";
2104 case LYX_ALIGN_NONE:
2105 case LYX_ALIGN_BLOCK:
2106 case LYX_ALIGN_LAYOUT:
2107 case LYX_ALIGN_SPECIAL:
2111 switch (column_info[i].valignment) {
2112 case LYX_VALIGN_TOP:
2115 case LYX_VALIGN_MIDDLE:
2118 case LYX_VALIGN_BOTTOM:
2123 << column_info[i].p_width.asLatexString()
2126 switch (column_info[i].alignment) {
2127 case LYX_ALIGN_LEFT:
2130 case LYX_ALIGN_RIGHT:
2138 if (column_info[i].right_line)
2145 ret += TeXLongtableHeaderFooter(os, buf, runparams);
2147 //+---------------------------------------------------------------------
2148 //+ the single row and columns (cells) +
2149 //+---------------------------------------------------------------------
2151 for (int i = 0; i < rows_; ++i) {
2152 if (isValidRow(i)) {
2153 ret += TeXRow(os, i, buf, runparams);
2154 if (is_long_tabular && row_info[i].newpage) {
2155 os << "\\newpage\n";
2161 //+---------------------------------------------------------------------
2162 //+ the closing of the tabular +
2163 //+---------------------------------------------------------------------
2165 if (is_long_tabular)
2166 os << "\\end{longtable}";
2168 os << "\\end{tabular}";
2170 os << "\n\\end{sideways}";
2178 int LyXTabular::linuxdoc(Buffer const & buf, ostream & os,
2179 const OutputParams & runparams) const
2181 os << "<tabular ca=\"";
2182 for (int i = 0; i < columns_; ++i) {
2183 switch (column_info[i].alignment) {
2184 case LYX_ALIGN_LEFT:
2187 case LYX_ALIGN_RIGHT:
2198 for (int i = 0; i < rows_; ++i) {
2199 for (int j = 0; j < columns_; ++j) {
2200 if (isPartOfMultiColumn(i, j))
2202 shared_ptr<InsetText> inset = getCellInset(cell);
2204 ret += inset->linuxdoc(buf, os, runparams);
2206 if (isLastCellInRow(cell)) {
2215 os << "</tabular>\n";
2220 int LyXTabular::docbookRow(Buffer const & buf, ostream & os, int row,
2221 OutputParams const & runparams) const
2224 int cell = getFirstCellInRow(row);
2227 for (int j = 0; j < columns_; ++j) {
2228 if (isPartOfMultiColumn(row, j))
2231 os << "<entry align=\"";
2232 switch (getAlignment(cell)) {
2233 case LYX_ALIGN_LEFT:
2236 case LYX_ALIGN_RIGHT:
2244 os << "\" valign=\"";
2245 switch (getVAlignment(cell)) {
2246 case LYX_VALIGN_TOP:
2249 case LYX_VALIGN_BOTTOM:
2252 case LYX_VALIGN_MIDDLE:
2257 if (isMultiColumn(cell)) {
2258 os << " namest=\"col" << j << "\" ";
2259 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
2263 ret += getCellInset(cell)->docbook(buf, os, runparams);
2272 int LyXTabular::docbook(Buffer const & buf, ostream & os,
2273 OutputParams const & runparams) const
2277 //+---------------------------------------------------------------------
2278 //+ first the opening preamble +
2279 //+---------------------------------------------------------------------
2281 os << "<tgroup cols=\"" << columns_
2282 << "\" colsep=\"1\" rowsep=\"1\">\n";
2284 for (int i = 0; i < columns_; ++i) {
2285 os << "<colspec colname=\"col" << i << "\" align=\"";
2286 switch (column_info[i].alignment) {
2287 case LYX_ALIGN_LEFT:
2290 case LYX_ALIGN_RIGHT:
2298 if (runparams.flavor == OutputParams::XML)
2304 //+---------------------------------------------------------------------
2305 //+ Long Tabular case +
2306 //+---------------------------------------------------------------------
2308 // output header info
2309 if (haveLTHead() || haveLTFirstHead()) {
2312 for (int i = 0; i < rows_; ++i) {
2313 if (row_info[i].endhead || row_info[i].endfirsthead) {
2314 ret += docbookRow(buf, os, i, runparams);
2320 // output footer info
2321 if (haveLTFoot() || haveLTLastFoot()) {
2324 for (int i = 0; i < rows_; ++i) {
2325 if (row_info[i].endfoot || row_info[i].endlastfoot) {
2326 ret += docbookRow(buf, os, i, runparams);
2333 //+---------------------------------------------------------------------
2334 //+ the single row and columns (cells) +
2335 //+---------------------------------------------------------------------
2339 for (int i = 0; i < rows_; ++i) {
2340 if (isValidRow(i)) {
2341 ret += docbookRow(buf, os, i, runparams);
2346 //+---------------------------------------------------------------------
2347 //+ the closing of the tabular +
2348 //+---------------------------------------------------------------------
2357 int LyXTabular::asciiTopHLine(ostream & os, int row,
2358 vector<unsigned int> const & clen) const
2360 int const fcell = getFirstCellInRow(row);
2361 int const n = numberOfCellsInRow(fcell) + fcell;
2364 for (int i = fcell; i < n; ++i) {
2374 for (int i = fcell; i < n; ++i) {
2385 int column = column_of_cell(i);
2386 int len = clen[column];
2387 while (column < columns_ - 1
2388 && isPartOfMultiColumn(row, ++column))
2389 len += clen[column] + 4;
2390 os << string(len, ch);
2405 int LyXTabular::asciiBottomHLine(ostream & os, int row,
2406 vector<unsigned int> const & clen) const
2408 int const fcell = getFirstCellInRow(row);
2409 int const n = numberOfCellsInRow(fcell) + fcell;
2412 for (int i = fcell; i < n; ++i) {
2413 if (bottomLine(i)) {
2422 for (int i = fcell; i < n; ++i) {
2423 if (bottomLine(i)) {
2433 int column = column_of_cell(i);
2434 int len = clen[column];
2435 while (column < columns_ -1
2436 && isPartOfMultiColumn(row, ++column))
2437 len += clen[column] + 4;
2438 os << string(len, ch);
2439 if (bottomLine(i)) {
2453 int LyXTabular::asciiPrintCell(Buffer const & buf, ostream & os,
2454 OutputParams const & runparams,
2455 int cell, int row, int column,
2456 vector<unsigned int> const & clen,
2457 bool onlydata) const
2460 int const ret = getCellInset(cell)->plaintext(buf, sstr, runparams);
2472 unsigned int len1 = sstr.str().length();
2473 unsigned int len2 = clen[column];
2474 while (column < columns_ -1
2475 && isPartOfMultiColumn(row, ++column))
2476 len2 += clen[column] + 4;
2479 switch (getAlignment(cell)) {
2481 case LYX_ALIGN_LEFT:
2484 case LYX_ALIGN_RIGHT:
2488 case LYX_ALIGN_CENTER:
2494 os << string(len1, ' ') << sstr.str() << string(len2, ' ');
2496 if (rightLine(cell))
2505 int LyXTabular::plaintext(Buffer const & buf, ostream & os,
2506 OutputParams const & runparams,
2508 bool onlydata, unsigned char delim) const
2512 // first calculate the width of the single columns
2513 vector<unsigned int> clen(columns_);
2516 // first all non (real) multicolumn cells!
2517 for (int j = 0; j < columns_; ++j) {
2519 for (int i = 0; i < rows_; ++i) {
2520 int cell = getCellNumber(i, j);
2521 if (isMultiColumnReal(cell))
2524 getCellInset(cell)->plaintext(buf, sstr, runparams);
2525 if (clen[j] < sstr.str().length())
2526 clen[j] = sstr.str().length();
2529 // then all (real) multicolumn cells!
2530 for (int j = 0; j < columns_; ++j) {
2531 for (int i = 0; i < rows_; ++i) {
2532 int cell = getCellNumber(i, j);
2533 if (!isMultiColumnReal(cell) || isPartOfMultiColumn(i, j))
2536 getCellInset(cell)->plaintext(buf, sstr, runparams);
2537 int len = int(sstr.str().length());
2538 int const n = cells_in_multicolumn(cell);
2539 for (int k = j; len > 0 && k < j + n - 1; ++k)
2541 if (len > int(clen[j + n - 1]))
2542 clen[j + n - 1] = len;
2547 for (int i = 0; i < rows_; ++i) {
2548 if (!onlydata && asciiTopHLine(os, i, clen))
2549 os << string(depth * 2, ' ');
2550 for (int j = 0; j < columns_; ++j) {
2551 if (isPartOfMultiColumn(i, j))
2553 if (onlydata && j > 0)
2555 ret += asciiPrintCell(buf, os, runparams,
2556 cell, i, j, clen, onlydata);
2561 os << string(depth * 2, ' ');
2562 if (asciiBottomHLine(os, i, clen))
2563 os << string(depth * 2, ' ');
2570 shared_ptr<InsetText> LyXTabular::getCellInset(int cell) const
2572 return cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2576 shared_ptr<InsetText> LyXTabular::getCellInset(int row, int column) const
2578 return cell_info[row][column].inset;
2582 int LyXTabular::getCellFromInset(InsetBase const * inset) const
2584 // is this inset part of the tabular?
2586 lyxerr << "Error: this is not a cell of the tabular!" << endl;
2587 BOOST_ASSERT(false);
2590 for (int cell = 0, n = getNumberOfCells(); cell < n; ++cell)
2591 if (getCellInset(cell).get() == inset) {
2592 lyxerr[Debug::INSETTEXT] << "LyXTabular::getCellFromInset: "
2593 << "cell=" << cell << endl;
2597 // We should have found a cell at this point
2598 lyxerr << "LyXTabular::getCellFromInset: Cell of inset "
2599 << inset << " not found!" << endl;
2600 BOOST_ASSERT(false);
2606 void LyXTabular::validate(LaTeXFeatures & features) const
2608 features.require("NeedTabularnewline");
2609 if (isLongTabular())
2610 features.require("longtable");
2612 features.require("rotating");
2613 for (int cell = 0; cell < numberofcells; ++cell) {
2614 if (getVAlignment(cell) != LYX_VALIGN_TOP ||
2615 (!getPWidth(cell).zero() && !isMultiColumn(cell)))
2616 features.require("array");
2617 getCellInset(cell)->validate(features);
2622 void LyXTabular::getLabelList(Buffer const & buffer,
2623 std::vector<string> & list) const
2625 for (int i = 0; i < rows_; ++i)
2626 for (int j = 0; j < columns_; ++j)
2627 getCellInset(i, j)->getLabelList(buffer, list);
2631 LyXTabular::BoxType LyXTabular::useParbox(int cell) const
2633 ParagraphList const & parlist = getCellInset(cell)->paragraphs();
2634 ParagraphList::const_iterator cit = parlist.begin();
2635 ParagraphList::const_iterator end = parlist.end();
2637 for (; cit != end; ++cit)
2638 for (int i = 0; i < cit->size(); ++i)
2639 if (cit->isNewline(i))