X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=f9503c7124d8e23bff0629da8dbffb019d3d02ee;hb=6e4e0869006aa4c225162164aaa14a70d041facf;hp=d92acf2e0ffe21769a633965402934b3b0f79321;hpb=77cc2c7c8c83481cabf5e0af2f83e41a22b19dc0;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index d92acf2e0f..f9503c7124 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -33,6 +33,7 @@ #include "DispatchResult.h" #include "FuncRequest.h" #include "FuncStatus.h" +#include "InsetIterator.h" #include "InsetList.h" #include "Language.h" #include "LaTeXFeatures.h" @@ -45,6 +46,8 @@ #include "Paragraph.h" #include "ParagraphParameters.h" #include "ParIterator.h" +#include "TexRow.h" +#include "texstream.h" #include "TextClass.h" #include "TextMetrics.h" @@ -61,10 +64,10 @@ #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" - -#include +#include "support/unique_ptr.h" #include +#include #include #include #include @@ -96,7 +99,7 @@ int const WIDTH_OF_LINE = 5; // space between double lines /// -boost::scoped_ptr paste_tabular; +unique_ptr paste_tabular; struct TabularFeature { @@ -110,6 +113,8 @@ TabularFeature tabularFeature[] = { // the SET/UNSET actions are used by the table dialog, // the TOGGLE actions by the table toolbar buttons + // FIXME: these values have been hardcoded in InsetMathGrid and other + // math insets. { Tabular::APPEND_ROW, "append-row", false }, { Tabular::APPEND_COLUMN, "append-column", false }, { Tabular::DELETE_ROW, "delete-row", false }, @@ -151,6 +156,7 @@ TabularFeature tabularFeature[] = { Tabular::SET_MROFFSET, "set-mroffset", true }, { Tabular::SET_ALL_LINES, "set-all-lines", false }, { Tabular::UNSET_ALL_LINES, "unset-all-lines", false }, + { Tabular::TOGGLE_LONGTABULAR, "toggle-longtabular", false }, { Tabular::SET_LONGTABULAR, "set-longtabular", false }, { Tabular::UNSET_LONGTABULAR, "unset-longtabular", false }, { Tabular::SET_PWIDTH, "set-pwidth", true }, @@ -177,6 +183,7 @@ TabularFeature tabularFeature[] = { Tabular::UNSET_LTCAPTION, "unset-ltcaption", false }, { Tabular::SET_SPECIAL_COLUMN, "set-special-column", true }, { Tabular::SET_SPECIAL_MULTICOLUMN, "set-special-multicolumn", true }, + { Tabular::TOGGLE_BOOKTABS, "toggle-booktabs", false }, { Tabular::SET_BOOKTABS, "set-booktabs", false }, { Tabular::UNSET_BOOKTABS, "unset-booktabs", false }, { Tabular::SET_TOP_SPACE, "set-top-space", true }, @@ -522,7 +529,7 @@ string const featureAsString(Tabular::Feature action) } -DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d) +DocIterator separatorPos(InsetTableCell const * cell, docstring const & align_d) { DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell); for (; dit; dit.forwardChar()) @@ -538,7 +545,7 @@ InsetTableCell splitCell(InsetTableCell & head, docstring const & align_d, bool { InsetTableCell tail = InsetTableCell(head); DocIterator const dit = separatorPos(&head, align_d); - hassep = dit; + hassep = (bool)dit; if (hassep) { pit_type const psize = head.paragraphs().front().size(); head.paragraphs().front().eraseChars(dit.pos(), psize, false); @@ -872,8 +879,8 @@ void Tabular::insertColumn(col_type const col, bool copy) setBottomLine(i, bottomLine(j)); setTopLine(i, topLine(j)); setLeftLine(i, leftLine(j)); + setRightLine(i, rightLine(j)); if (rightLine(i) && rightLine(j)) { - setRightLine(i, true); setRightLine(j, false); } if (buffer().params().track_changes) @@ -1028,7 +1035,7 @@ bool Tabular::updateColumnWidths() idx_type const i = cellIndex(r, c); if (columnSpan(i) == 1) { if (getAlignment(i) == LYX_ALIGN_DECIMAL - && cell_info[r][c].decimal_width!=0) + && cell_info[r][c].decimal_width != 0) new_width = max(new_width, cellInfo(i).width + max_dwidth[c] - cellInfo(i).decimal_width); else @@ -1099,7 +1106,7 @@ void Tabular::setAlignment(idx_type cell, LyXAlignment align, dpoint = from_utf8(lyxrc.default_decimal_point); } else { cellInfo(cell).alignment = align; - cellInset(cell).get()->setContentAlignment(align); + cellInset(cell)->setContentAlignment(align); } } @@ -1140,7 +1147,7 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) cur.pop(); } -} +} // namespace void Tabular::setColumnPWidth(Cursor & cur, idx_type cell, @@ -1317,6 +1324,27 @@ Tabular::getVAlignment(idx_type cell, bool onlycolumn) const } +int Tabular::offsetVAlignment() const +{ + // 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 + int offset_valign = 0; + switch (tabular_valignment) { + case Tabular::LYX_VALIGN_BOTTOM: + offset_valign = rowAscent(0) - height(); + break; + case Tabular::LYX_VALIGN_MIDDLE: + offset_valign = (- height()) / 2 + rowAscent(0); + break; + case Tabular::LYX_VALIGN_TOP: + offset_valign = rowAscent(0); + break; + } + return offset_valign; +} + + Length const Tabular::getPWidth(idx_type cell) const { if (isMultiColumn(cell)) @@ -1665,7 +1693,13 @@ bool Tabular::hasMultiColumn(col_type c) const } -Tabular::CellData & Tabular::cellInfo(idx_type cell) const +Tabular::CellData const & Tabular::cellInfo(idx_type cell) const +{ + return cell_info[cellRow(cell)][cellColumn(cell)]; +} + + +Tabular::CellData & Tabular::cellInfo(idx_type cell) { return cell_info[cellRow(cell)][cellColumn(cell)]; } @@ -1827,7 +1861,7 @@ int Tabular::getRotateCell(idx_type cell) const bool Tabular::needRotating() const { - if (rotate) + if (rotate && !is_long_tabular) return true; for (row_type r = 0; r < nrows(); ++r) for (col_type c = 0; c < ncols(); ++c) @@ -2305,7 +2339,7 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell, // 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); + DocIterator const dit = separatorPos(cellInset(cell), align_d); ismulticol |= !dit; } @@ -2530,7 +2564,7 @@ void Tabular::TeXRow(otexstream & os, row_type row, OutputParams const & runparams) const { idx_type cell = cellIndex(row, 0); - shared_ptr inset = cellInset(cell); + InsetTableCell const * inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); string const lang = par.getParLanguage(buffer().params())->lang(); @@ -2569,9 +2603,12 @@ void Tabular::TeXRow(otexstream & os, row_type row, } TeXCellPreamble(os, cell, ismulticol, ismultirow); - shared_ptr inset = cellInset(cell); + InsetTableCell const * inset = cellInset(cell); Paragraph const & par = inset->paragraphs().front(); + + os.texrow().forceStart(par.id(), 0); + bool rtl = par.isRTL(buffer().params()) && !par.empty() && getPWidth(cell).zero() @@ -2599,8 +2636,8 @@ void Tabular::TeXRow(otexstream & os, row_type row, if (getAlignment(cell) == LYX_ALIGN_DECIMAL) { // copy cell and split in 2 - InsetTableCell head = InsetTableCell(*cellInset(cell).get()); - head.setBuffer(buffer()); + InsetTableCell head = InsetTableCell(*cellInset(cell)); + head.setBuffer(const_cast(buffer())); DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition(); dit.pop_back(); dit.push_back(CursorSlice(head)); @@ -2616,6 +2653,17 @@ void Tabular::TeXRow(otexstream & os, row_type row, tail.setMacrocontextPositionRecursive(dit); tail.latex(os, newrp); } + } else if (ltCaption(row)) { + // Inside longtable caption rows, we must only output the caption inset + // with its content and omit anything outside of that (see #10791) + InsetIterator it = inset_iterator_begin(*const_cast(inset)); + InsetIterator i_end = inset_iterator_end(*const_cast(inset)); + for (; it != i_end; ++it) { + if (it->lyxCode() != CAPTION_CODE) + continue; + it->latex(os, runparams); + break; + } } else if (!isPartOfMultiRow(row, c)) { if (!runparams.nice) os.texrow().start(par.id(), 0); @@ -2673,16 +2721,17 @@ void Tabular::TeXRow(otexstream & os, row_type row, void Tabular::latex(otexstream & os, OutputParams const & runparams) const { bool const is_tabular_star = !tabular_width.zero(); + TexRow::RowEntry pos = TexRow::textEntry(runparams.lastid, runparams.lastpos); //+--------------------------------------------------------------------- //+ first the opening preamble + //+--------------------------------------------------------------------- os << safebreakln; - if (runparams.lastid != -1) - os.texrow().start(runparams.lastid, runparams.lastpos); + if (!TexRow::isNone(pos)) + os.texrow().start(pos); - if (rotate != 0) + if (rotate != 0 && !is_long_tabular) os << "\\begin{turn}{" << convert(rotate) << "}\n"; if (is_long_tabular) { @@ -2726,6 +2775,7 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << column_info[c].align_special; } else { if (!column_info[c].p_width.zero()) { + bool decimal = false; switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: os << ">{\\raggedright}"; @@ -2740,24 +2790,49 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const case LYX_ALIGN_BLOCK: case LYX_ALIGN_LAYOUT: case LYX_ALIGN_SPECIAL: + break; case LYX_ALIGN_DECIMAL: + os << ">{\\raggedleft}"; + decimal = true; break; } + char valign = 'p'; switch (column_info[c].valignment) { case LYX_VALIGN_TOP: - os << 'p'; + // this is the default break; case LYX_VALIGN_MIDDLE: - os << 'm'; + valign = 'm'; break; case LYX_VALIGN_BOTTOM: - os << 'b'; + valign = 'b'; break; - } - os << '{' - << from_ascii(column_info[c].p_width.asLatexString()) - << '}'; + } + os << valign; + + // Fixed-width cells with alignment at decimal separator + // are output as two cells of half the width with the decimal + // separator as column sep. This effectively puts the content + // centered, which differs from the normal decimal sep alignment + // and is not ideal, but we cannot do better ATM (see #9568). + // FIXME: Implement proper decimal sep alignment, e.g. via siunitx. + if (decimal) { + docstring const halffixedwith = + from_ascii(Length(column_info[c].p_width.value() / 2, + column_info[c].p_width.unit()).asLatexString()); + os << '{' + << halffixedwith + << '}' + << "@{\\extracolsep{0pt}" << column_info[c].decimal_point << "}" + << valign + << '{' + << halffixedwith + << '}'; + } else + os << '{' + << from_ascii(column_info[c].p_width.asLatexString()) + << '}'; } else { switch (column_info[c].alignment) { case LYX_ALIGN_LEFT: @@ -2807,8 +2882,11 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const os << "\\end{tabular}"; } - if (rotate != 0) + if (rotate != 0 && !is_long_tabular) os << breakln << "\\end{turn}"; + + if (!TexRow::isNone(pos)) + os.texrow().start(pos); } @@ -2976,6 +3054,13 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, continue; stringstream attr; + + Length const cwidth = column_info[c].p_width; + if (!cwidth.zero()) { + string const hwidth = cwidth.asHTMLString(); + attr << "style =\"width: " << hwidth << ";\" "; + } + attr << "align='"; switch (getAlignment(cell)) { case LYX_ALIGN_LEFT: @@ -3007,7 +3092,7 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row, else if (isMultiRow(cell)) attr << " rowspan='" << rowSpan(cell) << "'"; - xs << html::StartTag(celltag, attr.str()) << html::CR(); + xs << html::StartTag(celltag, attr.str(), true) << html::CR(); ret += cellInset(cell)->xhtml(xs, runparams); xs << html::EndTag(celltag) << html::CR(); ++cell; @@ -3310,21 +3395,26 @@ void Tabular::plaintext(odocstringstream & os, } -shared_ptr Tabular::cellInset(idx_type cell) const +shared_ptr Tabular::cellInset(idx_type cell) { return cell_info[cellRow(cell)][cellColumn(cell)].inset; } -shared_ptr Tabular::cellInset(row_type row, - col_type column) const +shared_ptr Tabular::cellInset(row_type row, col_type column) { return cell_info[row][column].inset; } +InsetTableCell const * Tabular::cellInset(idx_type cell) const +{ + return cell_info[cellRow(cell)][cellColumn(cell)].inset.get(); +} + + void Tabular::setCellInset(row_type row, col_type column, - shared_ptr ins) const + shared_ptr ins) { CellData & cd = cell_info[row][column]; cd.inset = ins; @@ -3346,7 +3436,16 @@ void Tabular::validate(LaTeXFeatures & features) const if (getVAlignment(cell) != LYX_VALIGN_TOP || !getPWidth(cell).zero()) features.require("array"); + // Tell footnote that we need a savenote + // environment in non-long tables or + // longtable headers/footers + else if (!is_long_tabular && !features.inFloat()) + features.saveNoteEnv("tabular"); + else if (!isValidRow(cellRow(cell))) + features.saveNoteEnv("longtable"); + cellInset(cell)->validate(features); + features.saveNoteEnv(string()); } } @@ -3401,13 +3500,6 @@ bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, { 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; @@ -3440,9 +3532,9 @@ docstring InsetTableCell::asString(bool intoInsets) void InsetTableCell::addToToc(DocIterator const & di, bool output_active, - UpdateType utype) const + UpdateType utype, TocBackend & backend) const { - InsetText::iterateForToc(di, output_active, utype); + InsetText::iterateForToc(di, output_active, utype, backend); } @@ -3464,13 +3556,14 @@ docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const InsetTabular::InsetTabular(Buffer * buf, row_type rows, col_type columns) : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), - first_visible_cell_(0), offset_valign_(0), rowselect_(false), colselect_(false) + rowselect_(false), colselect_(false) { } InsetTabular::InsetTabular(InsetTabular const & tab) - : Inset(tab), tabular(tab.tabular) + : Inset(tab), tabular(tab.tabular), + rowselect_(false), colselect_(false) { } @@ -3509,7 +3602,7 @@ bool InsetTabular::insetAllowed(InsetCode code) const bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const { return tabular.is_long_tabular && - (newtype == "Standard" || newtype == "LongTableNoNumber"); + (newtype == "Standard" || newtype == "Unnumbered"); } @@ -3557,7 +3650,7 @@ 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) + offset_valign_; + int h = yo(cur.bv()) - tabular.rowAscent(0) + tabular.offsetVAlignment(); row_type r = 0; for (; r < tabular.nrows() && y > h; ++r) h += tabular.rowAscent(r) + tabular.rowDescent(r) @@ -3597,7 +3690,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const MetricsInfo m = mi; Length const p_width = tabular.getPWidth(cell); if (!p_width.zero()) - m.base.textwidth = p_width.inPixels(mi.base); + m.base.textwidth = mi.base.inPixels(p_width); tabular.cellInset(cell)->metrics(m, dim); if (!p_width.zero()) dim.wid = m.base.textwidth; @@ -3611,7 +3704,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const // 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()); + InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell)); tail.setBuffer(tabular.buffer()); // we need to set macrocontext position everywhere // otherwise we crash with nested insets (e.g. footnotes) @@ -3657,32 +3750,17 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const 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); + default_line_space : + mi.base.inPixels(tabular.row_info[r].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); + default_line_space : + mi.base.inPixels(tabular.row_info[r].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) - offset_valign_; + dim.asc = tabular.rowAscent(0) - tabular.offsetVAlignment(); dim.des = tabular.height() - dim.asc; dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH; } @@ -3733,9 +3811,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const bool const original_selection_state = pi.selected; idx_type idx = 0; - first_visible_cell_ = Tabular::npos; - int yy = y + offset_valign_; + int yy = y + tabular.offsetVAlignment(); for (row_type r = 0; r < tabular.nrows(); ++r) { int nx = x; for (col_type c = 0; c < tabular.ncols(); ++c) { @@ -3749,9 +3826,6 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const continue; } - if (first_visible_cell_ == Tabular::npos) - first_visible_cell_ = idx; - pi.selected |= isCellSelected(cur, r, c); int const cx = nx + tabular.textHOffset(idx); int const cy = yy + tabular.textVOffset(idx); @@ -3773,7 +3847,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const { x += ADD_TO_TABULAR_WIDTH; - y += offset_valign_ - tabular.rowAscent(0); + y += tabular.offsetVAlignment() - tabular.rowAscent(0); pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(), pi.backgroundColor(this)); } @@ -3810,7 +3884,7 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const } int const w = tabular.cellWidth(cell); int const h = tabular.cellHeight(cell); - int const yy = y - tabular.rowAscent(r) + offset_valign_; + int const yy = y - tabular.rowAscent(r) + tabular.offsetVAlignment(); if (isCellSelected(cur, r, c)) pi.pain.fillRectangle(xx, yy, w, h, Color_selection); xx += w; @@ -3929,13 +4003,36 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) void InsetTabular::addToToc(DocIterator const & cpit, bool output_active, - UpdateType utype) const + UpdateType utype, TocBackend & backend) 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, utype); + cell(dit.idx())->addToToc(dit, output_active, utype, backend); +} + + +bool InsetTabular::hitSelectRow(BufferView const & bv, int x) const +{ + int const x0 = xo(bv) + ADD_TO_TABULAR_WIDTH; + return x < x0 || x > x0 + tabular.width(); +} + + +bool InsetTabular::hitSelectColumn(BufferView const & bv, int y) const +{ + int const y0 = yo(bv) - tabular.rowAscent(0) + tabular.offsetVAlignment(); + // FIXME: using ADD_TO_TABULAR_WIDTH is not really correct since + // there is no margin added vertically to tabular insets. + // However, it works for now. + return y < y0 + ADD_TO_TABULAR_WIDTH || y > y0 + tabular.height() - ADD_TO_TABULAR_WIDTH; +} + + +bool InsetTabular::clickable(BufferView const & bv, int x, int y) const +{ + return hitSelectRow(bv, x) || hitSelectColumn(bv, y); } @@ -3953,30 +4050,31 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) 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()) { + if (hitSelectRow(cur.bv(), cmd.x())) { row_type r = rowFromY(cur, cmd.y()); cur.idx() = tabular.getFirstCellInRow(r); + cur.pit() = 0; cur.pos() = 0; cur.resetAnchor(); cur.idx() = tabular.getLastCellInRow(r); + cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - cur.setSelection(true); + cur.selection(true); bvcur = cur; rowselect_ = true; break; } // select column - int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_; - if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH - || cmd.y() > y0 + tabular.height()) { + if (hitSelectColumn(cur.bv(), cmd.y())) { col_type c = columnFromX(cur, cmd.x()); cur.idx() = tabular.cellIndex(0, c); + cur.pit() = 0; cur.pos() = 0; cur.resetAnchor(); cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c); + cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - cur.setSelection(true); + cur.selection(true); bvcur = cur; colselect_ = true; break; @@ -4009,7 +4107,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = 0; bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); break; } // select (additional) column @@ -4021,7 +4119,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.pit() = 0; cur.pos() = 0; bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); break; } // only update if selection changes @@ -4030,7 +4128,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.noScreenUpdate(); setCursorFromCoordinates(cur, cmd.x(), cmd.y()); bvcur.setCursor(cur); - bvcur.setSelection(true); + bvcur.selection(true); // if this is a multicell selection, we just set the cursor to // the beginning of the cell's text. if (bvcur.selIsMultiCell()) { @@ -4047,12 +4145,12 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_BACKWARD: movePrevCell(cur); - cur.setSelection(false); + cur.selection(false); break; case LFUN_CELL_FORWARD: moveNextCell(cur); - cur.setSelection(false); + cur.selection(false); break; case LFUN_CHAR_FORWARD_SELECT: @@ -4249,55 +4347,21 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) cur.screenUpdateFlags(Update::Force | Update::FitCursor); break; -// case LFUN_SCREEN_DOWN: { -// //if (hasSelection()) -// // cur.selection() = false; -// 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, true); -// cur.idx() = tabular.cellBelow(first_visible_cell_) + col; -// } else { -// cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col; -// } -// cur.par() = 0; -// cur.pos() = 0; -// break; -// } -// -// case LFUN_SCREEN_UP: { -// //if (hasSelection()) -// // cur.selection() = false; -// 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, true); -// if (yo() > 0) -// cur.idx() = col; -// else -// cur.idx() = tabular.cellBelow(first_visible_cell_) + col; -// } else { -// cur.idx() = col; -// } -// cur.par() = cur.lastpar(); -// cur.pos() = cur.lastpos(); -// break; -// } - case LFUN_LAYOUT_TABULAR: cur.bv().showDialog("tabular"); break; - case LFUN_INSET_MODIFY: { - string arg; - if (cmd.getArg(1) == "from-dialog") - arg = cmd.getArg(0) + to_utf8(cmd.argument().substr(19)); + case LFUN_INSET_MODIFY: + // we come from the dialog + if (cmd.getArg(0) == "tabular") + tabularFeatures(cur, cmd.getLongArg(1)); else - arg = to_utf8(cmd.argument()); - if (!tabularFeatures(cur, arg)) cur.undispatched(); break; - } + + case LFUN_TABULAR_FEATURE: + tabularFeatures(cur, to_utf8(cmd.argument())); + break; // insert file functions case LFUN_FILE_INSERT_PLAINTEXT_PARA: @@ -4416,6 +4480,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_FONT_SIZE: case LFUN_FONT_UNDERLINE: case LFUN_FONT_STRIKEOUT: + case LFUN_FONT_CROSSOUT: case LFUN_FONT_UNDERUNDERLINE: case LFUN_FONT_UNDERWAVE: case LFUN_LANGUAGE: @@ -4464,25 +4529,9 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) } -// function sets an object as defined in func_status.h: -// states OK, Unknown, Disabled, On, Off. -bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, - FuncStatus & status) const +bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s, + string const & argument, FuncStatus & status) const { - 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; @@ -4498,8 +4547,6 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return true; } - string const argument = cmd.getLongArg(2); - row_type sel_row_start = 0; row_type sel_row_end = 0; col_type sel_col_start = 0; @@ -4614,9 +4661,13 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::SET_LINE_TOP: case Tabular::SET_LINE_BOTTOM: + status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + break; + case Tabular::SET_LINE_LEFT: case Tabular::SET_LINE_RIGHT: - status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setEnabled(!tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); break; case Tabular::TOGGLE_LINE_TOP: @@ -4630,12 +4681,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::TOGGLE_LINE_LEFT: - status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setEnabled(!tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.leftLine(cur.idx())); break; case Tabular::TOGGLE_LINE_RIGHT: - status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx()))); + status.setEnabled(!tabular.use_booktabs + && !tabular.ltCaption(tabular.cellRow(cur.idx()))); status.setOnOff(tabular.rightLine(cur.idx())); break; @@ -4644,12 +4697,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, // therefore allow always left but right and center only if there is no width case Tabular::M_ALIGN_LEFT: flag = false; + // fall through case Tabular::ALIGN_LEFT: status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_LEFT); break; case Tabular::M_ALIGN_RIGHT: flag = false; + // fall through case Tabular::ALIGN_RIGHT: status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); @@ -4658,6 +4713,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_ALIGN_CENTER: flag = false; + // fall through case Tabular::ALIGN_CENTER: status.setEnabled(!(tabular.isMultiRow(cur.idx()) && !tabular.getPWidth(cur.idx()).zero())); @@ -4678,6 +4734,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_TOP: flag = false; + // fall through case Tabular::VALIGN_TOP: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4687,6 +4744,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_BOTTOM: flag = false; + // fall through case Tabular::VALIGN_BOTTOM: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4696,6 +4754,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, case Tabular::M_VALIGN_MIDDLE: flag = false; + // fall through case Tabular::VALIGN_MIDDLE: status.setEnabled(!tabular.getPWidth(cur.idx()).zero() && !tabular.isMultiRow(cur.idx())); @@ -4704,6 +4763,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; case Tabular::SET_LONGTABULAR: + case Tabular::TOGGLE_LONGTABULAR: // setting as longtable is not allowed when table is inside a float if (cur.innerInsetOfType(FLOAT_CODE) != 0 || cur.innerInsetOfType(WRAP_CODE) != 0) @@ -4852,6 +4912,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setOnOff(tabular.ltCaption(sel_row_start)); break; + case Tabular::TOGGLE_BOOKTABS: case Tabular::SET_BOOKTABS: status.setOnOff(tabular.use_booktabs); break; @@ -4866,6 +4927,39 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, break; } return true; +} + + +// function sets an object as defined in FuncStatus.h: +// states OK, Unknown, Disabled, On, Off. +bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, + FuncStatus & status) const +{ + switch (cmd.action()) { + case LFUN_INSET_MODIFY: + if (cmd.getArg(0) != "tabular") + break; + if (cmd.getArg(1) == "for-dialog") { + // The dialog is asking the status of a command + if (&cur.inset() != this) + break; + string action = cmd.getArg(2); + string arg = cmd.getLongArg(3); + return getFeatureStatus(cur, action, arg, status); + } else { + // 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. + status.setEnabled(true); + return true; + } + + case LFUN_TABULAR_FEATURE: { + if (&cur.inset() != this) + break; + string action = cmd.getArg(0); + string arg = cmd.getLongArg(1); + return getFeatureStatus(cur, action, arg, status); } case LFUN_CAPTION_INSERT: { @@ -4882,7 +4976,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, } // check if there is already a caption bool have_caption = false; - InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get()); + InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx())); ParagraphList::const_iterator pit = itc.paragraphs().begin(); ParagraphList::const_iterator pend = itc.paragraphs().end(); for (; pit != pend; ++pit) { @@ -4939,7 +5033,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(false); return true; } - // Fall back + // fall through case LFUN_NEWLINE_INSERT: { if (tabular.getPWidth(cur.idx()).zero()) { status.setEnabled(false); @@ -5053,13 +5147,7 @@ docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const 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; }"); + features.useInsetLayout(getLayout()); } @@ -5083,7 +5171,7 @@ void InsetTabular::cursorPos(BufferView const & bv, // y offset correction y += cellYPos(sl.idx()); y += tabular.textVOffset(sl.idx()); - y += offset_valign_; + y += tabular.offsetVAlignment(); // x offset correction x += cellXPos(sl.idx()); @@ -5126,7 +5214,6 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const Inset * InsetTabular::editXY(Cursor & cur, int x, int y) { //lyxerr << "InsetTabular::editXY: " << this << endl; - cur.setSelection(false); cur.push(*this); cur.idx() = getNearestCell(cur.bv(), x, y); return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y); @@ -5293,23 +5380,23 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) } -bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) +void InsetTabular::tabularFeatures(Cursor & cur, string const & argument) { + cur.recordUndoInset(this); + istringstream is(argument); + // limit the size of strings we read to avoid memory problems + is >> setw(65636); string s; - is >> s; - if (insetCode(s) != TABULAR_CODE) - return false; - // Safe guard. size_t safe_guard = 0; for (;;) { if (is.eof()) - break; + return; safe_guard++; if (safe_guard > 1000) { LYXERR0("parameter max count reached!"); - break; + return; } is >> s; Tabular::Feature action = Tabular::LAST_ACTION; @@ -5331,7 +5418,6 @@ bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) LYXERR(Debug::DEBUG, "Feature: " << s << "\t\tvalue: " << val); tabularFeatures(cur, action, val); } - return true; } @@ -5426,8 +5512,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } - cur.recordUndoInset(this); - getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end); row_type const row = tabular.cellRow(cur.idx()); col_type const column = tabular.cellColumn(cur.idx()); @@ -5490,7 +5574,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(sel_row_start, column); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; case Tabular::DELETE_COLUMN: @@ -5513,7 +5597,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(row, sel_col_start); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; case Tabular::COPY_ROW: @@ -5603,6 +5687,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::M_VALIGN_BOTTOM: case Tabular::M_VALIGN_MIDDLE: flag = false; + // fall through case Tabular::VALIGN_TOP: case Tabular::VALIGN_BOTTOM: case Tabular::VALIGN_MIDDLE: @@ -5629,7 +5714,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.rightLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5686,7 +5771,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.getAlignment(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5725,6 +5810,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::SET_ALL_LINES: setLines = true; + // fall through case Tabular::UNSET_ALL_LINES: for (row_type r = sel_row_start; r <= sel_row_end; ++r) for (col_type c = sel_col_start; c <= sel_col_end; ++c) { @@ -5747,6 +5833,13 @@ void InsetTabular::tabularFeatures(Cursor & cur, } break; + case Tabular::TOGGLE_LONGTABULAR: + if (tabular.is_long_tabular) + tabularFeatures(cur, Tabular::UNSET_LONGTABULAR); + else + tabular.is_long_tabular = true; + break; + case Tabular::SET_LONGTABULAR: tabular.is_long_tabular = true; break; @@ -5842,6 +5935,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTFIRSTHEAD: flag = false; + // fall through case Tabular::SET_LTFIRSTHEAD: tabular.getRowOfLTFirstHead(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5850,6 +5944,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTHEAD: flag = false; + // fall through case Tabular::SET_LTHEAD: tabular.getRowOfLTHead(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5858,6 +5953,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTFOOT: flag = false; + // fall through case Tabular::SET_LTFOOT: tabular.getRowOfLTFoot(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5866,6 +5962,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTLASTFOOT: flag = false; + // fall through case Tabular::SET_LTLASTFOOT: tabular.getRowOfLTLastFoot(row, ltt); checkLongtableSpecial(ltt, value, flag); @@ -5874,6 +5971,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, case Tabular::UNSET_LTNEWPAGE: flag = false; + // fall through case Tabular::SET_LTNEWPAGE: tabular.setLTNewPage(row, flag); break; @@ -5884,7 +5982,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.setLTCaption(row, true); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); // If a row is set as caption, then also insert // a caption. Otherwise the LaTeX output is broken. // Select cell if it is non-empty @@ -5900,7 +5998,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.setLTCaption(row, false); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); FuncRequest fr(LFUN_INSET_DISSOLVE, "caption"); if (lyx::getStatus(fr).enabled()) lyx::dispatch(fr); @@ -5915,6 +6013,10 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } + case Tabular::TOGGLE_BOOKTABS: + tabular.use_booktabs = !tabular.use_booktabs; + break; + case Tabular::SET_BOOKTABS: tabular.use_booktabs = true; break; @@ -6072,6 +6174,7 @@ bool InsetTabular::pasteClipboard(Cursor & cur) inset->setChange(Change(buffer().params().track_changes ? Change::INSERTED : Change::UNCHANGED)); cur.pos() = 0; + cur.pit() = 0; } } return true;