X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fmathed%2FInsetMathGrid.cpp;h=e74d549c48506c91113e462d0345d2b518847664;hb=aafd52f44167d5510be1ddcb974daa9dae486933;hp=26319250ecd1600116095af274aa0324c1dbd262;hpb=f319fdbc2a4c8305d60f176566b818240066cfa9;p=lyx.git diff --git a/src/mathed/InsetMathGrid.cpp b/src/mathed/InsetMathGrid.cpp index 26319250ec..e74d549c48 100644 --- a/src/mathed/InsetMathGrid.cpp +++ b/src/mathed/InsetMathGrid.cpp @@ -3,54 +3,50 @@ * This file is part of LyX, the document processor. * Licence details can be found in the file COPYING. * - * \author André Pönitz + * \author André Pönitz * * Full author contact details are available in file CREDITS. */ #include +#include #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" -#include "Color.h" #include "Cursor.h" -#include "debug.h" #include "FuncRequest.h" -#include "gettext.h" -#include "Undo.h" #include "frontends/Clipboard.h" +#include "frontends/FontMetrics.h" #include "frontends/Painter.h" +#include "support/debug.h" +#include "support/docstream.h" +#include "support/gettext.h" #include "support/lstrings.h" -#include - +#include "support/lassert.h" -namespace lyx { - -using support::bformat; +#include -using std::endl; -using std::max; -using std::min; -using std::swap; +using namespace std; +using namespace lyx::support; -using std::string; -using std::istream; -using std::istringstream; -using std::vector; -namespace { +namespace lyx { -docstring verboseHLine(int n) +static docstring verboseHLine(int n) { docstring res; for (int i = 0; i < n; ++i) @@ -61,16 +57,26 @@ docstring verboseHLine(int n) } -int extractInt(istream & is) +static int extractInt(istream & is) { int num = 1; is >> num; return (num == 0) ? 1 : num; } + +static void resetGrid(InsetMathGrid & grid) +{ + while (grid.ncols() > 1) + grid.delCol(grid.ncols() - 1); + while (grid.nrows() > 1) + grid.delRow(grid.nrows() - 1); + grid.cell(0).erase(0, grid.cell(0).size()); + grid.setDefaults(); } + ////////////////////////////////////////////////////////////// @@ -80,19 +86,20 @@ InsetMathGrid::CellInfo::CellInfo() - ////////////////////////////////////////////////////////////// InsetMathGrid::RowInfo::RowInfo() - : lines_(0), skip_(0), allow_pagebreak_(true) + : lines_(0), skip_(0), allow_newpage_(true) {} -int InsetMathGrid::RowInfo::skipPixels() const +int InsetMathGrid::RowInfo::skipPixels(MetricsInfo const & mi) const { - return crskip_.inBP(); + frontend::FontMetrics const & fm = theFontMetrics(mi.base.font); + return crskip_.inPixels(mi.base.textwidth, + fm.width(char_type('M'))); } @@ -108,21 +115,8 @@ InsetMathGrid::ColInfo::ColInfo() ////////////////////////////////////////////////////////////// -InsetMathGrid::InsetMathGrid(char v, docstring const & h) - : InsetMathNest(guessColumns(h)), - rowinfo_(2), - colinfo_(guessColumns(h) + 1), - cellinfo_(1 * guessColumns(h)) -{ - setDefaults(); - valign(v); - halign(h); - //lyxerr << "created grid with " << ncols() << " columns" << endl; -} - - -InsetMathGrid::InsetMathGrid() - : InsetMathNest(1), +InsetMathGrid::InsetMathGrid(Buffer * buf) + : InsetMathNest(buf, 1), rowinfo_(1 + 1), colinfo_(1 + 1), cellinfo_(1), @@ -132,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), @@ -143,16 +137,17 @@ 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), v_align_(v) { setDefaults(); - valign(v); - halign(h); + setVerticalAlignment(v); + setHorizontalAlignments(h); } @@ -182,7 +177,23 @@ void InsetMathGrid::setDefaults() } -void InsetMathGrid::halign(docstring const & hh) +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; for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) { @@ -223,13 +234,11 @@ void InsetMathGrid::halign(docstring const & hh) } --it; if (newcolumn) { - colinfo_[col].lines_ = std::count( + colinfo_[col].lines_ = count( colinfo_[col].special_.begin(), colinfo_[col].special_.end(), '|'); - LYXERR(Debug::MATHED) - << "special column separator: `" - << to_utf8(colinfo_[col].special_) - << '\'' << endl; + LYXERR(Debug::MATHED, "special column separator: `" + << to_utf8(colinfo_[col].special_) << '\''); ++col; colinfo_[col].lines_ = 0; colinfo_[col].special_.clear(); @@ -242,13 +251,11 @@ void InsetMathGrid::halign(docstring const & hh) colinfo_[col].align_ = static_cast(c); if (!colinfo_[col].special_.empty()) { colinfo_[col].special_ += c; - colinfo_[col].lines_ = std::count( + colinfo_[col].lines_ = count( colinfo_[col].special_.begin(), colinfo_[col].special_.end(), '|'); - LYXERR(Debug::MATHED) - << "special column separator: `" - << to_utf8(colinfo_[col].special_) - << '\'' << endl; + LYXERR(Debug::MATHED, "special column separator: `" + << to_utf8(colinfo_[col].special_) << '\''); } ++col; colinfo_[col].lines_ = 0; @@ -268,7 +275,7 @@ void InsetMathGrid::halign(docstring const & hh) } -InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) const +InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) { col_type col = 0; for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) @@ -283,7 +290,7 @@ InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) const } -void InsetMathGrid::halign(char h, col_type col) +void InsetMathGrid::setHorizontalAlignment(char h, col_type col) { colinfo_[col].align_ = h; if (!colinfo_[col].special_.empty()) { @@ -295,13 +302,13 @@ void InsetMathGrid::halign(char h, col_type col) } -char InsetMathGrid::halign(col_type col) const +char InsetMathGrid::horizontalAlignment(col_type col) const { return colinfo_[col].align_; } -docstring InsetMathGrid::halign() const +docstring InsetMathGrid::horizontalAlignments() const { docstring res; for (col_type col = 0; col < ncols(); ++col) { @@ -317,13 +324,13 @@ docstring InsetMathGrid::halign() const } -void InsetMathGrid::valign(char c) +void InsetMathGrid::setVerticalAlignment(char c) { v_align_ = c; } -char InsetMathGrid::valign() const +char InsetMathGrid::verticalAlignment() const { return v_align_; } @@ -391,10 +398,10 @@ 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() + + rowinfo_[row - 1].skipPixels(mi) + rowsep() + rowinfo_[row].lines_ * hlinesep() + rowinfo_[row].ascent_; @@ -437,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(); /* @@ -504,14 +511,14 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const } */ metricsMarkers2(dim); - // Cache the inset dimension. + // Cache the inset dimension. setDimCache(mi, dim); } void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const { - drawWithMargin(pi, x, y, 0, 0); + drawWithMargin(pi, x, y, 1, 1); } @@ -531,7 +538,7 @@ void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y, - i * hlinesep() - hlinesep()/2 - rowsep()/2; pi.pain.line(x + lmargin + 1, yy, x + dim.width() - rmargin - 1, yy, - Color::foreground); + Color_foreground); } for (col_type col = 0; col <= ncols(); ++col) @@ -540,7 +547,7 @@ void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y, - i * vlinesep() - vlinesep()/2 - colsep()/2; pi.pain.line(xx, y - dim.ascent() + 1, xx, y + dim.descent() - 1, - Color::foreground); + Color_foreground); } drawMarkers2(pi, x, y); } @@ -577,7 +584,7 @@ void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const rowinfo_[row].offset_ = rowinfo_[row - 1].offset_ + rowinfo_[row - 1].descent_ + - //rowinfo_[row - 1].skipPixels() + + //rowinfo_[row - 1].skipPixels(mi) + 1 + //rowsep() + //rowinfo_[row].lines_ * hlinesep() + rowinfo_[row].ascent_; @@ -639,32 +646,41 @@ void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const } -void InsetMathGrid::drawT(TextPainter & pain, int x, int y) const +void InsetMathGrid::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const { // for (idx_type idx = 0; idx < nargs(); ++idx) // cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx)); } -docstring InsetMathGrid::eolString(row_type row, bool emptyline, 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; if (!rowinfo_[row].crskip_.zero()) eol += '[' + from_utf8(rowinfo_[row].crskip_.asLatexString()) + ']'; - else if(!rowinfo_[row].allow_pagebreak_) + else if(!rowinfo_[row].allow_newpage_) eol += '*'; // 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() && (nrows() == 1 || !emptyline)) + if (eol.empty() && row + 1 == nrows() && (nrows() == 1 || !last_eoln)) return docstring(); return (fragile ? "\\protect\\\\" : "\\\\") + eol; @@ -689,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) @@ -743,9 +748,9 @@ void InsetMathGrid::addCol(col_type newcol) for (row_type row = 0; row < nr; ++row) for (col_type col = 0; col < nc; ++col) { - new_cells[row * (nc + 1) + col + (col > newcol)] + new_cells[row * (nc + 1) + col + (col >= newcol)] = cells_[row * nc + col]; - new_cellinfo[row * (nc + 1) + col + (col > newcol)] + new_cellinfo[row * (nc + 1) + col + (col >= newcol)] = cellinfo_[row * nc + col]; } swap(cells_, new_cells); @@ -779,7 +784,7 @@ void InsetMathGrid::delCol(col_type col) void InsetMathGrid::copyCol(col_type col) { - addCol(col); + addCol(col+1); for (row_type row = 0; row < nrows(); ++row) cells_[row * ncols() + col + 1] = cells_[row * ncols() + col]; } @@ -800,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; @@ -827,14 +832,14 @@ bool InsetMathGrid::idxUpDown(Cursor & cur, bool up) const return false; cur.idx() += ncols(); } - cur.pos() = cur.cell().x2pos(cur.x_target() - cur.cell().xo(cur.bv())); + cur.pos() = cur.cell().x2pos(&cur.bv(), cur.x_target() - cur.cell().xo(cur.bv())); return true; } -bool InsetMathGrid::idxLeft(Cursor & cur) const +bool InsetMathGrid::idxBackward(Cursor & cur) const { - // leave matrix if on the left hand edge + // leave matrix if at the front edge if (cur.col() == 0) return false; --cur.idx(); @@ -843,9 +848,9 @@ bool InsetMathGrid::idxLeft(Cursor & cur) const } -bool InsetMathGrid::idxRight(Cursor & cur) const +bool InsetMathGrid::idxForward(Cursor & cur) const { - // leave matrix if on the right hand edge + // leave matrix if at the back edge if (cur.col() + 1 == ncols()) return false; ++cur.idx(); @@ -900,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 @@ -981,39 +986,97 @@ 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(celltag); + } + if (havetable) + os << ETag("mtr"); + } + 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("mtr"); + os << ETag("td"); + } + os << ETag("tr"); } - os << ETag("mtable"); + os << ETag("table"); +} + + +void InsetMathGrid::htmlize(HtmlStream & os) const +{ + htmlize(os, "class='mathtable'"); } void InsetMathGrid::write(WriteStream & os) const { + write(os, 0, 0, nrows(), ncols()); +} + +void InsetMathGrid::write(WriteStream & os, + row_type beg_row, col_type beg_col, + row_type end_row, col_type end_col) const +{ + MathEnsurer ensurer(os, false); docstring eol; - for (row_type row = 0; row < nrows(); ++row) { + 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 = 0; col < ncols(); ++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 = 0; col < lastcol; ++col) - os << cell(index(row, col)) << eocString(col, lastcol); - eol = eolString(row, emptyline, os.fragile()); + } + 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(), 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 < nrows()) + // 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() ? docstring const s = verboseHLine(rowinfo_[nrows()].lines_); if (!s.empty()) { if (eol.empty()) { @@ -1072,16 +1135,15 @@ void InsetMathGrid::splitCell(Cursor & cur) void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) { //lyxerr << "*** InsetMathGrid: request: " << cmd << endl; - switch (cmd.action) { + + Parse::flags parseflg = Parse::QUIET | Parse::USETEXT; + + FuncCode const act = cmd.action(); + switch (act) { // insert file functions case LFUN_LINE_DELETE: - // FIXME: We use recordUndoInset when a change reflects more - // than one cell, because recordUndo does not work for - // multiple cells. Unfortunately this puts the cursor in front - // of the inset after undo. This is (especilally for large - // grids) annoying. - recordUndoInset(cur); + cur.recordUndoInset(); //autocorrect_ = false; //macroModeClose(); //if (selection_) { @@ -1097,15 +1159,15 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) break; case LFUN_CELL_SPLIT: - recordUndo(cur); + cur.recordUndo(); splitCell(cur); break; case LFUN_CELL_BACKWARD: // See below. - cur.selection() = false; + cur.setSelection(false); if (!idxPrev(cur)) { - cmd = FuncRequest(LFUN_FINISHED_LEFT); + cmd = FuncRequest(LFUN_FINISHED_BACKWARD); cur.undispatched(); } break; @@ -1113,15 +1175,15 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_CELL_FORWARD: // Can't handle selection by additional 'shift' as this is // hard bound to LFUN_CELL_BACKWARD - cur.selection() = false; + cur.setSelection(false); if (!idxNext(cur)) { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cmd = FuncRequest(LFUN_FINISHED_FORWARD); cur.undispatched(); } break; - case LFUN_BREAK_LINE: { - recordUndoInset(cur); + case LFUN_NEWLINE_INSERT: { + cur.recordUndoInset(); row_type const r = cur.row(); addRow(r); @@ -1135,34 +1197,40 @@ 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_LEFT); + //cmd = FuncRequest(LFUN_FINISHED_BACKWARD); break; } - case LFUN_TABULAR_FEATURE: { - recordUndoInset(cur); + 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") - valign('t'); + setVerticalAlignment('t'); else if (s == "valign-middle") - valign('c'); + setVerticalAlignment('c'); else if (s == "valign-bottom") - valign('b'); + setVerticalAlignment('b'); else if (s == "align-left") - halign('l', cur.col()); + setHorizontalAlignment('l', cur.col()); else if (s == "align-right") - halign('r', cur.col()); + setHorizontalAlignment('r', cur.col()); else if (s == "align-center") - halign('c', cur.col()); + setHorizontalAlignment('c', cur.col()); else if (s == "append-row") for (int i = 0, n = extractInt(is); i < n; ++i) addRow(cur.row()); else if (s == "delete-row") { + cur.clearSelection(); // bug 4323 for (int i = 0, n = extractInt(is); i < n; ++i) { delRow(cur.row()); if (cur.idx() >= nargs()) @@ -1197,10 +1265,11 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) row_type const r = cur.row(); col_type const c = cur.col(); for (int i = 0, n = extractInt(is); i < n; ++i) - addCol(cur.col()); + addCol(cur.col() + 1); cur.idx() = index(r, c); } else if (s == "delete-column") { + cur.clearSelection(); // bug 4323 row_type const r = cur.row(); col_type const c = cur.col(); for (int i = 0, n = extractInt(is); i < n; ++i) @@ -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('|'); - BOOST_ASSERT(i != docstring::npos); + LASSERT(i != docstring::npos, /**/); 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('|'); - BOOST_ASSERT(i != docstring::npos); + LASSERT(i != docstring::npos, /**/); special.erase(i, 1); } } @@ -1250,11 +1319,17 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) cur.undispatched(); break; } - lyxerr << "returning FINISHED_LEFT" << endl; + // perhaps this should be FINISHED_BACKWARD -- just for clarity? + //lyxerr << "returning FINISHED_LEFT" << endl; break; } + case LFUN_CLIPBOARD_PASTE: + parseflg |= Parse::VERBATIM; + // fall through case LFUN_PASTE: { + if (cur.currentMode() <= TEXT_MODE) + parseflg |= Parse::TEXTMODE; cur.message(_("Paste")); cap::replaceSelection(cur); docstring topaste; @@ -1264,20 +1339,38 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) idocstringstream is(cmd.argument()); int n = 0; is >> n; - topaste = cap::getSelection(cur.buffer(), n); + topaste = cap::selection(n); } - InsetMathGrid grid(1, 1); + InsetMathGrid grid(buffer_, 1, 1); if (!topaste.empty()) - mathed_parse_normal(grid, topaste); + if ((topaste.size() == 1 && topaste.at(0) < 0x80) + || !mathed_parse_normal(grid, topaste, parseflg)) { + resetGrid(grid); + 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 - recordUndo(cur); + 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 - recordUndoInset(cur); + cur.recordUndoInset(); col_type const numcols = min(grid.ncols(), ncols() - col(cur.idx())); row_type const numrows = @@ -1287,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) @@ -1294,12 +1396,24 @@ 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 - finishUndo(); + // FIXME audit setBuffer calls + cur.inset().setBuffer(*buffer_); + cur.forceBufferUpdate(); + cur.finishUndo(); break; } @@ -1307,8 +1421,11 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) case LFUN_LINE_BEGIN: case LFUN_WORD_BACKWARD_SELECT: case LFUN_WORD_BACKWARD: - cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT || - cmd.action == LFUN_LINE_BEGIN_SELECT); + case LFUN_WORD_LEFT_SELECT: + case LFUN_WORD_LEFT: + 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; @@ -1319,17 +1436,20 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) cur.idx() = 0; cur.pos() = 0; } else { - cmd = FuncRequest(LFUN_FINISHED_LEFT); + cmd = FuncRequest(LFUN_FINISHED_BACKWARD); cur.undispatched(); } break; case LFUN_WORD_FORWARD_SELECT: case LFUN_WORD_FORWARD: + case LFUN_WORD_RIGHT_SELECT: + case LFUN_WORD_RIGHT: case LFUN_LINE_END_SELECT: case LFUN_LINE_END: - cur.selHandle(cmd.action == LFUN_WORD_FORWARD_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()) { @@ -1341,7 +1461,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd) cur.idx() = cur.lastidx(); cur.pos() = cur.lastpos(); } else { - cmd = FuncRequest(LFUN_FINISHED_RIGHT); + cmd = FuncRequest(LFUN_FINISHED_FORWARD); cur.undispatched(); } break; @@ -1355,17 +1475,31 @@ 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 = to_utf8(cmd.argument()); + 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.enabled(false); + status.setEnabled(false); status.message(from_utf8(N_("Only one row"))); return true; } if (ncols() <= 1 && (s == "delete-column" || s == "swap-column")) { - status.enabled(false); + status.setEnabled(false); status.message(from_utf8(N_("Only one column"))); return true; } @@ -1373,7 +1507,7 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, s == "delete-hline-above") || (rowinfo_[cur.row() + 1].lines_ == 0 && s == "delete-hline-below")) { - status.enabled(false); + status.setEnabled(false); status.message(from_utf8(N_("No hline to delete"))); return true; } @@ -1382,35 +1516,39 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, s == "delete-vline-left") || (colinfo_[cur.col() + 1].lines_ == 0 && s == "delete-vline-right")) { - status.enabled(false); + status.setEnabled(false); status.message(from_utf8(N_("No vline to delete"))); return true; } if (s == "valign-top" || s == "valign-middle" || s == "valign-bottom" || s == "align-left" || - s == "align-right" || s == "align-center" || - s == "append-row" || s == "delete-row" || + s == "align-right" || s == "align-center") { + status.setEnabled(true); + char const ha = horizontalAlignment(cur.col()); + char const va = verticalAlignment(); + status.setOnOff((s == "align-left" && ha == 'l') + || (s == "align-right" && ha == 'r') + || (s == "align-center" && ha == 'c') + || (s == "valign-top" && va == 't') + || (s == "valign-bottom" && va == 'b') + || (s == "valign-middle" && va == 'c')); + return true; + } + if (s == "append-row" || s == "delete-row" || s == "copy-row" || s == "swap-row" || s == "add-hline-above" || s == "add-hline-below" || s == "delete-hline-above" || s == "delete-hline-below" || s == "append-column" || s == "delete-column" || s == "copy-column" || s == "swap-column" || s == "add-vline-left" || s == "add-vline-right" || - s == "delete-vline-left" || s == "delete-vline-right") - status.enabled(true); - else { - status.enabled(false); + s == "delete-vline-left" || s == "delete-vline-right") { + status.setEnabled(true); + } else { + status.setEnabled(false); status.message(bformat( from_utf8(N_("Unknown tabular feature '%1$s'")), lyx::from_ascii(s))); } - status.setOnOff((s == "align-left" && halign(cur.col()) == 'l') - || (s == "align-right" && halign(cur.col()) == 'r') - || (s == "align-center" && halign(cur.col()) == 'c') - || (s == "valign-top" && valign() == 't') - || (s == "valign-bottom" && valign() == 'b') - || (s == "valign-middle" && valign() == 'm')); - #if 0 // FIXME: What did this code do? // Please check whether it is still needed! @@ -1423,28 +1561,29 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd, status.enable(false); break; } - if (!support::contains("tcb", cmd.argument()[0])) { + if (!contains("tcb", cmd.argument()[0])) { status.enable(false); break; } status.setOnOff(cmd.argument()[0] == v_align_); - status.enabled(true); + status.setEnabled(true); #endif return true; } case LFUN_CELL_SPLIT: - status.enabled(true); + status.setEnabled(cur.idx() != cur.lastidx()); return true; case LFUN_CELL_BACKWARD: case LFUN_CELL_FORWARD: - status.enabled(true); + status.setEnabled(true); return true; default: - return InsetMathNest::getStatus(cur, cmd, status); + break; } + return InsetMathNest::getStatus(cur, cmd, status); }