X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2FInsetTabular.cpp;h=88817357c16c663aa91c5aeef8ef3777ec457c80;hb=50060053e36b3e9dfe03bc33ed3abac1eacc54b0;hp=ac8e723d87cfc3f4a3acf5b970713ba703be1c1c;hpb=7f7dc5d314791ed6894d9d18cda032f32093af21;p=lyx.git diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index ac8e723d87..88817357c1 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -45,6 +45,8 @@ #include "Paragraph.h" #include "ParagraphParameters.h" #include "ParIterator.h" +#include "TexRow.h" +#include "texstream.h" #include "TextClass.h" #include "TextMetrics.h" @@ -61,8 +63,7 @@ #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" - -#include +#include "support/unique_ptr.h" #include #include @@ -96,7 +97,7 @@ int const WIDTH_OF_LINE = 5; // space between double lines /// -boost::scoped_ptr paste_tabular; +unique_ptr paste_tabular; struct TabularFeature { @@ -110,6 +111,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 +154,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 +181,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 +527,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 +543,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); @@ -652,7 +657,7 @@ Tabular::ColumnData::ColumnData() Tabular::ltType::ltType() - : topDL(false), + : set(false), topDL(false), bottomDL(false), empty(false) {} @@ -1028,7 +1033,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 +1104,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); } } @@ -1123,7 +1128,6 @@ namespace { */ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) { - inset->setAutoBreakRows(fixedWidth); inset->toggleFixedWidth(fixedWidth); if (fixedWidth) return; @@ -1318,6 +1322,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)) @@ -1666,7 +1691,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)]; } @@ -1688,7 +1719,8 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, cs.alignment = column_info[col].alignment; setRightLine(cell, right_border); - for (idx_type i = 1; i < number; ++i) { + idx_type lastcell = cellIndex(row, col + number - 1); + for (idx_type i = 1; i < lastcell - cell + 1; ++i) { CellData & cs1 = cellInfo(cell + i); cs1.multicolumn = CELL_PART_OF_MULTICOLUMN; cs.inset->appendParagraphs(cs1.inset->paragraphs()); @@ -2305,7 +2337,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 +2562,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 +2601,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 +2634,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)); @@ -2673,14 +2708,15 @@ 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) os << "\\begin{turn}{" << convert(rotate) << "}\n"; @@ -2726,6 +2762,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 +2777,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: @@ -2809,6 +2871,9 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const if (rotate != 0) os << breakln << "\\end{turn}"; + + if (!TexRow::isNone(pos)) + os.texrow().start(pos); } @@ -2976,6 +3041,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 +3079,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 +3382,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; @@ -3390,18 +3467,17 @@ bool InsetTableCell::allowParagraphCustomization(idx_type) const } +bool InsetTableCell::forceLocalFontSwitch() const +{ + return isFixedWidth; +} + + bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { 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; @@ -3433,9 +3509,10 @@ docstring InsetTableCell::asString(bool intoInsets) } -void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const +void InsetTableCell::addToToc(DocIterator const & di, bool output_active, + UpdateType utype, TocBackend & backend) const { - InsetText::iterateForToc(di, output_active); + InsetText::iterateForToc(di, output_active, utype, backend); } @@ -3456,14 +3533,15 @@ 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))), scx_(0), - rowselect_(false), colselect_(false) + : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), + rowselect_(false), colselect_(false) { } InsetTabular::InsetTabular(InsetTabular const & tab) - : Inset(tab), tabular(tab.tabular), scx_(0) + : Inset(tab), tabular(tab.tabular), + rowselect_(false), colselect_(false) { } @@ -3502,7 +3580,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"); } @@ -3550,7 +3628,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) @@ -3590,7 +3668,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.textwidth); + m.base.textwidth = p_width.inPixels(mi.base); tabular.cellInset(cell)->metrics(m, dim); if (!p_width.zero()) dim.wid = m.base.textwidth; @@ -3604,7 +3682,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) @@ -3651,31 +3729,16 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const } 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.row_info[r].top_space.inPixels(mi.base); 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.row_info[r].bottom_space.inPixels(mi.base); 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; } @@ -3714,11 +3777,10 @@ bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) void InsetTabular::draw(PainterInfo & pi, int x, int y) const { - x += scx_ + ADD_TO_TABULAR_WIDTH; + x += ADD_TO_TABULAR_WIDTH; BufferView * bv = pi.base.bv; Cursor & cur = pi.base.bv->cursor(); - resetPos(cur); // FIXME: As the full background is painted in drawBackground(), // we have no choice but to do a full repaint for the Text cells. @@ -3727,9 +3789,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) { @@ -3743,9 +3804,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); @@ -3766,8 +3824,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const { - x += scx_ + ADD_TO_TABULAR_WIDTH; - y += offset_valign_ - tabular.rowAscent(0); + x += ADD_TO_TABULAR_WIDTH; + y += tabular.offsetVAlignment() - tabular.rowAscent(0); pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(), pi.backgroundColor(this)); } @@ -3776,9 +3834,8 @@ void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const { Cursor & cur = pi.base.bv->cursor(); - resetPos(cur); - x += scx_ + ADD_TO_TABULAR_WIDTH; + x += ADD_TO_TABULAR_WIDTH; if (!cur.selection()) return; @@ -3805,7 +3862,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; @@ -3875,7 +3932,6 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection) { //lyxerr << "InsetTabular::edit: " << this << endl; cur.finishUndo(); - cur.setSelection(false); cur.push(*this); if (front) { if (isRightToLeft(cur)) @@ -3894,7 +3950,6 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection) } cur.setCurrentFont(); // FIXME: this accesses the position cache before it is initialized - //resetPos(cur); //cur.bv().fitCursor(); } @@ -3925,13 +3980,37 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype) } -void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const +void InsetTabular::addToToc(DocIterator const & cpit, bool output_active, + 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); + 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); } @@ -3949,30 +4028,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; @@ -4005,7 +4085,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 @@ -4017,7 +4097,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 @@ -4026,7 +4106,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()) { @@ -4043,12 +4123,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: @@ -4155,9 +4235,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) else movePrevCell(cur, entry_from); // if we're exiting the table, call the appropriate FINISHED lfun - if (sl == cur.top()) + if (sl == cur.top()) { cmd = FuncRequest(finish_lfun); - else + cur.undispatched(); + } else cur.dispatched(); cur.screenUpdateFlags(Update::Force | Update::FitCursor); @@ -4244,55 +4325,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: @@ -4459,25 +4506,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; @@ -4493,8 +4524,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; @@ -4609,9 +4638,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: @@ -4625,12 +4658,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; @@ -4699,6 +4734,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) @@ -4847,6 +4883,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; @@ -4861,6 +4898,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: { @@ -4877,7 +4947,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) { @@ -4934,6 +5004,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(false); return true; } + // Fall back case LFUN_NEWLINE_INSERT: { if (tabular.getPWidth(cur.idx()).zero()) { status.setEnabled(false); @@ -5047,13 +5118,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()); } @@ -5077,13 +5142,12 @@ 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()); x += tabular.textHOffset(sl.idx()); x += ADD_TO_TABULAR_WIDTH; - x += scx_; } @@ -5121,10 +5185,8 @@ 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); - resetPos(cur); return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y); } @@ -5174,36 +5236,6 @@ int InsetTabular::cellXPos(idx_type const cell) const } -void InsetTabular::resetPos(Cursor & cur) const -{ - BufferView & bv = cur.bv(); - int const maxwidth = bv.workWidth(); - - int const scx_old = scx_; - int const i = cur.find(this); - if (i == -1) { - scx_ = 0; - } else { - int const X1 = 0; - 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.cellWidth(cur[i].idx()); - - if (x1 < X1) - scx_ = X1 + 20 - x1; - else if (x2 > X2) - scx_ = X2 - 20 - x2; - else - scx_ = 0; - } - - // only update if offset changed - if (scx_ != scx_old) - cur.screenUpdateFlags(Update::Force | Update::FitCursor); -} - - void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) { row_type const row = tabular.cellRow(cur.idx()); @@ -5238,7 +5270,6 @@ void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) if (cur.selIsMultiCell()) { cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - resetPos(cur); return; } @@ -5261,7 +5292,6 @@ void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from) } cur.setCurrentFont(); - resetPos(cur); } @@ -5296,7 +5326,6 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) if (cur.selIsMultiCell()) { cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - resetPos(cur); return; } @@ -5319,27 +5348,24 @@ void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from) } cur.setCurrentFont(); - resetPos(cur); } -bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) +void InsetTabular::tabularFeatures(Cursor & cur, string const & argument) { + cur.recordUndoInset(this); + istringstream is(argument); 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; @@ -5361,7 +5387,6 @@ bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument) LYXERR(Debug::DEBUG, "Feature: " << s << "\t\tvalue: " << val); tabularFeatures(cur, action, val); } - return true; } @@ -5434,10 +5459,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; case Tabular::ALIGN_DECIMAL: - if (tabular.column_info[tabular.cellColumn(cur.idx())].alignment == LYX_ALIGN_DECIMAL) - setAlign = LYX_ALIGN_CENTER; - else - setAlign = LYX_ALIGN_DECIMAL; + setAlign = LYX_ALIGN_DECIMAL; break; case Tabular::M_VALIGN_TOP: @@ -5459,8 +5481,6 @@ void InsetTabular::tabularFeatures(Cursor & cur, break; } - 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()); col_type const column = tabular.cellColumn(cur.idx()); @@ -5523,7 +5543,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: @@ -5546,7 +5566,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: @@ -5662,7 +5682,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.rightLine(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5719,7 +5739,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.getAlignment(cur.selEnd().idx())); cur.pit() = 0; cur.pos() = 0; - cur.setSelection(false); + cur.selection(false); break; } @@ -5780,6 +5800,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; @@ -5917,10 +5944,12 @@ 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. - lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL)); + // Select cell if it is non-empty + if (cur.lastpos() > 0 || cur.lastpit() > 0) + lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL)); lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT)); break; } @@ -5931,7 +5960,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); @@ -5946,6 +5975,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; @@ -6262,7 +6295,6 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, if (usePaste) { paste_tabular.reset(new Tabular(buffer_, rows, maxCols)); loctab = paste_tabular.get(); - cols = 0; dirtyTabularStack(true); } else { loctab = &tabular; @@ -6442,4 +6474,22 @@ string InsetTabular::params2string(InsetTabular const & inset) } +void InsetTabular::setLayoutForHiddenCells(DocumentClass const & dc) +{ + for (Tabular::col_type c = 0; c < tabular.ncols(); ++c) { + for (Tabular::row_type r = 0; r < tabular.nrows(); ++r) { + if (!tabular.isPartOfMultiColumn(r,c) && + !tabular.isPartOfMultiRow(r,c)) + continue; + + ParagraphList & parlist = tabular.cellInset(r,c)->paragraphs(); + ParagraphList::iterator it = parlist.begin(); + ParagraphList::iterator const en = parlist.end(); + for (; it != en; ++it) + it->setLayout(dc.plainLayout()); + } + } +} + + } // namespace lyx