X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=5eb59e54d2513c8100e86b0ba3de223c4ec22f7d;hb=bfddee97e191a853f0576f4fab3f095c4e9ce0de;hp=4c586542e227f42857890e3694f96c32277cf4ac;hpb=1f8b6f8a0ab0c704298c2042fe8d3f32225205f7;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index 4c586542e2..5eb59e54d2 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -70,7 +70,6 @@ using namespace std; using namespace lyx::support; -using boost::shared_ptr; namespace lyx { @@ -89,7 +88,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 @@ -107,6 +106,8 @@ struct TabularFeature { TabularFeature tabularFeature[] = { + // 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 }, @@ -117,7 +118,6 @@ TabularFeature tabularFeature[] = { Tabular::SET_LINE_BOTTOM, "set-line-bottom", true }, { Tabular::SET_LINE_LEFT, "set-line-left", true }, { Tabular::SET_LINE_RIGHT, "set-line-right", true }, - //FIXME: get rid of those 4 TOGGLE actions in favor of the 4 above. { Tabular::TOGGLE_LINE_TOP, "toggle-line-top", false }, { Tabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom", false }, { Tabular::TOGGLE_LINE_LEFT, "toggle-line-left", false }, @@ -126,6 +126,7 @@ TabularFeature tabularFeature[] = { 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 }, @@ -136,7 +137,12 @@ TabularFeature tabularFeature[] = { 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 }, @@ -160,9 +166,10 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_LTLASTFOOT, "unset-ltlastfoot", true }, { Tabular::SET_LTNEWPAGE, "set-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_SPECIAL_MULTIROW, "set-special-multirow", false }, { Tabular::SET_BOOKTABS, "set-booktabs", false }, { Tabular::UNSET_BOOKTABS, "unset-booktabs", false }, { Tabular::SET_TOP_SPACE, "set-top-space", true }, @@ -175,6 +182,8 @@ TabularFeature tabularFeature[] = { 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 } }; @@ -252,6 +261,8 @@ string const tostr(LyXAlignment const & num) return "layout"; case LYX_ALIGN_SPECIAL: return "special"; + case LYX_ALIGN_DECIMAL: + return "decimal"; } return string(); } @@ -312,6 +323,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; @@ -503,6 +516,27 @@ string const featureAsString(Tabular::Feature action) } +InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep) +{ + InsetTableCell tail = InsetTableCell(head); + + DocIterator dit = doc_iterator_begin(&head.buffer(), &head); + for (; dit; dit.forwardChar()) + if (dit.inTexted() && dit.depth()==1 + && dit.paragraph().find(align_d, false, false, dit.pos())) + break; + + pit_type const psize = head.paragraphs().front().size(); + hassep = dit; + if (hassep) { + head.paragraphs().front().eraseChars(dit.pos(), psize, false); + tail.paragraphs().front().eraseChars(0, + dit.pos() < psize ? dit.pos() + 1 : psize, false); + } + + return tail; +} + ///////////////////////////////////////////////////////////////////// // @@ -518,6 +552,9 @@ Tabular::CellData::CellData(Buffer * buf) 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), @@ -535,8 +572,12 @@ Tabular::CellData::CellData(CellData const & cs) 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), @@ -545,7 +586,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 +602,12 @@ void Tabular::CellData::swap(CellData & rhs) 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); @@ -634,6 +679,7 @@ 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; use_booktabs = false; @@ -790,6 +836,7 @@ void Tabular::updateIndexes() { setBuffer(buffer()); numberofcells = 0; + // reset cell number for (row_type row = 0; row < nrows(); ++row) for (col_type column = 0; column < ncols(); ++column) { if (!isPartOfMultiColumn(row, column) @@ -804,15 +851,22 @@ void Tabular::updateIndexes() rowofcell.resize(numberofcells); columnofcell.resize(numberofcells); idx_type i = 0; + // 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) - || isPartOfMultiRow(row, 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; } } @@ -880,7 +934,7 @@ int Tabular::interColumnSpace(idx_type cell) const } -int Tabular::columnWidth(idx_type cell) const +int Tabular::cellWidth(idx_type cell) const { int w = 0; col_type const span = columnSpan(cell); @@ -908,14 +962,28 @@ int Tabular::cellHeight(idx_type cell) const bool Tabular::updateColumnWidths() { + 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) { int new_width = 0; 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) { @@ -954,21 +1022,35 @@ int Tabular::width() const } -void Tabular::setCellWidth(idx_type cell, int new_width) -{ - cellInfo(cell).width = new_width + 2 * WIDTH_OF_LINE - + interColumnSpace(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); + } } @@ -1048,13 +1130,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) { @@ -1073,6 +1148,13 @@ 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) { @@ -1168,8 +1250,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; } @@ -1191,9 +1274,9 @@ 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; } @@ -1202,14 +1285,31 @@ int Tabular::textHOffset(idx_type cell) const // 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); - // + interColumnSpace(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; @@ -1221,20 +1321,12 @@ int Tabular::textHOffset(idx_type cell) const int Tabular::textVOffset(idx_type cell) const { - row_type const r = cellRow(cell); - int y = cellHeight(cell) - rowDescent(r) - rowAscent(r); - switch (getVAlignment(cell)) { - case LYX_VALIGN_TOP: - y = 0; - break; - case LYX_VALIGN_MIDDLE: - y = y/2; - break; - case LYX_VALIGN_BOTTOM: - break; + int voffset = cellInfo(cell).voffset; + if (isMultiRow(cell)) { + row_type const row = cellRow(cell); + voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2; } - - return y; + return voffset; } @@ -1250,8 +1342,9 @@ Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const Tabular::idx_type Tabular::getLastCellInRow(row_type row) const { col_type c = ncols() - 1; - while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW - || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN) + 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; } @@ -1272,7 +1365,7 @@ Tabular::col_type Tabular::cellColumn(idx_type cell) const if (cell >= numberofcells) return ncols() - 1; if (cell == npos) - return 0; + return 0; return columnofcell[cell]; } @@ -1301,16 +1394,20 @@ 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 c = 0; c < ncols(); ++c) { os << "\n"; @@ -1341,6 +1438,7 @@ void Tabular::write(ostream & os) const os << " 0) setRightLine(cell, rightLine(cellIndex(row, col - 1))); @@ -1539,11 +1641,19 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number) for (idx_type i = 0; i < number; ++i) unsetMultiColumn(cellIndex(row + i, col)); - // unsetting of multicol may have invalidated cell index + // 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 row of the last selected cell setBottomLine(cell, bottomLine(cell + (number - 1)*ncols())); @@ -1562,11 +1672,12 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number) Tabular::idx_type Tabular::columnSpan(idx_type cell) const { row_type const row = cellRow(cell); - col_type column = cellColumn(cell) + 1; - while (column < ncols() && isPartOfMultiColumn(row, column)) - ++column; + col_type const col = cellColumn(cell); + int span = 1; + while (col + span < ncols() && isPartOfMultiColumn(row, col + span)) + ++span; - return column - cellColumn(cell); + return span; } @@ -1589,8 +1700,17 @@ void Tabular::unsetMultiColumn(idx_type cell) 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) + 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; + } updateIndexes(); } @@ -1601,6 +1721,7 @@ void Tabular::unsetMultiRow(idx_type cell) return; 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); @@ -1771,6 +1892,8 @@ bool Tabular::getLTNewPage(row_type row) const bool Tabular::haveLTHead() const { + if (!is_long_tabular) + return false; for (row_type i = 0; i < nrows(); ++i) if (row_info[i].endhead) return true; @@ -1780,7 +1903,7 @@ bool Tabular::haveLTHead() const bool Tabular::haveLTFirstHead() const { - if (endfirsthead.empty) + if (!is_long_tabular || endfirsthead.empty) return false; for (row_type r = 0; r < nrows(); ++r) if (row_info[r].endfirsthead) @@ -1791,6 +1914,8 @@ bool Tabular::haveLTFirstHead() const bool Tabular::haveLTFoot() const { + if (!is_long_tabular) + return false; for (row_type r = 0; r < nrows(); ++r) if (row_info[r].endfoot) return true; @@ -1800,7 +1925,7 @@ bool Tabular::haveLTFoot() const bool Tabular::haveLTLastFoot() const { - if (endlastfoot.empty) + if (!is_long_tabular || endlastfoot.empty) return false; for (row_type r = 0; r < nrows(); ++r) if (row_info[r].endlastfoot) @@ -1836,6 +1961,8 @@ bool Tabular::ltCaption(row_type row) const bool Tabular::haveLTCaption() const { + if (!is_long_tabular) + return false; for (row_type r = 0; r < nrows(); ++r) if (row_info[r].caption) return true; @@ -1901,7 +2028,7 @@ bool Tabular::isPartOfMultiRow(row_type row, col_type column) const } -int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const +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(...) @@ -1923,7 +2050,7 @@ int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const // do nothing if empty first row, or incomplete row line after if ((row == 0 && nset == 0) || (row > 0 && nset != ncols())) - return 0; + return; // only output complete row lines and the 1st row's clines if (nset == ncols()) { @@ -1935,27 +2062,35 @@ int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const } else if (row == 0) { 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 @@ -1989,7 +2124,7 @@ 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; + return; if (nset == ncols()) { if (use_booktabs) @@ -1999,33 +2134,40 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) co } else { 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, bool & ismultirow) 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)); @@ -2046,8 +2188,19 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft) || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft)) || (coldouble != celldouble); + + // we center in multicol when no decimal point + ismulticol |= ((column_info[c].alignment == LYX_ALIGN_DECIMAL) + && (cellInfo(cell).decimal_width == 0)); + + // 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()) { @@ -2101,7 +2254,7 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, // add extra vertical line if we want a double one os << '|'; os << "}{"; - } // end if ismulticol + } // end if ismulticol // we only need code for the first multirow cell ismultirow = isMultiRow(cell); @@ -2111,14 +2264,15 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, os << from_ascii(getPWidth(cell).asLatexString()); else // we need to set a default value - // needs to be discussed os << "*"; - os << "}{"; - } // end if ismultirow + os << "}"; + if (!getMROffset(cell).zero()) + os << "[" << from_ascii(getMROffset(cell).asLatexString()) << "]"; + os << "{"; + } // end if ismultirow if (getRotateCell(cell)) { os << "\\begin{sideways}\n"; - ++ret; } if (getUsebox(cell) == BOX_PARBOX) { os << "\\parbox["; @@ -2150,137 +2304,99 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, } os << "]{" << from_ascii(getPWidth(cell).asLatexString()) << "}\n"; - ++ret; } - return ret; } -int Tabular::TeXCellPostamble(odocstream & os, idx_type cell, - bool ismulticol, bool ismultirow) 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 || ismultirow) { + else if (getUsebox(cell) == BOX_MINIPAGE) + os << breakln << "\\end{minipage}"; + if (getRotateCell(cell)) + os << breakln << "\\end{sideways}"; + 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 if (haveLTCaption()) { for (row_type r = 0; r < nrows(); ++r) { - if (row_info[r].caption) { - ret += TeXRow(os, r, runparams); - } + if (row_info[r].caption) + 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 r = 0; r < nrows(); ++r) { - if (row_info[r].endfirsthead) { - ret += TeXRow(os, r, runparams); - } + 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) { - ret += TeXRow(os, r, runparams); - } + if (row_info[r].endhead) + TeXRow(os, r, 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) { - ret += TeXRow(os, r, runparams); - } + if (row_info[r].endfoot) + TeXRow(os, r, 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 r = 0; r < nrows(); ++r) { - if (row_info[r].endlastfoot) { - ret += TeXRow(os, r, runparams); - } + 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; } @@ -2294,8 +2410,8 @@ bool Tabular::isValidRow(row_type row) const } -int Tabular::TeXRow(odocstream & os, row_type row, - OutputParams const & runparams) const +void Tabular::TeXRow(otexstream & os, row_type row, + OutputParams const & runparams) const { idx_type cell = cellIndex(row, 0); shared_ptr inset = cellInset(cell); @@ -2303,14 +2419,13 @@ int Tabular::TeXRow(odocstream & os, row_type row, string const lang = par.getParLanguage(buffer().params())->lang(); //output the top line - int ret = TeXTopHLine(os, row, lang); + TeXTopHLine(os, row, lang); if (row_info[row].top_space_default) { if (use_booktabs) os << "\\addlinespace\n"; else os << "\\noalign{\\vskip\\doublerulesep}\n"; - ++ret; } else if(!row_info[row].top_space.zero()) { if (use_booktabs) os << "\\addlinespace[" @@ -2321,17 +2436,23 @@ int Tabular::TeXRow(odocstream & os, row_type row, << from_ascii(row_info[row].top_space.asLatexString()) << "}\n"; } - ++ret; } bool ismulticol = false; bool ismultirow = false; for (col_type c = 0; c < ncols(); ++c) { - if (isPartOfMultiRow(row, c)) - os << " & "; // we need to add a further column - if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c)) + if (isPartOfMultiColumn(row, c)) continue; + cell = cellIndex(row, c); - ret += TeXCellPreamble(os, cell, ismulticol, ismultirow); + + 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(); @@ -2358,14 +2479,38 @@ int Tabular::TeXRow(odocstream & os, row_type row, newrp.inTableCell = (getAlignment(cell) == LYX_ALIGN_BLOCK) ? OutputParams::PLAIN : OutputParams::ALIGNED; - ret += inset->latex(os, newrp); + + if (getAlignment(cell) == LYX_ALIGN_DECIMAL + && cellInfo(cell).decimal_width != 0) { + // copy cell and split in 2 + InsetTableCell head = InsetTableCell(*cellInset(cell).get()); + head.getText(0)->setMacrocontextPosition( + cellInset(cell)->getText(0)->macrocontextPosition()); + head.setBuffer(buffer()); + bool hassep = false; + InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep); + tail.getText(0)->setMacrocontextPosition( + head.getText(0)->macrocontextPosition()); + tail.setBuffer(head.buffer()); + head.latex(os, newrp); + os << '&'; + 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, ismultirow); + TeXCellPostamble(os, cell, ismulticol, ismultirow); if (cell != getLastCellInRow(row)) { // not last cell in row - os << " & "; + if (runparams.nice) + os << " & "; + else + os << " &\n"; } } if (row_info[row].caption && !endfirsthead.empty && !haveLTFirstHead()) @@ -2388,17 +2533,15 @@ int Tabular::TeXRow(odocstream & os, row_type row, << ']'; } os << '\n'; - ++ret; //output the bottom line - ret += TeXBottomHLine(os, row, lang); + TeXBottomHLine(os, row, lang); if (row_info[row].interline_space_default) { if (use_booktabs) os << "\\addlinespace\n"; else os << "\\noalign{\\vskip\\doublerulesep}\n"; - ++ret; } else if (!row_info[row].interline_space.zero()) { if (use_booktabs) os << "\\addlinespace[" @@ -2408,24 +2551,25 @@ int Tabular::TeXRow(odocstream & os, row_type row, os << "\\noalign{\\vskip" << 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 << safebreakln; + if (runparams.lastid != -1) + os.texrow().start(runparams.lastid, runparams.lastpos); + + if (rotate) os << "\\begin{sideways}\n"; - ++ret; - } + if (is_long_tabular) { os << "\\begin{longtable}"; switch (longtabular_alignment) { @@ -2439,7 +2583,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]"; @@ -2454,6 +2601,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const os << "{"; + if (is_tabular_star) + os << "@{\\extracolsep{\\fill}}"; + for (col_type c = 0; c < ncols(); ++c) { if (columnLeftLine(c)) os << '|'; @@ -2475,6 +2625,7 @@ 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; } @@ -2500,6 +2651,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const 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; @@ -2510,9 +2664,8 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const os << '|'; } os << "}\n"; - ++ret; - ret += TeXLongtableHeaderFooter(os, runparams); + TeXLongtableHeaderFooter(os, runparams); //+--------------------------------------------------------------------- //+ the single row and columns (cells) + @@ -2520,11 +2673,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const for (row_type r = 0; r < nrows(); ++r) { if (isValidRow(r)) { - ret += TeXRow(os, r, runparams); - if (is_long_tabular && row_info[r].newpage) { + TeXRow(os, r, runparams); + if (is_long_tabular && row_info[r].newpage) os << "\\newpage\n"; - ++ret; - } } } @@ -2534,14 +2685,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) + os << breakln << "\\end{sideways}"; } @@ -2694,9 +2846,10 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, - OutputParams const & runparams) const + OutputParams const & runparams, bool header) const { docstring ret; + string const celltag = header ? "th" : "td"; idx_type cell = getFirstCellInRow(row); xs << html::StartTag("tr"); @@ -2734,9 +2887,9 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, if (isMultiColumn(cell)) attr << " colspan='" << columnSpan(cell) << "'"; - xs << html::StartTag("td", attr.str()); + xs << html::StartTag(celltag, attr.str()) << html::CR(); ret += cellInset(cell)->xhtml(xs, runparams); - xs << html::EndTag("td"); + xs << html::EndTag(celltag) << html::CR(); ++cell; } xs << html::EndTag("tr"); @@ -2747,16 +2900,78 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const { docstring ret; - // It's unclear to me if we need to mess with the long table stuff. - // We can borrow that too from docbook, if so. - xs << html::StartTag("tbody"); + 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(); + 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(); + // 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(); + 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)) { + ret += xhtmlRow(xs, r, runparams, true); + } + } + xs << html::EndTag("thead") << html::CR(); + } + // output footer info + bool const havelastfoot = haveLTLastFoot(); + // as before. + bool const havefoot = !havelastfoot && haveLTFoot(); + 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)) { + 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"); + xs << html::EndTag("tbody") + << html::CR() + << html::EndTag("table") + << html::CR(); + if (is_long_tabular) + xs << html::EndTag("div") << html::CR(); return ret; } @@ -3051,14 +3266,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); } @@ -3129,11 +3350,19 @@ 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; + } } @@ -3146,7 +3375,14 @@ void InsetTabular::write(ostream & os) const docstring InsetTabular::contextMenu(BufferView const &, int, int) const { - // FIXME: depending on the selection state, we could offer a different menu. + // FIXME: depending on the selection state, + // we could offer a different menu. + return cell(0)->contextMenuName() + ";" + contextMenuName(); +} + + +docstring InsetTabular::contextMenuName() const +{ return from_ascii("context-tabular"); } @@ -3174,11 +3410,11 @@ 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); + int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; row_type r = 0; for (; r < tabular.nrows() && y > h; ++r) h += tabular.rowAscent(r) + tabular.rowDescent(r) - + tabular.interRowSpace(r); + + tabular.interRowSpace(r); return r - 1; } @@ -3190,7 +3426,7 @@ int InsetTabular::columnFromX(Cursor & cur, int x) const int w = xo(cur.bv()) + ADD_TO_TABULAR_WIDTH; col_type c = 0; for (; c < tabular.ncols() && x > w; ++c) - w += tabular.columnWidth(c); + w += tabular.cellWidth(c); return c - 1; } @@ -3205,8 +3441,8 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const } for (row_type r = 0; r < tabular.nrows(); ++r) { - int maxAsc = 0; - int maxDesc = 0; + int maxasc = 0; + int maxdes = 0; for (col_type c = 0; c < tabular.ncols(); ++c) { if (tabular.isPartOfMultiColumn(r, c) || tabular.isPartOfMultiRow(r, c)) @@ -3215,36 +3451,97 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const idx_type const cell = tabular.cellIndex(r, c); Dimension dim; MetricsInfo m = mi; - Length p_width; - if (tabular.cell_info[r][c].multicolumn == - Tabular::CELL_BEGIN_OF_MULTICOLUMN) - p_width = tabular.cellInfo(cell).p_width; - else - p_width = tabular.column_info[c].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); + 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_hoffset = 0; + int decimal_width = 0; + if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) { + // make a copy which we will split in 2 + InsetTableCell head = InsetTableCell(*tabular.cellInset(cell).get()); + head.getText(0)->setMacrocontextPosition( + tabular.cellInset(cell)->getText(0)->macrocontextPosition()); + head.setBuffer(tabular.buffer()); + // split in 2 and calculate width of each part + bool hassep = false; + InsetTableCell tail = + splitCell(head, tabular.column_info[c].decimal_point, hassep); + tail.getText(0)->setMacrocontextPosition( + head.getText(0)->macrocontextPosition()); + tail.setBuffer(head.buffer()); + Dimension dim1; + head.metrics(m, dim1); + decimal_hoffset = dim1.width(); + if (hassep) { + tail.metrics(m, dim1); + decimal_width = dim1.width(); + } + } + tabular.cell_info[r][c].decimal_hoffset = decimal_hoffset; + 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[r].top_space_default ? default_line_space : tabular.row_info[r].top_space.inPixels(mi.base.textwidth); - tabular.setRowAscent(r, maxAsc + ADD_TO_HEIGHT + top_space); + 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[r].bottom_space.inPixels(mi.base.textwidth); - tabular.setRowDescent(r, maxDesc + ADD_TO_HEIGHT + bottom_space); + 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 { @@ -3284,7 +3581,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const 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; @@ -3292,6 +3589,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const idx_type idx = 0; first_visible_cell = Tabular::npos; + + int yy = y + offset_valign_; for (row_type r = 0; r < tabular.nrows(); ++r) { int nx = x; for (col_type c = 0; c < tabular.ncols(); ++c) { @@ -3301,7 +3600,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const idx = tabular.cellIndex(r, c); if (tabular.isPartOfMultiRow(r, c)) { - nx += tabular.columnWidth(idx); + nx += tabular.cellWidth(idx); continue; } @@ -3310,22 +3609,31 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const pi.selected |= isCellSelected(cur, r, c); int const cx = nx + tabular.textHOffset(idx); - int const cy = y + tabular.textVOffset(idx); + int const cy = yy + tabular.textVOffset(idx); // Cache the Inset position. bv->coordCache().insets().add(cell(idx).get(), cx, cy); cell(idx)->draw(pi, cx, cy); - drawCellLines(pi.pain, nx, y, r, idx, pi.change_); - nx += tabular.columnWidth(idx); + drawCellLines(pi, nx, yy, r, idx); + nx += tabular.cellWidth(idx); pi.selected = original_selection_state; } if (r + 1 < tabular.nrows()) - y += tabular.rowDescent(r) + tabular.rowAscent(r + 1) + 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(); @@ -3333,15 +3641,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) @@ -3362,12 +3661,12 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const idx_type const cell = tabular.cellIndex(r, c); if (tabular.isPartOfMultiRow(r, c)) { - xx += tabular.columnWidth(cell); + xx += tabular.cellWidth(cell); continue; } - int const w = tabular.columnWidth(cell); + int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); - int const yy = y - tabular.rowAscent(r); + 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; @@ -3377,58 +3676,55 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const + tabular.interRowSpace(r + 1); } - } else { - x += cellXPos(cur.idx()); - x += tabular.textHOffset(cur.idx()); - cell(cur.idx())->drawSelection(pi, x, 0 /* ignored */); - } + } + // 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(Painter & pain, int x, int y, - row_type row, idx_type cell, Change const & change) const +void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y, + row_type row, idx_type cell) const { - y = y - tabular.rowAscent(row); - int const w = tabular.columnWidth(cell); + y -= tabular.rowAscent(row); + int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); - bool on_off = false; - Color col = Color_tabularline; - Color onoffcol = Color_tabularonoffline; - - if (change.changed()) { - col = change.color(); - onoffcol = change.color(); - } - - bool topalreadydrawn = row > 0 && !tabular.rowTopLine(row) - && tabular.bottomLine(tabular.cellAbove(cell)); - - if (!topalreadydrawn) { - on_off = !tabular.topLine(cell); - pain.line(x, y, x + w, y, - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); - } - on_off = !tabular.bottomLine(cell); - pain.line(x, y + h, x + w, y + h, - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); - - col_type const column = tabular.cellColumn(cell); - bool leftalreadydrawn = column > 0 && !tabular.leftLine(cell) - && tabular.rightLine(tabular.cellIndex(row, column - 1)); - - if (!leftalreadydrawn) { - on_off = !tabular.leftLine(cell); - pain.line(x, y, x, y + h, - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); - } - on_off = !tabular.rightLine(cell); - pain.line(x + w - tabular.interColumnSpace(cell), y, - x + w - tabular.interColumnSpace(cell), y + h, - on_off ? onoffcol : col, - on_off ? Painter::line_onoffdash : Painter::line_solid); + 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); + drawline = tabular.rightLine(cell) + || (col + 1 < tabular.ncols() + && tabular.leftLine(tabular.cellIndex(row, col + 1))); + pi.pain.line(x + w, y, x + w, y + h, + drawline ? linecolor : gridcolor, + drawline ? Painter::line_solid : Painter::line_onoffdash); } @@ -3480,7 +3776,7 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) } -void InsetTabular::addToToc(DocIterator const & cpit) +void InsetTabular::addToToc(DocIterator const & cpit) const { DocIterator dit = cpit; dit.forwardPos(); @@ -3497,14 +3793,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(); @@ -3516,10 +3814,10 @@ 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(); @@ -3545,13 +3843,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. @@ -3563,7 +3861,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } // select (additional) column if (colselect_) { - col_type c = columnFromX(cur, cmd.x); + 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. @@ -3575,9 +3873,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 @@ -3611,7 +3909,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: @@ -3619,21 +3925,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) @@ -3642,10 +3954,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... @@ -3693,6 +4009,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cmd = FuncRequest(finish_lfun); else cur.dispatched(); + + cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; } @@ -3707,7 +4025,7 @@ 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); + cur.selHandle(act == LFUN_DOWN_SELECT); if (tabular.cellRow(cur.idx()) != tabular.nrows() - 1) { cur.idx() = tabular.cellBelow(cur.idx()); cur.pit() = 0; @@ -3729,6 +4047,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.setCurrentFont(); return; } + cur.screenUpdateFlags(Update::FitCursor); break; case LFUN_UP_SELECT: @@ -3740,7 +4059,7 @@ 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) { cur.idx() = tabular.cellAbove(cur.idx()); cur.pit() = cur.lastpit(); @@ -3762,6 +4081,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.setCurrentFont(); return; } + cur.screenUpdateFlags(Update::FitCursor); break; // case LFUN_SCREEN_DOWN: { @@ -3770,7 +4090,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; @@ -3786,7 +4106,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 @@ -3868,7 +4188,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CLIPBOARD_PASTE: case LFUN_PRIMARY_SELECTION_PASTE: { - docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ? + docstring const clip = (act == LFUN_CLIPBOARD_PASTE) ? theClipboard().getAsText() : theSelection().get(); if (clip.empty()) @@ -3897,8 +4217,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); } @@ -3969,13 +4288,21 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { - switch (cmd.action) { + switch (cmd.action()) { case LFUN_INSET_MODIFY: { if (&cur.inset() != this || cmd.getArg(0) != "tabular") break; - string const s = cmd.getArg(1); // 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) { @@ -3986,7 +4313,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } if (action == Tabular::LAST_ACTION) { status.clear(); - status.unknown(true); + status.setUnknown(true); return true; } @@ -4006,7 +4333,6 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::SET_MPWIDTH: case Tabular::SET_SPECIAL_COLUMN: case Tabular::SET_SPECIAL_MULTICOLUMN: - case Tabular::SET_SPECIAL_MULTIROW: case Tabular::APPEND_ROW: case Tabular::APPEND_COLUMN: case Tabular::DELETE_ROW: @@ -4019,6 +4345,18 @@ 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::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. @@ -4027,6 +4365,8 @@ 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. @@ -4068,24 +4408,28 @@ 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: - status.setEnabled(!tabular.isMultiRow(cur.idx())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_LEFT); break; case Tabular::M_ALIGN_RIGHT: flag = false; case Tabular::ALIGN_RIGHT: - status.setEnabled(!tabular.isMultiRow(cur.idx())); + 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())); + status.setEnabled(!(tabular.isMultiRow(cur.idx()) + && !tabular.getPWidth(cur.idx()).zero())); status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_CENTER); break; @@ -4095,6 +4439,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, 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: @@ -4123,6 +4473,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, 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; @@ -4132,18 +4488,22 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::TOGGLE_ROTATE_TABULAR: case Tabular::SET_ROTATE_TABULAR: + status.setEnabled(tabular.tabular_width.zero()); status.setOnOff(tabular.rotate); 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; @@ -4228,6 +4588,8 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, // only one row can be the caption // and a multirow cannot be set as caption + case Tabular::SET_LTCAPTION: + case Tabular::UNSET_LTCAPTION: case Tabular::TOGGLE_LTCAPTION: status.setEnabled(sel_row_start == sel_row_end && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt) @@ -4275,11 +4637,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); @@ -4289,8 +4652,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_BREAK_PARAGRAPH: + // 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; @@ -4351,9 +4719,9 @@ 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); } @@ -4395,13 +4763,7 @@ int InsetTabular::docbook(odocstream & os, OutputParams const & runparams) const docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const { - // 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. - xs << html::StartTag("table"); - docstring ret = tabular.xhtml(xs, rp); - xs << html::EndTag("table"); - return ret; + return tabular.xhtml(xs, rp); } @@ -4436,20 +4798,13 @@ void InsetTabular::cursorPos(BufferView const & bv, { cell(sl.idx())->cursorPos(bv, sl, boundary, x, y); - int const row = tabular.cellRow(sl.idx()); - int const col = tabular.cellColumn(sl.idx()); - // y offset correction - for (int r = 0; r < row; ++r) - y += tabular.rowDescent(r) + tabular.rowAscent(r + 1) - + tabular.interRowSpace(r + 1); - + y += cellYPos(sl.idx()); y += tabular.textVOffset(sl.idx()); + y += offset_valign_; // x offset correction - for (int c = 0; c < col; ++c) - x += tabular.column_info[c].width; - + x += cellXPos(sl.idx()); x += tabular.textHOffset(sl.idx()); x += ADD_TO_TABULAR_WIDTH; x += scx_; @@ -4463,7 +4818,7 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const Inset const & inset = *tabular.cellInset(cell); Point o = bv.coordCache().getInsets().xy(&inset); int const xbeg = o.x_ - tabular.textHOffset(cell); - int const xend = xbeg + tabular.columnWidth(cell); + int const xend = xbeg + tabular.cellWidth(cell); row_type const row = tabular.cellRow(cell); int const ybeg = o.y_ - tabular.rowAscent(row) - tabular.interRowSpace(row); @@ -4522,13 +4877,23 @@ InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int } +int InsetTabular::cellYPos(idx_type const cell) const +{ + 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; +} + + 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.columnWidth(c); - + lx += tabular.column_info[c].width; return lx; } @@ -4547,7 +4912,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; @@ -4559,7 +4924,7 @@ 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); } @@ -4788,6 +5153,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, setAlign = LYX_ALIGN_BLOCK; break; + case Tabular::ALIGN_DECIMAL: + setAlign = LYX_ALIGN_DECIMAL; + break; + case Tabular::M_VALIGN_TOP: case Tabular::VALIGN_TOP: setVAlign = Tabular::LYX_VALIGN_TOP; @@ -4807,7 +5176,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()); @@ -4817,6 +5186,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); @@ -4830,6 +5203,10 @@ 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_MULTICOLUMN: if (value == "none") @@ -4838,10 +5215,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.setAlignSpecial(cur.idx(), from_utf8(value), feature); break; - case Tabular::SET_SPECIAL_MULTIROW: - //FIXME: noting to do here? - break; - case Tabular::APPEND_ROW: // append the row into the tabular tabular.appendRow(cur.idx()); @@ -4927,14 +5300,15 @@ void InsetTabular::tabularFeatures(Cursor & cur, 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: + 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, flag); + tabular.setAlignment(tabular.cellIndex(r, c), setAlign, + !tabular.getPWidth(c).zero()); break; case Tabular::M_VALIGN_TOP: @@ -4949,13 +5323,11 @@ void InsetTabular::tabularFeatures(Cursor & cur, 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.unsetMultiColumn(cur.idx()); - else + if (!tabular.isMultiColumn(cur.idx())) tabular.setMultiColumn(cur.idx(), 1); break; } @@ -4970,14 +5342,28 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.setSelection(false); break; } - - case Tabular::MULTIROW: { + + case Tabular::UNSET_MULTICOLUMN: { + if (!cur.selection()) { + if (tabular.isMultiColumn(cur.idx())) + tabular.unsetMultiColumn(cur.idx()); + } + break; + } + + case Tabular::MULTICOLUMN: { + if (tabular.isMultiColumn(cur.idx())) + tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN); + else + tabularFeatures(cur, Tabular::SET_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.unsetMultiRow(cur.idx()); - else + if (!tabular.isMultiRow(cur.idx())) tabular.setMultiRow(cur.idx(), 1); break; } @@ -4993,6 +5379,22 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::UNSET_MULTIROW: { + if (!cur.selection()) { + if (tabular.isMultiRow(cur.idx())) + tabular.unsetMultiRow(cur.idx()); + } + break; + } + + case Tabular::MULTIROW: { + if (tabular.isMultiRow(cur.idx())) + tabularFeatures(cur, Tabular::UNSET_MULTIROW); + else + tabularFeatures(cur, Tabular::SET_MULTIROW); + break; + } + case Tabular::SET_ALL_LINES: setLines = true; case Tabular::UNSET_ALL_LINES: @@ -5141,23 +5543,38 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.setLTNewPage(row, !tabular.getLTNewPage(row)); 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; } @@ -5223,6 +5640,11 @@ void InsetTabular::tabularFeatures(Cursor & cur, 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;