X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathGrid.cpp;h=16e519c11f42544fbdae3e64b479221c9fb3af9b;hb=c9609fe56a2deb40f001503c2fd707c990a2e0e2;hp=2883309cf8b280c078e7091761057c499c7727df;hpb=b62b366a6709a034adc8dcbeb8add559e3a70c39;p=lyx.git diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index 2883309cf8..16e519c11f 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -13,11 +13,13 @@ #include "InsetMathGrid.h" +#include "InsetMathUnknown.h" #include "MathData.h" #include "MathParser.h" #include "MathStream.h" #include "MetricsInfo.h" +#include "Buffer.h" #include "BufferView.h" #include "CutAndPaste.h" #include "FuncStatus.h" @@ -41,6 +43,7 @@ using namespace std; using namespace lyx::support; + namespace lyx { static docstring verboseHLine(int n) @@ -65,9 +68,9 @@ static int extractInt(istream & is) static void resetGrid(InsetMathGrid & grid) { while (grid.ncols() > 1) - grid.delCol(grid.ncols()); + grid.delCol(grid.ncols() - 1); while (grid.nrows() > 1) - grid.delRow(grid.nrows()); + grid.delRow(grid.nrows() - 1); grid.cell(0).erase(0, grid.cell(0).size()); grid.setDefaults(); } @@ -112,8 +115,8 @@ InsetMathGrid::ColInfo::ColInfo() ////////////////////////////////////////////////////////////// -InsetMathGrid::InsetMathGrid() - : InsetMathNest(1), +InsetMathGrid::InsetMathGrid(Buffer * buf) + : InsetMathNest(buf, 1), rowinfo_(1 + 1), colinfo_(1 + 1), cellinfo_(1), @@ -123,8 +126,8 @@ InsetMathGrid::InsetMathGrid() } -InsetMathGrid::InsetMathGrid(col_type m, row_type n) - : InsetMathNest(m * n), +InsetMathGrid::InsetMathGrid(Buffer * buf, col_type m, row_type n) + : InsetMathNest(buf, m * n), rowinfo_(n + 1), colinfo_(m + 1), cellinfo_(m * n), @@ -134,8 +137,9 @@ InsetMathGrid::InsetMathGrid(col_type m, row_type n) } -InsetMathGrid::InsetMathGrid(col_type m, row_type n, char v, docstring const & h) - : InsetMathNest(m * n), +InsetMathGrid::InsetMathGrid(Buffer * buf, col_type m, row_type n, char v, + docstring const & h) + : InsetMathNest(buf, m * n), rowinfo_(n + 1), colinfo_(m + 1), cellinfo_(m * n), @@ -173,6 +177,22 @@ void InsetMathGrid::setDefaults() } +bool InsetMathGrid::interpretString(Cursor & cur, docstring const & str) +{ + if (str == "\\hline") { + FuncRequest fr = FuncRequest(LFUN_INSET_MODIFY, "tabular add-hline-above"); + FuncStatus status; + if (getStatus(cur, fr, status)) { + if (status.enabled()) { + rowinfo_[cur.row()].lines_++; + return true; + } + } + } + return InsetMathNest::interpretString(cur, str); +} + + void InsetMathGrid::setHorizontalAlignments(docstring const & hh) { col_type col = 0; @@ -378,8 +398,8 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const // compute vertical offsets rowinfo_[0].offset_ = 0; for (row_type row = 1; row <= nrows(); ++row) { - rowinfo_[row].offset_ = - rowinfo_[row - 1].offset_ + + rowinfo_[row].offset_ = + rowinfo_[row - 1].offset_ + rowinfo_[row - 1].descent_ + rowinfo_[row - 1].skipPixels(mi) + rowsep() + @@ -424,20 +444,20 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const } - dim.wid = colinfo_[ncols() - 1].offset_ - + colinfo_[ncols() - 1].width_ - + vlinesep() * colinfo_[ncols()].lines_ - + border(); + dim.wid = colinfo_[ncols() - 1].offset_ + + colinfo_[ncols() - 1].width_ + + vlinesep() * colinfo_[ncols()].lines_ + + border(); - dim.asc = - rowinfo_[0].offset_ - + rowinfo_[0].ascent_ - + hlinesep() * rowinfo_[0].lines_ - + border(); + dim.asc = - rowinfo_[0].offset_ + + rowinfo_[0].ascent_ + + hlinesep() * rowinfo_[0].lines_ + + border(); - dim.des = rowinfo_[nrows() - 1].offset_ - + rowinfo_[nrows() - 1].descent_ - + hlinesep() * rowinfo_[nrows()].lines_ - + border(); + dim.des = rowinfo_[nrows() - 1].offset_ + + rowinfo_[nrows() - 1].descent_ + + hlinesep() * rowinfo_[nrows()].lines_ + + border(); /* @@ -633,7 +653,16 @@ void InsetMathGrid::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const } -docstring InsetMathGrid::eolString(row_type row, bool fragile) const +void InsetMathGrid::updateBuffer(ParIterator const & it, UpdateType utype) +{ + // pass down + for (idx_type idx = 0; idx < nargs(); ++idx) + cell(idx).updateBuffer(it, utype); +} + + +docstring InsetMathGrid::eolString(row_type row, bool fragile, + bool /*latex*/, bool last_eoln) const { docstring eol; @@ -645,13 +674,13 @@ docstring InsetMathGrid::eolString(row_type row, bool fragile) const // make sure an upcoming '[' does not break anything if (row + 1 < nrows()) { MathData const & c = cell(index(row + 1, 0)); - if (c.size() && c.front()->getChar() == '[') + if (!c.empty() && c.front()->getChar() == '[') //eol += "[0pt]"; eol += "{}"; } // only add \\ if necessary - if (eol.empty() && row + 1 == nrows()) + if (eol.empty() && row + 1 == nrows() && (nrows() == 1 || !last_eoln)) return docstring(); return (fragile ? "\\protect\\\\" : "\\\\") + eol; @@ -676,17 +705,6 @@ void InsetMathGrid::addRow(row_type row) } -void InsetMathGrid::appendRow() -{ - rowinfo_.push_back(RowInfo()); - //cells_.insert(cells_.end(), ncols(), MathData()); - for (col_type col = 0; col < ncols(); ++col) { - cells_.push_back(cells_type::value_type()); - cellinfo_.push_back(CellInfo()); - } -} - - void InsetMathGrid::delRow(row_type row) { if (nrows() == 1) @@ -787,7 +805,7 @@ int InsetMathGrid::cellXOffset(BufferView const & bv, idx_type idx) const { col_type c = col(idx); int x = colinfo_[c].offset_; - char align = colinfo_[c].align_; + char align = displayColAlign(c, row(idx)); Dimension const & celldim = cell(idx).dimension(bv); if (align == 'r' || align == 'R') x += colinfo_[c].width_ - celldim.wid; @@ -887,7 +905,7 @@ bool InsetMathGrid::idxDelete(idx_type & idx) // try to delete entire sequence of ncols() empty cells if possible for (idx_type i = idx; i < idx + ncols(); ++i) - if (cell(i).size()) + if (!cell(i).empty()) return false; // move cells if necessary @@ -968,14 +986,52 @@ void InsetMathGrid::normalize(NormalStream & os) const void InsetMathGrid::mathmlize(MathStream & os) const { - os << MTag("mtable"); + bool const havetable = nrows() > 1 || ncols() > 1; + if (havetable) + os << MTag("mtable"); + char const * const celltag = havetable ? "mtd" : "mrow"; for (row_type row = 0; row < nrows(); ++row) { - os << MTag("mtr"); - for (col_type col = 0; col < ncols(); ++col) + if (havetable) + os << MTag("mtr"); + for (col_type col = 0; col < ncols(); ++col) { + os << MTag(celltag); os << cell(index(row, col)); - os << ETag("mtr"); + os << ETag(celltag); + } + if (havetable) + os << ETag("mtr"); } - os << ETag("mtable"); + if (havetable) + os << ETag("mtable"); +} + + +// FIXME XHTML +// We need to do something about alignment here. +void InsetMathGrid::htmlize(HtmlStream & os, string attrib) const +{ + bool const havetable = nrows() > 1 || ncols() > 1; + if (!havetable) { + os << cell(index(0, 0)); + return; + } + os << MTag("table", attrib); + for (row_type row = 0; row < nrows(); ++row) { + os << MTag("tr"); + for (col_type col = 0; col < ncols(); ++col) { + os << MTag("td"); + os << cell(index(row, col)); + os << ETag("td"); + } + os << ETag("tr"); + } + os << ETag("table"); +} + + +void InsetMathGrid::htmlize(HtmlStream & os) const +{ + htmlize(os, "class='mathtable'"); } @@ -992,25 +1048,32 @@ void InsetMathGrid::write(WriteStream & os, docstring eol; for (row_type row = beg_row; row < end_row; ++row) { os << verboseHLine(rowinfo_[row].lines_); - // don't write & and empty cells at end of line + // don't write & and empty cells at end of line, + // unless there are vertical lines col_type lastcol = 0; bool emptyline = true; - for (col_type col = beg_col; col < end_col; ++col) - if (!cell(index(row, col)).empty()) { + bool last_eoln = true; + for (col_type col = beg_col; col < end_col; ++col) { + bool const empty_cell = cell(index(row, col)).empty(); + if (!empty_cell) + last_eoln = false; + if (!empty_cell || colinfo_[col + 1].lines_) { lastcol = col + 1; emptyline = false; } + } for (col_type col = beg_col; col < lastcol; ++col) { os << cell(index(row, col)); if (os.pendingBrace()) ModeSpecifier specifier(os, TEXT_MODE); os << eocString(col, lastcol); } - eol = eolString(row, os.fragile()); + eol = eolString(row, os.fragile(), os.latex(), last_eoln); os << eol; // append newline only if line wasn't completely empty - // and this was not the last line in the grid - if (!emptyline && row + 1 < end_row) + // and the formula is not written on a single line + bool const empty = emptyline && eol.empty(); + if (!empty && nrows() > 1) os << "\n"; } // @TODO use end_row instead of nrows() ? @@ -1075,10 +1138,11 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) Parse::flags parseflg = Parse::QUIET | Parse::USETEXT; - switch (cmd.action) { + FuncCode const act = cmd.action(); + switch (act) { // insert file functions - case LFUN_LINE_DELETE: + case LFUN_LINE_DELETE_FORWARD: cur.recordUndoInset(); //autocorrect_ = false; //macroModeClose(); @@ -1133,18 +1197,23 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) if (cur.idx() > 0) --cur.idx(); cur.pos() = cur.lastpos(); - + cur.forceBufferUpdate(); //mathcursor->normalize(); //cmd = FuncRequest(LFUN_FINISHED_BACKWARD); break; } - case LFUN_TABULAR_FEATURE: { + case LFUN_INSET_MODIFY: { cur.recordUndoInset(); //lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl; istringstream is(to_utf8(cmd.argument())); string s; is >> s; + if (s != "tabular") { + InsetMathNest::doDispatch(cur, cmd); + return; + } + is >> s; if (s == "valign-top") setVerticalAlignment('t'); else if (s == "valign-middle") @@ -1233,7 +1302,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) docstring & special = colinfo_[cur.col()].special_; if (!special.empty()) { docstring::size_type i = special.rfind('|'); - LASSERT(i != docstring::npos, /**/); + LASSERT(i != docstring::npos, break); special.erase(i, 1); } } @@ -1242,7 +1311,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) docstring & special = colinfo_[cur.col()+1].special_; if (!special.empty()) { docstring::size_type i = special.find('|'); - LASSERT(i != docstring::npos, /**/); + LASSERT(i != docstring::npos, break); special.erase(i, 1); } } @@ -1265,27 +1334,40 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) cap::replaceSelection(cur); docstring topaste; if (cmd.argument().empty() && !theClipboard().isInternal()) - topaste = theClipboard().getAsText(); + topaste = theClipboard().getAsText(Clipboard::PlainTextType); else { idocstringstream is(cmd.argument()); int n = 0; is >> n; topaste = cap::selection(n); } - InsetMathGrid grid(1, 1); + InsetMathGrid grid(buffer_, 1, 1); if (!topaste.empty()) - if ((topaste.size() == 1 && topaste.at(0) < 0x80) + if ((topaste.size() == 1 && isAscii(topaste)) || !mathed_parse_normal(grid, topaste, parseflg)) { resetGrid(grid); - mathed_parse_normal(grid, topaste, - parseflg | Parse::VERBATIM); + mathed_parse_normal(grid, topaste, parseflg | Parse::VERBATIM); } + bool hline_enabled = false; + FuncRequest fr = FuncRequest(LFUN_INSET_MODIFY, "tabular add-hline-above"); + FuncStatus status; + if (getStatus(cur, fr, status)) + hline_enabled = status.enabled(); if (grid.nargs() == 1) { // single cell/part of cell - cur.recordUndo(); + cur.recordUndoInset(); cur.cell().insert(cur.pos(), grid.cell(0)); cur.pos() += grid.cell(0).size(); + if (hline_enabled) + rowinfo_[cur.row()].lines_ += grid.rowinfo_[0].lines_; + else { + for (unsigned int l = 0; l < grid.rowinfo_[0].lines_; ++l) { + cur.cell().insert(0, + MathAtom(new InsetMathUnknown(from_ascii("\\hline")))); + cur.pos()++; + } + } } else { // multiple cells cur.recordUndoInset(); @@ -1298,6 +1380,15 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) idx_type i = index(r + cur.row(), c + col(cur.idx())); cell(i).insert(0, grid.cell(grid.index(r, c))); } + if (hline_enabled) + rowinfo_[r].lines_ += grid.rowinfo_[r].lines_; + else { + for (unsigned int l = 0; l < grid.rowinfo_[r].lines_; ++l) { + idx_type i = index(r + cur.row(), 0); + cell(i).insert(0, + MathAtom(new InsetMathUnknown(from_ascii("\\hline")))); + } + } // append the left over horizontal cells to the last column idx_type i = index(r + cur.row(), ncols() - 1); for (InsetMath::col_type c = numcols; c < grid.ncols(); ++c) @@ -1305,11 +1396,23 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) } // append the left over vertical cells to the last _cell_ idx_type i = nargs() - 1; - for (row_type r = numrows; r < grid.nrows(); ++r) + for (row_type r = numrows; r < grid.nrows(); ++r) { for (col_type c = 0; c < grid.ncols(); ++c) cell(i).append(grid.cell(grid.index(r, c))); + if (hline_enabled) + rowinfo_[r].lines_ += grid.rowinfo_[r].lines_; + else { + for (unsigned int l = 0; l < grid.rowinfo_[r].lines_; ++l) { + cell(i).insert(0, + MathAtom(new InsetMathUnknown(from_ascii("\\hline")))); + } + } + } } cur.clearSelection(); // bug 393 + // FIXME audit setBuffer calls + cur.inset().setBuffer(*buffer_); + cur.forceBufferUpdate(); cur.finishUndo(); break; } @@ -1320,9 +1423,9 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_WORD_BACKWARD: case LFUN_WORD_LEFT_SELECT: case LFUN_WORD_LEFT: - cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT || - cmd.action == LFUN_WORD_LEFT_SELECT || - cmd.action == LFUN_LINE_BEGIN_SELECT); + cur.selHandle(act == LFUN_WORD_BACKWARD_SELECT || + act == LFUN_WORD_LEFT_SELECT || + act == LFUN_LINE_BEGIN_SELECT); cur.macroModeClose(); if (cur.pos() != 0) { cur.pos() = 0; @@ -1344,9 +1447,9 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_WORD_RIGHT: case LFUN_LINE_END_SELECT: case LFUN_LINE_END: - cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT || - cmd.action == LFUN_WORD_RIGHT_SELECT || - cmd.action == LFUN_LINE_END_SELECT); + cur.selHandle(act == LFUN_WORD_FORWARD_SELECT || + act == LFUN_WORD_RIGHT_SELECT || + act == LFUN_LINE_END_SELECT); cur.macroModeClose(); cur.clearTargetX(); if (cur.pos() != cur.lastpos()) { @@ -1372,9 +1475,23 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { - switch (cmd.action) { - case LFUN_TABULAR_FEATURE: { - string const s = cmd.getArg(0); + switch (cmd.action()) { + case LFUN_INSET_MODIFY: { + istringstream is(to_utf8(cmd.argument())); + string s; + is >> s; + if (s != "tabular") { + // We only now about table actions here. + break; + } + if (&cur.inset() != this) { + // Table actions requires that the cursor is _inside_ the + // table. + status.setEnabled(false); + status.message(from_utf8(N_("Cursor not in table"))); + return true; + } + is >> s; if (nrows() <= 1 && (s == "delete-row" || s == "swap-row")) { status.setEnabled(false); status.message(from_utf8(N_("Only one row"))); @@ -1455,7 +1572,7 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, } case LFUN_CELL_SPLIT: - status.setEnabled(true); + status.setEnabled(cur.idx() != cur.lastidx()); return true; case LFUN_CELL_BACKWARD: @@ -1464,8 +1581,9 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, return true; default: - return InsetMathNest::getStatus(cur, cmd, status); + break; } + return InsetMathNest::getStatus(cur, cmd, status); }