X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=af0c510bf987535e53c5c691091596d6fc3278d9;hb=4824f7c9db8301550c1bc53c340fbeae916a46f3;hp=9b0abc9690dd2f0ca0941f64170925bdfcdb47e2;hpb=f961b605755866de6b27df591746c5ae06d6a335;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 9b0abc9690..b124743446 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -12,6 +12,8 @@ * \author André Pönitz * \author Jürgen Vigna * \author Uwe Stöhr + * \author Edwin Leuven + * \author Scott Kostyshak * * Full author contact details are available in file CREDITS. */ @@ -31,13 +33,15 @@ #include "DispatchResult.h" #include "FuncRequest.h" #include "FuncStatus.h" +#include "InsetList.h" #include "Language.h" #include "LaTeXFeatures.h" #include "Lexer.h" -#include "LyXFunc.h" +#include "LyX.h" #include "LyXRC.h" #include "MetricsInfo.h" #include "OutputParams.h" +#include "output_xhtml.h" #include "Paragraph.h" #include "ParagraphParameters.h" #include "ParIterator.h" @@ -60,16 +64,14 @@ #include -#include +#include #include #include -#include +#include using namespace std; using namespace lyx::support; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; namespace lyx { @@ -88,7 +90,7 @@ namespace Alert = frontend::Alert; namespace { int const ADD_TO_HEIGHT = 2; // in cell -int const ADD_TO_TABULAR_WIDTH = 6; // horiz space before and after the table +int const ADD_TO_TABULAR_WIDTH = 6; // horizontal space before and after the table int const default_line_space = 10; // ? int const WIDTH_OF_LINE = 5; // space between double lines @@ -100,144 +102,99 @@ boost::scoped_ptr paste_tabular; struct TabularFeature { Tabular::Feature action; string feature; + bool need_value; }; TabularFeature tabularFeature[] = { - { Tabular::APPEND_ROW, "append-row" }, - { Tabular::APPEND_COLUMN, "append-column" }, - { Tabular::DELETE_ROW, "delete-row" }, - { Tabular::DELETE_COLUMN, "delete-column" }, - { Tabular::COPY_ROW, "copy-row" }, - { Tabular::COPY_COLUMN, "copy-column" }, - { Tabular::TOGGLE_LINE_TOP, "toggle-line-top" }, - { Tabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" }, - { Tabular::TOGGLE_LINE_LEFT, "toggle-line-left" }, - { Tabular::TOGGLE_LINE_RIGHT, "toggle-line-right" }, - { Tabular::ALIGN_LEFT, "align-left" }, - { Tabular::ALIGN_RIGHT, "align-right" }, - { Tabular::ALIGN_CENTER, "align-center" }, - { Tabular::ALIGN_BLOCK, "align-block" }, - { Tabular::VALIGN_TOP, "valign-top" }, - { Tabular::VALIGN_BOTTOM, "valign-bottom" }, - { Tabular::VALIGN_MIDDLE, "valign-middle" }, - { Tabular::M_ALIGN_LEFT, "m-align-left" }, - { Tabular::M_ALIGN_RIGHT, "m-align-right" }, - { Tabular::M_ALIGN_CENTER, "m-align-center" }, - { Tabular::M_VALIGN_TOP, "m-valign-top" }, - { Tabular::M_VALIGN_BOTTOM, "m-valign-bottom" }, - { Tabular::M_VALIGN_MIDDLE, "m-valign-middle" }, - { Tabular::MULTICOLUMN, "multicolumn" }, - { Tabular::SET_ALL_LINES, "set-all-lines" }, - { Tabular::UNSET_ALL_LINES, "unset-all-lines" }, - { Tabular::SET_LONGTABULAR, "set-longtabular" }, - { Tabular::UNSET_LONGTABULAR, "unset-longtabular" }, - { Tabular::SET_PWIDTH, "set-pwidth" }, - { Tabular::SET_MPWIDTH, "set-mpwidth" }, - { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular" }, - { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" }, - { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular" }, - { Tabular::SET_ROTATE_CELL, "set-rotate-cell" }, - { Tabular::UNSET_ROTATE_CELL, "unset-rotate-cell" }, - { Tabular::TOGGLE_ROTATE_CELL, "toggle-rotate-cell" }, - { Tabular::SET_USEBOX, "set-usebox" }, - { Tabular::SET_LTHEAD, "set-lthead" }, - { Tabular::UNSET_LTHEAD, "unset-lthead" }, - { Tabular::SET_LTFIRSTHEAD, "set-ltfirsthead" }, - { Tabular::UNSET_LTFIRSTHEAD, "unset-ltfirsthead" }, - { Tabular::SET_LTFOOT, "set-ltfoot" }, - { Tabular::UNSET_LTFOOT, "unset-ltfoot" }, - { Tabular::SET_LTLASTFOOT, "set-ltlastfoot" }, - { Tabular::UNSET_LTLASTFOOT, "unset-ltlastfoot" }, - { Tabular::SET_LTNEWPAGE, "set-ltnewpage" }, - { Tabular::TOGGLE_LTCAPTION, "toggle-ltcaption" }, - { Tabular::SET_SPECIAL_COLUMN, "set-special-column" }, - { Tabular::SET_SPECIAL_MULTI, "set-special-multi" }, - { Tabular::SET_BOOKTABS, "set-booktabs" }, - { Tabular::UNSET_BOOKTABS, "unset-booktabs" }, - { Tabular::SET_TOP_SPACE, "set-top-space" }, - { Tabular::SET_BOTTOM_SPACE, "set-bottom-space" }, - { Tabular::SET_INTERLINE_SPACE, "set-interline-space" }, - { Tabular::SET_BORDER_LINES, "set-border-lines" }, - { Tabular::TABULAR_VALIGN_TOP, "tabular-valign-top"}, - { Tabular::TABULAR_VALIGN_MIDDLE, "tabular-valign-middle"}, - { Tabular::TABULAR_VALIGN_BOTTOM, "tabular-valign-bottom"}, - { Tabular::LONGTABULAR_ALIGN_LEFT, "longtabular-align-left" }, - { Tabular::LONGTABULAR_ALIGN_CENTER, "longtabular-align-center" }, - { Tabular::LONGTABULAR_ALIGN_RIGHT, "longtabular-align-right" }, - { Tabular::LAST_ACTION, "" } + // the SET/UNSET actions are used by the table dialog, + // the TOGGLE actions by the table toolbar buttons + { Tabular::APPEND_ROW, "append-row", false }, + { Tabular::APPEND_COLUMN, "append-column", false }, + { Tabular::DELETE_ROW, "delete-row", false }, + { Tabular::DELETE_COLUMN, "delete-column", false }, + { Tabular::COPY_ROW, "copy-row", false }, + { Tabular::COPY_COLUMN, "copy-column", false }, + { Tabular::MOVE_COLUMN_RIGHT, "move-column-right", false }, + { Tabular::MOVE_COLUMN_LEFT, "move-column-left", false }, + { Tabular::MOVE_ROW_DOWN, "move-row-down", false }, + { Tabular::MOVE_ROW_UP, "move-row-up", false }, + { Tabular::SET_LINE_TOP, "set-line-top", true }, + { Tabular::SET_LINE_BOTTOM, "set-line-bottom", true }, + { Tabular::SET_LINE_LEFT, "set-line-left", true }, + { Tabular::SET_LINE_RIGHT, "set-line-right", true }, + { Tabular::TOGGLE_LINE_TOP, "toggle-line-top", false }, + { Tabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom", false }, + { Tabular::TOGGLE_LINE_LEFT, "toggle-line-left", false }, + { Tabular::TOGGLE_LINE_RIGHT, "toggle-line-right", false }, + { Tabular::ALIGN_LEFT, "align-left", false }, + { Tabular::ALIGN_RIGHT, "align-right", false }, + { Tabular::ALIGN_CENTER, "align-center", false }, + { Tabular::ALIGN_BLOCK, "align-block", false }, + { Tabular::ALIGN_DECIMAL, "align-decimal", false }, + { Tabular::VALIGN_TOP, "valign-top", false }, + { Tabular::VALIGN_BOTTOM, "valign-bottom", false }, + { Tabular::VALIGN_MIDDLE, "valign-middle", false }, + { Tabular::M_ALIGN_LEFT, "m-align-left", false }, + { Tabular::M_ALIGN_RIGHT, "m-align-right", false }, + { Tabular::M_ALIGN_CENTER, "m-align-center", false }, + { Tabular::M_VALIGN_TOP, "m-valign-top", false }, + { Tabular::M_VALIGN_BOTTOM, "m-valign-bottom", false }, + { Tabular::M_VALIGN_MIDDLE, "m-valign-middle", false }, + { Tabular::MULTICOLUMN, "multicolumn", false }, + { Tabular::SET_MULTICOLUMN, "set-multicolumn", false }, + { Tabular::UNSET_MULTICOLUMN, "unset-multicolumn", false }, + { Tabular::MULTIROW, "multirow", false }, + { Tabular::SET_MULTIROW, "set-multirow", false }, + { Tabular::UNSET_MULTIROW, "unset-multirow", false }, + { Tabular::SET_MROFFSET, "set-mroffset", true }, + { Tabular::SET_ALL_LINES, "set-all-lines", false }, + { Tabular::UNSET_ALL_LINES, "unset-all-lines", false }, + { Tabular::SET_LONGTABULAR, "set-longtabular", false }, + { Tabular::UNSET_LONGTABULAR, "unset-longtabular", false }, + { Tabular::SET_PWIDTH, "set-pwidth", true }, + { Tabular::SET_MPWIDTH, "set-mpwidth", true }, + { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular", true }, + { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular", true }, + { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular", true }, + { Tabular::SET_ROTATE_CELL, "set-rotate-cell", true }, + { Tabular::UNSET_ROTATE_CELL, "unset-rotate-cell", true }, + { Tabular::TOGGLE_ROTATE_CELL, "toggle-rotate-cell", true }, + { Tabular::SET_USEBOX, "set-usebox", true }, + { Tabular::SET_LTHEAD, "set-lthead", true }, + { Tabular::UNSET_LTHEAD, "unset-lthead", true }, + { Tabular::SET_LTFIRSTHEAD, "set-ltfirsthead", true }, + { Tabular::UNSET_LTFIRSTHEAD, "unset-ltfirsthead", true }, + { Tabular::SET_LTFOOT, "set-ltfoot", true }, + { Tabular::UNSET_LTFOOT, "unset-ltfoot", true }, + { Tabular::SET_LTLASTFOOT, "set-ltlastfoot", true }, + { Tabular::UNSET_LTLASTFOOT, "unset-ltlastfoot", true }, + { Tabular::SET_LTNEWPAGE, "set-ltnewpage", false }, + { Tabular::UNSET_LTNEWPAGE, "unset-ltnewpage", false }, + { Tabular::TOGGLE_LTCAPTION, "toggle-ltcaption", false }, + { Tabular::SET_LTCAPTION, "set-ltcaption", false }, + { Tabular::UNSET_LTCAPTION, "unset-ltcaption", false }, + { Tabular::SET_SPECIAL_COLUMN, "set-special-column", true }, + { Tabular::SET_SPECIAL_MULTICOLUMN, "set-special-multicolumn", true }, + { Tabular::SET_BOOKTABS, "set-booktabs", false }, + { Tabular::UNSET_BOOKTABS, "unset-booktabs", false }, + { Tabular::SET_TOP_SPACE, "set-top-space", true }, + { Tabular::SET_BOTTOM_SPACE, "set-bottom-space", true }, + { Tabular::SET_INTERLINE_SPACE, "set-interline-space", true }, + { Tabular::SET_BORDER_LINES, "set-border-lines", false }, + { Tabular::TABULAR_VALIGN_TOP, "tabular-valign-top", false}, + { Tabular::TABULAR_VALIGN_MIDDLE, "tabular-valign-middle", false}, + { Tabular::TABULAR_VALIGN_BOTTOM, "tabular-valign-bottom", false}, + { Tabular::LONGTABULAR_ALIGN_LEFT, "longtabular-align-left", false }, + { Tabular::LONGTABULAR_ALIGN_CENTER, "longtabular-align-center", false }, + { Tabular::LONGTABULAR_ALIGN_RIGHT, "longtabular-align-right", false }, + { Tabular::SET_DECIMAL_POINT, "set-decimal-point", true }, + { Tabular::SET_TABULAR_WIDTH, "set-tabular-width", true }, + { Tabular::LAST_ACTION, "", false } }; -class FeatureEqual : public unary_function { -public: - FeatureEqual(Tabular::Feature feature) - : feature_(feature) {} - bool operator()(TabularFeature const & tf) const { - return tf.action == feature_; - } -private: - Tabular::Feature feature_; -}; - - -template -string const write_attribute(string const & name, T const & t) -{ - string const s = tostr(t); - return s.empty() ? s : " " + name + "=\"" + s + "\""; -} - -template <> -string const write_attribute(string const & name, string const & t) -{ - return t.empty() ? t : " " + name + "=\"" + t + "\""; -} - - -template <> -string const write_attribute(string const & name, docstring const & t) -{ - return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\""; -} - - -template <> -string const write_attribute(string const & name, bool const & b) -{ - // we write only true attribute values so we remove a bit of the - // file format bloat for tabulars. - return b ? write_attribute(name, convert(b)) : string(); -} - - -template <> -string const write_attribute(string const & name, int const & i) -{ - // we write only true attribute values so we remove a bit of the - // file format bloat for tabulars. - return i ? write_attribute(name, convert(i)) : string(); -} - - -template <> -string const write_attribute(string const & name, Tabular::idx_type const & i) -{ - // we write only true attribute values so we remove a bit of the - // file format bloat for tabulars. - return i ? write_attribute(name, convert(i)) : string(); -} - - -template <> -string const write_attribute(string const & name, Length const & value) -{ - // we write only the value if we really have one same reson as above. - return value.zero() ? string() : write_attribute(name, value.asString()); -} - - string const tostr(LyXAlignment const & num) { switch (num) { @@ -255,6 +212,8 @@ string const tostr(LyXAlignment const & num) return "layout"; case LYX_ALIGN_SPECIAL: return "special"; + case LYX_ALIGN_DECIMAL: + return "decimal"; } return string(); } @@ -315,6 +274,8 @@ bool string2type(string const str, LyXAlignment & num) num = LYX_ALIGN_CENTER; else if (str == "right") num = LYX_ALIGN_RIGHT; + else if (str == "decimal") + num = LYX_ALIGN_DECIMAL; else return false; return true; @@ -493,19 +454,101 @@ void l_getline(istream & is, string & str) } } +template +string const write_attribute(string const & name, T const & t) +{ + string const s = tostr(t); + return s.empty() ? s : " " + name + "=\"" + s + "\""; +} + +template <> +string const write_attribute(string const & name, string const & t) +{ + return t.empty() ? t : " " + name + "=\"" + t + "\""; +} + + +template <> +string const write_attribute(string const & name, docstring const & t) +{ + return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\""; +} + + +template <> +string const write_attribute(string const & name, bool const & b) +{ + // we write only true attribute values so we remove a bit of the + // file format bloat for tabulars. + return b ? write_attribute(name, convert(b)) : string(); +} + + +template <> +string const write_attribute(string const & name, int const & i) +{ + // we write only true attribute values so we remove a bit of the + // file format bloat for tabulars. + return i ? write_attribute(name, convert(i)) : string(); +} + + +template <> +string const write_attribute(string const & name, Tabular::idx_type const & i) +{ + // we write only true attribute values so we remove a bit of the + // file format bloat for tabulars. + return i ? write_attribute(name, convert(i)) : string(); +} + + +template <> +string const write_attribute(string const & name, Length const & value) +{ + // we write only the value if we really have one same reson as above. + return value.zero() ? string() : write_attribute(name, value.asString()); +} + } // namespace -string const featureAsString(Tabular::Feature feature) +string const featureAsString(Tabular::Feature action) { - TabularFeature * end = tabularFeature + - sizeof(tabularFeature) / sizeof(TabularFeature); - TabularFeature * it = find_if(tabularFeature, end, - FeatureEqual(feature)); - return (it == end) ? string() : it->feature; + for (size_t i = 0; i != Tabular::LAST_ACTION; ++i) { + if (tabularFeature[i].action == action) + return tabularFeature[i].feature; + } + return string(); } +DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d) +{ + DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell); + for (; dit; dit.forwardChar()) + if (dit.inTexted() && dit.depth() == 1 + && dit.paragraph().find(align_d, false, false, dit.pos())) + break; + + return dit; +} + + +InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep) +{ + InsetTableCell tail = InsetTableCell(head); + DocIterator const dit = separatorPos(&head, align_d); + hassep = dit; + if (hassep) { + pit_type const psize = head.paragraphs().front().size(); + head.paragraphs().front().eraseChars(dit.pos(), psize, false); + tail.paragraphs().front().eraseChars(0, + dit.pos() < psize ? dit.pos() + 1 : psize, false); + } + + return tail; +} + ///////////////////////////////////////////////////////////////////// // @@ -518,14 +561,18 @@ Tabular::CellData::CellData(Buffer * buf) : cellno(0), width(0), multicolumn(Tabular::CELL_NORMAL), + multirow(Tabular::CELL_NORMAL), alignment(LYX_ALIGN_CENTER), valignment(LYX_VALIGN_TOP), + decimal_hoffset(0), + decimal_width(0), + voffset(0), top_line(false), bottom_line(false), left_line(false), right_line(false), usebox(BOX_NONE), - rotate(false), + rotate(0), inset(new InsetTableCell(buf)) { inset->setBuffer(*buf); @@ -536,8 +583,13 @@ Tabular::CellData::CellData(CellData const & cs) : cellno(cs.cellno), width(cs.width), multicolumn(cs.multicolumn), + multirow(cs.multirow), + mroffset(cs.mroffset), alignment(cs.alignment), valignment(cs.valignment), + decimal_hoffset(cs.decimal_hoffset), + decimal_width(cs.decimal_width), + voffset(cs.voffset), top_line(cs.top_line), bottom_line(cs.bottom_line), left_line(cs.left_line), @@ -546,7 +598,7 @@ Tabular::CellData::CellData(CellData const & cs) rotate(cs.rotate), align_special(cs.align_special), p_width(cs.p_width), - inset(dynamic_cast(cs.inset->clone())) + inset(static_cast(cs.inset->clone())) { } @@ -561,8 +613,13 @@ void Tabular::CellData::swap(CellData & rhs) std::swap(cellno, rhs.cellno); std::swap(width, rhs.width); std::swap(multicolumn, rhs.multicolumn); + std::swap(multirow, rhs.multirow); + std::swap(mroffset, rhs.mroffset); std::swap(alignment, rhs.alignment); std::swap(valignment, rhs.valignment); + std::swap(decimal_hoffset, rhs.decimal_hoffset); + std::swap(decimal_width, rhs.decimal_width); + std::swap(voffset, rhs.voffset); std::swap(top_line, rhs.top_line); std::swap(bottom_line, rhs.bottom_line); std::swap(left_line, rhs.left_line); @@ -614,11 +671,8 @@ Tabular::Tabular(Buffer * buffer, row_type rows_arg, col_type columns_arg) void Tabular::setBuffer(Buffer & buffer) { buffer_ = &buffer; - size_t row_count = row_info.size(); - size_t column_count = column_info.size(); - // set silly default lines - for (row_type i = 0; i < row_count; ++i) - for (col_type j = 0; j < column_count; ++j) + for (row_type i = 0; i < nrows(); ++i) + for (col_type j = 0; j < ncols(); ++j) cell_info[i][j].inset->setBuffer(*buffer_); } @@ -637,49 +691,73 @@ void Tabular::init(Buffer * buf, row_type rows_arg, updateIndexes(); is_long_tabular = false; tabular_valignment = LYX_VALIGN_MIDDLE; + tabular_width = Length(); longtabular_alignment = LYX_LONGTABULAR_ALIGN_CENTER; - rotate = false; + rotate = 0; use_booktabs = false; - size_t row_count = row_info.size(); - size_t column_count = column_info.size(); // set silly default lines - for (row_type i = 0; i < row_count; ++i) - for (col_type j = 0; j < column_count; ++j) { - cell_info[i][j].inset->setBuffer(*buffer_); - cell_info[i][j].top_line = true; - cell_info[i][j].left_line = true; - cell_info[i][j].bottom_line = i == 0 || i == row_count - 1; - cell_info[i][j].right_line = j == column_count - 1; + for (row_type r = 0; r < nrows(); ++r) + for (col_type c = 0; c < ncols(); ++c) { + cell_info[r][c].inset->setBuffer(*buffer_); + cell_info[r][c].top_line = true; + cell_info[r][c].left_line = true; + cell_info[r][c].bottom_line = r == 0 || r == nrows() - 1; + cell_info[r][c].right_line = c == ncols() - 1; } } -void Tabular::appendRow(idx_type const cell) +void Tabular::deleteRow(row_type const row) { - BufferParams const & bp = buffer_->params(); - row_type const row = cellRow(cell); + // Not allowed to delete last row + if (nrows() == 1) + return; - row_vector::iterator rit = row_info.begin() + row; - row_info.insert(rit, RowData()); - // now set the values of the row before - row_info[row] = row_info[row + 1]; + for (col_type c = 0; c < ncols(); ++c) { + // Care about multirow cells + if (row + 1 < nrows() && + cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW && + cell_info[row + 1][c].multirow == CELL_PART_OF_MULTIROW) { + cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW; + } + } + row_info.erase(row_info.begin() + row); + cell_info.erase(cell_info.begin() + row); + updateIndexes(); +} - row_type const nrows = row_info.size(); - col_type const ncols = column_info.size(); - cell_vvector old(nrows - 1); - for (row_type i = 0; i < nrows - 1; ++i) - swap(cell_info[i], old[i]); +void Tabular::copyRow(row_type const row) +{ + insertRow(row, true); +} - cell_info = cell_vvector(nrows, cell_vector(ncols, CellData(buffer_))); - for (row_type i = 0; i <= row; ++i) - swap(cell_info[i], old[i]); - for (row_type i = row + 2; i < nrows; ++i) - swap(cell_info[i], old[i - 1]); +void Tabular::appendRow(row_type row) +{ + insertRow(row, false); +} + +void Tabular::insertRow(row_type const row, bool copy) +{ + row_info.insert(row_info.begin() + row + 1, RowData(row_info[row])); + cell_info.insert(cell_info.begin() + row + 1, + cell_vector(0, CellData(buffer_))); + + for (col_type c = 0; c < ncols(); ++c) { + cell_info[row + 1].insert(cell_info[row + 1].begin() + c, + copy ? CellData(cell_info[row][c]) : CellData(buffer_)); + if (buffer().params().trackChanges) + cell_info[row + 1][c].inset->setChange(Change(Change::INSERTED)); + if (cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW) + cell_info[row + 1][c].multirow = CELL_PART_OF_MULTIROW; + } + updateIndexes(); - for (col_type c = 0; c < ncols; ++c) { + for (col_type c = 0; c < ncols(); ++c) { + if (isPartOfMultiRow(row, c)) + continue; // inherit line settings idx_type const i = cellIndex(row + 1, c); idx_type const j = cellIndex(row, c); @@ -691,150 +769,168 @@ void Tabular::appendRow(idx_type const cell) setBottomLine(j, false); } // mark track changes - if (bp.trackChanges) + if (buffer().params().trackChanges) cellInfo(i).inset->setChange(Change(Change::INSERTED)); } } -void Tabular::deleteRow(row_type const row) +void Tabular::moveColumn(col_type col, ColDirection direction) { - // Not allowed to delete last row - if (row_info.size() == 1) - return; + if (direction == Tabular::LEFT) + col = col - 1; - row_info.erase(row_info.begin() + row); - cell_info.erase(cell_info.begin() + row); + std::swap(column_info[col], column_info[col + 1]); + + for (row_type r = 0; r < nrows(); ++r) { + std::swap(cell_info[r][col], cell_info[r][col + 1]); + std::swap(cell_info[r][col].left_line, cell_info[r][col + 1].left_line); + std::swap(cell_info[r][col].right_line, cell_info[r][col + 1].right_line); + + // FIXME track changes is broken for tabular features (#8469) + idx_type const i = cellIndex(r, col); + idx_type const j = cellIndex(r, col + 1); + if (buffer().params().trackChanges) { + cellInfo(i).inset->setChange(Change(Change::INSERTED)); + cellInfo(j).inset->setChange(Change(Change::INSERTED)); + } + } updateIndexes(); } -void Tabular::copyRow(row_type const row) +void Tabular::moveRow(row_type row, RowDirection direction) { - row_info.insert(row_info.begin() + row, row_info[row]); - cell_info.insert(cell_info.begin() + row, cell_info[row]); - - if (buffer().params().trackChanges) - for (col_type j = 0; j < column_info.size(); ++j) - cell_info[row + 1][j].inset->setChange(Change(Change::INSERTED)); + if (direction == Tabular::UP) + row = row - 1; - updateIndexes(); -} + std::swap(row_info[row], row_info[row + 1]); + for (col_type c = 0; c < ncols(); ++c) { + std::swap(cell_info[row][c], cell_info[row + 1][c]); + std::swap(cell_info[row][c].top_line, cell_info[row + 1][c].top_line); + std::swap(cell_info[row][c].bottom_line, cell_info[row + 1][c].bottom_line); -void Tabular::appendColumn(idx_type const cell) -{ - col_type const c = cellColumn(cell); - column_vector::iterator cit = column_info.begin() + c + 1; - column_info.insert(cit, ColumnData()); - row_type const nrows = row_info.size(); - // set the column values of the column before - column_info[c + 1] = column_info[c]; - - for (row_type r = 0; r < nrows; ++r) { - cell_info[r].insert(cell_info[r].begin() + c + 1, - CellData(buffer_)); -#if 0 -// FIXME: This code does not work. It deletes the cell's content and -// it triggers an assertion if the cursor is at pos > 0. - if (cell_info[r][c].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) - cell_info[r][c + 1].multicolumn = CELL_PART_OF_MULTICOLUMN; - else - cell_info[r][c + 1].multicolumn = cell_info[r][c].multicolumn; -#endif - } - updateIndexes(); - for (row_type r = 0; r < nrows; ++r) { - // inherit line settings - idx_type const i = cellIndex(r, c + 1); - idx_type const j = cellIndex(r, c); - setBottomLine(i, bottomLine(j)); - setTopLine(i, topLine(j)); - setLeftLine(i, leftLine(j)); - if (rightLine(j) && rightLine(j)) { - setRightLine(i, true); - setRightLine(j, false); - } - // - cellInfo(i).inset->clear(); - if (buffer().params().trackChanges) + // FIXME track changes is broken for tabular features (#8469) + idx_type const i = cellIndex(row, c); + idx_type const j = cellIndex(row + 1, c); + if (buffer().params().trackChanges) { cellInfo(i).inset->setChange(Change(Change::INSERTED)); + cellInfo(j).inset->setChange(Change(Change::INSERTED)); + } } + updateIndexes(); } -void Tabular::deleteColumn(col_type const column) +void Tabular::deleteColumn(col_type const col) { // Not allowed to delete last column - if (column_info.size() == 1) + if (ncols() == 1) return; - size_t const row_count = row_info.size(); - for (row_type i = 0; i < row_count; ++i) { + for (row_type r = 0; r < nrows(); ++r) { // Care about multicolumn cells - if (column + 1 < column_info.size() && - cell_info[i][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN && - cell_info[i][column + 1].multicolumn == CELL_PART_OF_MULTICOLUMN) { - cell_info[i][column + 1].multicolumn = CELL_BEGIN_OF_MULTICOLUMN; + if (col + 1 < ncols() && + cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN && + cell_info[r][col + 1].multicolumn == CELL_PART_OF_MULTICOLUMN) { + cell_info[r][col + 1].multicolumn = CELL_BEGIN_OF_MULTICOLUMN; } - cell_info[i].erase(cell_info[i].begin() + column); + cell_info[r].erase(cell_info[r].begin() + col); } - column_info.erase(column_info.begin() + column); + column_info.erase(column_info.begin() + col); updateIndexes(); } -void Tabular::copyColumn(col_type const column) +void Tabular::copyColumn(col_type const col) { - BufferParams const & bp = buffer().params(); - column_info.insert(column_info.begin() + column, column_info[column]); + insertColumn(col, true); +} - size_t row_count = row_info.size(); - for (row_type i = 0; i < row_count; ++i) - cell_info[i].insert(cell_info[i].begin() + column, cell_info[i][column]); - if (bp.trackChanges) - for (row_type i = 0; i < row_count; ++i) - cell_info[i][column + 1].inset->setChange(Change(Change::INSERTED)); +void Tabular::appendColumn(col_type col) +{ + insertColumn(col, false); +} + + +void Tabular::insertColumn(col_type const col, bool copy) +{ + BufferParams const & bp = buffer().params(); + column_info.insert(column_info.begin() + col + 1, ColumnData(column_info[col])); + + for (row_type r = 0; r < nrows(); ++r) { + cell_info[r].insert(cell_info[r].begin() + col + 1, + copy ? CellData(cell_info[r][col]) : CellData(buffer_)); + if (bp.trackChanges) + cell_info[r][col + 1].inset->setChange(Change(Change::INSERTED)); + if (cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) + cell_info[r][col + 1].multicolumn = CELL_PART_OF_MULTICOLUMN; + } updateIndexes(); + for (row_type r = 0; r < nrows(); ++r) { + // inherit line settings + idx_type const i = cellIndex(r, col + 1); + idx_type const j = cellIndex(r, col); + setBottomLine(i, bottomLine(j)); + setTopLine(i, topLine(j)); + setLeftLine(i, leftLine(j)); + if (rightLine(j) && rightLine(j)) { + setRightLine(i, true); + setRightLine(j, false); + } + if (buffer().params().trackChanges) + cellInfo(i).inset->setChange(Change(Change::INSERTED)); + } } void Tabular::updateIndexes() { setBuffer(buffer()); - col_type ncols = column_info.size(); - row_type nrows = row_info.size(); numberofcells = 0; - for (row_type row = 0; row < nrows; ++row) - for (col_type column = 0; column < ncols; ++column) { - if (!isPartOfMultiColumn(row, column)) + // reset cell number + for (row_type row = 0; row < nrows(); ++row) + for (col_type column = 0; column < ncols(); ++column) { + if (!isPartOfMultiColumn(row, column) + && !isPartOfMultiRow(row, column)) ++numberofcells; - cell_info[row][column].cellno = numberofcells - 1; + if (isPartOfMultiRow(row, column)) + cell_info[row][column].cellno = cell_info[row - 1][column].cellno; + else + cell_info[row][column].cellno = numberofcells - 1; } rowofcell.resize(numberofcells); columnofcell.resize(numberofcells); idx_type i = 0; - for (row_type row = 0; row < nrows; ++row) - for (col_type column = 0; column < ncols; ++column) { + // reset column and row of cells and update their width and alignment + for (row_type row = 0; row < nrows(); ++row) + for (col_type column = 0; column < ncols(); ++column) { if (isPartOfMultiColumn(row, column)) continue; - rowofcell[i] = row; - columnofcell[i] = column; + // columnofcell needs to be called before setting width and aligment + // multirow cells inherit the width from the column width + if (!isPartOfMultiRow(row, column)) { + columnofcell[i] = column; + rowofcell[i] = row; + } setFixedWidth(row, column); - updateContentAlignment(row, column); + if (isPartOfMultiRow(row, column)) + continue; + cell_info[row][column].inset->setContentAlignment( + getAlignment(cellIndex(row, column))); ++i; } } -Tabular::idx_type Tabular::numberOfCellsInRow(idx_type const cell) const +Tabular::idx_type Tabular::numberOfCellsInRow(row_type const row) const { - row_type const row = cellRow(cell); idx_type result = 0; - for (col_type i = 0; i < column_info.size(); ++i) - if (cell_info[row][i].multicolumn != Tabular::CELL_PART_OF_MULTICOLUMN) + for (col_type c = 0; c < ncols(); ++c) + if (cell_info[row][c].multicolumn != Tabular::CELL_PART_OF_MULTICOLUMN) ++result; return result; } @@ -868,35 +964,9 @@ bool Tabular::rightLine(idx_type cell) const } -bool Tabular::topAlreadyDrawn(idx_type cell) const +int Tabular::interRowSpace(row_type row) const { - row_type row = cellRow(cell); - if (row == 0) - return false; - idx_type i = cellIndex(row - 1, cellColumn(cell)); - return !rowTopLine(row) && bottomLine(i); -} - - -bool Tabular::leftAlreadyDrawn(idx_type cell) const -{ - col_type col = cellColumn(cell); - if (col == 0) - return false; - idx_type i = cellIndex(cellRow(cell), col - 1); - return rightLine(i) && !leftLine(cell); -} - - -bool Tabular::isLastRow(idx_type cell) const -{ - return cellRow(cell) == row_info.size() - 1; -} - - -int Tabular::getAdditionalHeight(row_type row) const -{ - if (!row || row >= row_info.size()) + if (!row || row >= nrows()) return 0; int const interline_space = row_info[row - 1].interline_space_default ? @@ -908,17 +978,17 @@ int Tabular::getAdditionalHeight(row_type row) const } -int Tabular::getAdditionalWidth(idx_type cell) const +int Tabular::interColumnSpace(idx_type cell) const { col_type const nextcol = cellColumn(cell) + columnSpan(cell); - if (rightLine(cell) - && nextcol < column_info.size() && leftLine(cellIndex(cellRow(cell), nextcol))) + if (rightLine(cell) && nextcol < ncols() + && leftLine(cellIndex(cellRow(cell), nextcol))) return WIDTH_OF_LINE; return 0; } -int Tabular::columnWidth(idx_type cell) const +int Tabular::cellWidth(idx_type cell) const { int w = 0; col_type const span = columnSpan(cell); @@ -929,18 +999,45 @@ int Tabular::columnWidth(idx_type cell) const } +int Tabular::cellHeight(idx_type cell) const +{ + row_type const span = rowSpan(cell); + row_type const row = cellRow(cell); + int h = 0; + for(row_type r = row; r < row + span ; ++r) { + h += rowAscent(r) + rowDescent(r); + if (r != row + span - 1) + h += interRowSpace(r + 1); + } + + return h; +} + + bool Tabular::updateColumnWidths() { - col_type const ncols = column_info.size(); - row_type const nrows = row_info.size(); + vector max_dwidth(ncols(), 0); + for(col_type c = 0; c < ncols(); ++c) + for(row_type r = 0; r < nrows(); ++r) { + idx_type const i = cellIndex(r, c); + if (getAlignment(i) == LYX_ALIGN_DECIMAL) + max_dwidth[c] = max(max_dwidth[c], cell_info[r][c].decimal_width); + } + bool update = false; // for each col get max of single col cells - for(col_type c = 0; c < ncols; ++c) { + for(col_type c = 0; c < ncols(); ++c) { int new_width = 0; - for(row_type r = 0; r < nrows; ++r) { + for(row_type r = 0; r < nrows(); ++r) { idx_type const i = cellIndex(r, c); - if (columnSpan(i) == 1) - new_width = max(new_width, cellInfo(i).width); + if (columnSpan(i) == 1) { + if (getAlignment(i) == LYX_ALIGN_DECIMAL + && cell_info[r][c].decimal_width!=0) + new_width = max(new_width, cellInfo(i).width + + max_dwidth[c] - cellInfo(i).decimal_width); + else + new_width = max(new_width, cellInfo(i).width); + } } if (column_info[c].width != new_width) { @@ -949,8 +1046,8 @@ bool Tabular::updateColumnWidths() } } // update col widths to fit merged cells - for(col_type c = 0; c < ncols; ++c) - for(row_type r = 0; r < nrows; ++r) { + for(col_type c = 0; c < ncols(); ++c) + for(row_type r = 0; r < nrows(); ++r) { idx_type const i = cellIndex(r, c); int const span = columnSpan(i); if (span == 1 || c > cellColumn(i)) @@ -972,29 +1069,42 @@ bool Tabular::updateColumnWidths() int Tabular::width() const { - col_type const ncols = column_info.size(); int width = 0; - for (col_type i = 0; i < ncols; ++i) - width += column_info[i].width; + for (col_type c = 0; c < ncols(); ++c) + width += column_info[c].width; return width; } -void Tabular::setCellWidth(idx_type cell, int new_width) -{ - cellInfo(cell).width = new_width + 2 * WIDTH_OF_LINE - + getAdditionalWidth(cell); -} - - void Tabular::setAlignment(idx_type cell, LyXAlignment align, - bool onlycolumn) + bool has_width) { - if (!isMultiColumn(cell) || onlycolumn) - column_info[cellColumn(cell)].alignment = align; - if (!onlycolumn) - cellInfo(cell).alignment = align; - cellInset(cell).get()->setContentAlignment(align); + col_type const col = cellColumn(cell); + // set alignment for the whole row if we are not in a multicolumn cell, + // exclude possible multicolumn cells in the row + if (!isMultiColumn(cell)) { + for (row_type r = 0; r < nrows(); ++r) { + // only if the column has no width the multirow inherits the + // alignment of the column, otherwise it is left aligned + if (!(isMultiRow(cellIndex(r, col)) && has_width) + && !isMultiColumn(cellIndex(r, col))) { + cell_info[r][col].alignment = align; + cell_info[r][col].inset->setContentAlignment(align); + } + if ((isMultiRow(cellIndex(r, col)) && has_width) + && !isMultiColumn(cellIndex(r, col))) { + cell_info[r][col].alignment = LYX_ALIGN_LEFT; + cell_info[r][col].inset->setContentAlignment(LYX_ALIGN_LEFT); + } + } + column_info[col].alignment = align; + docstring & dpoint = column_info[col].decimal_point; + if (align == LYX_ALIGN_DECIMAL && dpoint.empty()) + dpoint = from_utf8(lyxrc.default_decimal_point); + } else { + cellInfo(cell).alignment = align; + cellInset(cell).get()->setContentAlignment(align); + } } @@ -1041,11 +1151,16 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, Length const & width) { - col_type const j = cellColumn(cell); + col_type const c = cellColumn(cell); - column_info[j].p_width = width; - for (row_type i = 0; i < row_info.size(); ++i) { - idx_type const cell = cellIndex(i, j); + column_info[c].p_width = width; + // reset the vertical alignment to top if the fixed with + // is removed or zero because only fixed width columns can + // have a vertical alignment + if (column_info[c].p_width.zero()) + column_info[c].valignment = LYX_VALIGN_TOP; + for (row_type r = 0; r < nrows(); ++r) { + idx_type const cell = cellIndex(r, c); // because of multicolumns toggleFixedWidth(cur, cellInset(cell).get(), !getPWidth(cell).zero()); @@ -1069,13 +1184,6 @@ bool Tabular::setFixedWidth(row_type r, col_type c) } -void Tabular::updateContentAlignment(row_type r, col_type c) -{ - cell_info[r][c].inset->setContentAlignment( - getAlignment(cellIndex(r, c))); -} - - bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell, Length const & width) { @@ -1094,25 +1202,23 @@ bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell, } +bool Tabular::setMROffset(Cursor &, idx_type cell, Length const & mroffset) +{ + cellInfo(cell).mroffset = mroffset; + return true; +} + + void Tabular::setAlignSpecial(idx_type cell, docstring const & special, Tabular::Feature what) { - if (what == SET_SPECIAL_MULTI) + if (what == SET_SPECIAL_MULTICOLUMN) cellInfo(cell).align_special = special; else column_info[cellColumn(cell)].align_special = special; } -void Tabular::setAllLines(idx_type cell, bool line) -{ - setTopLine(cell, line); - setBottomLine(cell, line); - setRightLine(cell, line); - setLeftLine(cell, line); -} - - void Tabular::setTopLine(idx_type i, bool line) { cellInfo(i).top_line = line; @@ -1138,22 +1244,18 @@ void Tabular::setRightLine(idx_type cell, bool line) bool Tabular::rowTopLine(row_type r) const { - idx_type i0 = getFirstCellInRow(r); - idx_type i1 = getLastCellInRow(r); bool all_rows_set = true; - for (idx_type j = i0; all_rows_set && j <= i1; ++j) - all_rows_set = cellInfo(j).top_line; + for (col_type c = 0; all_rows_set && c < ncols(); ++c) + all_rows_set = cellInfo(cellIndex(r, c)).top_line; return all_rows_set; } bool Tabular::rowBottomLine(row_type r) const { - idx_type i0 = getFirstCellInRow(r); - idx_type i1 = getLastCellInRow(r); bool all_rows_set = true; - for (idx_type j = i0; all_rows_set && j <= i1; ++j) - all_rows_set = cellInfo(j).bottom_line; + for (col_type c = 0; all_rows_set && c < ncols(); ++c) + all_rows_set = cellInfo(cellIndex(r, c)).bottom_line; return all_rows_set; } @@ -1165,9 +1267,8 @@ bool Tabular::columnLeftLine(col_type c) const int nrows_left = 0; int total = 0; - row_type const nrows = row_info.size(); - for (row_type r = 0; r < nrows; ++r) { - idx_type i = cellIndex(r, c); + for (row_type r = 0; r < nrows(); ++r) { + idx_type const i = cellIndex(r, c); if (c == cellColumn(i)) { ++total; bool right = c > 0 && cellInfo(cellIndex(r, c - 1)).right_line; @@ -1186,14 +1287,13 @@ bool Tabular::columnRightLine(col_type c) const int nrows_right = 0; int total = 0; - row_type const nrows = row_info.size(); - for (row_type r = 0; r < nrows; ++r) { + for (row_type r = 0; r < nrows(); ++r) { idx_type i = cellIndex(r, c); if (c == cellColumn(i) + columnSpan(i) - 1) { ++total; - bool left = (c + 1 < column_info.size() + bool left = (c + 1 < ncols() && cellInfo(cellIndex(r, c + 1)).left_line) - || c + 1 == column_info.size(); + || c + 1 == ncols(); if (cellInfo(i).right_line && left) ++nrows_right; } @@ -1204,8 +1304,9 @@ bool Tabular::columnRightLine(col_type c) const LyXAlignment Tabular::getAlignment(idx_type cell, bool onlycolumn) const { - if (!onlycolumn && isMultiColumn(cell)) + if (!onlycolumn && (isMultiColumn(cell) || isMultiRow(cell))) return cellInfo(cell).alignment; + return column_info[cellColumn(cell)].alignment; } @@ -1213,7 +1314,7 @@ LyXAlignment Tabular::getAlignment(idx_type cell, bool onlycolumn) const Tabular::VAlignment Tabular::getVAlignment(idx_type cell, bool onlycolumn) const { - if (!onlycolumn && isMultiColumn(cell)) + if (!onlycolumn && (isMultiColumn(cell) || isMultiRow(cell))) return cellInfo(cell).valignment; return column_info[cellColumn(cell)].valignment; } @@ -1227,67 +1328,95 @@ Length const Tabular::getPWidth(idx_type cell) const } -int Tabular::cellWidth(idx_type cell) const +Length const Tabular::getMROffset(idx_type cell) const { - return cellInfo(cell).width; + return cellInfo(cell).mroffset; } -int Tabular::getBeginningOfTextInCell(idx_type cell) const +int Tabular::textHOffset(idx_type cell) const { - int x = 0; + // the LaTeX Way :-( + int x = WIDTH_OF_LINE; + + int const w = cellWidth(cell) - cellInfo(cell).width; switch (getAlignment(cell)) { case LYX_ALIGN_CENTER: - x += (columnWidth(cell) - cellWidth(cell)) / 2; + x += w / 2; break; case LYX_ALIGN_RIGHT: - x += columnWidth(cell) - cellWidth(cell); - // + getAdditionalWidth(cell); + x += w; break; + case LYX_ALIGN_DECIMAL: { + // we center when no decimal point + if (cellInfo(cell).decimal_width == 0) { + x += w / 2; + break; + } + col_type const c = cellColumn(cell); + int max_dhoffset = 0; + for(row_type r = 0; r < row_info.size() ; ++r) { + idx_type const i = cellIndex(r, c); + if (getAlignment(i) == LYX_ALIGN_DECIMAL + && cellInfo(i).decimal_width != 0) + max_dhoffset = max(max_dhoffset, cellInfo(i).decimal_hoffset); + } + x += max_dhoffset - cellInfo(cell).decimal_hoffset; + } default: // LYX_ALIGN_LEFT: nothing :-) break; } - // the LaTeX Way :-( - x += WIDTH_OF_LINE; return x; } -bool Tabular::isFirstCellInRow(idx_type cell) const +int Tabular::textVOffset(idx_type cell) const { - return cellColumn(cell) == 0; + int voffset = cellInfo(cell).voffset; + if (isMultiRow(cell)) { + row_type const row = cellRow(cell); + voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2; + } + return voffset; } Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const { - if (row > row_info.size() - 1) - row = row_info.size() - 1; - return cell_info[row][0].cellno; -} - - -bool Tabular::isLastCellInRow(idx_type cell) const -{ - return cellRightColumn(cell) == column_info.size() - 1; + col_type c = 0; + idx_type const numcells = numberOfCellsInRow(row); + // we check against numcells to make sure we do not crash if all the + // cells are multirow (bug #7535), but in that case our return value + // is really invalid, i.e., it is NOT the first cell in the row. but + // i do not know what to do here. (rgh) + while (c < numcells - 1 + && cell_info[row][c].multirow == CELL_PART_OF_MULTIROW) + ++c; + return cell_info[row][c].cellno; } Tabular::idx_type Tabular::getLastCellInRow(row_type row) const { - if (row > row_info.size() - 1) - row = row_info.size() - 1; - return cell_info[row][column_info.size() - 1].cellno; + col_type c = ncols() - 1; + // of course we check against 0 so we don't crash. but we have the same + // problem as in the previous routine: if all the cells are part of a + // multirow or part of a multi column, then our return value is invalid. + while (c > 0 + && (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW + || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN)) + --c; + return cell_info[row][c].cellno; } Tabular::row_type Tabular::cellRow(idx_type cell) const { if (cell >= numberofcells) - return row_info.size() - 1; + return nrows() - 1; if (cell == npos) return 0; return rowofcell[cell]; @@ -1297,35 +1426,24 @@ Tabular::row_type Tabular::cellRow(idx_type cell) const Tabular::col_type Tabular::cellColumn(idx_type cell) const { if (cell >= numberofcells) - return column_info.size() - 1; + return ncols() - 1; if (cell == npos) - return 0; + return 0; return columnofcell[cell]; } -Tabular::col_type Tabular::cellRightColumn(idx_type cell) const -{ - row_type const row = cellRow(cell); - col_type column = cellColumn(cell); - while (column < column_info.size() - 1 && - cell_info[row][column + 1].multicolumn == CELL_PART_OF_MULTICOLUMN) - ++column; - return column; -} - - void Tabular::write(ostream & os) const { // header line os << "\n"; // global longtable options os << "(rotate)) << write_attribute("booktabs", use_booktabs) << write_attribute("islongtable", is_long_tabular) << write_attribute("firstHeadTopDL", endfirsthead.topDL) @@ -1339,58 +1457,64 @@ void Tabular::write(ostream & os) const << write_attribute("lastFootBottomDL", endlastfoot.bottomDL) << write_attribute("lastFootEmpty", endlastfoot.empty); // longtables cannot be aligned vertically - if (!is_long_tabular) + if (!is_long_tabular) { os << write_attribute("tabularvalignment", tabular_valignment); + os << write_attribute("tabularwidth", tabular_width); + } if (is_long_tabular) os << write_attribute("longtabularalignment", longtabular_alignment); os << ">\n"; - for (col_type j = 0; j < column_info.size(); ++j) { + for (col_type c = 0; c < ncols(); ++c) { os << "\n"; } - for (row_type i = 0; i < row_info.size(); ++i) { + for (row_type r = 0; r < nrows(); ++r) { static const string def("default"); os << "\n"; - for (col_type j = 0; j < column_info.size(); ++j) { + for (col_type c = 0; c < ncols(); ++c) { os << "\n"; os << "\\begin_inset "; - cell_info[i][j].inset->write(os); + cell_info[r][c].inset->write(os); os << "\n\\end_inset\n" << "\n"; } @@ -1407,14 +1531,13 @@ void Tabular::read(Lexer & lex) l_getline(is, line); if (!prefixIs(line, "= 2, /**/); + LATTEST(version >= 2); int rows_arg; if (!getTokenValue(line, "rows", rows_arg)) @@ -1433,6 +1556,7 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "booktabs", use_booktabs); getTokenValue(line, "islongtable", is_long_tabular); getTokenValue(line, "tabularvalignment", tabular_valignment); + getTokenValue(line, "tabularwidth", tabular_width); getTokenValue(line, "longtabularalignment", longtabular_alignment); getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL); getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL); @@ -1445,20 +1569,21 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL); getTokenValue(line, "lastFootEmpty", endlastfoot.empty); - for (col_type j = 0; j < column_info.size(); ++j) { + for (col_type c = 0; c < ncols(); ++c) { l_getline(is,line); if (!prefixIs(line," got" << line << ')' << endl; return; } - getTokenValue(line, "alignment", column_info[j].alignment); - getTokenValue(line, "valignment", column_info[j].valignment); - getTokenValue(line, "width", column_info[j].p_width); - getTokenValue(line, "special", column_info[j].align_special); + getTokenValue(line, "alignment", column_info[c].alignment); + getTokenValue(line, "decimal_point", column_info[c].decimal_point); + getTokenValue(line, "valignment", column_info[c].valignment); + getTokenValue(line, "width", column_info[c].p_width); + getTokenValue(line, "special", column_info[c].align_special); } - for (row_type i = 0; i < row_info.size(); ++i) { + for (row_type i = 0; i < nrows(); ++i) { l_getline(is, line); if (!prefixIs(line, " got" @@ -1477,7 +1602,7 @@ void Tabular::read(Lexer & lex) getTokenValue(line, "endlastfoot", row_info[i].endlastfoot); getTokenValue(line, "newpage", row_info[i].newpage); getTokenValue(line, "caption", row_info[i].caption); - for (col_type j = 0; j < column_info.size(); ++j) { + for (col_type j = 0; j < ncols(); ++j) { l_getline(is, line); if (!prefixIs(line, " got" @@ -1485,6 +1610,8 @@ void Tabular::read(Lexer & lex) return; } getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn); + getTokenValue(line, "multirow", cell_info[i][j].multirow); + getTokenValue(line, "mroffset", cell_info[i][j].mroffset); getTokenValue(line, "alignment", cell_info[i][j].alignment); getTokenValue(line, "valignment", cell_info[i][j].valignment); getTokenValue(line, "topline", cell_info[i][j].top_line); @@ -1524,14 +1651,18 @@ void Tabular::read(Lexer & lex) bool Tabular::isMultiColumn(idx_type cell) const { - return cellInfo(cell).multicolumn != CELL_NORMAL; + return (cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN + || cellInfo(cell).multicolumn == CELL_PART_OF_MULTICOLUMN); } -bool Tabular::isMultiColumnReal(idx_type cell) const +bool Tabular::hasMultiColumn(col_type c) const { - return cellColumn(cell) != cellRightColumn(cell) && - cellInfo(cell).multicolumn != CELL_NORMAL; + for (row_type r = 0; r < nrows(); ++r) { + if (isMultiColumn(cellIndex(r, c))) + return true; + } + return false; } @@ -1541,12 +1672,22 @@ Tabular::CellData & Tabular::cellInfo(idx_type cell) const } -void Tabular::setMultiColumn(idx_type cell, idx_type number) +Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, + bool const right_border) { + idx_type const col = cellColumn(cell); + idx_type const row = cellRow(cell); + for (idx_type i = 0; i < number; ++i) + unsetMultiRow(cellIndex(row, col + i)); + + // unsetting of multirow may have invalidated cell index + cell = cellIndex(row, col); CellData & cs = cellInfo(cell); cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN; - cs.alignment = column_info[cellColumn(cell)].alignment; - setRightLine(cell, rightLine(cell + number - 1)); + if (column_info[col].alignment != LYX_ALIGN_DECIMAL) + cs.alignment = column_info[col].alignment; + setRightLine(cell, right_border); + for (idx_type i = 1; i < number; ++i) { CellData & cs1 = cellInfo(cell + i); cs1.multicolumn = CELL_PART_OF_MULTICOLUMN; @@ -1554,53 +1695,130 @@ void Tabular::setMultiColumn(idx_type cell, idx_type number) cs1.inset->clear(); } updateIndexes(); + return cell; +} + + +bool Tabular::isMultiRow(idx_type cell) const +{ + return (cellInfo(cell).multirow == CELL_BEGIN_OF_MULTIROW + || cellInfo(cell).multirow == CELL_PART_OF_MULTIROW); +} + +bool Tabular::hasMultiRow(row_type r) const +{ + for (col_type c = 0; c < ncols(); ++c) { + if (isMultiRow(cellIndex(r, c))) + return true; + } + return false; +} + +Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number, + bool const bottom_border) +{ + idx_type const col = cellColumn(cell); + idx_type const row = cellRow(cell); + for (idx_type i = 0; i < number; ++i) + unsetMultiColumn(cellIndex(row + i, col)); + + // unsetting of multirow may have invalidated cell index + cell = cellIndex(row, col); + CellData & cs = cellInfo(cell); + cs.multirow = CELL_BEGIN_OF_MULTIROW; + cs.valignment = LYX_VALIGN_MIDDLE; + // the horizontal alignment of multirow cells can only + // be changed for the whole table row, + // support changing this only for the multirow cell can be done via + // \multirowsetup + // this feature would be a fileformat change + // until LyX supports this, use the deault alignment of multirow + // cells: left + cs.alignment = LYX_ALIGN_LEFT; + + // set the bottom line of the last selected cell + setBottomLine(cell, bottom_border); + + for (idx_type i = 1; i < number; ++i) { + CellData & cs1 = cell_info[row + i][col]; + cs1.multirow = CELL_PART_OF_MULTIROW; + cs.inset->appendParagraphs(cs1.inset->paragraphs()); + cs1.inset->clear(); + } + updateIndexes(); + return cell; } Tabular::idx_type Tabular::columnSpan(idx_type cell) const { row_type const row = cellRow(cell); - col_type const ncols = column_info.size(); - idx_type result = 1; - col_type column = cellColumn(cell) + 1; - while (column < ncols && isPartOfMultiColumn(row, column)) { - ++result; - ++column; + col_type const col = cellColumn(cell); + int span = 1; + while (col + span < ncols() && isPartOfMultiColumn(row, col + span)) + ++span; + + return span; +} + + +Tabular::idx_type Tabular::rowSpan(idx_type cell) const +{ + col_type const column = cellColumn(cell); + col_type row = cellRow(cell) + 1; + while (row < nrows() && isPartOfMultiRow(row, column)) + ++row; + + return row - cellRow(cell); +} + + +void Tabular::unsetMultiColumn(idx_type cell) +{ + if (!isMultiColumn(cell)) + return; + + row_type const row = cellRow(cell); + col_type const col = cellColumn(cell); + row_type const span = columnSpan(cell); + for (col_type c = 0; c < span; ++c) { + // in the table dialog the lines are set in every case + // when unsetting a multicolumn this leads to an additional right + // line for every cell that was part of the former multicolumn cell, + // except if the cell is in the last column + // therefore remove this line + if (cell_info[row][col + c].multicolumn == CELL_BEGIN_OF_MULTICOLUMN + && (col + c) < (col + span - 1)) + cell_info[row][col + c].right_line = false; + cell_info[row][col + c].multicolumn = CELL_NORMAL; } - return result; + updateIndexes(); } -Tabular::idx_type Tabular::unsetMultiColumn(idx_type cell) +void Tabular::unsetMultiRow(idx_type cell) { - row_type const row = cellRow(cell); - col_type column = cellColumn(cell); - - idx_type result = 0; + if (!isMultiRow(cell)) + return; - if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) { - cell_info[row][column].multicolumn = CELL_NORMAL; - ++column; - while (column < column_info.size() && - cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN) - { - cell_info[row][column].multicolumn = CELL_NORMAL; - ++column; - ++result; - } - } + cellInfo(cell).valignment = LYX_VALIGN_TOP; + cellInfo(cell).alignment = LYX_ALIGN_CENTER; + row_type const row = cellRow(cell); + col_type const col = cellColumn(cell); + row_type const span = rowSpan(cell); + for (row_type r = 0; r < span; ++r) + cell_info[row + r][col].multirow = CELL_NORMAL; updateIndexes(); - return result; } -void Tabular::setRotateCell(idx_type cell, bool flag) +void Tabular::setRotateCell(idx_type cell, int value) { - cellInfo(cell).rotate = flag; + cellInfo(cell).rotate = value; } -bool Tabular::getRotateCell(idx_type cell) const +int Tabular::getRotateCell(idx_type cell) const { return cellInfo(cell).rotate; } @@ -1610,9 +1828,9 @@ bool Tabular::needRotating() const { if (rotate) return true; - for (row_type i = 0; i < row_info.size(); ++i) - for (col_type j = 0; j < column_info.size(); ++j) - if (cell_info[i][j].rotate) + for (row_type r = 0; r < nrows(); ++r) + for (col_type c = 0; c < ncols(); ++c) + if (cell_info[r][c].rotate != 0) return true; return false; } @@ -1628,25 +1846,31 @@ bool Tabular::isLastCell(idx_type cell) const Tabular::idx_type Tabular::cellAbove(idx_type cell) const { - if (cellRow(cell) > 0) - return cell_info[cellRow(cell)-1][cellColumn(cell)].cellno; - return cell; + if (cellRow(cell) == 0) + return cell; + + col_type const col = cellColumn(cell); + row_type r = cellRow(cell) - 1; + while (r > 0 && cell_info[r][col].multirow == CELL_PART_OF_MULTIROW) + --r; + + return cell_info[r][col].cellno; } Tabular::idx_type Tabular::cellBelow(idx_type cell) const { - if (cellRow(cell) + 1 < row_info.size()) - return cell_info[cellRow(cell)+1][cellColumn(cell)].cellno; + row_type const nextrow = cellRow(cell) + rowSpan(cell); + if (nextrow < nrows()) + return cell_info[nextrow][cellColumn(cell)].cellno; return cell; } -Tabular::idx_type Tabular::cellIndex(row_type row, - col_type column) const +Tabular::idx_type Tabular::cellIndex(row_type row, col_type column) const { - BOOST_ASSERT(column != npos && column < column_info.size() - && row != npos && row < row_info.size()); + LASSERT(column != npos && column < ncols(), column = 0); + LASSERT(row != npos && row < nrows(), row = 0); return cell_info[row][column].cellno; } @@ -1747,41 +1971,49 @@ bool Tabular::getLTNewPage(row_type row) const } -bool Tabular::haveLTHead() const +bool Tabular::haveLTHead(bool withcaptions) const { - for (row_type i = 0; i < row_info.size(); ++i) - if (row_info[i].endhead) + if (!is_long_tabular) + return false; + for (row_type i = 0; i < nrows(); ++i) + if (row_info[i].endhead && + (withcaptions || !row_info[i].caption)) return true; return false; } -bool Tabular::haveLTFirstHead() const +bool Tabular::haveLTFirstHead(bool withcaptions) const { - if (endfirsthead.empty) + if (!is_long_tabular || endfirsthead.empty) return false; - for (row_type i = 0; i < row_info.size(); ++i) - if (row_info[i].endfirsthead) + for (row_type r = 0; r < nrows(); ++r) + if (row_info[r].endfirsthead && + (withcaptions || !row_info[r].caption)) return true; return false; } -bool Tabular::haveLTFoot() const +bool Tabular::haveLTFoot(bool withcaptions) const { - for (row_type i = 0; i < row_info.size(); ++i) - if (row_info[i].endfoot) + if (!is_long_tabular) + return false; + for (row_type r = 0; r < nrows(); ++r) + if (row_info[r].endfoot && + (withcaptions || !row_info[r].caption)) return true; return false; } -bool Tabular::haveLTLastFoot() const +bool Tabular::haveLTLastFoot(bool withcaptions) const { - if (endlastfoot.empty) + if (!is_long_tabular || endlastfoot.empty) return false; - for (row_type i = 0; i < row_info.size(); ++i) - if (row_info[i].endlastfoot) + for (row_type r = 0; r < nrows(); ++r) + if (row_info[r].endlastfoot && + (withcaptions || !row_info[r].caption)) return true; return false; } @@ -1791,11 +2023,16 @@ Tabular::idx_type Tabular::setLTCaption(row_type row, bool what) { idx_type i = getFirstCellInRow(row); if (what) { - setMultiColumn(i, numberOfCellsInRow(i)); + setMultiColumn(i, numberOfCellsInRow(row), false); setTopLine(i, false); setBottomLine(i, false); setLeftLine(i, false); setRightLine(i, false); + if (!row_info[row].endfirsthead && !row_info[row].endhead && + !row_info[row].endfoot && !row_info[row].endlastfoot) { + setLTHead(row, true, endfirsthead, true); + row_info[row].endfirsthead = true; + } } else { unsetMultiColumn(i); // When unsetting a caption row, also all existing @@ -1812,11 +2049,34 @@ bool Tabular::ltCaption(row_type row) const } -bool Tabular::haveLTCaption() const +bool Tabular::haveLTCaption(CaptionType captiontype) const { - for (row_type i = 0; i < row_info.size(); ++i) - if (row_info[i].caption) - return true; + if (!is_long_tabular) + return false; + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].caption) { + switch (captiontype) { + case CAPTION_FIRSTHEAD: + if (row_info[r].endfirsthead) + return true; + break; + case CAPTION_HEAD: + if (row_info[r].endhead) + return true; + break; + case CAPTION_FOOT: + if (row_info[r].endfoot) + return true; + break; + case CAPTION_LASTFOOT: + if (row_info[r].endlastfoot) + return true; + break; + case CAPTION_ANY: + return true; + } + } + } return false; } @@ -1825,7 +2085,7 @@ bool Tabular::haveLTCaption() const void Tabular::setRowAscent(row_type row, int height) { - if (row >= row_info.size() || row_info[row].ascent == height) + if (row >= nrows() || row_info[row].ascent == height) return; row_info[row].ascent = height; } @@ -1833,7 +2093,7 @@ void Tabular::setRowAscent(row_type row, int height) void Tabular::setRowDescent(row_type row, int height) { - if (row >= row_info.size() || row_info[row].descent == height) + if (row >= nrows() || row_info[row].descent == height) return; row_info[row].descent = height; } @@ -1841,15 +2101,14 @@ void Tabular::setRowDescent(row_type row, int height) int Tabular::rowAscent(row_type row) const { - if (row >= row_info.size()) - return 0; + LASSERT(row < nrows(), row = 0); return row_info[row].ascent; } int Tabular::rowDescent(row_type row) const { - LASSERT(row < row_info.size(), /**/); + LASSERT(row < nrows(), row = 0); return row_info[row].descent; } @@ -1857,89 +2116,118 @@ int Tabular::rowDescent(row_type row) const int Tabular::height() const { int height = 0; - for (row_type row = 0; row < row_info.size(); ++row) + for (row_type row = 0; row < nrows(); ++row) height += rowAscent(row) + rowDescent(row) + - getAdditionalHeight(row); + interRowSpace(row); return height; } bool Tabular::isPartOfMultiColumn(row_type row, col_type column) const { - LASSERT(row < row_info.size(), /**/); - LASSERT(column < column_info.size(), /**/); + LASSERT(row < nrows(), return false); + LASSERT(column < ncols(), return false); return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN; } -int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const +bool Tabular::isPartOfMultiRow(row_type row, col_type column) const +{ + LASSERT(row < nrows(), return false); + LASSERT(column < ncols(), return false); + return cell_info[row][column].multirow == CELL_PART_OF_MULTIROW; +} + + +void Tabular::TeXTopHLine(otexstream & os, row_type row, string const lang) const { // we only output complete row lines and the 1st row here, the rest // is done in Tabular::TeXBottomHLine(...) // get for each column the topline (if any) - col_type const ncols = column_info.size(); vector topline; col_type nset = 0; - for (col_type c = 0; c < ncols; ++c) { + for (col_type c = 0; c < ncols(); ++c) { topline.push_back(topLine(cellIndex(row, c))); + // If cell is part of a multirow and not the first cell of the + // multirow, no line must be drawn. + if (row != 0) + if (isMultiRow(cellIndex(row, c)) + && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW) + topline[c] = false; if (topline[c]) ++nset; } // do nothing if empty first row, or incomplete row line after - if ((row == 0 && nset == 0) || (row > 0 && nset != ncols)) - return 0; + if ((row == 0 && nset == 0) || (row > 0 && nset != ncols())) + return; // only output complete row lines and the 1st row's clines - if (nset == ncols) { + if (nset == ncols()) { if (use_booktabs) { os << (row == 0 ? "\\toprule " : "\\midrule "); } else { os << "\\hline "; } } else if (row == 0) { - for (col_type c = 0; c < ncols; ++c) { + for (col_type c = 0; c < ncols(); ++c) { if (topline[c]) { + col_type offset = 0; + for (col_type j = 0 ; j < c; ++j) + if (column_info[j].alignment == LYX_ALIGN_DECIMAL) + ++offset; + //babel makes the "-" character an active one, so we have to suppress this here //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# if (lang == "slovak" || lang == "czech") - os << (use_booktabs ? "\\expandafter\\cmidrule\\expandafter{\\expandafter" : - "\\expandafter\\cline\\expandafter{\\expandafter") - << c + 1 << "\\string-"; + os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") + << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; else - os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 << '-'; - // get to last column of line span - while (c < ncols && topline[c]) - ++c; - os << c << "} "; + os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; + + col_type cstart = c; + for ( ; c < ncols() && topline[c]; ++c) {} + + for (col_type j = cstart ; j < c ; ++j) + if (column_info[j].alignment == LYX_ALIGN_DECIMAL) + ++offset; + + os << c + offset << "} "; } } } os << "\n"; - return 1; } -int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) const +void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const lang) const { // we output bottomlines of row r and the toplines of row r+1 // if the latter do not span the whole tabular // get the bottomlines of row r, and toplines in next row - bool lastrow = row == row_info.size() - 1; - col_type const ncols = column_info.size(); + bool lastrow = row == nrows() - 1; vector bottomline, topline; bool nextrowset = true; - for (col_type c = 0; c < ncols; ++c) { + for (col_type c = 0; c < ncols(); ++c) { bottomline.push_back(bottomLine(cellIndex(row, c))); topline.push_back(!lastrow && topLine(cellIndex(row + 1, c))); + // If cell is part of a multirow and not the last cell of the + // multirow, no line must be drawn. + if (!lastrow) + if (isMultiRow(cellIndex(row, c)) + && isMultiRow(cellIndex(row + 1, c)) + && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) { + bottomline[c] = false; + topline[c] = false; + } nextrowset &= topline[c]; } // combine this row's bottom lines and next row's toplines if necessary col_type nset = 0; - for (col_type c = 0; c < ncols; ++c) { + for (col_type c = 0; c < ncols(); ++c) { if (!nextrowset) bottomline[c] = bottomline[c] || topline[c]; if (bottomline[c]) @@ -1947,43 +2235,51 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) co } // do nothing if empty, OR incomplete row line with a topline in next row - if (nset == 0 || (nextrowset && nset != ncols)) - return 0; + if (nset == 0 || (nextrowset && nset != ncols())) + return; - if (nset == ncols) { + if (nset == ncols()) { if (use_booktabs) os << (lastrow ? "\\bottomrule" : "\\midrule"); else - os << "\\hline"; + os << "\\hline "; } else { - for (col_type c = 0; c < ncols; ++c) { + for (col_type c = 0; c < ncols(); ++c) { if (bottomline[c]) { + col_type offset = 0; + for (col_type j = 0 ; j < c; ++j) + if (column_info[j].alignment == LYX_ALIGN_DECIMAL) + ++offset; + //babel makes the "-" character an active one, so we have to suppress this here //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289# if (lang == "slovak" || lang == "czech") - os << (use_booktabs ? "\\expandafter\\cmidrule\\expandafter{\\expandafter" : - "\\expandafter\\cline\\expandafter{\\expandafter") - << c + 1 << "\\string-"; + os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") + << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-"; else - os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 << '-'; - // get to last column of line span - while (c < ncols && bottomline[c]) - ++c; - os << c << "} "; + os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-'; + + col_type cstart = c; + for ( ; c < ncols() && bottomline[c]; ++c) {} + + for (col_type j = cstart ; j < c ; ++j) + if (column_info[j].alignment == LYX_ALIGN_DECIMAL) + ++offset; + + os << c + offset << "} "; } } } os << "\n"; - return 1; } -int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, bool & ismulticol) const +void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, + bool & ismulticol, bool & ismultirow) const { - int ret = 0; row_type const r = cellRow(cell); if (is_long_tabular && row_info[r].caption) - return ret; + return; Tabular::VAlignment valign = getVAlignment(cell, !isMultiColumn(cell)); LyXAlignment align = getAlignment(cell, !isMultiColumn(cell)); @@ -1993,18 +2289,33 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, bool & ismulticol) col_type const nextcol = c + columnSpan(cell); bool colright = columnRightLine(c); bool colleft = columnLeftLine(c); - bool nextcolleft = nextcol < column_info.size() && columnLeftLine(nextcol); - bool nextcellleft = nextcol < column_info.size() + bool nextcolleft = nextcol < ncols() && columnLeftLine(nextcol); + bool nextcellleft = nextcol < ncols() && leftLine(cellIndex(r, nextcol)); bool coldouble = colright && nextcolleft; bool celldouble = rightLine(cell) && nextcellleft; - ismulticol = isMultiColumn(cell) + + ismulticol = isMultiColumn(cell) || (c == 0 && colleft != leftLine(cell)) || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft) || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft)) || (coldouble != celldouble); + + // we center in multicol when no decimal point + if (column_info[c].alignment == LYX_ALIGN_DECIMAL) { + docstring const align_d = column_info[c].decimal_point; + DocIterator const dit = separatorPos(cellInset(cell).get(), align_d); + ismulticol |= !dit; + } + + // up counter by 1 for each decimally aligned col since they use 2 latex cols + int latexcolspan = columnSpan(cell); + for(col_type col = c; col < c + columnSpan(cell); ++col) + if (column_info[col].alignment == LYX_ALIGN_DECIMAL) + ++latexcolspan; + if (ismulticol) { - os << "\\multicolumn{" << columnSpan(cell) << "}{"; + os << "\\multicolumn{" << latexcolspan << "}{"; if (c ==0 && leftLine(cell)) os << '|'; if (!cellInfo(cell).align_special.empty()) { @@ -2058,11 +2369,26 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, bool & ismulticol) // add extra vertical line if we want a double one os << '|'; os << "}{"; - } - if (getRotateCell(cell)) { - os << "\\begin{sideways}\n"; - ++ret; - } + } // end if ismulticol + + // we only need code for the first multirow cell + ismultirow = isMultiRow(cell); + if (ismultirow) { + os << "\\multirow{" << rowSpan(cell) << "}{"; + if (!getPWidth(cell).zero()) + os << from_ascii(getPWidth(cell).asLatexString()); + else + // we need to set a default value + os << "*"; + os << "}"; + if (!getMROffset(cell).zero()) + os << "[" << from_ascii(getMROffset(cell).asLatexString()) << "]"; + os << "{"; + } // end if ismultirow + + if (getRotateCell(cell) != 0) + os << "\\begin{turn}{" << convert(getRotateCell(cell)) << "}\n"; + if (getUsebox(cell) == BOX_PARBOX) { os << "\\parbox["; switch (valign) { @@ -2093,136 +2419,99 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, bool & ismulticol) } os << "]{" << from_ascii(getPWidth(cell).asLatexString()) << "}\n"; - ++ret; } - return ret; } -int Tabular::TeXCellPostamble(odocstream & os, idx_type cell, bool ismulticol) const +void Tabular::TeXCellPostamble(otexstream & os, idx_type cell, + bool ismulticol, bool ismultirow) const { - int ret = 0; row_type const r = cellRow(cell); if (is_long_tabular && row_info[r].caption) - return ret; + return; // usual cells if (getUsebox(cell) == BOX_PARBOX) os << '}'; - else if (getUsebox(cell) == BOX_MINIPAGE) { - os << "%\n\\end{minipage}"; - ret += 2; - } - if (getRotateCell(cell)) { - os << "%\n\\end{sideways}"; - ++ret; - } - if (ismulticol) { + else if (getUsebox(cell) == BOX_MINIPAGE) + os << breakln << "\\end{minipage}"; + if (getRotateCell(cell) != 0) + os << breakln << "\\end{turn}"; + if (ismultirow) + os << '}'; + if (ismulticol) os << '}'; - } - return ret; } -int Tabular::TeXLongtableHeaderFooter(odocstream & os, - OutputParams const & runparams) const +void Tabular::TeXLongtableHeaderFooter(otexstream & os, + OutputParams const & runparams) const { if (!is_long_tabular) - return 0; + return; - int ret = 0; // caption handling - // the caption must be output before the headers + // output caption which is in no header or footer if (haveLTCaption()) { - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].caption) { - ret += TeXRow(os, i, runparams); - } + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].caption && + !row_info[r].endfirsthead && !row_info[r].endhead && + !row_info[r].endfoot && !row_info[r].endlastfoot) + TeXRow(os, r, runparams); } } // output first header info - // first header must be output before the header, otherwise the - // correct caption placement becomes really weird if (haveLTFirstHead()) { - if (endfirsthead.topDL) { + if (endfirsthead.topDL) os << "\\hline\n"; - ++ret; - } - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].endfirsthead) { - ret += TeXRow(os, i, runparams); - } + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].endfirsthead) + TeXRow(os, r, runparams); } - if (endfirsthead.bottomDL) { + if (endfirsthead.bottomDL) os << "\\hline\n"; - ++ret; - } os << "\\endfirsthead\n"; - ++ret; } // output header info if (haveLTHead()) { - if (endfirsthead.empty && !haveLTFirstHead()) { + if (endfirsthead.empty && !haveLTFirstHead()) os << "\\endfirsthead\n"; - ++ret; - } - if (endhead.topDL) { + if (endhead.topDL) os << "\\hline\n"; - ++ret; + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].endhead) + TeXRow(os, r, runparams); } - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].endhead) { - ret += TeXRow(os, i, runparams); - } - } - if (endhead.bottomDL) { + if (endhead.bottomDL) os << "\\hline\n"; - ++ret; - } os << "\\endhead\n"; - ++ret; } // output footer info if (haveLTFoot()) { - if (endfoot.topDL) { + if (endfoot.topDL) os << "\\hline\n"; - ++ret; + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].endfoot) + TeXRow(os, r, runparams); } - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].endfoot) { - ret += TeXRow(os, i, runparams); - } - } - if (endfoot.bottomDL) { + if (endfoot.bottomDL) os << "\\hline\n"; - ++ret; - } os << "\\endfoot\n"; - ++ret; - if (endlastfoot.empty && !haveLTLastFoot()) { + if (endlastfoot.empty && !haveLTLastFoot()) os << "\\endlastfoot\n"; - ++ret; - } } // output lastfooter info if (haveLTLastFoot()) { - if (endlastfoot.topDL) { + if (endlastfoot.topDL) os << "\\hline\n"; - ++ret; - } - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].endlastfoot) { - ret += TeXRow(os, i, runparams); - } + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].endlastfoot) + TeXRow(os, r, runparams); } - if (endlastfoot.bottomDL) { + if (endlastfoot.bottomDL) os << "\\hline\n"; - ++ret; - } os << "\\endlastfoot\n"; - ++ret; } - return ret; } @@ -2236,46 +2525,56 @@ bool Tabular::isValidRow(row_type row) const } -int Tabular::TeXRow(odocstream & os, row_type i, - OutputParams const & runparams) const +void Tabular::TeXRow(otexstream & os, row_type row, + OutputParams const & runparams) const { - idx_type cell = cellIndex(i, 0); + idx_type cell = cellIndex(row, 0); shared_ptr inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); string const lang = par.getParLanguage(buffer().params())->lang(); //output the top line - int ret = TeXTopHLine(os, i, lang); + TeXTopHLine(os, row, lang); - if (row_info[i].top_space_default) { + if (row_info[row].top_space_default) { if (use_booktabs) os << "\\addlinespace\n"; else os << "\\noalign{\\vskip\\doublerulesep}\n"; - ++ret; - } else if(!row_info[i].top_space.zero()) { + } else if(!row_info[row].top_space.zero()) { if (use_booktabs) os << "\\addlinespace[" - << from_ascii(row_info[i].top_space.asLatexString()) + << from_ascii(row_info[row].top_space.asLatexString()) << "]\n"; else { os << "\\noalign{\\vskip" - << from_ascii(row_info[i].top_space.asLatexString()) + << from_ascii(row_info[row].top_space.asLatexString()) << "}\n"; } - ++ret; } bool ismulticol = false; - for (col_type j = 0; j < column_info.size(); ++j) { - if (isPartOfMultiColumn(i, j)) + bool ismultirow = false; + for (col_type c = 0; c < ncols(); ++c) { + if (isPartOfMultiColumn(row, c)) continue; - ret += TeXCellPreamble(os, cell, ismulticol); + + cell = cellIndex(row, c); + + if (isPartOfMultiRow(row, c) + && column_info[c].alignment != LYX_ALIGN_DECIMAL) { + if (cell != getLastCellInRow(row)) + os << " & "; + continue; + } + + TeXCellPreamble(os, cell, ismulticol, ismultirow); shared_ptr inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); bool rtl = par.isRTL(buffer().params()) && !par.empty() - && getPWidth(cell).zero(); + && getPWidth(cell).zero() + && !runparams.use_polyglossia; if (rtl) { string const lang = @@ -2284,7 +2583,7 @@ int Tabular::TeXRow(odocstream & os, row_type i, os << "\\textFR{"; else if (lang == "arabic_arabi") os << "\\textAR{"; - // currently, remaning RTL languages are + // currently, remaining RTL languages are // arabic_arabtex and hebrew else os << "\\R{"; @@ -2296,75 +2595,95 @@ int Tabular::TeXRow(odocstream & os, row_type i, newrp.inTableCell = (getAlignment(cell) == LYX_ALIGN_BLOCK) ? OutputParams::PLAIN : OutputParams::ALIGNED; - ret += inset->latex(os, newrp); + + if (getAlignment(cell) == LYX_ALIGN_DECIMAL) { + // copy cell and split in 2 + InsetTableCell head = InsetTableCell(*cellInset(cell).get()); + head.setBuffer(buffer()); + DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition(); + dit.pop_back(); + dit.push_back(CursorSlice(head)); + head.setMacrocontextPositionRecursive(dit); + bool hassep = false; + InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep); + head.latex(os, newrp); + if (hassep) { + os << '&'; + tail.setBuffer(head.buffer()); + dit.pop_back(); + dit.push_back(CursorSlice(tail)); + tail.setMacrocontextPositionRecursive(dit); + tail.latex(os, newrp); + } + } else if (!isPartOfMultiRow(row, c)) { + if (!runparams.nice) + os.texrow().start(par.id(), 0); + inset->latex(os, newrp); + } + runparams.encoding = newrp.encoding; if (rtl) os << '}'; - ret += TeXCellPostamble(os, cell, ismulticol); - if (!isLastCellInRow(cell)) { // not last cell in row - os << " & "; + TeXCellPostamble(os, cell, ismulticol, ismultirow); + if (cell != getLastCellInRow(row)) { // not last cell in row + if (runparams.nice) + os << " & "; + else + os << " &\n"; } - ++cell; } - if (row_info[i].caption && !endfirsthead.empty && !haveLTFirstHead()) - // if no first header and no empty first header is used, - // the caption needs to be terminated by \endfirsthead - // (bug 6057) - os << "\\endfirsthead"; - else - os << "\\tabularnewline"; - if (row_info[i].bottom_space_default) { + os << "\\tabularnewline"; + if (row_info[row].bottom_space_default) { if (use_booktabs) os << "\\addlinespace"; else os << "[\\doublerulesep]"; - } else if (!row_info[i].bottom_space.zero()) { + } else if (!row_info[row].bottom_space.zero()) { if (use_booktabs) os << "\\addlinespace"; os << '[' - << from_ascii(row_info[i].bottom_space.asLatexString()) + << from_ascii(row_info[row].bottom_space.asLatexString()) << ']'; } os << '\n'; - ++ret; //output the bottom line - ret += TeXBottomHLine(os, i, lang); + TeXBottomHLine(os, row, lang); - if (row_info[i].interline_space_default) { + if (row_info[row].interline_space_default) { if (use_booktabs) os << "\\addlinespace\n"; else os << "\\noalign{\\vskip\\doublerulesep}\n"; - ++ret; - } else if (!row_info[i].interline_space.zero()) { + } else if (!row_info[row].interline_space.zero()) { if (use_booktabs) os << "\\addlinespace[" - << from_ascii(row_info[i].interline_space.asLatexString()) + << from_ascii(row_info[row].interline_space.asLatexString()) << "]\n"; else os << "\\noalign{\\vskip" - << from_ascii(row_info[i].interline_space.asLatexString()) + << from_ascii(row_info[row].interline_space.asLatexString()) << "}\n"; - ++ret; } - return ret; } -int Tabular::latex(odocstream & os, OutputParams const & runparams) const +void Tabular::latex(otexstream & os, OutputParams const & runparams) const { - int ret = 0; + bool const is_tabular_star = !tabular_width.zero(); //+--------------------------------------------------------------------- //+ first the opening preamble + //+--------------------------------------------------------------------- - if (rotate) { - os << "\\begin{sideways}\n"; - ++ret; - } + os << safebreakln; + if (runparams.lastid != -1) + os.texrow().start(runparams.lastid, runparams.lastpos); + + if (rotate != 0) + os << "\\begin{turn}{" << convert(rotate) << "}\n"; + if (is_long_tabular) { os << "\\begin{longtable}"; switch (longtabular_alignment) { @@ -2378,7 +2697,10 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const break; } } else { - os << "\\begin{tabular}"; + if (is_tabular_star) + os << "\\begin{tabular*}{" << from_ascii(tabular_width.asLatexString()) << "}"; + else + os << "\\begin{tabular}"; switch (tabular_valignment) { case LYX_VALIGN_TOP: os << "[t]"; @@ -2393,14 +2715,17 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const os << "{"; - for (col_type i = 0; i < column_info.size(); ++i) { - if (columnLeftLine(i)) + if (is_tabular_star) + os << "@{\\extracolsep{\\fill}}"; + + for (col_type c = 0; c < ncols(); ++c) { + if (columnLeftLine(c)) os << '|'; - if (!column_info[i].align_special.empty()) { - os << column_info[i].align_special; + if (!column_info[c].align_special.empty()) { + os << column_info[c].align_special; } else { - if (!column_info[i].p_width.zero()) { - switch (column_info[i].alignment) { + if (!column_info[c].p_width.zero()) { + switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: os << ">{\\raggedright}"; break; @@ -2414,10 +2739,11 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const case LYX_ALIGN_BLOCK: case LYX_ALIGN_LAYOUT: case LYX_ALIGN_SPECIAL: + case LYX_ALIGN_DECIMAL: break; } - switch (column_info[i].valignment) { + switch (column_info[c].valignment) { case LYX_VALIGN_TOP: os << 'p'; break; @@ -2429,41 +2755,41 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const break; } os << '{' - << from_ascii(column_info[i].p_width.asLatexString()) + << from_ascii(column_info[c].p_width.asLatexString()) << '}'; } else { - switch (column_info[i].alignment) { + switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: os << 'l'; break; case LYX_ALIGN_RIGHT: os << 'r'; break; + case LYX_ALIGN_DECIMAL: + os << "r@{\\extracolsep{0pt}" << column_info[c].decimal_point << "}l"; + break; default: os << 'c'; break; } } // end if else !column_info[i].p_width } // end if else !column_info[i].align_special - if (columnRightLine(i)) + if (columnRightLine(c)) os << '|'; } os << "}\n"; - ++ret; - ret += TeXLongtableHeaderFooter(os, runparams); + TeXLongtableHeaderFooter(os, runparams); //+--------------------------------------------------------------------- //+ the single row and columns (cells) + //+--------------------------------------------------------------------- - for (row_type i = 0; i < row_info.size(); ++i) { - if (isValidRow(i)) { - ret += TeXRow(os, i, runparams); - if (is_long_tabular && row_info[i].newpage) { + for (row_type r = 0; r < nrows(); ++r) { + if (isValidRow(r)) { + TeXRow(os, r, runparams); + if (is_long_tabular && row_info[r].newpage) os << "\\newpage\n"; - ++ret; - } } } @@ -2473,14 +2799,15 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const if (is_long_tabular) os << "\\end{longtable}"; - else - os << "\\end{tabular}"; - if (rotate) { - os << "\n\\end{sideways}"; - ++ret; + else { + if (is_tabular_star) + os << "\\end{tabular*}"; + else + os << "\\end{tabular}"; } - return ret; + if (rotate != 0) + os << breakln << "\\end{turn}"; } @@ -2491,8 +2818,8 @@ int Tabular::docbookRow(odocstream & os, row_type row, idx_type cell = getFirstCellInRow(row); os << "\n"; - for (col_type j = 0; j < column_info.size(); ++j) { - if (isPartOfMultiColumn(row, j)) + for (col_type c = 0; c < ncols(); ++c) { + if (isPartOfMultiColumn(row, c)) continue; os << "'; @@ -2544,12 +2871,12 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const //+ first the opening preamble + //+--------------------------------------------------------------------- - os << "\n"; - for (col_type i = 0; i < column_info.size(); ++i) { - os << "\n"; ++ret; - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].caption) { - ret += docbookRow(os, i, runparams); + for (row_type r = 0; r < nrows(); ++r) { + if (row_info[r].caption) { + ret += docbookRow(os, r, runparams); } } os << "\n"; ++ret; } // output header info - if (haveLTHead() || haveLTFirstHead()) { + if (haveLTHead(false) || haveLTFirstHead(false)) { os << "\n"; ++ret; - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].endhead || row_info[i].endfirsthead) { - ret += docbookRow(os, i, runparams); + for (row_type r = 0; r < nrows(); ++r) { + if ((row_info[r].endhead || row_info[r].endfirsthead) && + !row_info[r].caption) { + ret += docbookRow(os, r, runparams); } } os << "\n"; ++ret; } // output footer info - if (haveLTFoot() || haveLTLastFoot()) { + if (haveLTFoot(false) || haveLTLastFoot(false)) { os << "\n"; ++ret; - for (row_type i = 0; i < row_info.size(); ++i) { - if (row_info[i].endfoot || row_info[i].endlastfoot) { - ret += docbookRow(os, i, runparams); + for (row_type r = 0; r < nrows(); ++r) { + if ((row_info[r].endfoot || row_info[r].endlastfoot) && + !row_info[r].caption) { + ret += docbookRow(os, r, runparams); } } os << "\n"; @@ -2614,9 +2944,9 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const os << "\n"; ++ret; - for (row_type i = 0; i < row_info.size(); ++i) { - if (isValidRow(i)) { - ret += docbookRow(os, i, runparams); + for (row_type r = 0; r < nrows(); ++r) { + if (isValidRow(r)) { + ret += docbookRow(os, r, runparams); } } os << "\n"; @@ -2632,11 +2962,147 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const } -bool Tabular::plaintextTopHLine(odocstream & os, row_type row, +docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, + OutputParams const & runparams, bool header) const +{ + docstring ret; + string const celltag = header ? "th" : "td"; + idx_type cell = getFirstCellInRow(row); + + xs << html::StartTag("tr"); + for (col_type c = 0; c < ncols(); ++c) { + if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c)) + continue; + + stringstream attr; + attr << "align='"; + switch (getAlignment(cell)) { + case LYX_ALIGN_LEFT: + attr << "left"; + break; + case LYX_ALIGN_RIGHT: + attr << "right"; + break; + default: + attr << "center"; + break; + } + attr << "'"; + attr << " valign='"; + switch (getVAlignment(cell)) { + case LYX_VALIGN_TOP: + attr << "top"; + break; + case LYX_VALIGN_BOTTOM: + attr << "bottom"; + break; + case LYX_VALIGN_MIDDLE: + attr << "middle"; + } + attr << "'"; + + if (isMultiColumn(cell)) + attr << " colspan='" << columnSpan(cell) << "'"; + else if (isMultiRow(cell)) + attr << " rowspan='" << rowSpan(cell) << "'"; + + xs << html::StartTag(celltag, attr.str()) << html::CR(); + ret += cellInset(cell)->xhtml(xs, runparams); + xs << html::EndTag(celltag) << html::CR(); + ++cell; + } + xs << html::EndTag("tr"); + return ret; +} + + +docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const +{ + docstring ret; + + if (is_long_tabular) { + // we'll wrap it in a div, so as to deal with alignment + string align; + switch (longtabular_alignment) { + case LYX_LONGTABULAR_ALIGN_LEFT: + align = "left"; + break; + case LYX_LONGTABULAR_ALIGN_CENTER: + align = "center"; + break; + case LYX_LONGTABULAR_ALIGN_RIGHT: + align = "right"; + break; + } + xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'") + << html::CR(); + // The caption flag wins over head/foot + if (haveLTCaption()) { + xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'") + << html::CR(); + for (row_type r = 0; r < nrows(); ++r) + if (row_info[r].caption) + ret += xhtmlRow(xs, r, runparams); + xs << html::EndTag("div") << html::CR(); + } + } + + xs << html::StartTag("table") << html::CR(); + + // output header info + bool const havefirsthead = haveLTFirstHead(false); + // if we have a first head, then we are going to ignore the + // headers for the additional pages, since there aren't any + // in XHTML. this test accomplishes that. + bool const havehead = !havefirsthead && haveLTHead(false); + if (havehead || havefirsthead) { + xs << html::StartTag("thead") << html::CR(); + for (row_type r = 0; r < nrows(); ++r) { + if (((havefirsthead && row_info[r].endfirsthead) || + (havehead && row_info[r].endhead)) && + !row_info[r].caption) { + ret += xhtmlRow(xs, r, runparams, true); + } + } + xs << html::EndTag("thead") << html::CR(); + } + // output footer info + bool const havelastfoot = haveLTLastFoot(false); + // as before. + bool const havefoot = !havelastfoot && haveLTFoot(false); + if (havefoot || havelastfoot) { + xs << html::StartTag("tfoot") << html::CR(); + for (row_type r = 0; r < nrows(); ++r) { + if (((havelastfoot && row_info[r].endlastfoot) || + (havefoot && row_info[r].endfoot)) && + !row_info[r].caption) { + ret += xhtmlRow(xs, r, runparams); + } + } + xs << html::EndTag("tfoot") << html::CR(); + } + + xs << html::StartTag("tbody") << html::CR(); + for (row_type r = 0; r < nrows(); ++r) { + if (isValidRow(r)) { + ret += xhtmlRow(xs, r, runparams); + } + } + xs << html::EndTag("tbody") + << html::CR() + << html::EndTag("table") + << html::CR(); + if (is_long_tabular) + xs << html::EndTag("div") << html::CR(); + return ret; +} + + +bool Tabular::plaintextTopHLine(odocstringstream & os, row_type row, vector const & clen) const { idx_type const fcell = getFirstCellInRow(row); - idx_type const n = numberOfCellsInRow(fcell) + fcell; + idx_type const n = numberOfCellsInRow(row) + fcell; idx_type tmp = 0; for (idx_type i = fcell; i < n; ++i) { @@ -2662,7 +3128,7 @@ bool Tabular::plaintextTopHLine(odocstream & os, row_type row, } col_type column = cellColumn(i); int len = clen[column]; - while (column < column_info.size() - 1 + while (column < ncols() - 1 && isPartOfMultiColumn(row, ++column)) len += clen[column] + 4; os << docstring(len, ch); @@ -2680,11 +3146,11 @@ bool Tabular::plaintextTopHLine(odocstream & os, row_type row, } -bool Tabular::plaintextBottomHLine(odocstream & os, row_type row, +bool Tabular::plaintextBottomHLine(odocstringstream & os, row_type row, vector const & clen) const { idx_type const fcell = getFirstCellInRow(row); - idx_type const n = numberOfCellsInRow(fcell) + fcell; + idx_type const n = numberOfCellsInRow(row) + fcell; idx_type tmp = 0; for (idx_type i = fcell; i < n; ++i) { @@ -2710,8 +3176,7 @@ bool Tabular::plaintextBottomHLine(odocstream & os, row_type row, } col_type column = cellColumn(i); int len = clen[column]; - while (column < column_info.size() -1 - && isPartOfMultiColumn(row, ++column)) + while (column < ncols() - 1 && isPartOfMultiColumn(row, ++column)) len += clen[column] + 4; os << docstring(len, ch); if (bottomLine(i)) { @@ -2728,14 +3193,14 @@ bool Tabular::plaintextBottomHLine(odocstream & os, row_type row, } -void Tabular::plaintextPrintCell(odocstream & os, +void Tabular::plaintextPrintCell(odocstringstream & os, OutputParams const & runparams, idx_type cell, row_type row, col_type column, vector const & clen, - bool onlydata) const + bool onlydata, size_t max_length) const { odocstringstream sstr; - cellInset(cell)->plaintext(sstr, runparams); + cellInset(cell)->plaintext(sstr, runparams, max_length); if (onlydata) { os << sstr.str(); @@ -2749,8 +3214,7 @@ void Tabular::plaintextPrintCell(odocstream & os, unsigned int len1 = sstr.str().length(); unsigned int len2 = clen[column]; - while (column < column_info.size() -1 - && isPartOfMultiColumn(row, ++column)) + while (column < ncols() - 1 && isPartOfMultiColumn(row, ++column)) len2 += clen[column] + 4; len2 -= len1; @@ -2779,64 +3243,68 @@ void Tabular::plaintextPrintCell(odocstream & os, } -void Tabular::plaintext(odocstream & os, +void Tabular::plaintext(odocstringstream & os, OutputParams const & runparams, int const depth, - bool onlydata, char_type delim) const + bool onlydata, char_type delim, size_t max_length) const { // first calculate the width of the single columns - vector clen(column_info.size()); + vector clen(ncols()); if (!onlydata) { - // first all non (real) multicolumn cells! - for (col_type j = 0; j < column_info.size(); ++j) { - clen[j] = 0; - for (row_type i = 0; i < row_info.size(); ++i) { - idx_type cell = cellIndex(i, j); - if (isMultiColumnReal(cell)) + // first all non multicolumn cells! + for (col_type c = 0; c < ncols(); ++c) { + clen[c] = 0; + for (row_type r = 0; r < nrows(); ++r) { + idx_type cell = cellIndex(r, c); + if (isMultiColumn(cell)) continue; odocstringstream sstr; - cellInset(cell)->plaintext(sstr, runparams); - if (clen[j] < sstr.str().length()) - clen[j] = sstr.str().length(); + cellInset(cell)->plaintext(sstr, runparams, max_length); + if (clen[c] < sstr.str().length()) + clen[c] = sstr.str().length(); } } - // then all (real) multicolumn cells! - for (col_type j = 0; j < column_info.size(); ++j) { - for (row_type i = 0; i < row_info.size(); ++i) { - idx_type cell = cellIndex(i, j); - if (!isMultiColumnReal(cell) || isPartOfMultiColumn(i, j)) + // then all multicolumn cells! + for (col_type c = 0; c < ncols(); ++c) { + for (row_type r = 0; r < nrows(); ++r) { + idx_type cell = cellIndex(r, c); + if (cell_info[r][c].multicolumn != CELL_BEGIN_OF_MULTICOLUMN) continue; odocstringstream sstr; - cellInset(cell)->plaintext(sstr, runparams); + cellInset(cell)->plaintext(sstr, runparams, max_length); int len = int(sstr.str().length()); idx_type const n = columnSpan(cell); - for (col_type k = j; len > 0 && k < j + n - 1; ++k) + for (col_type k = c; len > 0 && k < c + n - 1; ++k) len -= clen[k]; - if (len > int(clen[j + n - 1])) - clen[j + n - 1] = len; + if (len > int(clen[c + n - 1])) + clen[c + n - 1] = len; } } } idx_type cell = 0; - for (row_type i = 0; i < row_info.size(); ++i) { - if (!onlydata && plaintextTopHLine(os, i, clen)) + for (row_type r = 0; r < nrows(); ++r) { + if (!onlydata && plaintextTopHLine(os, r, clen)) os << docstring(depth * 2, ' '); - for (col_type j = 0; j < column_info.size(); ++j) { - if (isPartOfMultiColumn(i, j)) + for (col_type c = 0; c < ncols(); ++c) { + if (isPartOfMultiColumn(r, c) || isPartOfMultiRow(r,c)) continue; - if (onlydata && j > 0) + if (onlydata && c > 0) // we don't use operator<< for single UCS4 character. // see explanation in docstream.h os.put(delim); - plaintextPrintCell(os, runparams, cell, i, j, clen, onlydata); + plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata, max_length); ++cell; + if (os.str().size() > max_length) + break; } os << endl; if (!onlydata) { os << docstring(depth * 2, ' '); - if (plaintextBottomHLine(os, i, clen)) + if (plaintextBottomHLine(os, r, clen)) os << docstring(depth * 2, ' '); } + if (os.str().size() > max_length) + break; } } @@ -2872,6 +3340,8 @@ void Tabular::validate(LaTeXFeatures & features) const if (needRotating()) features.require("rotating"); for (idx_type cell = 0; cell < numberofcells; ++cell) { + if (isMultiRow(cell)) + features.require("multirow"); if (getVAlignment(cell) != LYX_VALIGN_TOP || !getPWidth(cell).zero()) features.require("array"); @@ -2922,14 +3392,20 @@ bool InsetTableCell::allowParagraphCustomization(idx_type) const bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { - bool enabled; - switch (cmd.action) { + bool enabled = true; + switch (cmd.action()) { case LFUN_LAYOUT: enabled = !forcePlainLayout(); break; case LFUN_LAYOUT_PARAGRAPH: enabled = allowParagraphCustomization(); break; + + case LFUN_MATH_DISPLAY: + if (!hasFixedWidth()) { + enabled = false; + break; + } //fall-through default: return InsetText::getStatus(cur, cmd, status); } @@ -2956,6 +3432,20 @@ docstring InsetTableCell::asString(bool intoInsets) } +void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const +{ + InsetText::iterateForToc(di, output_active); +} + + +docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const +{ + if (!isFixedWidth) + return InsetText::insetAsXHTML(xs, rp, InsetText::JustText); + return InsetText::xhtml(xs, rp); +} + + ///////////////////////////////////////////////////////////////////// // @@ -2992,11 +3482,26 @@ void InsetTabular::setBuffer(Buffer & buf) bool InsetTabular::insetAllowed(InsetCode code) const { - if (code == MATHMACRO_CODE - || (code == CAPTION_CODE && !tabular.is_long_tabular)) + switch (code) { + case FLOAT_CODE: + case MARGIN_CODE: + case MATHMACRO_CODE: + case WRAP_CODE: return false; - return true; + case CAPTION_CODE: + return tabular.is_long_tabular; + + default: + return true; + } +} + + +bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const +{ + return tabular.is_long_tabular && + (newtype == "Standard" || newtype == "LongTableNoNumber"); } @@ -3007,10 +3512,17 @@ void InsetTabular::write(ostream & os) const } -docstring InsetTabular::contextMenu(BufferView const &, int, int) const +string InsetTabular::contextMenu(BufferView const &, int, int) const +{ + // FIXME: depending on the selection state, + // we could offer a different menu. + return cell(0)->contextMenuName() + ";" + contextMenuName(); +} + + +string InsetTabular::contextMenuName() const { - // FIXME: depending on the selection state, we could offer a different menu. - return from_ascii("context-tabular"); + return "context-tabular"; } @@ -3037,14 +3549,12 @@ void InsetTabular::read(Lexer & lex) int InsetTabular::rowFromY(Cursor & cur, int y) const { // top y coordinate of tabular - int h = yo(cur.bv()) - tabular.rowAscent(0); - size_t nrows = tabular.row_info.size(); + int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; row_type r = 0; - for (; r < nrows && y > h; ++r) { - h += tabular.rowAscent(r); - h += tabular.rowDescent(r); - h += tabular.getAdditionalHeight(r); - } + for (; r < tabular.nrows() && y > h; ++r) + h += tabular.rowAscent(r) + tabular.rowDescent(r) + + tabular.interRowSpace(r); + return r - 1; } @@ -3053,10 +3563,9 @@ int InsetTabular::columnFromX(Cursor & cur, int x) const { // left x coordinate of tabular int w = xo(cur.bv()) + ADD_TO_TABULAR_WIDTH; - size_t ncols = tabular.column_info.size(); col_type c = 0; - for (; c < ncols && x > w; ++c) - w += tabular.columnWidth(c); + for (; c < tabular.ncols() && x > w; ++c) + w += tabular.cellWidth(c); return c - 1; } @@ -3065,52 +3574,112 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const { //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " << // mi.base.textwidth << "\n"; - if (!mi.base.bv) { - LYXERR0("need bv"); - LASSERT(false, /**/); - } - - row_type i = 0; - for (idx_type cell = 0; i < tabular.row_info.size(); ++i) { - int maxAsc = 0; - int maxDesc = 0; - for (col_type j = 0; j < tabular.column_info.size(); ++j) { - if (tabular.isPartOfMultiColumn(i, j)) - // Multicolumn cell, but not first one + LBUFERR(mi.base.bv); + + for (row_type r = 0; r < tabular.nrows(); ++r) { + int maxasc = 0; + int maxdes = 0; + for (col_type c = 0; c < tabular.ncols(); ++c) { + if (tabular.isPartOfMultiColumn(r, c) + || tabular.isPartOfMultiRow(r, c)) + // multicolumn or multirow cell, but not first one continue; + idx_type const cell = tabular.cellIndex(r, c); Dimension dim; MetricsInfo m = mi; - Length p_width; - if (tabular.cell_info[i][j].multicolumn == - Tabular::CELL_BEGIN_OF_MULTICOLUMN) - p_width = tabular.cellInfo(cell).p_width; - else - p_width = tabular.column_info[j].p_width; + Length const p_width = tabular.getPWidth(cell); if (!p_width.zero()) m.base.textwidth = p_width.inPixels(mi.base.textwidth); tabular.cellInset(cell)->metrics(m, dim); if (!p_width.zero()) dim.wid = m.base.textwidth; - tabular.setCellWidth(cell, dim.wid); - maxAsc = max(maxAsc, dim.asc); - maxDesc = max(maxDesc, dim.des); - ++cell; + tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE + + tabular.interColumnSpace(cell); + + // FIXME(?): do we need a second metrics call? + TextMetrics const & tm = + mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0)); + + // determine horizontal offset because of decimal align (if necessary) + int decimal_width = 0; + if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) { + InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell).get()); + tail.setBuffer(tabular.buffer()); + // we need to set macrocontext position everywhere + // otherwise we crash with nested insets (e.g. footnotes) + // after decimal point + DocIterator dit = tabular.cellInset(cell)->getText(0)->macrocontextPosition(); + dit.pop_back(); + dit.push_back(CursorSlice(tail)); + tail.setMacrocontextPositionRecursive(dit); + + // remove text leading decimal point + docstring const align_d = tabular.column_info[c].decimal_point; + dit = separatorPos(&tail, align_d); + + pit_type const psize = tail.paragraphs().front().size(); + if (dit) { + tail.paragraphs().front().eraseChars(0, + dit.pos() < psize ? dit.pos() + 1 : psize, false); + Dimension dim1; + tail.metrics(m, dim1); + decimal_width = dim1.width(); + } + } + tabular.cell_info[r][c].decimal_hoffset = tm.width() - decimal_width; + tabular.cell_info[r][c].decimal_width = decimal_width; + + // with LYX_VALIGN_BOTTOM the descent is relative to the last par + // = descent of text in last par + TEXT_TO_INSET_OFFSET: + int const lastpardes = tm.last().second->descent() + + TEXT_TO_INSET_OFFSET; + int offset = 0; + switch (tabular.getVAlignment(cell)) { + case Tabular::LYX_VALIGN_TOP: + break; + case Tabular::LYX_VALIGN_MIDDLE: + offset = -(dim.des - lastpardes)/2; + break; + case Tabular::LYX_VALIGN_BOTTOM: + offset = -(dim.des - lastpardes); + break; + } + tabular.cell_info[r][c].voffset = offset; + maxasc = max(maxasc, dim.asc - offset); + maxdes = max(maxdes, dim.des + offset); } - int const top_space = tabular.row_info[i].top_space_default ? + int const top_space = tabular.row_info[r].top_space_default ? default_line_space : - tabular.row_info[i].top_space.inPixels(mi.base.textwidth); - tabular.setRowAscent(i, maxAsc + ADD_TO_HEIGHT + top_space); - int const bottom_space = tabular.row_info[i].bottom_space_default ? + tabular.row_info[r].top_space.inPixels(mi.base.textwidth); + tabular.setRowAscent(r, maxasc + ADD_TO_HEIGHT + top_space); + int const bottom_space = tabular.row_info[r].bottom_space_default ? default_line_space : - tabular.row_info[i].bottom_space.inPixels(mi.base.textwidth); - tabular.setRowDescent(i, maxDesc + ADD_TO_HEIGHT + bottom_space); + tabular.row_info[r].bottom_space.inPixels(mi.base.textwidth); + tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space); + } + + // for top-alignment the first horizontal table line must be exactly at + // the position of the base line of the surrounding text line + // for bottom alignment, the same is for the last table line + switch (tabular.tabular_valignment) { + case Tabular::LYX_VALIGN_BOTTOM: + offset_valign_ = tabular.rowAscent(0) - tabular.height(); + break; + case Tabular::LYX_VALIGN_MIDDLE: + offset_valign_ = (- tabular.height()) / 2 + tabular.rowAscent(0); + break; + case Tabular::LYX_VALIGN_TOP: + offset_valign_ = tabular.rowAscent(0); + break; } + tabular.updateColumnWidths(); - dim.asc = tabular.rowAscent(0); + dim.asc = tabular.rowAscent(0) - offset_valign_; dim.des = tabular.height() - dim.asc; dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH; } + bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) const { @@ -3120,7 +3689,11 @@ bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) col_type cs, ce; getSelection(cur, rs, re, cs, ce); - if (col >= cs && col <= ce && row >= rs && row <= re) + idx_type const cell = tabular.cellIndex(row, col); + col_type const cspan = tabular.columnSpan(cell); + row_type const rspan = tabular.rowSpan(cell); + if (col + cspan - 1 >= cs && col <= ce + && row + rspan - 1 >= rs && row <= re) return true; } else if (col == tabular.cellColumn(cur.idx()) @@ -3140,63 +3713,65 @@ bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) void InsetTabular::draw(PainterInfo & pi, int x, int y) const { - //lyxerr << "InsetTabular::draw: " << x << " " << y << endl; + x += scx_ + ADD_TO_TABULAR_WIDTH; + BufferView * bv = pi.base.bv; Cursor & cur = pi.base.bv->cursor(); + resetPos(cur); - // FIXME: As the full background is painted in drawSelection(), + // FIXME: As the full background is painted in drawBackground(), // we have no choice but to do a full repaint for the Text cells. pi.full_repaint = true; - resetPos(bv->cursor()); - - x += scx_; - x += ADD_TO_TABULAR_WIDTH; - - bool const original_drawing_state = pi.pain.isDrawingEnabled(); bool const original_selection_state = pi.selected; idx_type idx = 0; first_visible_cell = Tabular::npos; - for (row_type i = 0; i < tabular.row_info.size(); ++i) { + + int yy = y + offset_valign_; + for (row_type r = 0; r < tabular.nrows(); ++r) { int nx = x; - int const a = tabular.rowAscent(i); - int const d = tabular.rowDescent(i); - idx = tabular.cellIndex(i, 0); - for (col_type j = 0; j < tabular.column_info.size(); ++j) { - if (tabular.isPartOfMultiColumn(i, j)) + for (col_type c = 0; c < tabular.ncols(); ++c) { + if (tabular.isPartOfMultiColumn(r, c)) + continue; + + idx = tabular.cellIndex(r, c); + + if (tabular.isPartOfMultiRow(r, c)) { + nx += tabular.cellWidth(idx); continue; + } + if (first_visible_cell == Tabular::npos) first_visible_cell = idx; - pi.selected |= isCellSelected(cur, i, j); - int const cx = nx + tabular.getBeginningOfTextInCell(idx); + pi.selected |= isCellSelected(cur, r, c); + int const cx = nx + tabular.textHOffset(idx); + int const cy = yy + tabular.textVOffset(idx); // Cache the Inset position. - bv->coordCache().insets().add(cell(idx).get(), cx, y); - if (nx + tabular.columnWidth(idx) < 0 - || nx > bv->workWidth() - || y + d < 0 - || y - a > bv->workHeight()) { - pi.pain.setDrawingEnabled(false); - cell(idx)->draw(pi, cx, y); - drawCellLines(pi.pain, nx, y, i, idx, pi.change_); - pi.pain.setDrawingEnabled(original_drawing_state); - } else { - cell(idx)->draw(pi, cx, y); - drawCellLines(pi.pain, nx, y, i, idx, pi.change_); - } - nx += tabular.columnWidth(idx); - ++idx; + bv->coordCache().insets().add(cell(idx).get(), cx, cy); + cell(idx)->draw(pi, cx, cy); + drawCellLines(pi, nx, yy, r, idx); + nx += tabular.cellWidth(idx); pi.selected = original_selection_state; } - if (i + 1 < tabular.row_info.size()) - y += d + tabular.rowAscent(i + 1) + - tabular.getAdditionalHeight(i + 1); + if (r + 1 < tabular.nrows()) + yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + + tabular.interRowSpace(r + 1); } } +void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const +{ + x += scx_ + ADD_TO_TABULAR_WIDTH; + y += offset_valign_ - tabular.rowAscent(0); + pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(), + pi.backgroundColor(this)); +} + + void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const { Cursor & cur = pi.base.bv->cursor(); @@ -3204,15 +3779,6 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const x += scx_ + ADD_TO_TABULAR_WIDTH; - // FIXME: it is wrong to completely paint the background - // if we want to do single row painting. - - // Paint background of current tabular - int const w = tabular.width(); - int const h = tabular.height(); - int yy = y - tabular.rowAscent(0); - pi.pain.fillRectangle(x, yy, w, h, pi.backgroundColor(this)); - if (!cur.selection()) return; if (&cur.inset() != this) @@ -3224,72 +3790,83 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const tabular.cellRow(cur.idx()), tabular.cellColumn(cur.idx())); if (cur.selIsMultiCell() || full_cell_selected) { - y -= tabular.rowAscent(0); - for (row_type j = 0; j < tabular.row_info.size(); ++j) { - int const a = tabular.rowAscent(j); - int const h = a + tabular.rowDescent(j); + for (row_type r = 0; r < tabular.nrows(); ++r) { int xx = x; - y += tabular.getAdditionalHeight(j); - for (col_type i = 0; i < tabular.column_info.size(); ++i) { - if (tabular.isPartOfMultiColumn(j, i)) + for (col_type c = 0; c < tabular.ncols(); ++c) { + if (tabular.isPartOfMultiColumn(r, c)) continue; - idx_type const cell = - tabular.cellIndex(j, i); - int const w = tabular.columnWidth(cell); - if (isCellSelected(cur, j, i)) - pi.pain.fillRectangle(xx, y, w, h, Color_selection); - xx += w; - } - y += h; - } - - } else { - x += cellXPos(cur.idx()); - x += tabular.getBeginningOfTextInCell(cur.idx()); - cell(cur.idx())->drawSelection(pi, x, 0 /* ignored */); - } -} - -void InsetTabular::drawCellLines(Painter & pain, int x, int y, - row_type row, idx_type cell, Change const & change) const -{ - int x2 = x + tabular.columnWidth(cell); - bool on_off = false; - Color col = Color_tabularline; - Color onoffcol = Color_tabularonoffline; + idx_type const cell = tabular.cellIndex(r, c); - if (change.changed()) { - col = change.color(); - onoffcol = change.color(); - } + if (tabular.isPartOfMultiRow(r, c)) { + xx += tabular.cellWidth(cell); + continue; + } + int const w = tabular.cellWidth(cell); + int const h = tabular.cellHeight(cell); + int const yy = y - tabular.rowAscent(r) + offset_valign_; + if (isCellSelected(cur, r, c)) + pi.pain.fillRectangle(xx, yy, w, h, Color_selection); + xx += w; + } + if (r + 1 < tabular.nrows()) + y += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + + tabular.interRowSpace(r + 1); + } - if (!tabular.topAlreadyDrawn(cell)) { - on_off = !tabular.topLine(cell); - pain.line(x, y - tabular.rowAscent(row), - x2, y - tabular.rowAscent(row), - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); - } - on_off = !tabular.bottomLine(cell); - pain.line(x, y + tabular.rowDescent(row), - x2, y + tabular.rowDescent(row), - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); - if (!tabular.leftAlreadyDrawn(cell)) { - on_off = !tabular.leftLine(cell); - pain.line(x, y - tabular.rowAscent(row), - x, y + tabular.rowDescent(row), - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); - } - on_off = !tabular.rightLine(cell); - pain.line(x2 - tabular.getAdditionalWidth(cell), - y - tabular.rowAscent(row), - x2 - tabular.getAdditionalWidth(cell), - y + tabular.rowDescent(row), - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); + } + // FIXME: This code has no effect because InsetTableCell does not handle + // drawSelection other than the trivial implementation in Inset. + //else { + // x += cellXPos(cur.idx()); + // x += tabular.textHOffset(cur.idx()); + // cell(cur.idx())->drawSelection(pi, x, 0 /* ignored */); + //} +} + + +void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, + row_type row, idx_type cell) const +{ + y -= tabular.rowAscent(row); + int const w = tabular.cellWidth(cell); + int const h = tabular.cellHeight(cell); + Color const linecolor = pi.textColor(Color_tabularline); + Color const gridcolor = pi.textColor(Color_tabularonoffline); + + // Top + bool drawline = tabular.topLine(cell) + || (row > 0 && tabular.bottomLine(tabular.cellAbove(cell))); + pi.pain.line(x, y, x + w, y, + drawline ? linecolor : gridcolor, + drawline ? Painter::line_solid : Painter::line_onoffdash); + + // Bottom + drawline = tabular.bottomLine(cell); + pi.pain.line(x, y + h, x + w, y + h, + drawline ? linecolor : gridcolor, + drawline ? Painter::line_solid : Painter::line_onoffdash); + + // Left + col_type const col = tabular.cellColumn(cell); + drawline = tabular.leftLine(cell) + || (col > 0 && tabular.rightLine(tabular.cellIndex(row, col - 1))); + pi.pain.line(x, y, x, y + h, + drawline ? linecolor : gridcolor, + drawline ? Painter::line_solid : Painter::line_onoffdash); + + // Right + x -= tabular.interColumnSpace(cell); + col_type next_cell_col = col + 1; + while (next_cell_col < tabular.ncols() + && tabular.isMultiColumn(tabular.cellIndex(row, next_cell_col))) + next_cell_col++; + drawline = tabular.rightLine(cell) + || (next_cell_col < tabular.ncols() + && tabular.leftLine(tabular.cellIndex(row, next_cell_col))); + pi.pain.line(x + w, y, x + w, y + h, + drawline ? linecolor : gridcolor, + drawline ? Painter::line_solid : Painter::line_onoffdash); } @@ -3308,35 +3885,52 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection) cur.pos() = 0; } else { if (isRightToLeft(cur)) - cur.idx() = tabular.getFirstCellInRow(tabular.row_info.size() - 1); + cur.idx() = tabular.getFirstCellInRow(tabular.nrows() - 1); else cur.idx() = tabular.numberofcells - 1; cur.pit() = 0; cur.pos() = cur.lastpos(); // FIXME crude guess } + cur.setCurrentFont(); // FIXME: this accesses the position cache before it is initialized //resetPos(cur); //cur.bv().fitCursor(); } -void InsetTabular::updateLabels(ParIterator const & it) +void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) { // In a longtable, tell captions what the current float is Counters & cnts = buffer().masterBuffer()->params().documentClass().counters(); string const saveflt = cnts.current_float(); - if (tabular.is_long_tabular) + if (tabular.is_long_tabular) { cnts.current_float("table"); + // in longtables, we only step the counter once + cnts.step(from_ascii("table"), utype); + cnts.isLongtable(true); + } ParIterator it2 = it; it2.forwardPos(); size_t const end = it2.nargs(); for ( ; it2.idx() < end; it2.top().forwardIdx()) - buffer().updateLabels(it2); + buffer().updateBuffer(it2, utype); //reset afterwards - if (tabular.is_long_tabular) + if (tabular.is_long_tabular) { cnts.current_float(saveflt); + cnts.isLongtable(false); + } +} + + +void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const +{ + DocIterator dit = cpit; + dit.forwardPos(); + size_t const end = dit.nargs(); + for ( ; dit.idx() < end; dit.top().forwardIdx()) + cell(dit.idx())->addToToc(dit, output_active); } @@ -3347,14 +3941,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) CursorSlice sl = cur.top(); Cursor & bvcur = cur.bv().cursor(); - switch (cmd.action) { + FuncCode const act = cmd.action(); + + switch (act) { case LFUN_MOUSE_PRESS: { //lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl; // select row - if (cmd.x < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH - || cmd.x > xo(cur.bv()) + tabular.width()) { - row_type r = rowFromY(cur, cmd.y); + if (cmd.x() < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH + || cmd.x() > xo(cur.bv()) + tabular.width()) { + row_type r = rowFromY(cur, cmd.y()); cur.idx() = tabular.getFirstCellInRow(r); cur.pos() = 0; cur.resetAnchor(); @@ -3366,14 +3962,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) break; } // select column - int const y0 = yo(cur.bv()) - tabular.rowAscent(0); - if (cmd.y < y0 + ADD_TO_TABULAR_WIDTH - || cmd.y > y0 + tabular.height()) { - col_type c = columnFromX(cur, cmd.x); + int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; + if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH + || cmd.y() > y0 + tabular.height()) { + col_type c = columnFromX(cur, cmd.x()); cur.idx() = tabular.cellIndex(0, c); cur.pos() = 0; cur.resetAnchor(); - cur.idx() = tabular.cellIndex(tabular.row_info.size() - 1, c); + cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c); cur.pos() = cur.lastpos(); cur.setSelection(true); bvcur = cur; @@ -3395,13 +3991,13 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) //lyxerr << "# InsetTabular::MouseMotion\n" << bvcur << endl; if (cmd.button() == mouse_button::button1) { // only accept motions to places not deeper nested than the real anchor - if (!bvcur.anchor_.hasPart(cur)) { + if (!bvcur.realAnchor().hasPart(cur)) { cur.undispatched(); break; } // select (additional) row if (rowselect_) { - row_type r = rowFromY(cur, cmd.y); + row_type r = rowFromY(cur, cmd.y()); cur.idx() = tabular.getLastCellInRow(r); // we need to reset the cursor's pit and pos now, as the old ones // may no longer be valid. @@ -3413,8 +4009,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } // select (additional) column if (colselect_) { - col_type c = columnFromX(cur, cmd.x); - cur.idx() = tabular.cellIndex(tabular.row_info.size() - 1, c); + col_type c = columnFromX(cur, cmd.x()); + cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c); // we need to reset the cursor's pit and pos now, as the old ones // may no longer be valid. cur.pit() = 0; @@ -3425,9 +4021,9 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } // only update if selection changes if (bvcur.idx() == cur.idx() && - !(bvcur.anchor_.idx() == cur.idx() && bvcur.pos() != cur.pos())) - cur.noUpdate(); - setCursorFromCoordinates(cur, cmd.x, cmd.y); + !(bvcur.realAnchor().idx() == cur.idx() && bvcur.pos() != cur.pos())) + cur.noScreenUpdate(); + setCursorFromCoordinates(cur, cmd.x(), cmd.y()); bvcur.setCursor(cur); bvcur.setSelection(true); // if this is a multicell selection, we just set the cursor to @@ -3461,7 +4057,15 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CHAR_RIGHT_SELECT: case LFUN_CHAR_RIGHT: case LFUN_CHAR_LEFT_SELECT: - case LFUN_CHAR_LEFT: { + case LFUN_CHAR_LEFT: + case LFUN_WORD_FORWARD: + case LFUN_WORD_FORWARD_SELECT: + case LFUN_WORD_BACKWARD: + case LFUN_WORD_BACKWARD_SELECT: + case LFUN_WORD_RIGHT: + case LFUN_WORD_RIGHT_SELECT: + case LFUN_WORD_LEFT: + case LFUN_WORD_LEFT_SELECT: { // determine whether we move to next or previous cell, where to enter // the new cell from, and which command to "finish" (i.e., exit the // inset) with: @@ -3469,21 +4073,27 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) EntryDirection entry_from = ENTRY_DIRECTION_IGNORE; FuncCode finish_lfun; - if (cmd.action == LFUN_CHAR_FORWARD - || cmd.action == LFUN_CHAR_FORWARD_SELECT) { + if (act == LFUN_CHAR_FORWARD + || act == LFUN_CHAR_FORWARD_SELECT + || act == LFUN_WORD_FORWARD + || act == LFUN_WORD_FORWARD_SELECT) { next_cell = true; finish_lfun = LFUN_FINISHED_FORWARD; } - else if (cmd.action == LFUN_CHAR_BACKWARD - || cmd.action == LFUN_CHAR_BACKWARD_SELECT) { + else if (act == LFUN_CHAR_BACKWARD + || act == LFUN_CHAR_BACKWARD_SELECT + || act == LFUN_WORD_BACKWARD + || act == LFUN_WORD_BACKWARD_SELECT) { next_cell = false; finish_lfun = LFUN_FINISHED_BACKWARD; } // LEFT or RIGHT commands --- the interpretation will depend on the // table's direction. else { - bool const right = cmd.action == LFUN_CHAR_RIGHT - || cmd.action == LFUN_CHAR_RIGHT_SELECT; + bool const right = act == LFUN_CHAR_RIGHT + || act == LFUN_CHAR_RIGHT_SELECT + || act == LFUN_WORD_RIGHT + || act == LFUN_WORD_RIGHT_SELECT; next_cell = isRightToLeft(cur) != right; if (lyxrc.visual_cursor) @@ -3492,10 +4102,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) finish_lfun = right ? LFUN_FINISHED_RIGHT : LFUN_FINISHED_LEFT; } - bool const select = cmd.action == LFUN_CHAR_FORWARD_SELECT || - cmd.action == LFUN_CHAR_BACKWARD_SELECT || - cmd.action == LFUN_CHAR_RIGHT_SELECT || - cmd.action == LFUN_CHAR_LEFT_SELECT; + bool const select = act == LFUN_CHAR_FORWARD_SELECT + || act == LFUN_CHAR_BACKWARD_SELECT + || act == LFUN_CHAR_RIGHT_SELECT + || act == LFUN_CHAR_LEFT_SELECT + || act == LFUN_WORD_FORWARD_SELECT + || act == LFUN_WORD_RIGHT_SELECT + || act == LFUN_WORD_BACKWARD_SELECT + || act == LFUN_WORD_LEFT_SELECT; // If we have a multicell selection or we're // not doing some LFUN_*_SELECT thing anyway... @@ -3519,6 +4133,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (select_whole && !empty_cell){ getText(cur.idx())->selectAll(cur); cur.dispatched(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; } @@ -3543,6 +4158,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cmd = FuncRequest(finish_lfun); else cur.dispatched(); + + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; } @@ -3557,13 +4174,18 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // if our Text didn't do anything to the cursor // then we try to put the cursor into the cell below // setting also the right targetX. - cur.selHandle(cmd.action == LFUN_DOWN_SELECT); - if (tabular.cellRow(cur.idx()) != tabular.row_info.size() - 1) { + cur.selHandle(act == LFUN_DOWN_SELECT); + if (tabular.cellRow(cur.idx()) != tabular.nrows() - 1) { + int const xtarget = cur.targetX(); + // WARNING: Once cur.idx() has been reset, the cursor is in + // an inconsistent state until pos() has been set. Be careful + // what you do with it! cur.idx() = tabular.cellBelow(cur.idx()); cur.pit() = 0; TextMetrics const & tm = cur.bv().textMetrics(cell(cur.idx())->getText(0)); - cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX()); + cur.pos() = tm.x2pos(cur.pit(), 0, xtarget); + cur.setCurrentFont(); } } if (sl == cur.top()) { @@ -3575,8 +4197,11 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (cur.selIsMultiCell()) { cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); + cur.setCurrentFont(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); return; } + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; case LFUN_UP_SELECT: @@ -3588,15 +4213,20 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // if our Text didn't do anything to the cursor // then we try to put the cursor into the cell above // setting also the right targetX. - cur.selHandle(cmd.action == LFUN_UP_SELECT); + cur.selHandle(act == LFUN_UP_SELECT); if (tabular.cellRow(cur.idx()) != 0) { + int const xtarget = cur.targetX(); + // WARNING: Once cur.idx() has been reset, the cursor is in + // an inconsistent state until pos() has been set. Be careful + // what you do with it! cur.idx() = tabular.cellAbove(cur.idx()); cur.pit() = cur.lastpit(); Text const * text = cell(cur.idx())->getText(0); TextMetrics const & tm = cur.bv().textMetrics(text); ParagraphMetrics const & pm = tm.parMetrics(cur.lastpit()); - cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, cur.targetX()); + cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, xtarget); + cur.setCurrentFont(); } } if (sl == cur.top()) { @@ -3606,8 +4236,11 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (cur.selIsMultiCell()) { cur.pit() = 0; cur.pos() = cur.lastpos(); + cur.setCurrentFont(); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); return; } + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; // case LFUN_SCREEN_DOWN: { @@ -3616,7 +4249,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // col_type const col = tabular.cellColumn(cur.idx()); // int const t = cur.bv().top_y() + cur.bv().height(); // if (t < yo() + tabular.getHeightOfTabular()) { -// cur.bv().scrollDocView(t); +// cur.bv().scrollDocView(t, true); // cur.idx() = tabular.cellBelow(first_visible_cell) + col; // } else { // cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col; @@ -3632,7 +4265,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // col_type const col = tabular.cellColumn(cur.idx()); // int const t = cur.bv().top_y() + cur.bv().height(); // if (yo() < 0) { -// cur.bv().scrollDocView(t); +// cur.bv().scrollDocView(t, true); // if (yo() > 0) // cur.idx() = col; // else @@ -3646,17 +4279,19 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // } case LFUN_LAYOUT_TABULAR: - cur.bv().showDialog("tabular", params2string(*this), this); - break; - - case LFUN_INSET_DIALOG_UPDATE: - cur.bv().updateDialog("tabular", params2string(*this)); + cur.bv().showDialog("tabular"); break; - case LFUN_TABULAR_FEATURE: - if (!tabularFeatures(cur, to_utf8(cmd.argument()))) + case LFUN_INSET_MODIFY: { + string arg; + if (cmd.getArg(1) == "from-dialog") + arg = cmd.getArg(0) + to_utf8(cmd.argument().substr(19)); + else + arg = to_utf8(cmd.argument()); + if (!tabularFeatures(cur, arg)) cur.undispatched(); break; + } // insert file functions case LFUN_FILE_INSERT_PLAINTEXT_PARA: @@ -3693,8 +4328,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) if (cur.selIsMultiCell()) { cur.recordUndoInset(DELETE_UNDO); cutSelection(cur); - } - cell(cur.idx())->dispatch(cur, cmd); + BufferView * bv = &cur.bv(); + docstring::const_iterator cit = cmd.argument().begin(); + docstring::const_iterator const end = cmd.argument().end(); + for (; cit != end; ++cit) + bv->translateAndInsert(*cit, getText(cur.idx()), cur); + + cur.resetAnchor(); + bv->bookmarkEditPosition(); + } else + cell(cur.idx())->dispatch(cur, cmd); break; case LFUN_CHAR_DELETE_BACKWARD: @@ -3718,8 +4361,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CLIPBOARD_PASTE: case LFUN_PRIMARY_SELECTION_PASTE: { - docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ? - theClipboard().getAsText() : + docstring const clip = (act == LFUN_CLIPBOARD_PASTE) ? + theClipboard().getAsText(Clipboard::PlainTextType) : theSelection().get(); if (clip.empty()) break; @@ -3747,8 +4390,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cell(cur.idx())->dispatch(cur, cmd); break; } - if (theClipboard().isInternal() || - (!theClipboard().hasInternal() && theClipboard().hasLyXContents())) { + if (theClipboard().isInternal()) { cur.recordUndoInset(INSERT_UNDO); pasteClipboard(cur); } @@ -3768,9 +4410,11 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_FONT_SIZE: case LFUN_FONT_UNDERLINE: case LFUN_FONT_STRIKEOUT: - case LFUN_FONT_UULINE: - case LFUN_FONT_UWAVE: + case LFUN_FONT_UNDERUNDERLINE: + case LFUN_FONT_UNDERWAVE: case LFUN_LANGUAGE: + case LFUN_PARAGRAPH_PARAMS_APPLY: + case LFUN_PARAGRAPH_PARAMS: case LFUN_WORD_CAPITALIZE: case LFUN_WORD_UPCASE: case LFUN_WORD_LOWCASE: @@ -3780,10 +4424,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) col_type cs, ce; getSelection(cur, rs, re, cs, ce); Cursor tmpcur = cur; - for (row_type i = rs; i <= re; ++i) { - for (col_type j = cs; j <= ce; ++j) { + for (row_type r = rs; r <= re; ++r) { + for (col_type c = cs; c <= ce; ++c) { // cursor follows cell: - tmpcur.idx() = tabular.cellIndex(i, j); + tmpcur.idx() = tabular.cellIndex(r, c); // select this cell only: tmpcur.pit() = 0; tmpcur.pos() = 0; @@ -3819,25 +4463,36 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { + switch (cmd.action()) { + case LFUN_INSET_MODIFY: { + if (&cur.inset() != this || cmd.getArg(0) != "tabular") + break; + + // FIXME: We only check for the very first argument... + string const s = cmd.getArg(1); + // We always enable the lfun if it is coming from the dialog + // because the dialog makes sure all the settings are valid, + // even though the first argument might not be valid now. + if (s == "from-dialog") { + status.setEnabled(true); + return true; + } + int action = Tabular::LAST_ACTION; int i = 0; for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) { - string const tmp = tabularFeature[i].feature; - if (tmp == to_utf8(cmd.argument()).substr(0, tmp.length())) { + if (tabularFeature[i].feature == s) { action = tabularFeature[i].action; break; } } if (action == Tabular::LAST_ACTION) { status.clear(); - status.unknown(true); + status.setUnknown(true); return true; } - string const argument - = ltrim(to_utf8(cmd.argument()).substr(tabularFeature[i].feature.length())); + string const argument = cmd.getLongArg(2); row_type sel_row_start = 0; row_type sel_row_end = 0; @@ -3852,7 +4507,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::SET_PWIDTH: case Tabular::SET_MPWIDTH: case Tabular::SET_SPECIAL_COLUMN: - case Tabular::SET_SPECIAL_MULTI: + case Tabular::SET_SPECIAL_MULTICOLUMN: case Tabular::APPEND_ROW: case Tabular::APPEND_COLUMN: case Tabular::DELETE_ROW: @@ -3865,6 +4520,68 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.clear(); return true; + case Tabular::SET_TABULAR_WIDTH: + status.setEnabled(!tabular.rotate && !tabular.is_long_tabular + && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE); + break; + + case Tabular::MOVE_COLUMN_RIGHT: + case Tabular::MOVE_COLUMN_LEFT: + case Tabular::MOVE_ROW_DOWN: + case Tabular::MOVE_ROW_UP: { + if (cur.selection()) { + status.message(_("Selections not supported.")); + status.setEnabled(false); + break; + } + + if ((action == Tabular::MOVE_COLUMN_RIGHT && + tabular.ncols() == tabular.cellColumn(cur.idx()) + 1) || + (action == Tabular::MOVE_COLUMN_LEFT && + tabular.cellColumn(cur.idx()) == 0) || + (action == Tabular::MOVE_ROW_DOWN && + tabular.nrows() == tabular.cellRow(cur.idx()) + 1) || + (action == Tabular::MOVE_ROW_UP && + tabular.cellRow(cur.idx()) == 0)) { + status.setEnabled(false); + break; + } + + if (action == Tabular::MOVE_COLUMN_RIGHT || + action == Tabular::MOVE_COLUMN_LEFT) { + if (tabular.hasMultiColumn(tabular.cellColumn(cur.idx())) || + tabular.hasMultiColumn(tabular.cellColumn(cur.idx()) + + (action == Tabular::MOVE_COLUMN_RIGHT ? 1 : -1))) { + status.message(_("Multi-column in current or" + " destination column.")); + status.setEnabled(false); + break; + } + } + + if (action == Tabular::MOVE_ROW_DOWN || + action == Tabular::MOVE_ROW_UP) { + if (tabular.hasMultiRow(tabular.cellRow(cur.idx())) || + tabular.hasMultiRow(tabular.cellRow(cur.idx()) + + (action == Tabular::MOVE_ROW_DOWN ? 1 : -1))) { + status.message(_("Multi-row in current or" + " destination row.")); + status.setEnabled(false); + break; + } + } + + status.setEnabled(true); + break; + } + + case Tabular::SET_DECIMAL_POINT: + status.setEnabled( + tabular.getAlignment(cur.idx()) == LYX_ALIGN_DECIMAL); + break; + + case Tabular::SET_MULTICOLUMN: + case Tabular::UNSET_MULTICOLUMN: case Tabular::MULTICOLUMN: // If a row is set as longtable caption, it must not be allowed // to unset that this row is a multicolumn. @@ -3873,12 +4590,29 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setOnOff(tabular.isMultiColumn(cur.idx())); break; + case Tabular::SET_MULTIROW: + case Tabular::UNSET_MULTIROW: + case Tabular::MULTIROW: + // If a row is set as longtable caption, it must not be allowed + // to unset that this row is a multirow. + status.setEnabled(sel_col_start == sel_col_end + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setOnOff(tabular.isMultiRow(cur.idx())); + break; + case Tabular::SET_ALL_LINES: case Tabular::UNSET_ALL_LINES: case Tabular::SET_BORDER_LINES: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); break; + case Tabular::SET_LINE_TOP: + case Tabular::SET_LINE_BOTTOM: + case Tabular::SET_LINE_LEFT: + case Tabular::SET_LINE_RIGHT: + status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + case Tabular::TOGGLE_LINE_TOP: status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.topLine(cur.idx())); @@ -3899,6 +4633,9 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setOnOff(tabular.rightLine(cur.idx())); break; + // multirow cells only inherit the alignment of the column if the column has + // no width, otherwise they are left-aligned + // therefore allow always left but right and center only if there is no width case Tabular::M_ALIGN_LEFT: flag = false; case Tabular::ALIGN_LEFT: @@ -3908,23 +4645,36 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_ALIGN_RIGHT: flag = false; case Tabular::ALIGN_RIGHT: + status.setEnabled(!(tabular.isMultiRow(cur.idx()) + && !tabular.getPWidth(cur.idx()).zero())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_RIGHT); break; case Tabular::M_ALIGN_CENTER: flag = false; case Tabular::ALIGN_CENTER: + status.setEnabled(!(tabular.isMultiRow(cur.idx()) + && !tabular.getPWidth(cur.idx()).zero())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_CENTER); break; case Tabular::ALIGN_BLOCK: - status.setEnabled(!tabular.getPWidth(cur.idx()).zero()); + status.setEnabled(!tabular.getPWidth(cur.idx()).zero() + && !tabular.isMultiRow(cur.idx())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_BLOCK); break; + case Tabular::ALIGN_DECIMAL: + status.setEnabled(!tabular.isMultiRow(cur.idx()) + && !tabular.isMultiColumn(cur.idx())); + status.setOnOff(tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_DECIMAL); + break; + case Tabular::M_VALIGN_TOP: flag = false; case Tabular::VALIGN_TOP: + status.setEnabled(!tabular.getPWidth(cur.idx()).zero() + && !tabular.isMultiRow(cur.idx())); status.setOnOff( tabular.getVAlignment(cur.idx(), flag) == Tabular::LYX_VALIGN_TOP); break; @@ -3932,6 +4682,8 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_BOTTOM: flag = false; case Tabular::VALIGN_BOTTOM: + status.setEnabled(!tabular.getPWidth(cur.idx()).zero() + && !tabular.isMultiRow(cur.idx())); status.setOnOff( tabular.getVAlignment(cur.idx(), flag) == Tabular::LYX_VALIGN_BOTTOM); break; @@ -3939,11 +4691,19 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_MIDDLE: flag = false; case Tabular::VALIGN_MIDDLE: + status.setEnabled(!tabular.getPWidth(cur.idx()).zero() + && !tabular.isMultiRow(cur.idx())); status.setOnOff( tabular.getVAlignment(cur.idx(), flag) == Tabular::LYX_VALIGN_MIDDLE); break; case Tabular::SET_LONGTABULAR: + // setting as longtable is not allowed when table is inside a float + if (cur.innerInsetOfType(FLOAT_CODE) != 0 + || cur.innerInsetOfType(WRAP_CODE) != 0) + status.setEnabled(false); + else + status.setEnabled(true); status.setOnOff(tabular.is_long_tabular); break; @@ -3953,18 +4713,21 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::TOGGLE_ROTATE_TABULAR: case Tabular::SET_ROTATE_TABULAR: - status.setOnOff(tabular.rotate); + status.setOnOff(tabular.rotate != 0); break; case Tabular::TABULAR_VALIGN_TOP: + status.setEnabled(tabular.tabular_width.zero()); status.setOnOff(tabular.tabular_valignment == Tabular::LYX_VALIGN_TOP); break; case Tabular::TABULAR_VALIGN_MIDDLE: + status.setEnabled(tabular.tabular_width.zero()); status.setOnOff(tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE); break; case Tabular::TABULAR_VALIGN_BOTTOM: + status.setEnabled(tabular.tabular_width.zero()); status.setOnOff(tabular.tabular_valignment == Tabular::LYX_VALIGN_BOTTOM); break; @@ -3983,7 +4746,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::UNSET_ROTATE_TABULAR: - status.setOnOff(!tabular.rotate); + status.setOnOff(tabular.rotate == 0); break; case Tabular::TOGGLE_ROTATE_CELL: @@ -4002,60 +4765,84 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; // every row can only be one thing: - // either a footer or header or caption + // either a footer or header case Tabular::SET_LTFIRSTHEAD: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTFIRSTHEAD: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)); break; case Tabular::SET_LTHEAD: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTHEAD: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt)); break; case Tabular::SET_LTFOOT: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTFOOT: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt)); break; case Tabular::SET_LTLASTFOOT: - status.setEnabled(sel_row_start == sel_row_end - && !tabular.ltCaption(sel_row_start)); + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)); break; case Tabular::UNSET_LTLASTFOOT: + status.setEnabled(sel_row_start == sel_row_end); status.setOnOff(!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)); break; case Tabular::SET_LTNEWPAGE: status.setOnOff(tabular.getLTNewPage(sel_row_start)); break; + case Tabular::UNSET_LTNEWPAGE: + status.setOnOff(!tabular.getLTNewPage(sel_row_start)); + break; - // only one row can be the caption - case Tabular::TOGGLE_LTCAPTION: + // only one row in head/firsthead/foot/lasthead can be the caption + // and a multirow cannot be set as caption + case Tabular::SET_LTCAPTION: status.setEnabled(sel_row_start == sel_row_end - && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) - && !tabular.getRowOfLTHead(sel_row_start, dummyltt) - && !tabular.getRowOfLTFoot(sel_row_start, dummyltt) - && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt) - && (!tabular.haveLTCaption() - || tabular.ltCaption(sel_row_start))); + && (!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FIRSTHEAD)) + && (!tabular.getRowOfLTHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_HEAD)) + && (!tabular.getRowOfLTFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FOOT)) + && (!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_LASTFOOT)) + && !tabular.isMultiRow(sel_row_start)); + status.setOnOff(tabular.ltCaption(sel_row_start)); + break; + + case Tabular::UNSET_LTCAPTION: + status.setEnabled(sel_row_start == sel_row_end && tabular.ltCaption(sel_row_start)); + break; + + case Tabular::TOGGLE_LTCAPTION: + status.setEnabled(sel_row_start == sel_row_end && (tabular.ltCaption(sel_row_start) + || ((!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FIRSTHEAD)) + && (!tabular.getRowOfLTHead(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_HEAD)) + && (!tabular.getRowOfLTFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_FOOT)) + && (!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt) + || !tabular.haveLTCaption(Tabular::CAPTION_LASTFOOT))))); status.setOnOff(tabular.ltCaption(sel_row_start)); break; @@ -4075,6 +4862,37 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return true; } + case LFUN_CAPTION_INSERT: { + // caption is only allowed in caption cell of longtable + if (!tabular.ltCaption(tabular.cellRow(cur.idx()))) { + status.setEnabled(false); + return true; + } + // only standard caption is allowed + string arg = cmd.getArg(0); + if (!arg.empty() && arg != "Standard") { + status.setEnabled(false); + return true; + } + // check if there is already a caption + bool have_caption = false; + InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get()); + ParagraphList::const_iterator pit = itc.paragraphs().begin(); + ParagraphList::const_iterator pend = itc.paragraphs().end(); + for (; pit != pend; ++pit) { + InsetList::const_iterator it = pit->insetList().begin(); + InsetList::const_iterator end = pit->insetList().end(); + for (; it != end; ++it) { + if (it->inset->lyxCode() == CAPTION_CODE) { + have_caption = true; + break; + } + } + } + status.setEnabled(!have_caption); + return true; + } + // These are only enabled inside tabular case LFUN_CELL_BACKWARD: case LFUN_CELL_FORWARD: @@ -4094,11 +4912,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case LFUN_MATH_MUTATE: case LFUN_MATH_DISPLAY: case LFUN_NOTE_INSERT: - case LFUN_OPTIONAL_INSERT: + case LFUN_ARGUMENT_INSERT: case LFUN_BOX_INSERT: case LFUN_BRANCH_INSERT: case LFUN_PHANTOM_INSERT: case LFUN_WRAP_INSERT: + case LFUN_PREVIEW_INSERT: case LFUN_ERT_INSERT: { if (cur.selIsMultiCell()) { status.setEnabled(false); @@ -4108,8 +4927,13 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } // disable in non-fixed-width cells - case LFUN_NEWLINE_INSERT: - case LFUN_BREAK_PARAGRAPH: { + case LFUN_PARAGRAPH_BREAK: + // multirow does not allow paragraph breaks + if (tabular.isMultiRow(cur.idx())) { + status.setEnabled(false); + return true; + } + case LFUN_NEWLINE_INSERT: { if (tabular.getPWidth(cur.idx()).zero()) { status.setEnabled(false); return true; @@ -4127,8 +4951,8 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, row_type rs, re; col_type cs, ce; getSelection(cur, rs, re, cs, ce); - if (paste_tabular && paste_tabular->column_info.size() == ce - cs + 1 - && paste_tabular->row_info.size() == re - rs + 1) + if (paste_tabular && paste_tabular->ncols() == ce - cs + 1 + && paste_tabular->nrows() == re - rs + 1) status.setEnabled(true); else { status.setEnabled(false); @@ -4144,17 +4968,11 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, // relay this lfun to Inset, not to the cell. return Inset::getStatus(cur, cmd, status); - case LFUN_INSET_MODIFY: - if (insetCode(cmd.getArg(0)) == TABULAR_CODE) { - status.setEnabled(true); - return true; - } - // Fall through - default: // we try to handle this event in the insets dispatch function. return cell(cur.idx())->getStatus(cur, cmd, status); } + return false; } @@ -4176,17 +4994,18 @@ Inset::DisplayType InsetTabular::display() const } -int InsetTabular::latex(odocstream & os, OutputParams const & runparams) const +void InsetTabular::latex(otexstream & os, OutputParams const & runparams) const { - return tabular.latex(os, runparams); + tabular.latex(os, runparams); } -int InsetTabular::plaintext(odocstream & os, OutputParams const & runparams) const +int InsetTabular::plaintext(odocstringstream & os, + OutputParams const & runparams, size_t max_length) const { os << '\n'; // output table on a new line int const dp = runparams.linelen > 0 ? runparams.depth : 0; - tabular.plaintext(os, runparams, dp, false, 0); + tabular.plaintext(os, runparams, dp, false, 0, max_length); return PLAINTEXT_NEWLINE; } @@ -4218,9 +5037,22 @@ int InsetTabular::docbook(odocstream & os, OutputParams const & runparams) const } +docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const +{ + return tabular.xhtml(xs, rp); +} + + void InsetTabular::validate(LaTeXFeatures & features) const { tabular.validate(features); + // FIXME XHTML + // It'd be better to be able to get this from an InsetLayout, but at present + // InsetLayouts do not seem really to work for things that aren't InsetTexts. + if (features.runparams().flavor == OutputParams::HTML) + features.addCSSSnippet( + "table { border: 1px solid black; display: inline-block; }\n" + "td { border: 1px solid black; padding: 0.5ex; }"); } @@ -4242,26 +5074,13 @@ void InsetTabular::cursorPos(BufferView const & bv, cell(sl.idx())->cursorPos(bv, sl, boundary, x, y); // y offset correction - int const row = tabular.cellRow(sl.idx()); - for (int i = 0; i <= row; ++i) { - if (i != 0) { - y += tabular.rowAscent(i); - y += tabular.getAdditionalHeight(i); - } - if (i != row) - y += tabular.rowDescent(i); - } + y += cellYPos(sl.idx()); + y += tabular.textVOffset(sl.idx()); + y += offset_valign_; // x offset correction - int const col = tabular.cellColumn(sl.idx()); - int idx = tabular.cellIndex(row, 0); - for (int j = 0; j < col; ++j) { - if (tabular.isPartOfMultiColumn(row, j)) - continue; - x += tabular.columnWidth(idx); - ++idx; - } - x += tabular.getBeginningOfTextInCell(idx); + x += cellXPos(sl.idx()); + x += tabular.textHOffset(sl.idx()); x += ADD_TO_TABULAR_WIDTH; x += scx_; } @@ -4273,12 +5092,12 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const int yy = 0; Inset const & inset = *tabular.cellInset(cell); Point o = bv.coordCache().getInsets().xy(&inset); - int const xbeg = o.x_ - tabular.getBeginningOfTextInCell(cell); - int const xend = xbeg + tabular.columnWidth(cell); + int const xbeg = o.x_ - tabular.textHOffset(cell); + int const xend = xbeg + tabular.cellWidth(cell); row_type const row = tabular.cellRow(cell); - int const ybeg = o.y_ - tabular.rowAscent(row) - - tabular.getAdditionalHeight(row); - int const yend = o.y_ + tabular.rowDescent(row); + int const ybeg = o.y_ - tabular.rowAscent(row) + - tabular.interRowSpace(row) - tabular.textVOffset(cell); + int const yend = ybeg + tabular.cellHeight(cell); if (x < xbeg) xx = xbeg - x; @@ -4333,16 +5152,23 @@ InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int } -int InsetTabular::cellXPos(idx_type const cell) const +int InsetTabular::cellYPos(idx_type const cell) const { - idx_type c = cell; + row_type row = tabular.cellRow(cell); + int ly = 0; + for (row_type r = 0; r < row; ++r) + ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + + tabular.interRowSpace(r + 1); + return ly; +} - for (; !tabular.isFirstCellInRow(c); --c) - ; - int lx = 0; - for (; c < cell; ++c) - lx += tabular.columnWidth(c); +int InsetTabular::cellXPos(idx_type const cell) const +{ + col_type col = tabular.cellColumn(cell); + int lx = 0; + for (col_type c = 0; c < col; ++c) + lx += tabular.column_info[c].width; return lx; } @@ -4361,7 +5187,7 @@ void InsetTabular::resetPos(Cursor & cur) const int const X2 = maxwidth; int const offset = ADD_TO_TABULAR_WIDTH + 2; int const x1 = xo(cur.bv()) + cellXPos(cur[i].idx()) + offset; - int const x2 = x1 + tabular.columnWidth(cur[i].idx()); + int const x2 = x1 + tabular.cellWidth(cur[i].idx()); if (x1 < X1) scx_ = X1 + 20 - x1; @@ -4373,27 +5199,37 @@ void InsetTabular::resetPos(Cursor & cur) const // only update if offset changed if (scx_ != scx_old) - cur.updateFlags(Update::Force | Update::FitCursor); + cur.screenUpdateFlags(Update::Force | Update::FitCursor); } void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) { + row_type const row = tabular.cellRow(cur.idx()); + col_type const col = tabular.cellColumn(cur.idx()); + if (isRightToLeft(cur)) { - if (tabular.isFirstCellInRow(cur.idx())) { - row_type const row = tabular.cellRow(cur.idx()); - if (row == tabular.row_info.size() - 1) + if (tabular.cellColumn(cur.idx()) == 0) { + if (row == tabular.nrows() - 1) return; cur.idx() = tabular.cellBelow(tabular.getLastCellInRow(row)); } else { if (cur.idx() == 0) return; - --cur.idx(); + if (col == 0) + cur.idx() = tabular.getLastCellInRow(row - 1); + else + cur.idx() = tabular.cellIndex(row, col - 1); } } else { if (tabular.isLastCell(cur.idx())) return; - ++cur.idx(); + if (cur.idx() == tabular.getLastCellInRow(row)) + cur.idx() = tabular.cellIndex(row + 1, 0); + else { + col_type const colnextcell = col + tabular.columnSpan(cur.idx()); + cur.idx() = tabular.cellIndex(row, colnextcell); + } } cur.boundary(false); @@ -4423,16 +5259,18 @@ void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) break; } - + cur.setCurrentFont(); resetPos(cur); } void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) { + row_type const row = tabular.cellRow(cur.idx()); + col_type const col = tabular.cellColumn(cur.idx()); + if (isRightToLeft(cur)) { - if (tabular.isLastCellInRow(cur.idx())) { - row_type const row = tabular.cellRow(cur.idx()); + if (cur.idx() == tabular.getLastCellInRow(row)) { if (row == 0) return; cur.idx() = tabular.getFirstCellInRow(row); @@ -4440,12 +5278,18 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) } else { if (tabular.isLastCell(cur.idx())) return; - ++cur.idx(); + if (cur.idx() == tabular.getLastCellInRow(row)) + cur.idx() = tabular.cellIndex(row + 1, 0); + else + cur.idx() = tabular.cellIndex(row, col + 1); } } else { if (cur.idx() == 0) // first cell return; - --cur.idx(); + if (col == 0) + cur.idx() = tabular.getLastCellInRow(row - 1); + else + cur.idx() = tabular.cellIndex(row, col - 1); } if (cur.selIsMultiCell()) { @@ -4473,32 +5317,49 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) break; } - + cur.setCurrentFont(); resetPos(cur); } -bool InsetTabular::tabularFeatures(Cursor & cur, string const & what) +bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) { - Tabular::Feature action = Tabular::LAST_ACTION; + istringstream is(argument); + string s; + is >> s; + if (insetCode(s) != TABULAR_CODE) + return false; - int i = 0; - for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) { - string const tmp = tabularFeature[i].feature; + // Safe guard. + size_t safe_guard = 0; + for (;;) { + if (is.eof()) + break; + safe_guard++; + if (safe_guard > 1000) { + LYXERR0("parameter max count reached!"); + break; + } + is >> s; + Tabular::Feature action = Tabular::LAST_ACTION; - if (tmp == what.substr(0, tmp.length())) { - //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(), - //tabularFeatures[i].feature.length())) + size_t i = 0; + for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) { + if (s != tabularFeature[i].feature) + continue; action = tabularFeature[i].action; break; } + if (action == Tabular::LAST_ACTION) { + LYXERR0("Feature not found " << s); + continue; + } + string val; + if (tabularFeature[i].need_value) + is >> val; + LYXERR(Debug::DEBUG, "Feature: " << s << "\t\tvalue: " << val); + tabularFeatures(cur, action, val); } - if (action == Tabular::LAST_ACTION) - return false; - - string const val = - ltrim(what.substr(tabularFeature[i].feature.length())); - tabularFeatures(cur, action, val); return true; } @@ -4521,21 +5382,24 @@ static void checkLongtableSpecial(Tabular::ltType & ltt, } } + bool InsetTabular::oneCellHasRotationState(bool rotated, row_type row_start, row_type row_end, - col_type col_start, col_type col_end) const { - - for (row_type i = row_start; i <= row_end; ++i) { - for (col_type j = col_start; j <= col_end; ++j) { - if (tabular.getRotateCell(tabular.cellIndex(i, j)) - == rotated) { - return true; + col_type col_start, col_type col_end) const +{ + for (row_type r = row_start; r <= row_end; ++r) + for (col_type c = col_start; c <= col_end; ++c) + if (rotated) { + if (tabular.getRotateCell(tabular.cellIndex(r, c)) != 0) + return true; + } else { + if (tabular.getRotateCell(tabular.cellIndex(r, c)) == 0) + return true; } - } - } return false; } + void InsetTabular::tabularFeatures(Cursor & cur, Tabular::Feature feature, string const & value) { @@ -4568,6 +5432,13 @@ void InsetTabular::tabularFeatures(Cursor & cur, setAlign = LYX_ALIGN_BLOCK; break; + case Tabular::ALIGN_DECIMAL: + if (tabular.column_info[tabular.cellColumn(cur.idx())].alignment == LYX_ALIGN_DECIMAL) + setAlign = LYX_ALIGN_CENTER; + else + setAlign = LYX_ALIGN_DECIMAL; + break; + case Tabular::M_VALIGN_TOP: case Tabular::VALIGN_TOP: setVAlign = Tabular::LYX_VALIGN_TOP; @@ -4587,7 +5458,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } - cur.recordUndoInset(ATOMIC_UNDO); + cur.recordUndoInset(ATOMIC_UNDO, this); getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end); row_type const row = tabular.cellRow(cur.idx()); @@ -4597,6 +5468,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, switch (feature) { + case Tabular::SET_TABULAR_WIDTH: + tabular.setTabularWidth(Length(value)); + break; + case Tabular::SET_PWIDTH: { Length const len(value); tabular.setColumnPWidth(cur, cur.idx(), len); @@ -4610,26 +5485,39 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.setMColumnPWidth(cur, cur.idx(), Length(value)); break; + case Tabular::SET_MROFFSET: + tabular.setMROffset(cur, cur.idx(), Length(value)); + break; + case Tabular::SET_SPECIAL_COLUMN: - case Tabular::SET_SPECIAL_MULTI: - tabular.setAlignSpecial(cur.idx(), from_utf8(value), feature); + case Tabular::SET_SPECIAL_MULTICOLUMN: + if (value == "none") + tabular.setAlignSpecial(cur.idx(), docstring(), feature); + else + tabular.setAlignSpecial(cur.idx(), from_utf8(value), feature); break; case Tabular::APPEND_ROW: // append the row into the tabular - tabular.appendRow(cur.idx()); + tabular.appendRow(row); break; case Tabular::APPEND_COLUMN: // append the column into the tabular - tabular.appendColumn(cur.idx()); + tabular.appendColumn(column); cur.idx() = tabular.cellIndex(row, column); break; case Tabular::DELETE_ROW: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) + if (sel_row_end == tabular.nrows() - 1 && sel_row_start != 0) { + for (col_type c = 0; c < tabular.ncols(); c++) + tabular.setBottomLine(tabular.cellIndex(sel_row_start - 1, c), + tabular.bottomLine(tabular.cellIndex(sel_row_end, c))); + } + + for (row_type r = sel_row_start; r <= sel_row_end; ++r) tabular.deleteRow(sel_row_start); - if (sel_row_start >= tabular.row_info.size()) + if (sel_row_start >= tabular.nrows()) --sel_row_start; cur.idx() = tabular.cellIndex(sel_row_start, column); cur.pit() = 0; @@ -4638,9 +5526,21 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::DELETE_COLUMN: - for (col_type i = sel_col_start; i <= sel_col_end; ++i) + if (sel_col_end == tabular.ncols() - 1 && sel_col_start != 0) { + for (row_type r = 0; r < tabular.nrows(); r++) + tabular.setRightLine(tabular.cellIndex(r, sel_col_start - 1), + tabular.rightLine(tabular.cellIndex(r, sel_col_end))); + } + + if (sel_col_start == 0 && sel_col_end != tabular.ncols() - 1) { + for (row_type r = 0; r < tabular.nrows(); r++) + tabular.setLeftLine(tabular.cellIndex(r, sel_col_end + 1), + tabular.leftLine(tabular.cellIndex(r, 0))); + } + + for (col_type c = sel_col_start; c <= sel_col_end; ++c) tabular.deleteColumn(sel_col_start); - if (sel_col_start >= tabular.column_info.size()) + if (sel_col_start >= tabular.ncols()) --sel_col_start; cur.idx() = tabular.cellIndex(row, sel_col_start); cur.pit() = 0; @@ -4657,49 +5557,78 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(row, column); break; + case Tabular::MOVE_COLUMN_RIGHT: + tabular.moveColumn(column, Tabular::RIGHT); + cur.idx() = tabular.cellIndex(row, column + 1); + break; + + case Tabular::MOVE_COLUMN_LEFT: + tabular.moveColumn(column, Tabular::LEFT); + cur.idx() = tabular.cellIndex(row, column - 1); + break; + + case Tabular::MOVE_ROW_DOWN: + tabular.moveRow(row, Tabular::DOWN); + cur.idx() = tabular.cellIndex(row + 1, column); + break; + + case Tabular::MOVE_ROW_UP: + tabular.moveRow(row, Tabular::UP); + cur.idx() = tabular.cellIndex(row - 1, column); + break; + + case Tabular::SET_LINE_TOP: case Tabular::TOGGLE_LINE_TOP: { - bool lineSet = !tabular.topLine(cur.idx()); - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setTopLine(tabular.cellIndex(i, j), lineSet); + bool lineSet = (feature == Tabular::SET_LINE_TOP) + ? (value == "true") : !tabular.topLine(cur.idx()); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setTopLine(tabular.cellIndex(r, c), lineSet); break; } + case Tabular::SET_LINE_BOTTOM: case Tabular::TOGGLE_LINE_BOTTOM: { - bool lineSet = !tabular.bottomLine(cur.idx()); - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setBottomLine(tabular.cellIndex(i, j), lineSet); + bool lineSet = (feature == Tabular::SET_LINE_BOTTOM) + ? (value == "true") : !tabular.bottomLine(cur.idx()); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setBottomLine(tabular.cellIndex(r, c), lineSet); break; } + case Tabular::SET_LINE_LEFT: case Tabular::TOGGLE_LINE_LEFT: { - bool lineSet = !tabular.leftLine(cur.idx()); - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setLeftLine(tabular.cellIndex(i, j), lineSet); + bool lineSet = (feature == Tabular::SET_LINE_LEFT) + ? (value == "true") : !tabular.leftLine(cur.idx()); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setLeftLine(tabular.cellIndex(r, c), lineSet); break; } + case Tabular::SET_LINE_RIGHT: case Tabular::TOGGLE_LINE_RIGHT: { - bool lineSet = !tabular.rightLine(cur.idx()); - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setRightLine(tabular.cellIndex(i, j), lineSet); + bool lineSet = (feature == Tabular::SET_LINE_RIGHT) + ? (value == "true") : !tabular.rightLine(cur.idx()); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setRightLine(tabular.cellIndex(r, c), lineSet); break; } case Tabular::M_ALIGN_LEFT: case Tabular::M_ALIGN_RIGHT: case Tabular::M_ALIGN_CENTER: - flag = false; case Tabular::ALIGN_LEFT: case Tabular::ALIGN_RIGHT: case Tabular::ALIGN_CENTER: case Tabular::ALIGN_BLOCK: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setAlignment(tabular.cellIndex(i, j), setAlign, flag); + case Tabular::ALIGN_DECIMAL: + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setAlignment(tabular.cellIndex(r, c), setAlign, + !tabular.getPWidth(c).zero()); break; case Tabular::M_VALIGN_TOP: @@ -4709,50 +5638,142 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::VALIGN_TOP: case Tabular::VALIGN_BOTTOM: case Tabular::VALIGN_MIDDLE: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setVAlignment(tabular.cellIndex(i, j), setVAlign, flag); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setVAlignment(tabular.cellIndex(r, c), setVAlign, flag); break; - case Tabular::MULTICOLUMN: { + case Tabular::SET_MULTICOLUMN: { if (!cur.selection()) { // just multicol for one single cell // check whether we are completely in a multicol + if (!tabular.isMultiColumn(cur.idx())) + tabular.setMultiColumn(cur.idx(), 1, + tabular.rightLine(cur.idx())); + break; + } + // we have a selection so this means we just add all these + // cells to form a multicolumn cell + idx_type const s_start = cur.selBegin().idx(); + row_type const col_start = tabular.cellColumn(s_start); + row_type const col_end = tabular.cellColumn(cur.selEnd().idx()); + cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1, + tabular.rightLine(cur.selEnd().idx())); + cur.pit() = 0; + cur.pos() = 0; + cur.setSelection(false); + break; + } + + case Tabular::UNSET_MULTICOLUMN: { + if (!cur.selection()) { if (tabular.isMultiColumn(cur.idx())) tabular.unsetMultiColumn(cur.idx()); + } + break; + } + + case Tabular::MULTICOLUMN: { + if (!cur.selection()) { + if (tabular.isMultiColumn(cur.idx())) + tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN); else - tabular.setMultiColumn(cur.idx(), 1); + tabularFeatures(cur, Tabular::SET_MULTICOLUMN); + break; + } + bool merge = false; + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + row_type const r = sel_row_start; + if (!tabular.isMultiColumn(tabular.cellIndex(r, c)) + || (r > sel_row_start && !tabular.isPartOfMultiColumn(r, c))) + merge = true; + } + // If the selection contains at least one singlecol cell + // or multiple multicol cells, + // we assume the user will merge is to a single multicol + if (merge) + tabularFeatures(cur, Tabular::SET_MULTICOLUMN); + else + tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN); + break; + } + + case Tabular::SET_MULTIROW: { + if (!cur.selection()) { + // just multirow for one single cell + // check whether we are completely in a multirow + if (!tabular.isMultiRow(cur.idx())) + tabular.setMultiRow(cur.idx(), 1, + tabular.bottomLine(cur.idx())); break; } // we have a selection so this means we just add all this - // cells to form a multicolumn cell + // cells to form a multirow cell idx_type const s_start = cur.selBegin().idx(); - idx_type const s_end = cur.selEnd().idx(); - tabular.setMultiColumn(s_start, s_end - s_start + 1); - cur.idx() = s_start; + row_type const row_start = tabular.cellRow(s_start); + row_type const row_end = tabular.cellRow(cur.selEnd().idx()); + cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1, + tabular.bottomLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; cur.setSelection(false); break; } + case Tabular::UNSET_MULTIROW: { + if (!cur.selection()) { + if (tabular.isMultiRow(cur.idx())) + tabular.unsetMultiRow(cur.idx()); + } + break; + } + + case Tabular::MULTIROW: { + if (!cur.selection()) { + if (tabular.isMultiRow(cur.idx())) + tabularFeatures(cur, Tabular::UNSET_MULTIROW); + else + tabularFeatures(cur, Tabular::SET_MULTIROW); + break; + } + bool merge = false; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + col_type const c = sel_col_start; + if (!tabular.isMultiRow(tabular.cellIndex(r, c)) + || (r > sel_row_start && !tabular.isPartOfMultiRow(r, c))) + merge = true; + } + // If the selection contains at least one singlerow cell + // or multiple multirow cells, + // we assume the user will merge is to a single multirow + if (merge) + tabularFeatures(cur, Tabular::SET_MULTIROW); + else + tabularFeatures(cur, Tabular::UNSET_MULTIROW); + break; + } + case Tabular::SET_ALL_LINES: setLines = true; case Tabular::UNSET_ALL_LINES: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setAllLines( - tabular.cellIndex(i,j), setLines); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + idx_type const cell = tabular.cellIndex(r, c); + tabular.setTopLine(cell, setLines); + tabular.setBottomLine(cell, setLines); + tabular.setRightLine(cell, setLines); + tabular.setLeftLine(cell, setLines); + } break; case Tabular::SET_BORDER_LINES: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.setLeftLine(tabular.cellIndex(i, sel_col_start), true); - tabular.setRightLine(tabular.cellIndex(i, sel_col_end), true); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.setLeftLine(tabular.cellIndex(r, sel_col_start), true); + tabular.setRightLine(tabular.cellIndex(r, sel_col_end), true); } - for (col_type j = sel_col_start; j <= sel_col_end; ++j) { - tabular.setTopLine(tabular.cellIndex(sel_row_start, j), true); - tabular.setBottomLine(tabular.cellIndex(sel_row_end, j), true); + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + tabular.setTopLine(tabular.cellIndex(sel_row_start, c), true); + tabular.setBottomLine(tabular.cellIndex(sel_row_end, c), true); } break; @@ -4761,9 +5782,9 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::UNSET_LONGTABULAR: - for (row_type i = 0; i < tabular.row_info.size(); ++i) { - if (tabular.ltCaption(i)) { - cur.idx() = tabular.cellIndex(i, 0); + for (row_type r = 0; r < tabular.nrows(); ++r) { + if (tabular.ltCaption(r)) { + cur.idx() = tabular.cellIndex(r, 0); cur.pit() = 0; cur.pos() = 0; tabularFeatures(cur, Tabular::TOGGLE_LTCAPTION); @@ -4773,15 +5794,16 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::SET_ROTATE_TABULAR: - tabular.rotate = true; + tabular.rotate = convert(value); break; case Tabular::UNSET_ROTATE_TABULAR: - tabular.rotate = false; + tabular.rotate = 0; break; case Tabular::TOGGLE_ROTATE_TABULAR: - tabular.rotate = !tabular.rotate; + // when pressing the rotate button we default to 90° rotation + tabular.rotate != 0 ? tabular.rotate = 0 : tabular.rotate = 90; break; case Tabular::TABULAR_VALIGN_TOP: @@ -4811,16 +5833,15 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_ROTATE_CELL: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setRotateCell( - tabular.cellIndex(i, j), true); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setRotateCell(tabular.cellIndex(r, c), convert(value)); break; case Tabular::UNSET_ROTATE_CELL: - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setRotateCell(tabular.cellIndex(i, j), false); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setRotateCell(tabular.cellIndex(r, c), 0); break; case Tabular::TOGGLE_ROTATE_CELL: @@ -4828,10 +5849,14 @@ void InsetTabular::tabularFeatures(Cursor & cur, bool oneNotRotated = oneCellHasRotationState(false, sel_row_start, sel_row_end, sel_col_start, sel_col_end); - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setRotateCell(tabular.cellIndex(i, j), - oneNotRotated); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) { + // when pressing the rotate cell button we default to 90° rotation + if (oneNotRotated) + tabular.setRotateCell(tabular.cellIndex(r, c), 90); + else + tabular.setRotateCell(tabular.cellIndex(r, c), 0); + } } break; @@ -4839,9 +5864,9 @@ void InsetTabular::tabularFeatures(Cursor & cur, Tabular::BoxType val = Tabular::BoxType(convert(value)); if (val == tabular.getUsebox(cur.idx())) val = Tabular::BOX_NONE; - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - for (col_type j = sel_col_start; j <= sel_col_end; ++j) - tabular.setUsebox(tabular.cellIndex(i, j), val); + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.setUsebox(tabular.cellIndex(r, c), val); break; } @@ -4877,27 +5902,44 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.setLTFoot(row, flag, ltt, true); break; + case Tabular::UNSET_LTNEWPAGE: + flag = false; case Tabular::SET_LTNEWPAGE: - tabular.setLTNewPage(row, !tabular.getLTNewPage(row)); + tabular.setLTNewPage(row, flag); break; - case Tabular::TOGGLE_LTCAPTION: { - bool const set = !tabular.ltCaption(row); - cur.idx() = tabular.setLTCaption(row, set); + case Tabular::SET_LTCAPTION: { + if (tabular.ltCaption(row)) + break; + cur.idx() = tabular.setLTCaption(row, true); + cur.pit() = 0; + cur.pos() = 0; + cur.setSelection(false); + // If a row is set as caption, then also insert + // a caption. Otherwise the LaTeX output is broken. + lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL)); + lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT)); + break; + } + + case Tabular::UNSET_LTCAPTION: { + if (!tabular.ltCaption(row)) + break; + cur.idx() = tabular.setLTCaption(row, false); cur.pit() = 0; cur.pos() = 0; cur.setSelection(false); + FuncRequest fr(LFUN_INSET_DISSOLVE, "caption"); + if (lyx::getStatus(fr).enabled()) + lyx::dispatch(fr); + break; + } - if (set) { - // When a row is set as caption, then also insert - // a caption. Otherwise the LaTeX output is broken. - lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL)); - lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT)); - } else { - FuncRequest fr(LFUN_INSET_DISSOLVE, "caption"); - if (lyx::getStatus(fr).enabled()) - lyx::dispatch(fr); - } + case Tabular::TOGGLE_LTCAPTION: { + if (tabular.ltCaption(row)) + tabularFeatures(cur, Tabular::UNSET_LTCAPTION); + else + tabularFeatures(cur, Tabular::SET_LTCAPTION); break; } @@ -4912,17 +5954,17 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_TOP_SPACE: { Length len; if (value == "default") - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - tabular.row_info[i].top_space_default = true; - else if (isValidLength(value, &len)) - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.row_info[i].top_space_default = false; - tabular.row_info[i].top_space = len; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + tabular.row_info[r].top_space_default = true; + else if (value == "none") + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.row_info[r].top_space_default = false; + tabular.row_info[r].top_space = len; } - else - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.row_info[i].top_space_default = false; - tabular.row_info[i].top_space = len; + else if (isValidLength(value, &len)) + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.row_info[r].top_space_default = false; + tabular.row_info[r].top_space = len; } break; } @@ -4930,17 +5972,17 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_BOTTOM_SPACE: { Length len; if (value == "default") - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - tabular.row_info[i].bottom_space_default = true; - else if (isValidLength(value, &len)) - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.row_info[i].bottom_space_default = false; - tabular.row_info[i].bottom_space = len; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + tabular.row_info[r].bottom_space_default = true; + else if (value == "none") + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.row_info[r].bottom_space_default = false; + tabular.row_info[r].bottom_space = len; } - else - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.row_info[i].bottom_space_default = false; - tabular.row_info[i].bottom_space = len; + else if (isValidLength(value, &len)) + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.row_info[r].bottom_space_default = false; + tabular.row_info[r].bottom_space = len; } break; } @@ -4948,21 +5990,26 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_INTERLINE_SPACE: { Length len; if (value == "default") - for (row_type i = sel_row_start; i <= sel_row_end; ++i) - tabular.row_info[i].interline_space_default = true; - else if (isValidLength(value, &len)) - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.row_info[i].interline_space_default = false; - tabular.row_info[i].interline_space = len; + for (row_type r = sel_row_start; r <= sel_row_end; ++r) + tabular.row_info[r].interline_space_default = true; + else if (value == "none") + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.row_info[r].interline_space_default = false; + tabular.row_info[r].interline_space = len; } - else - for (row_type i = sel_row_start; i <= sel_row_end; ++i) { - tabular.row_info[i].interline_space_default = false; - tabular.row_info[i].interline_space = len; + else if (isValidLength(value, &len)) + for (row_type r = sel_row_start; r <= sel_row_end; ++r) { + tabular.row_info[r].interline_space_default = false; + tabular.row_info[r].interline_space = len; } break; } + case Tabular::SET_DECIMAL_POINT: + for (col_type c = sel_col_start; c <= sel_col_end; ++c) + tabular.column_info[c].decimal_point = from_utf8(value); + break; + // dummy stuff just to avoid warnings case Tabular::LAST_ACTION: break; @@ -4970,21 +6017,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, } -bool InsetTabular::showInsetDialog(BufferView * bv) const -{ - bv->showDialog("tabular", params2string(*this), - const_cast(this)); - return true; -} - - -void InsetTabular::openLayoutDialog(BufferView * bv) const -{ - bv->showDialog("tabular", params2string(*this), - const_cast(this)); -} - - bool InsetTabular::copySelection(Cursor & cur) { if (!cur.selection()) @@ -4996,25 +6028,25 @@ bool InsetTabular::copySelection(Cursor & cur) paste_tabular.reset(new Tabular(tabular)); - for (row_type i = 0; i < rs; ++i) + for (row_type r = 0; r < rs; ++r) paste_tabular->deleteRow(0); row_type const rows = re - rs + 1; - while (paste_tabular->row_info.size() > rows) + while (paste_tabular->nrows() > rows) paste_tabular->deleteRow(rows); - for (col_type i = 0; i < cs; ++i) + for (col_type c = 0; c < cs; ++c) paste_tabular->deleteColumn(0); col_type const columns = ce - cs + 1; - while (paste_tabular->column_info.size() > columns) + while (paste_tabular->ncols() > columns) paste_tabular->deleteColumn(columns); paste_tabular->setBuffer(tabular.buffer()); odocstringstream os; OutputParams const runparams(0); - paste_tabular->plaintext(os, runparams, 0, true, '\t'); + paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX); // Needed for the "Edit->Paste recent" menu and the system clipboard. cap::copySelection(cur, os.str()); @@ -5042,10 +6074,10 @@ bool InsetTabular::pasteClipboard(Cursor & cur) } for (row_type r1 = 0, r2 = actrow; - r1 < paste_tabular->row_info.size() && r2 < tabular.row_info.size(); + r1 < paste_tabular->nrows() && r2 < tabular.nrows(); ++r1, ++r2) { for (col_type c1 = 0, c2 = actcol; - c1 < paste_tabular->column_info.size() && c2 < tabular.column_info.size(); + c1 < paste_tabular->ncols() && c2 < tabular.ncols(); ++c1, ++c2) { if (paste_tabular->isPartOfMultiColumn(r1, c1) && tabular.isPartOfMultiColumn(r2, c2)) @@ -5061,6 +6093,9 @@ bool InsetTabular::pasteClipboard(Cursor & cur) shared_ptr inset( new InsetTableCell(*paste_tabular->cellInset(r1, c1))); tabular.setCellInset(r2, c2, inset); + // FIXME?: why do we need to do this explicitly? (EL) + tabular.cellInset(r2, c2)->setBuffer(tabular.buffer()); + // FIXME: change tracking (MG) inset->setChange(Change(buffer().params().trackChanges ? Change::INSERTED : Change::UNCHANGED)); @@ -5079,10 +6114,10 @@ void InsetTabular::cutSelection(Cursor & cur) row_type rs, re; col_type cs, ce; getSelection(cur, rs, re, cs, ce); - for (row_type i = rs; i <= re; ++i) { - for (col_type j = cs; j <= ce; ++j) { + for (row_type r = rs; r <= re; ++r) { + for (col_type c = cs; c <= ce; ++c) { shared_ptr t - = cell(tabular.cellIndex(i, j)); + = cell(tabular.cellIndex(r, c)); if (buffer().params().trackChanges) // FIXME: Change tracking (MG) t->setChange(Change(Change::DELETED)); @@ -5102,13 +6137,15 @@ void InsetTabular::cutSelection(Cursor & cur) bool InsetTabular::isRightToLeft(Cursor & cur) const { - LASSERT(cur.depth() > 1, /**/); + // LASSERT: It might be better to abandon this Buffer. + LASSERT(cur.depth() > 1, return false); Paragraph const & parentpar = cur[cur.depth() - 2].paragraph(); pos_type const parentpos = cur[cur.depth() - 2].pos(); return parentpar.getFontSettings(buffer().params(), parentpos).language()->rightToLeft(); } + docstring InsetTabular::asString(idx_type stidx, idx_type enidx, bool intoInsets) { @@ -5138,12 +6175,8 @@ void InsetTabular::getSelection(Cursor & cur, CursorSlice const & end = cur.selEnd(); cs = tabular.cellColumn(beg.idx()); ce = tabular.cellColumn(end.idx()); - if (cs > ce) { - ce = cs; - cs = tabular.cellColumn(end.idx()); - } else { - ce = tabular.cellRightColumn(end.idx()); - } + if (cs > ce) + swap(cs, ce); rs = tabular.cellRow(beg.idx()); re = tabular.cellRow(end.idx()); @@ -5239,8 +6272,8 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, idx_type const cells = loctab->numberofcells; p = 0; cols = ocol; - rows = loctab->row_info.size(); - col_type const columns = loctab->column_info.size(); + rows = loctab->nrows(); + col_type const columns = loctab->ncols(); while (cell < cells && p < len && row < rows && (p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos) @@ -5289,13 +6322,17 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, } -void InsetTabular::addPreview(PreviewLoader & loader) const +void InsetTabular::addPreview(DocIterator const & inset_pos, + PreviewLoader & loader) const { - row_type const rows = tabular.row_info.size(); - col_type const columns = tabular.column_info.size(); - for (row_type i = 0; i < rows; ++i) { - for (col_type j = 0; j < columns; ++j) - tabular.cellInset(i, j)->addPreview(loader); + DocIterator cell_pos = inset_pos; + + cell_pos.push_back(CursorSlice(*const_cast(this))); + for (row_type r = 0; r < tabular.nrows(); ++r) { + for (col_type c = 0; c < tabular.ncols(); ++c) { + cell_pos.top().idx() = tabular.cellIndex(r, c); + tabular.cellInset(r, c)->addPreview(cell_pos, loader); + } } }