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.
21 #include "LaTeXFeatures.h"
29 #include "insets/insettabular.h"
30 #include "insets/insettext.h"
32 #include "support/LAssert.h"
33 #include "support/LIstream.h"
34 #include "support/lstrings.h"
35 #include "support/lyxmanip.h"
36 #include "support/tostr.h"
38 #include "frontends/Alert.h"
39 #include "frontends/Painter.h"
44 using namespace lyx::support;
54 #ifndef CXX_GLOBAL_CSTD
60 int const WIDTH_OF_LINE = 5;
63 string const write_attribute(string const & name, T const & t)
65 string const s = tostr(t);
66 return s.empty() ? s : " " + name + "=\"" + s + "\"";
69 string const write_attribute(string const & name, string const & t)
71 return t.empty() ? t : " " + name + "=\"" + t + "\"";
75 string const write_attribute(string const & name, bool const & b)
77 // we write only true attribute values so we remove a bit of the
78 // file format bloat for tabulars.
79 return b ? write_attribute(name, tostr(b)) : string();
83 string const write_attribute(string const & name, int const & i)
85 // we write only true attribute values so we remove a bit of the
86 // file format bloat for tabulars.
87 return i ? write_attribute(name, tostr(i)) : string();
91 string const write_attribute(string const & name, LyXLength const & value)
93 // we write only the value if we really have one same reson as above.
94 return value.zero() ? string() : write_attribute(name, value.asString());
98 string const tostr(LyXAlignment const & num)
103 case LYX_ALIGN_BLOCK:
107 case LYX_ALIGN_CENTER:
109 case LYX_ALIGN_RIGHT:
111 case LYX_ALIGN_LAYOUT:
113 case LYX_ALIGN_SPECIAL:
120 string const tostr(LyXTabular::VAlignment const & num)
123 case LyXTabular::LYX_VALIGN_TOP:
125 case LyXTabular::LYX_VALIGN_MIDDLE:
127 case LyXTabular::LYX_VALIGN_BOTTOM:
134 string const tostr(LyXTabular::BoxType const & num)
137 case LyXTabular::BOX_NONE:
139 case LyXTabular::BOX_PARBOX:
141 case LyXTabular::BOX_MINIPAGE:
147 // I would have liked a fromstr template a lot better. (Lgb)
148 bool string2type(string const str, LyXAlignment & num)
151 num = LYX_ALIGN_NONE;
152 else if (str == "block")
153 num = LYX_ALIGN_BLOCK;
154 else if (str == "left")
155 num = LYX_ALIGN_LEFT;
156 else if (str == "center")
157 num = LYX_ALIGN_CENTER;
158 else if (str == "right")
159 num = LYX_ALIGN_RIGHT;
166 bool string2type(string const str, LyXTabular::VAlignment & num)
169 num = LyXTabular::LYX_VALIGN_TOP;
170 else if (str == "middle" )
171 num = LyXTabular::LYX_VALIGN_MIDDLE;
172 else if (str == "bottom")
173 num = LyXTabular::LYX_VALIGN_BOTTOM;
180 bool string2type(string const str, LyXTabular::BoxType & num)
183 num = LyXTabular::BOX_NONE;
184 else if (str == "parbox")
185 num = LyXTabular::BOX_PARBOX;
186 else if (str == "minipage")
187 num = LyXTabular::BOX_MINIPAGE;
194 bool string2type(string const str, bool & num)
198 else if (str == "false")
206 bool getTokenValue(string const & str, const char * token, string & ret)
209 size_t token_length = strlen(token);
210 string::size_type pos = str.find(token);
212 if (pos == string::npos || pos + token_length + 1 >= str.length()
213 || str[pos + token_length] != '=')
215 pos += token_length + 1;
217 if ((ch != '"') && (ch != '\'')) { // only read till next space
221 while ((pos < str.length() - 1) && (str[++pos] != ch))
228 bool getTokenValue(string const & str, const char * token, int & num)
232 if (!getTokenValue(str, token, tmp))
239 bool getTokenValue(string const & str, const char * token, LyXAlignment & num)
242 if (!getTokenValue(str, token, tmp))
244 return string2type(tmp, num);
248 bool getTokenValue(string const & str, const char * token,
249 LyXTabular::VAlignment & num)
252 if (!getTokenValue(str, token, tmp))
254 return string2type(tmp, num);
258 bool getTokenValue(string const & str, const char * token,
259 LyXTabular::BoxType & num)
262 if (!getTokenValue(str, token, tmp))
264 return string2type(tmp, num);
268 bool getTokenValue(string const & str, const char * token, bool & flag)
270 // set the flag always to false as this should be the default for bools
271 // not in the file-format.
274 if (!getTokenValue(str, token, tmp))
276 return string2type(tmp, flag);
280 bool getTokenValue(string const & str, const char * token, LyXLength & len)
282 // set the lenght to be zero() as default as this it should be if not
283 // in the file format.
286 if (!getTokenValue(str, token, tmp))
288 return isValidLength(tmp, &len);
292 void l_getline(istream & is, string & str)
295 while (str.empty()) {
297 if (!str.empty() && str[str.length() - 1] == '\r')
298 str.erase(str.length() - 1);
304 /// Define a few methods for the inner structs
306 LyXTabular::cellstruct::cellstruct(BufferParams const & bg)
311 multicolumn = LyXTabular::CELL_NORMAL;
312 alignment = LYX_ALIGN_CENTER;
313 valignment = LYX_VALIGN_TOP;
323 LyXTabular::rowstruct::rowstruct()
330 endfirsthead = false;
337 LyXTabular::columnstruct::columnstruct()
341 alignment = LYX_ALIGN_CENTER;
342 valignment = LYX_VALIGN_TOP;
347 LyXTabular::ltType::ltType()
355 LyXTabular::LyXTabular(BufferParams const & bp,
356 InsetTabular * inset, int rows_arg, int columns_arg)
360 init(bp, rows_arg, columns_arg);
364 LyXTabular::LyXTabular(BufferParams const & bp,
365 InsetTabular * inset, LyXTabular const & lt)
369 init(bp, lt.rows_, lt.columns_, <);
373 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
381 // activates all lines and sets all widths to 0
382 void LyXTabular::init(BufferParams const & bp,
383 int rows_arg, int columns_arg, LyXTabular const * lt)
386 columns_ = columns_arg;
387 row_info = row_vector(rows_, rowstruct());
388 column_info = column_vector(columns_, columnstruct());
389 cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
397 for (int i = 0; i < rows_; ++i) {
398 for (int j = 0; j < columns_; ++j) {
399 cell_info[i][j].inset.setOwner(owner_);
400 cell_info[i][j].inset.setDrawFrame(InsetText::LOCKED);
401 cell_info[i][j].cellno = cellno++;
403 cell_info[i].back().right_line = true;
405 row_info.back().bottom_line = true;
406 row_info.front().bottom_line = true;
408 for (int i = 0; i < columns_; ++i)
409 calculate_width_of_column(i);
411 column_info.back().right_line = true;
413 calculate_width_of_tabular();
416 columnofcell.clear();
417 set_row_column_number_info();
418 is_long_tabular = false;
423 void LyXTabular::appendRow(BufferParams const & bp, int cell)
427 int row = row_of_cell(cell);
429 row_vector::iterator rit = row_info.begin() + row;
430 row_info.insert(rit, rowstruct());
431 // now set the values of the row before
432 row_info[row] = row_info[row + 1];
435 cell_vvector::iterator cit = cell_info.begin() + row;
436 cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct(bp)));
438 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
441 for (int i = 0; i <= row; ++i)
442 for (int j = 0; j < columns_; ++j)
443 c_info[i][j] = cell_info[i][j];
445 for (int i = row + 1; i < rows_; ++i)
446 for (int j = 0; j < columns_; ++j)
447 c_info[i][j] = cell_info[i-1][j];
451 for (int j = 0; j < columns_; ++j) {
452 cell_info[row][j].inset.clear(false);
453 if (bp.tracking_changes)
454 cell_info[row][j].inset.markNew(true);
461 void LyXTabular::deleteRow(int row)
463 // Not allowed to delete last row
467 row_info.erase(row_info.begin() + row);
468 cell_info.erase(cell_info.begin() + row);
474 void LyXTabular::appendColumn(BufferParams const & bp, int cell)
478 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
480 int const column = column_of_cell(cell);
481 column_vector::iterator cit = column_info.begin() + column + 1;
482 column_info.insert(cit, columnstruct());
483 // set the column values of the column before
484 column_info[column + 1] = column_info[column];
486 for (int i = 0; i < rows_; ++i) {
487 for (int j = 0; j <= column; ++j)
488 c_info[i][j] = cell_info[i][j];
490 for (int j = column + 1; j < columns_; ++j)
491 c_info[i][j] = cell_info[i][j - 1];
493 // care about multicolumns
494 if (c_info[i][column + 1].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
495 c_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
497 if (column + 2 >= columns_
498 || c_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
499 c_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 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::reinit()
532 void LyXTabular::Reinit(bool reset_widths)
535 for (int i = 0; i < rows_; ++i) {
536 for (int j = 0; j < columns_; ++j) {
537 cell_info[i][j].width_of_cell = 0;
538 cell_info[i][j].inset.setOwner(owner_);
543 for (int i = 0; i < columns_; ++i)
544 calculate_width_of_column(i);
546 calculate_width_of_tabular();
548 set_row_column_number_info();
552 void LyXTabular::set_row_column_number_info(bool oldformat)
555 for (int row = 0; row < rows_; ++row) {
556 for (int column = 0; column < columns_; ++column) {
557 if (cell_info[row][column].multicolumn
558 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
560 cell_info[row][column].cellno = numberofcells;
563 ++numberofcells; // because this is one more than as we start from 0
565 rowofcell.resize(numberofcells);
566 columnofcell.resize(numberofcells);
568 for (int row = 0, column = 0, c = 0;
569 c < numberofcells && row < rows_ && column < columns_;) {
571 columnofcell[c] = column;
575 } while (column < columns_ &&
576 cell_info[row][column].multicolumn
577 == LyXTabular::CELL_PART_OF_MULTICOLUMN);
579 if (column == columns_) {
585 for (int row = 0; row < rows_; ++row) {
586 for (int column = 0; column < columns_; ++column) {
587 if (isPartOfMultiColumn(row,column))
589 // now set the right line of multicolumns right for oldformat read
591 cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
593 int cn = cells_in_multicolumn(cell_info[row][column].cellno);
594 cell_info[row][column].right_line =
595 cell_info[row][column+cn-1].right_line;
597 cell_info[row][column].inset.setAutoBreakRows(
598 !getPWidth(getCellNumber(row, column)).zero());
604 int LyXTabular::getNumberOfCells() const
606 return numberofcells;
610 int LyXTabular::numberOfCellsInRow(int cell) const
612 int const row = row_of_cell(cell);
614 for (int i = 0; i < columns_; ++i)
615 if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
621 // returns 1 if there is a topline, returns 0 if not
622 bool LyXTabular::topLine(int cell, bool onlycolumn) const
624 if (!onlycolumn && isMultiColumn(cell))
625 return cellinfo_of_cell(cell).top_line;
626 return row_info[row_of_cell(cell)].top_line;
630 bool LyXTabular::bottomLine(int cell, bool onlycolumn) const
632 if (!onlycolumn && isMultiColumn(cell))
633 return cellinfo_of_cell(cell).bottom_line;
634 return row_info[row_of_cell(cell)].bottom_line;
638 bool LyXTabular::leftLine(int cell, bool onlycolumn) const
640 if (!onlycolumn && isMultiColumn(cell) &&
641 (isFirstCellInRow(cell) || isMultiColumn(cell-1)))
643 if (cellinfo_of_cell(cell).align_special.empty())
644 return cellinfo_of_cell(cell).left_line;
645 return prefixIs(ltrim(cellinfo_of_cell(cell).align_special), "|");
647 if (column_info[column_of_cell(cell)].align_special.empty())
648 return column_info[column_of_cell(cell)].left_line;
649 return prefixIs(ltrim(column_info[column_of_cell(cell)].align_special), "|");
653 bool LyXTabular::rightLine(int cell, bool onlycolumn) const
655 if (!onlycolumn && isMultiColumn(cell) &&
656 (isLastCellInRow(cell) || isMultiColumn(cell+1)))
658 if (cellinfo_of_cell(cell).align_special.empty())
659 return cellinfo_of_cell(cell).right_line;
660 return suffixIs(rtrim(cellinfo_of_cell(cell).align_special), "|");
662 if (column_info[column_of_cell(cell)].align_special.empty())
663 return column_info[right_column_of_cell(cell)].right_line;
664 return suffixIs(rtrim(column_info[column_of_cell(cell)].align_special), "|");
668 bool LyXTabular::topAlreadyDrawn(int cell) const
670 int row = row_of_cell(cell);
671 if (row > 0 && !getAdditionalHeight(row)) {
672 int column = column_of_cell(cell);
675 && cell_info[row][column].multicolumn
676 == LyXTabular::CELL_PART_OF_MULTICOLUMN)
678 if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
679 return row_info[row].bottom_line;
681 return cell_info[row][column].bottom_line;
687 bool LyXTabular::leftAlreadyDrawn(int cell) const
689 int column = column_of_cell(cell);
691 int row = row_of_cell(cell);
693 (cell_info[row][column].multicolumn ==
694 LyXTabular::CELL_PART_OF_MULTICOLUMN));
695 if (getAdditionalWidth(cell_info[row][column].cellno))
697 return rightLine(cell_info[row][column].cellno);
703 bool LyXTabular::isLastRow(int cell) const
705 return (row_of_cell(cell) == rows_ - 1);
709 int LyXTabular::getAdditionalHeight(int row) const
711 if (!row || row >= rows_)
717 for (int column = 0; column < columns_ && bottom; ++column) {
718 switch (cell_info[row - 1][column].multicolumn) {
719 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
720 bottom = cell_info[row - 1][column].bottom_line;
722 case LyXTabular::CELL_NORMAL:
723 bottom = row_info[row - 1].bottom_line;
726 for (int column = 0; column < columns_ && top; ++column) {
727 switch (cell_info[row][column].multicolumn) {
728 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
729 top = cell_info[row][column].top_line;
731 case LyXTabular::CELL_NORMAL:
732 top = row_info[row].top_line;
736 return WIDTH_OF_LINE;
741 int LyXTabular::getAdditionalWidth(int cell) const
743 // internally already set in setWidthOfCell
744 // used to get it back in text.C
745 int const col = right_column_of_cell(cell);
746 int const row = row_of_cell(cell);
747 if (col < columns_ - 1 && rightLine(cell) &&
748 leftLine(cell_info[row][col+1].cellno)) // column_info[col+1].left_line)
750 return WIDTH_OF_LINE;
756 // returns the maximum over all rows
757 int LyXTabular::getWidthOfColumn(int cell) const
759 int const column1 = column_of_cell(cell);
760 int const column2 = right_column_of_cell(cell);
762 for (int i = column1; i <= column2; ++i)
763 result += column_info[i].width_of_column;
768 int LyXTabular::getWidthOfTabular() const
770 return width_of_tabular;
774 // returns true if a complete update is necessary, otherwise false
775 bool LyXTabular::setWidthOfMulticolCell(int cell, int new_width)
777 if (!isMultiColumn(cell))
780 int const row = row_of_cell(cell);
781 int const column1 = column_of_cell(cell);
782 int const column2 = right_column_of_cell(cell);
783 int const old_val = cell_info[row][column2].width_of_cell;
785 // first set columns to 0 so we can calculate the right width
786 for (int i = column1; i <= column2; ++i) {
787 cell_info[row][i].width_of_cell = 0;
789 // set the width to MAX_WIDTH until width > 0
790 int width = new_width + 2 * WIDTH_OF_LINE;
792 for (; i < column2 && width > column_info[i].width_of_column; ++i) {
793 cell_info[row][i].width_of_cell = column_info[i].width_of_column;
794 width -= column_info[i].width_of_column;
797 cell_info[row][i].width_of_cell = width;
799 if (old_val != cell_info[row][column2].width_of_cell) {
800 // in this case we have to recalculate all multicolumn cells which
801 // have this column as one of theirs but not as last one
802 calculate_width_of_column_NMC(i);
803 recalculateMulticolumnsOfColumn(i);
804 calculate_width_of_column(i);
810 void LyXTabular::recalculateMulticolumnsOfColumn(int column)
812 // the last column does not have to be recalculated because all
813 // multicolumns will have here there last multicolumn cell which
814 // always will have the whole rest of the width of the cell.
815 if (column > (columns_ - 2))
817 for(int row = 0; row < rows_; ++row) {
818 int mc = cell_info[row][column].multicolumn;
819 int nmc = cell_info[row][column+1].multicolumn;
820 // we only have to update multicolumns which do not have this
821 // column as their last column!
822 if (mc == CELL_BEGIN_OF_MULTICOLUMN ||
823 (mc == CELL_PART_OF_MULTICOLUMN &&
824 nmc == CELL_PART_OF_MULTICOLUMN))
826 int const cellno = cell_info[row][column].cellno;
827 setWidthOfMulticolCell(cellno,
828 getWidthOfCell(cellno) - 2 * WIDTH_OF_LINE);
834 // returns 1 if a complete update is necessary, otherwise 0
835 void LyXTabular::setWidthOfCell(int cell, int new_width)
837 int const row = row_of_cell(cell);
838 int const column1 = column_of_cell(cell);
843 if (rightLine(cell_info[row][column1].cellno, true) &&
844 column1 < columns_ - 1 &&
845 leftLine(cell_info[row][column1+1].cellno, true))
847 add_width = WIDTH_OF_LINE;
850 if (getWidthOfCell(cell) == new_width + 2 * WIDTH_OF_LINE + add_width)
853 if (isMultiColumn(cell, true)) {
854 tmp = setWidthOfMulticolCell(cell, new_width);
856 width = new_width + 2 * WIDTH_OF_LINE + add_width;
857 cell_info[row][column1].width_of_cell = width;
858 tmp = calculate_width_of_column_NMC(column1);
860 recalculateMulticolumnsOfColumn(column1);
863 for (int i = 0; i < columns_; ++i)
864 calculate_width_of_column(i);
865 calculate_width_of_tabular();
870 void LyXTabular::setAlignment(int cell, LyXAlignment align, bool onlycolumn)
872 if (!isMultiColumn(cell) || onlycolumn)
873 column_info[column_of_cell(cell)].alignment = align;
875 cellinfo_of_cell(cell).alignment = align;
879 void LyXTabular::setVAlignment(int cell, VAlignment align, bool onlycolumn)
881 if (!isMultiColumn(cell) || onlycolumn)
882 column_info[column_of_cell(cell)].valignment = align;
884 cellinfo_of_cell(cell).valignment = align;
888 void LyXTabular::setColumnPWidth(int cell, LyXLength const & width)
890 int const j = column_of_cell(cell);
892 column_info[j].p_width = width;
893 for (int i = 0; i < rows_; ++i) {
894 int const cell = getCellNumber(i, j);
895 // because of multicolumns
896 getCellInset(cell).setAutoBreakRows(!getPWidth(cell).zero());
901 bool LyXTabular::setMColumnPWidth(int cell, LyXLength const & width)
903 bool const flag = !width.zero();
905 cellinfo_of_cell(cell).p_width = width;
906 if (isMultiColumn(cell)) {
907 getCellInset(cell).setAutoBreakRows(flag);
914 void LyXTabular::setAlignSpecial(int cell, string const & special,
915 LyXTabular::Feature what)
917 if (what == SET_SPECIAL_MULTI)
918 cellinfo_of_cell(cell).align_special = special;
920 column_info[column_of_cell(cell)].align_special = special;
924 void LyXTabular::setAllLines(int cell, bool line)
926 setTopLine(cell, line);
927 setBottomLine(cell, line);
928 setRightLine(cell, line);
929 setLeftLine(cell, line);
933 void LyXTabular::setTopLine(int cell, bool line, bool onlycolumn)
935 int const row = row_of_cell(cell);
936 if (onlycolumn || !isMultiColumn(cell))
937 row_info[row].top_line = line;
939 cellinfo_of_cell(cell).top_line = line;
943 void LyXTabular::setBottomLine(int cell, bool line, bool onlycolumn)
945 if (onlycolumn || !isMultiColumn(cell))
946 row_info[row_of_cell(cell)].bottom_line = line;
948 cellinfo_of_cell(cell).bottom_line = line;
952 void LyXTabular::setLeftLine(int cell, bool line, bool onlycolumn)
954 if (onlycolumn || !isMultiColumn(cell))
955 column_info[column_of_cell(cell)].left_line = line;
957 cellinfo_of_cell(cell).left_line = line;
961 void LyXTabular::setRightLine(int cell, bool line, bool onlycolumn)
963 if (onlycolumn || !isMultiColumn(cell))
964 column_info[right_column_of_cell(cell)].right_line = line;
966 cellinfo_of_cell(cell).right_line = line;
970 LyXAlignment LyXTabular::getAlignment(int cell, bool onlycolumn) const
972 if (!onlycolumn && isMultiColumn(cell))
973 return cellinfo_of_cell(cell).alignment;
974 return column_info[column_of_cell(cell)].alignment;
978 LyXTabular::VAlignment
979 LyXTabular::getVAlignment(int cell, bool onlycolumn) const
981 if (!onlycolumn && isMultiColumn(cell))
982 return cellinfo_of_cell(cell).valignment;
983 return column_info[column_of_cell(cell)].valignment;
987 LyXLength const LyXTabular::getPWidth(int cell) const
989 if (isMultiColumn(cell))
990 return cellinfo_of_cell(cell).p_width;
991 return column_info[column_of_cell(cell)].p_width;
995 LyXLength const LyXTabular::getColumnPWidth(int cell) const
997 return column_info[column_of_cell(cell)].p_width;
1001 LyXLength const LyXTabular::getMColumnPWidth(int cell) const
1003 if (isMultiColumn(cell))
1004 return cellinfo_of_cell(cell).p_width;
1009 string const LyXTabular::getAlignSpecial(int cell, int what) const
1011 if (what == SET_SPECIAL_MULTI)
1012 return cellinfo_of_cell(cell).align_special;
1013 return column_info[column_of_cell(cell)].align_special;
1017 int LyXTabular::getWidthOfCell(int cell) const
1019 int const row = row_of_cell(cell);
1020 int const column1 = column_of_cell(cell);
1021 int const column2 = right_column_of_cell(cell);
1023 for (int i = column1; i <= column2; ++i)
1024 result += cell_info[row][i].width_of_cell;
1029 int LyXTabular::getBeginningOfTextInCell(int cell) const
1033 switch (getAlignment(cell)) {
1034 case LYX_ALIGN_CENTER:
1035 x += (getWidthOfColumn(cell) - getWidthOfCell(cell)) / 2;
1037 case LYX_ALIGN_RIGHT:
1038 x += getWidthOfColumn(cell) - getWidthOfCell(cell);
1039 // + getAdditionalWidth(cell);
1042 // LYX_ALIGN_LEFT: nothing :-)
1046 // the LaTeX Way :-(
1052 bool LyXTabular::isFirstCellInRow(int cell) const
1054 return column_of_cell(cell) == 0;
1058 int LyXTabular::getFirstCellInRow(int row) const
1060 if (row > rows_ - 1)
1062 return cell_info[row][0].cellno;
1066 bool LyXTabular::isLastCellInRow(int cell) const
1068 return right_column_of_cell(cell) == columns_ - 1;
1072 int LyXTabular::getLastCellInRow(int row) const
1074 if (row > rows_ - 1)
1076 return cell_info[row][columns_-1].cellno;
1080 void LyXTabular::calculate_width_of_column(int column)
1083 for (int i = 0; i < rows_; ++i)
1084 maximum = max(cell_info[i][column].width_of_cell, maximum);
1085 column_info[column].width_of_column = maximum;
1090 // Calculate the columns regarding ONLY the normal cells and if this
1091 // column is inside a multicolumn cell then use it only if its the last
1092 // column of this multicolumn cell as this gives an added width to the
1093 // column, all the rest should be adapted!
1095 bool LyXTabular::calculate_width_of_column_NMC(int column)
1097 int const old_column_width = column_info[column].width_of_column;
1099 for (int i = 0; i < rows_; ++i) {
1100 int cell = getCellNumber(i, column);
1101 bool ismulti = isMultiColumn(cell, true);
1102 if ((!ismulti || column == right_column_of_cell(cell)) &&
1103 cell_info[i][column].width_of_cell > max)
1105 max = cell_info[i][column].width_of_cell;
1108 column_info[column].width_of_column = max;
1109 return column_info[column].width_of_column != old_column_width;
1113 void LyXTabular::calculate_width_of_tabular()
1115 width_of_tabular = 0;
1116 for (int i = 0; i < columns_; ++i)
1117 width_of_tabular += column_info[i].width_of_column;
1121 int LyXTabular::row_of_cell(int cell) const
1123 if (cell >= numberofcells)
1127 return rowofcell[cell];
1131 int LyXTabular::column_of_cell(int cell) const
1133 if (cell >= numberofcells)
1134 return columns_ - 1;
1137 return columnofcell[cell];
1141 int LyXTabular::right_column_of_cell(int cell) const
1143 int const row = row_of_cell(cell);
1144 int column = column_of_cell(cell);
1145 while (column < columns_ - 1 &&
1146 cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
1152 void LyXTabular::write(Buffer const * buf, ostream & os) const
1156 << write_attribute("version", 3)
1157 << write_attribute("rows", rows_)
1158 << write_attribute("columns", columns_)
1160 // global longtable options
1162 << write_attribute("rotate", rotate)
1163 << write_attribute("islongtable", is_long_tabular)
1164 << write_attribute("firstHeadTopDL", endfirsthead.topDL)
1165 << write_attribute("firstHeadBottomDL", endfirsthead.bottomDL)
1166 << write_attribute("firstHeadEmpty", endfirsthead.empty)
1167 << write_attribute("headTopDL", endhead.topDL)
1168 << write_attribute("headBottomDL", endhead.bottomDL)
1169 << write_attribute("footTopDL", endfoot.topDL)
1170 << write_attribute("footBottomDL", endfoot.bottomDL)
1171 << write_attribute("lastFootTopDL", endlastfoot.topDL)
1172 << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
1173 << write_attribute("lastFootEmpty", endlastfoot.empty)
1175 for (int j = 0; j < columns_; ++j) {
1177 << write_attribute("alignment", column_info[j].alignment)
1178 << write_attribute("valignment", column_info[j].valignment)
1179 << write_attribute("leftline", column_info[j].left_line)
1180 << write_attribute("rightline", column_info[j].right_line)
1181 << write_attribute("width", column_info[j].p_width.asString())
1182 << write_attribute("special", column_info[j].align_special)
1185 for (int i = 0; i < rows_; ++i) {
1187 << write_attribute("topline", row_info[i].top_line)
1188 << write_attribute("bottomline", row_info[i].bottom_line)
1189 << write_attribute("endhead", row_info[i].endhead)
1190 << write_attribute("endfirsthead", row_info[i].endfirsthead)
1191 << write_attribute("endfoot", row_info[i].endfoot)
1192 << write_attribute("endlastfoot", row_info[i].endlastfoot)
1193 << write_attribute("newpage", row_info[i].newpage)
1195 for (int j = 0; j < columns_; ++j) {
1197 << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1198 << write_attribute("alignment", cell_info[i][j].alignment)
1199 << write_attribute("valignment", cell_info[i][j].valignment)
1200 << write_attribute("topline", cell_info[i][j].top_line)
1201 << write_attribute("bottomline", cell_info[i][j].bottom_line)
1202 << write_attribute("leftline", cell_info[i][j].left_line)
1203 << write_attribute("rightline", cell_info[i][j].right_line)
1204 << write_attribute("rotate", cell_info[i][j].rotate)
1205 << write_attribute("usebox", cell_info[i][j].usebox)
1206 << write_attribute("width", cell_info[i][j].p_width)
1207 << write_attribute("special", cell_info[i][j].align_special)
1209 os << "\\begin_inset ";
1210 cell_info[i][j].inset.write(buf, os);
1211 os << "\n\\end_inset \n"
1216 os << "</lyxtabular>\n";
1220 void LyXTabular::setHeaderFooterRows(int hr, int fhr, int fr, int lfr)
1224 row_info[--hr].endhead = true;
1226 // set firstheader info
1227 if (fhr && fhr < rows_) {
1228 if (row_info[fhr].endhead) {
1230 row_info[--fhr].endfirsthead = true;
1231 row_info[fhr].endhead = false;
1233 } else if (row_info[fhr - 1].endhead) {
1234 endfirsthead.empty = true;
1236 while (fhr > 0 && !row_info[--fhr].endhead) {
1237 row_info[fhr].endfirsthead = true;
1242 if (fr && fr < rows_) {
1243 if (row_info[fr].endhead && row_info[fr-1].endhead) {
1244 while (fr > 0 && !row_info[--fr].endhead) {
1245 row_info[fr].endfoot = true;
1246 row_info[fr].endhead = false;
1248 } else if (row_info[fr].endfirsthead && row_info[fr-1].endfirsthead) {
1249 while (fr > 0 && !row_info[--fr].endfirsthead) {
1250 row_info[fr].endfoot = true;
1251 row_info[fr].endfirsthead = false;
1253 } else if (!row_info[fr - 1].endhead && !row_info[fr - 1].endfirsthead) {
1254 while (fr > 0 && !row_info[--fr].endhead &&
1255 !row_info[fr].endfirsthead)
1257 row_info[fr].endfoot = true;
1261 // set lastfooter info
1262 if (lfr && lfr < rows_) {
1263 if (row_info[lfr].endhead && row_info[lfr - 1].endhead) {
1264 while (lfr > 0 && !row_info[--lfr].endhead) {
1265 row_info[lfr].endlastfoot = true;
1266 row_info[lfr].endhead = false;
1268 } else if (row_info[lfr].endfirsthead &&
1269 row_info[lfr - 1].endfirsthead)
1271 while (lfr > 0 && !row_info[--lfr].endfirsthead) {
1272 row_info[lfr].endlastfoot = true;
1273 row_info[lfr].endfirsthead = false;
1275 } else if (row_info[lfr].endfoot
1276 && row_info[lfr - 1].endfoot) {
1277 while (lfr > 0 && !row_info[--lfr].endfoot) {
1278 row_info[lfr].endlastfoot = true;
1279 row_info[lfr].endfoot = false;
1281 } else if (!row_info[fr - 1].endhead
1282 && !row_info[fr - 1].endfirsthead &&
1283 !row_info[fr - 1].endfoot)
1286 !row_info[--lfr].endhead && !row_info[lfr].endfirsthead &&
1287 !row_info[lfr].endfoot)
1289 row_info[lfr].endlastfoot = true;
1291 } else if (haveLTFoot()) {
1292 endlastfoot.empty = true;
1298 void LyXTabular::read(Buffer const * buf, LyXLex & lex)
1301 istream & is = lex.getStream();
1303 l_getline(is, line);
1304 if (!prefixIs(line, "<lyxtabular ")
1305 && !prefixIs(line, "<LyXTabular ")) {
1311 if (!getTokenValue(line, "version", version))
1313 Assert(version >= 2);
1316 if (!getTokenValue(line, "rows", rows_arg))
1319 if (!getTokenValue(line, "columns", columns_arg))
1321 init(buf->params, rows_arg, columns_arg);
1322 l_getline(is, line);
1323 if (!prefixIs(line, "<features")) {
1324 lyxerr << "Wrong tabular format (expected <features ...> got"
1325 << line << ')' << endl;
1328 getTokenValue(line, "rotate", rotate);
1329 getTokenValue(line, "islongtable", is_long_tabular);
1330 // compatibility read for old longtable options. Now we can make any
1331 // row part of the header/footer type we want before it was strict
1332 // sequential from the first row down (as LaTeX does it!). So now when
1333 // we find a header/footer line we have to go up the rows and set it
1334 // on all preceding rows till the first or one with already a h/f option
1335 // set. If we find a firstheader on the same line as a header or a
1336 // lastfooter on the same line as a footer then this should be set empty.
1344 getTokenValue(line, "endhead", hrow);
1345 getTokenValue(line, "endfirsthead", fhrow);
1346 getTokenValue(line, "endfoot", frow);
1347 getTokenValue(line, "endlastfoot", lfrow);
1348 setHeaderFooterRows(abs(hrow), abs(fhrow), abs(frow), abs(lfrow));
1350 getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
1351 getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
1352 getTokenValue(line, "firstHeadEmpty", endfirsthead.empty);
1353 getTokenValue(line, "headTopDL", endhead.topDL);
1354 getTokenValue(line, "headBottomDL", endhead.bottomDL);
1355 getTokenValue(line, "footTopDL", endfoot.topDL);
1356 getTokenValue(line, "footBottomDL", endfoot.bottomDL);
1357 getTokenValue(line, "lastFootTopDL", endlastfoot.topDL);
1358 getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
1359 getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
1361 for (int j = 0; j < columns_; ++j) {
1363 if (!prefixIs(line,"<column")) {
1364 lyxerr << "Wrong tabular format (expected <column ...> got"
1365 << line << ')' << endl;
1368 getTokenValue(line, "alignment", column_info[j].alignment);
1369 getTokenValue(line, "valignment", column_info[j].valignment);
1370 getTokenValue(line, "leftline", column_info[j].left_line);
1371 getTokenValue(line, "rightline", column_info[j].right_line);
1372 getTokenValue(line, "width", column_info[j].p_width);
1373 getTokenValue(line, "special", column_info[j].align_special);
1376 for (int i = 0; i < rows_; ++i) {
1377 l_getline(is, line);
1378 if (!prefixIs(line, "<row")) {
1379 lyxerr << "Wrong tabular format (expected <row ...> got"
1380 << line << ')' << endl;
1383 getTokenValue(line, "topline", row_info[i].top_line);
1384 getTokenValue(line, "bottomline", row_info[i].bottom_line);
1385 getTokenValue(line, "endfirsthead", row_info[i].endfirsthead);
1386 getTokenValue(line, "endhead", row_info[i].endhead);
1387 getTokenValue(line, "endfoot", row_info[i].endfoot);
1388 getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
1389 getTokenValue(line, "newpage", row_info[i].newpage);
1390 for (int j = 0; j < columns_; ++j) {
1391 l_getline(is, line);
1392 if (!prefixIs(line, "<cell")) {
1393 lyxerr << "Wrong tabular format (expected <cell ...> got"
1394 << line << ')' << endl;
1397 getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1398 getTokenValue(line, "alignment", cell_info[i][j].alignment);
1399 getTokenValue(line, "valignment", cell_info[i][j].valignment);
1400 getTokenValue(line, "topline", cell_info[i][j].top_line);
1401 getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1402 getTokenValue(line, "leftline", cell_info[i][j].left_line);
1403 getTokenValue(line, "rightline", cell_info[i][j].right_line);
1404 getTokenValue(line, "rotate", cell_info[i][j].rotate);
1405 getTokenValue(line, "usebox", cell_info[i][j].usebox);
1406 getTokenValue(line, "width", cell_info[i][j].p_width);
1407 getTokenValue(line, "special", cell_info[i][j].align_special);
1408 l_getline(is, line);
1409 if (prefixIs(line, "\\begin_inset")) {
1410 cell_info[i][j].inset.read(buf, lex);
1411 l_getline(is, line);
1413 if (!prefixIs(line, "</cell>")) {
1414 lyxerr << "Wrong tabular format (expected </cell> got"
1415 << line << ')' << endl;
1419 l_getline(is, line);
1420 if (!prefixIs(line, "</row>")) {
1421 lyxerr << "Wrong tabular format (expected </row> got"
1422 << line << ')' << endl;
1426 while (!prefixIs(line, "</lyxtabular>")) {
1427 l_getline(is, line);
1429 set_row_column_number_info();
1433 bool LyXTabular::isMultiColumn(int cell, bool real) const
1435 return (!real || column_of_cell(cell) != right_column_of_cell(cell)) &&
1436 cellinfo_of_cell(cell).multicolumn != LyXTabular::CELL_NORMAL;
1440 LyXTabular::cellstruct & LyXTabular::cellinfo_of_cell(int cell) const
1442 return cell_info[row_of_cell(cell)][column_of_cell(cell)];
1446 void LyXTabular::setMultiColumn(Buffer * buffer, int cell, int number)
1448 cellstruct & cs = cellinfo_of_cell(cell);
1449 cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1450 cs.alignment = column_info[column_of_cell(cell)].alignment;
1451 cs.top_line = row_info[row_of_cell(cell)].top_line;
1452 cs.bottom_line = row_info[row_of_cell(cell)].bottom_line;
1453 cs.right_line = column_info[column_of_cell(cell+number-1)].right_line;
1454 for (int i = 1; i < number; ++i) {
1455 cellstruct & cs1 = cellinfo_of_cell(cell + i);
1456 cs1.multicolumn = CELL_PART_OF_MULTICOLUMN;
1457 cs.inset.appendParagraphs(buffer, cs1.inset.paragraphs);
1458 cs1.inset.clear(false);
1460 set_row_column_number_info();
1464 int LyXTabular::cells_in_multicolumn(int cell) const
1466 int const row = row_of_cell(cell);
1467 int column = column_of_cell(cell);
1470 while (column < columns_ &&
1471 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1480 int LyXTabular::unsetMultiColumn(int cell)
1482 int const row = row_of_cell(cell);
1483 int column = column_of_cell(cell);
1487 if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1488 cell_info[row][column].multicolumn = CELL_NORMAL;
1490 while (column < columns_ &&
1491 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1493 cell_info[row][column].multicolumn = CELL_NORMAL;
1498 set_row_column_number_info();
1503 void LyXTabular::setLongTabular(bool what)
1505 is_long_tabular = what;
1509 bool LyXTabular::isLongTabular() const
1511 return is_long_tabular;
1515 void LyXTabular::setRotateTabular(bool flag)
1521 bool LyXTabular::getRotateTabular() const
1527 void LyXTabular::setRotateCell(int cell, bool flag)
1529 cellinfo_of_cell(cell).rotate = flag;
1533 bool LyXTabular::getRotateCell(int cell) const
1535 return cellinfo_of_cell(cell).rotate;
1539 bool LyXTabular::needRotating() const
1543 for (int i = 0; i < rows_; ++i)
1544 for (int j = 0; j < columns_; ++j)
1545 if (cell_info[i][j].rotate)
1551 bool LyXTabular::isLastCell(int cell) const
1553 if (cell + 1 < numberofcells)
1559 int LyXTabular::getCellAbove(int cell) const
1561 if (row_of_cell(cell) > 0)
1562 return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1567 int LyXTabular::getCellBelow(int cell) const
1569 if (row_of_cell(cell) + 1 < rows_)
1570 return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1575 int LyXTabular::getLastCellAbove(int cell) const
1577 if (row_of_cell(cell) <= 0)
1579 if (!isMultiColumn(cell))
1580 return getCellAbove(cell);
1581 return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1585 int LyXTabular::getLastCellBelow(int cell) const
1587 if (row_of_cell(cell) + 1 >= rows_)
1589 if (!isMultiColumn(cell))
1590 return getCellBelow(cell);
1591 return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1595 int LyXTabular::getCellNumber(int row, int column) const
1597 Assert(column >= 0 || column < columns_ || row >= 0 || row < rows_);
1598 return cell_info[row][column].cellno;
1602 void LyXTabular::setUsebox(int cell, BoxType type)
1604 cellinfo_of_cell(cell).usebox = type;
1608 LyXTabular::BoxType LyXTabular::getUsebox(int cell) const
1610 if (column_info[column_of_cell(cell)].p_width.zero() &&
1611 !(isMultiColumn(cell) && !cellinfo_of_cell(cell).p_width.zero()))
1613 if (cellinfo_of_cell(cell).usebox > 1)
1614 return cellinfo_of_cell(cell).usebox;
1615 return useParbox(cell);
1620 // This are functions used for the longtable support
1622 void LyXTabular::setLTHead(int row, bool flag, ltType const & hd, bool first)
1627 row_info[row].endfirsthead = flag;
1631 row_info[row].endhead = flag;
1636 bool LyXTabular::getRowOfLTHead(int row, ltType & hd) const
1639 hd.set = haveLTHead();
1640 return row_info[row].endhead;
1644 bool LyXTabular::getRowOfLTFirstHead(int row, ltType & hd) const
1647 hd.set = haveLTFirstHead();
1648 return row_info[row].endfirsthead;
1652 void LyXTabular::setLTFoot(int row, bool flag, ltType const & fd, bool last)
1657 row_info[row].endlastfoot = flag;
1661 row_info[row].endfoot = flag;
1666 bool LyXTabular::getRowOfLTFoot(int row, ltType & fd) const
1669 fd.set = haveLTFoot();
1670 return row_info[row].endfoot;
1674 bool LyXTabular::getRowOfLTLastFoot(int row, ltType & fd) const
1677 fd.set = haveLTLastFoot();
1678 return row_info[row].endlastfoot;
1682 void LyXTabular::setLTNewPage(int row, bool what)
1684 row_info[row].newpage = what;
1688 bool LyXTabular::getLTNewPage(int row) const
1690 return row_info[row].newpage;
1694 bool LyXTabular::haveLTHead() const
1696 for (int i = 0; i < rows_; ++i)
1697 if (row_info[i].endhead)
1703 bool LyXTabular::haveLTFirstHead() const
1705 if (endfirsthead.empty)
1707 for (int i = 0; i < rows_; ++i)
1708 if (row_info[i].endfirsthead)
1714 bool LyXTabular::haveLTFoot() const
1716 for (int i = 0; i < rows_; ++i)
1717 if (row_info[i].endfoot)
1723 bool LyXTabular::haveLTLastFoot() const
1725 if (endlastfoot.empty)
1727 for (int i = 0; i < rows_; ++i)
1728 if (row_info[i].endlastfoot)
1734 // end longtable support functions
1736 void LyXTabular::setAscentOfRow(int row, int height)
1738 if (row >= rows_ || row_info[row].ascent_of_row == height)
1740 row_info[row].ascent_of_row = height;
1744 void LyXTabular::setDescentOfRow(int row, int height)
1746 if (row >= rows_ || row_info[row].descent_of_row == height)
1748 row_info[row].descent_of_row = height;
1752 int LyXTabular::getAscentOfRow(int row) const
1756 return row_info[row].ascent_of_row;
1760 int LyXTabular::getDescentOfRow(int row) const
1764 return row_info[row].descent_of_row;
1768 int LyXTabular::getHeightOfTabular() const
1771 for (int row = 0; row < rows_; ++row)
1772 height += getAscentOfRow(row) + getDescentOfRow(row) +
1773 getAdditionalHeight(row);
1778 bool LyXTabular::isPartOfMultiColumn(int row, int column) const
1780 if (row >= rows_ || column >= columns_)
1782 return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN;
1786 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1788 if (row < 0 || row >= rows_)
1791 int const fcell = getFirstCellInRow(row);
1792 int const n = numberOfCellsInRow(fcell) + fcell;
1795 for (int i = fcell; i < n; ++i) {
1799 if (tmp == n - fcell) {
1802 for (int i = fcell; i < n; ++i) {
1805 << column_of_cell(i) + 1
1807 << right_column_of_cell(i) + 1
1819 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1821 if (row < 0 || row >= rows_)
1824 int const fcell = getFirstCellInRow(row);
1825 int const n = numberOfCellsInRow(fcell) + fcell;
1828 for (int i = fcell; i < n; ++i) {
1832 if (tmp == n - fcell) {
1835 for (int i = fcell; i < n; ++i) {
1836 if (bottomLine(i)) {
1838 << column_of_cell(i) + 1
1840 << right_column_of_cell(i) + 1
1852 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
1856 if (getRotateCell(cell)) {
1857 os << "\\begin{sideways}\n";
1860 if (isMultiColumn(cell)) {
1861 os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
1862 if (!cellinfo_of_cell(cell).align_special.empty()) {
1863 os << cellinfo_of_cell(cell).align_special << "}{";
1865 if (leftLine(cell) &&
1866 (isFirstCellInRow(cell) ||
1867 (!isMultiColumn(cell - 1) && !leftLine(cell, true) &&
1868 !rightLine(cell - 1, true))))
1872 if (!getPWidth(cell).zero()) {
1873 switch (getVAlignment(cell)) {
1874 case LYX_VALIGN_TOP:
1877 case LYX_VALIGN_MIDDLE:
1880 case LYX_VALIGN_BOTTOM:
1885 << getPWidth(cell).asLatexString()
1888 switch (getAlignment(cell)) {
1889 case LYX_ALIGN_LEFT:
1892 case LYX_ALIGN_RIGHT:
1900 if (rightLine(cell))
1902 if (((cell + 1) < numberofcells) && !isFirstCellInRow(cell+1) &&
1908 if (getUsebox(cell) == BOX_PARBOX) {
1910 switch (getVAlignment(cell)) {
1911 case LYX_VALIGN_TOP:
1914 case LYX_VALIGN_MIDDLE:
1917 case LYX_VALIGN_BOTTOM:
1921 os << "]{" << getPWidth(cell).asLatexString() << "}{";
1922 } else if (getUsebox(cell) == BOX_MINIPAGE) {
1923 os << "\\begin{minipage}[";
1924 switch (getVAlignment(cell)) {
1925 case LYX_VALIGN_TOP:
1928 case LYX_VALIGN_MIDDLE:
1931 case LYX_VALIGN_BOTTOM:
1935 os << "]{" << getPWidth(cell).asLatexString() << "}\n";
1942 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
1947 if (getUsebox(cell) == BOX_PARBOX)
1949 else if (getUsebox(cell) == BOX_MINIPAGE) {
1950 os << "%\n\\end{minipage}";
1953 if (isMultiColumn(cell)) {
1956 if (getRotateCell(cell)) {
1957 os << "%\n\\end{sideways}";
1964 int LyXTabular::TeXLongtableHeaderFooter(ostream & os, Buffer const * buf,
1965 LatexRunParams const & runparams) const
1967 if (!is_long_tabular)
1971 // output header info
1973 if (endhead.topDL) {
1977 for (int i = 0; i < rows_; ++i) {
1978 if (row_info[i].endhead) {
1979 ret += TeXRow(os, i, buf, runparams);
1982 if (endhead.bottomDL) {
1986 os << "\\endhead\n";
1988 if (endfirsthead.empty) {
1989 os << "\\endfirsthead\n";
1993 // output firstheader info
1994 if (haveLTFirstHead()) {
1995 if (endfirsthead.topDL) {
1999 for (int i = 0; i < rows_; ++i) {
2000 if (row_info[i].endfirsthead) {
2001 ret += TeXRow(os, i, buf, runparams);
2004 if (endfirsthead.bottomDL) {
2008 os << "\\endfirsthead\n";
2011 // output footer info
2013 if (endfoot.topDL) {
2017 for (int i = 0; i < rows_; ++i) {
2018 if (row_info[i].endfoot) {
2019 ret += TeXRow(os, i, buf, runparams);
2022 if (endfoot.bottomDL) {
2026 os << "\\endfoot\n";
2028 if (endlastfoot.empty) {
2029 os << "\\endlastfoot\n";
2033 // output lastfooter info
2034 if (haveLTLastFoot()) {
2035 if (endlastfoot.topDL) {
2039 for (int i = 0; i < rows_; ++i) {
2040 if (row_info[i].endlastfoot) {
2041 ret += TeXRow(os, i, buf, runparams);
2044 if (endlastfoot.bottomDL) {
2048 os << "\\endlastfoot\n";
2055 bool LyXTabular::isValidRow(int const row) const
2057 if (!is_long_tabular)
2059 return (!row_info[row].endhead && !row_info[row].endfirsthead &&
2060 !row_info[row].endfoot && !row_info[row].endlastfoot);
2064 int LyXTabular::TeXRow(ostream & os, int const i, Buffer const * buf,
2065 LatexRunParams const & runparams) const
2068 int cell = getCellNumber(i, 0);
2070 ret += TeXTopHLine(os, i);
2071 for (int j = 0; j < columns_; ++j) {
2072 if (isPartOfMultiColumn(i, j))
2074 ret += TeXCellPreamble(os, cell);
2075 InsetText & inset = getCellInset(cell);
2077 bool rtl = inset.paragraphs.begin()->isRightToLeftPar(buf->params) &&
2078 !inset.paragraphs.begin()->empty() && getPWidth(cell).zero();
2082 ret += inset.latex(buf, os, runparams);
2086 ret += TeXCellPostamble(os, cell);
2087 if (!isLastCellInRow(cell)) { // not last cell in row
2093 os << "\\tabularnewline\n";
2095 ret += TeXBottomHLine(os, i);
2100 int LyXTabular::latex(Buffer const * buf, ostream & os,
2101 LatexRunParams const & runparams) const
2105 //+---------------------------------------------------------------------
2106 //+ first the opening preamble +
2107 //+---------------------------------------------------------------------
2110 os << "\\begin{sideways}\n";
2113 if (is_long_tabular)
2114 os << "\\begin{longtable}{";
2116 os << "\\begin{tabular}{";
2117 for (int i = 0; i < columns_; ++i) {
2118 if (!column_info[i].align_special.empty()) {
2119 os << column_info[i].align_special;
2121 if (column_info[i].left_line)
2123 if (!column_info[i].p_width.zero()) {
2124 switch (column_info[i].alignment) {
2125 case LYX_ALIGN_LEFT:
2126 os << ">{\\raggedright}";
2128 case LYX_ALIGN_RIGHT:
2129 os << ">{\\raggedleft}";
2131 case LYX_ALIGN_CENTER:
2132 os << ">{\\centering}";
2134 case LYX_ALIGN_NONE:
2135 case LYX_ALIGN_BLOCK:
2136 case LYX_ALIGN_LAYOUT:
2137 case LYX_ALIGN_SPECIAL:
2141 switch (column_info[i].valignment) {
2142 case LYX_VALIGN_TOP:
2145 case LYX_VALIGN_MIDDLE:
2148 case LYX_VALIGN_BOTTOM:
2153 << column_info[i].p_width.asLatexString()
2156 switch (column_info[i].alignment) {
2157 case LYX_ALIGN_LEFT:
2160 case LYX_ALIGN_RIGHT:
2168 if (column_info[i].right_line)
2175 ret += TeXLongtableHeaderFooter(os, buf, runparams);
2177 //+---------------------------------------------------------------------
2178 //+ the single row and columns (cells) +
2179 //+---------------------------------------------------------------------
2181 for (int i = 0; i < rows_; ++i) {
2182 if (isValidRow(i)) {
2183 ret += TeXRow(os, i, buf, runparams);
2184 if (is_long_tabular && row_info[i].newpage) {
2185 os << "\\newpage\n";
2191 //+---------------------------------------------------------------------
2192 //+ the closing of the tabular +
2193 //+---------------------------------------------------------------------
2195 if (is_long_tabular)
2196 os << "\\end{longtable}";
2198 os << "\\end{tabular}";
2200 os << "\n\\end{sideways}";
2208 int LyXTabular::linuxdoc(Buffer const * buf, ostream & os) const
2210 os << "<tabular ca=\"";
2211 for (int i = 0; i < columns_; ++i) {
2212 switch (column_info[i].alignment) {
2213 case LYX_ALIGN_LEFT:
2216 case LYX_ALIGN_RIGHT:
2227 for (int i = 0; i < rows_; ++i) {
2228 for (int j = 0; j < columns_; ++j) {
2229 if (isPartOfMultiColumn(i, j))
2231 InsetText & inset = getCellInset(cell);
2233 ret += inset.linuxdoc(buf, os);
2235 if (isLastCellInRow(cell)) {
2244 os << "</tabular>\n";
2249 int LyXTabular::docbookRow(Buffer const * buf, ostream & os, int row) const
2252 int cell = getFirstCellInRow(row);
2255 for (int j = 0; j < columns_; ++j) {
2256 if (isPartOfMultiColumn(row, j))
2259 os << "<entry align=\"";
2260 switch (getAlignment(cell)) {
2261 case LYX_ALIGN_LEFT:
2264 case LYX_ALIGN_RIGHT:
2272 os << "\" valign=\"";
2273 switch (getVAlignment(cell)) {
2274 case LYX_VALIGN_TOP:
2277 case LYX_VALIGN_BOTTOM:
2280 case LYX_VALIGN_MIDDLE:
2285 if (isMultiColumn(cell)) {
2286 os << " namest=\"col" << j << "\" ";
2287 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
2291 ret += getCellInset(cell).docbook(buf, os, true);
2300 int LyXTabular::docbook(Buffer const * buf, ostream & os,
2301 bool /*mixcont*/) const
2305 //+---------------------------------------------------------------------
2306 //+ first the opening preamble +
2307 //+---------------------------------------------------------------------
2309 os << "<tgroup cols=\"" << columns_
2310 << "\" colsep=\"1\" rowsep=\"1\">\n";
2312 for (int i = 0; i < columns_; ++i) {
2313 os << "<colspec colname=\"col" << i << "\" align=\"";
2314 switch (column_info[i].alignment) {
2315 case LYX_ALIGN_LEFT:
2318 case LYX_ALIGN_RIGHT:
2329 //+---------------------------------------------------------------------
2330 //+ Long Tabular case +
2331 //+---------------------------------------------------------------------
2333 // output header info
2334 if (haveLTHead() || haveLTFirstHead()) {
2337 for (int i = 0; i < rows_; ++i) {
2338 if (row_info[i].endhead || row_info[i].endfirsthead) {
2339 ret += docbookRow(buf, os, i);
2345 // output footer info
2346 if (haveLTFoot() || haveLTLastFoot()) {
2349 for (int i = 0; i < rows_; ++i) {
2350 if (row_info[i].endfoot || row_info[i].endlastfoot) {
2351 ret += docbookRow(buf, os, i);
2358 //+---------------------------------------------------------------------
2359 //+ the single row and columns (cells) +
2360 //+---------------------------------------------------------------------
2364 for (int i = 0; i < rows_; ++i) {
2365 if (isValidRow(i)) {
2366 ret += docbookRow(buf, os, i);
2371 //+---------------------------------------------------------------------
2372 //+ the closing of the tabular +
2373 //+---------------------------------------------------------------------
2382 int LyXTabular::asciiTopHLine(ostream & os, int row,
2383 vector<unsigned int> const & clen) const
2385 int const fcell = getFirstCellInRow(row);
2386 int const n = numberOfCellsInRow(fcell) + fcell;
2389 for (int i = fcell; i < n; ++i) {
2399 for (int i = fcell; i < n; ++i) {
2410 int column = column_of_cell(i);
2411 int len = clen[column];
2412 while (isPartOfMultiColumn(row, ++column))
2413 len += clen[column] + 4;
2414 os << string(len, ch);
2429 int LyXTabular::asciiBottomHLine(ostream & os, int row,
2430 vector<unsigned int> const & clen) const
2432 int const fcell = getFirstCellInRow(row);
2433 int const n = numberOfCellsInRow(fcell) + fcell;
2436 for (int i = fcell; i < n; ++i) {
2437 if (bottomLine(i)) {
2446 for (int i = fcell; i < n; ++i) {
2447 if (bottomLine(i)) {
2457 int column = column_of_cell(i);
2458 int len = clen[column];
2459 while (isPartOfMultiColumn(row, ++column))
2460 len += clen[column] + 4;
2461 os << string(len, ch);
2462 if (bottomLine(i)) {
2476 int LyXTabular::asciiPrintCell(Buffer const * buf, ostream & os,
2477 int cell, int row, int column,
2478 vector<unsigned int> const & clen,
2479 bool onlydata) const
2482 int ret = getCellInset(cell).ascii(buf, sstr, 0);
2494 unsigned int len1 = sstr.str().length();
2495 unsigned int len2 = clen[column];
2496 while (isPartOfMultiColumn(row, ++column))
2497 len2 += clen[column] + 4;
2500 switch (getAlignment(cell)) {
2502 case LYX_ALIGN_LEFT:
2505 case LYX_ALIGN_RIGHT:
2509 case LYX_ALIGN_CENTER:
2515 os << string(len1, ' ') << sstr.str() << string(len2, ' ');
2517 if (rightLine(cell))
2526 int LyXTabular::ascii(Buffer const * buf, ostream & os, int const depth,
2527 bool onlydata, unsigned char delim) const
2531 // first calculate the width of the single columns
2532 vector<unsigned int> clen(columns_);
2535 // first all non (real) multicolumn cells!
2536 for (int j = 0; j < columns_; ++j) {
2538 for (int i = 0; i < rows_; ++i) {
2539 int cell = getCellNumber(i, j);
2540 if (isMultiColumn(cell, true))
2543 getCellInset(cell).ascii(buf, sstr, 0);
2544 if (clen[j] < sstr.str().length())
2545 clen[j] = sstr.str().length();
2548 // then all (real) multicolumn cells!
2549 for (int j = 0; j < columns_; ++j) {
2550 for (int i = 0; i < rows_; ++i) {
2551 int cell = getCellNumber(i, j);
2552 if (!isMultiColumn(cell, true) || isPartOfMultiColumn(i, j))
2555 getCellInset(cell).ascii(buf, sstr, 0);
2556 int len = int(sstr.str().length());
2557 int const n = cells_in_multicolumn(cell);
2558 for (int k = j; len > 0 && k < j + n - 1; ++k)
2560 if (len > int(clen[j + n - 1]))
2561 clen[j + n - 1] = len;
2566 for (int i = 0; i < rows_; ++i) {
2567 if (!onlydata && asciiTopHLine(os, i, clen))
2568 for (int j = 0; j < depth; ++j)
2570 for (int j = 0; j < columns_; ++j) {
2571 if (isPartOfMultiColumn(i, j))
2573 if (onlydata && j > 0)
2575 ret += asciiPrintCell(buf, os, cell, i, j, clen, onlydata);
2580 for (int j = 0; j < depth; ++j)
2582 if (asciiBottomHLine(os, i, clen))
2583 for (int j = 0; j < depth; ++j)
2591 InsetText & LyXTabular::getCellInset(int cell) const
2594 return cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2598 InsetText & LyXTabular::getCellInset(int row, int column) const
2600 cur_cell = getCellNumber(row, column);
2601 return cell_info[row][column].inset;
2605 int LyXTabular::getCellFromInset(InsetOld const * inset, int maybe_cell) const
2607 // is this inset part of the tabular?
2608 if (!inset || inset->owner() != owner_) {
2609 lyxerr << "Error: this is not a cell of the tabular!" << endl;
2613 const int save_cur_cell = cur_cell;
2614 int cell = cur_cell;
2615 if (&getCellInset(cell) != inset) {
2617 if (cell == -1 || &getCellInset(cell) != inset)
2622 for (cell = getNumberOfCells(); cell >= 0; --cell)
2623 if (&getCellInset(cell) == inset)
2626 lyxerr[Debug::INSETTEXT]
2627 << "LyXTabular::getCellFromInset: "
2629 << ", cur_cell=" << save_cur_cell
2630 << ", maybe_cell=" << maybe_cell
2632 // We should have found a cell at this point
2634 lyxerr << "LyXTabular::getCellFromInset: "
2635 << "Cell not found!" << endl;
2643 void LyXTabular::validate(LaTeXFeatures & features) const
2645 features.require("NeedTabularnewline");
2646 if (isLongTabular())
2647 features.require("longtable");
2649 features.require("rotating");
2650 for (int cell = 0; cell < numberofcells; ++cell) {
2651 if (getVAlignment(cell) != LYX_VALIGN_TOP ||
2652 (!getPWidth(cell).zero() && !isMultiColumn(cell)))
2653 features.require("array");
2654 getCellInset(cell).validate(features);
2659 void LyXTabular::getLabelList(std::vector<string> & list) const
2661 for (int i = 0; i < rows_; ++i)
2662 for (int j = 0; j < columns_; ++j)
2663 getCellInset(i, j).getLabelList(list);
2667 LyXTabular::BoxType LyXTabular::useParbox(int cell) const
2669 ParagraphList const & parlist = getCellInset(cell).paragraphs;
2670 ParagraphList::const_iterator cit = parlist.begin();
2671 ParagraphList::const_iterator end = parlist.end();
2673 for (; cit != end; ++cit)
2674 for (int i = 0; i < cit->size(); ++i)
2675 if (cit->isNewline(i))