]> git.lyx.org Git - lyx.git/blobdiff - src/mathed/InsetMathGrid.cpp
Fix bug 5802 (http://bugzilla.lyx.org/show_bug.cgi?id=5802)
[lyx.git] / src / mathed / InsetMathGrid.cpp
index ae009cff22ede84115c219f841cc81a7c131d2b6..61e13dfe8c0904839ad562563138a05d8cc9b6bd 100644 (file)
@@ -3,12 +3,13 @@
  * 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 <config.h>
+#include <algorithm>
 
 #include "InsetMathGrid.h"
 
@@ -24,6 +25,7 @@
 #include "FuncRequest.h"
 
 #include "frontends/Clipboard.h"
+#include "frontends/FontMetrics.h"
 #include "frontends/Painter.h"
 
 #include "support/debug.h"
@@ -31,7 +33,7 @@
 #include "support/gettext.h"
 #include "support/lstrings.h"
 
-#include <boost/assert.hpp>
+#include "support/lassert.h"
 
 #include <sstream>
 
@@ -60,6 +62,17 @@ static int extractInt(istream & is)
 }
 
 
+static void resetGrid(InsetMathGrid & grid)
+{
+       while (grid.ncols() > 1)
+               grid.delCol(grid.ncols());
+       while (grid.nrows() > 1)
+               grid.delRow(grid.nrows());
+       grid.cell(0).erase(0, grid.cell(0).size());
+       grid.setDefaults();
+}
+
+
 
 //////////////////////////////////////////////////////////////
 
@@ -79,9 +92,11 @@ InsetMathGrid::RowInfo::RowInfo()
 
 
 
-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')));
 }
 
 
@@ -97,19 +112,6 @@ 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),
          rowinfo_(1 + 1),
@@ -140,8 +142,8 @@ InsetMathGrid::InsetMathGrid(col_type m, row_type n, char v, docstring const & h
                v_align_(v)
 {
        setDefaults();
-       valign(v);
-       halign(h);
+       setVerticalAlignment(v);
+       setHorizontalAlignments(h);
 }
 
 
@@ -171,7 +173,7 @@ void InsetMathGrid::setDefaults()
 }
 
 
-void InsetMathGrid::halign(docstring const & hh)
+void InsetMathGrid::setHorizontalAlignments(docstring const & hh)
 {
        col_type col = 0;
        for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) {
@@ -253,7 +255,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)
@@ -268,7 +270,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()) {
@@ -280,13 +282,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) {
@@ -302,13 +304,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_;
 }
@@ -379,7 +381,7 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const
                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_;
@@ -489,7 +491,7 @@ void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const
        }
 */
        metricsMarkers2(dim);
-       // Cache the inset dimension. 
+       // Cache the inset dimension.
        setDimCache(mi, dim);
 }
 
@@ -562,7 +564,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_;
@@ -764,7 +766,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];
 }
@@ -979,26 +981,39 @@ void InsetMathGrid::mathmlize(MathStream & os) const
 
 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
                col_type lastcol = 0;
                bool emptyline = true;
-               for (col_type col = 0; col < ncols(); ++col)
+               for (col_type col = beg_col; col < end_col; ++col)
                        if (!cell(index(row, col)).empty()) {
                                lastcol = col + 1;
                                emptyline = false;
                        }
-               for (col_type col = 0; col < lastcol; ++col)
-                       os << cell(index(row, col)) << eocString(col, lastcol);
+               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, emptyline, os.fragile());
                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())
+               if (!emptyline && row + 1 < end_row)
                        os << "\n";
        }
+       // @TODO use end_row instead of nrows() ?
        docstring const s = verboseHLine(rowinfo_[nrows()].lines_);
        if (!s.empty()) {
                if (eol.empty()) {
@@ -1057,15 +1072,13 @@ void InsetMathGrid::splitCell(Cursor & cur)
 void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
 {
        //lyxerr << "*** InsetMathGrid: request: " << cmd << endl;
+
+       Parse::flags parseflg = Parse::QUIET;
+
        switch (cmd.action) {
 
        // 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.
                cur.recordUndoInset();
                //autocorrect_ = false;
                //macroModeClose();
@@ -1088,7 +1101,7 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CELL_BACKWARD:
                // See below.
-               cur.selection() = false;
+               cur.setSelection(false);
                if (!idxPrev(cur)) {
                        cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
                        cur.undispatched();
@@ -1098,14 +1111,14 @@ 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_FORWARD);
                        cur.undispatched();
                }
                break;
 
-       case LFUN_NEW_LINE: {
+       case LFUN_NEWLINE_INSERT: {
                cur.recordUndoInset();
                row_type const r = cur.row();
                addRow(r);
@@ -1133,17 +1146,17 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
                string s;
                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());
@@ -1220,7 +1233,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);
                        }
                }
@@ -1229,7 +1242,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);
                        }
                }
@@ -1242,7 +1255,12 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
                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;
@@ -1256,7 +1274,12 @@ void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
                }
                InsetMathGrid grid(1, 1);
                if (!topaste.empty())
-                       mathed_parse_normal(grid, topaste);
+                       if (topaste.size() == 1
+                           || !mathed_parse_normal(grid, topaste, parseflg)) {
+                               resetGrid(grid);
+                               mathed_parse_normal(grid, topaste,
+                                               parseflg | Parse::VERBATIM);
+                       }
 
                if (grid.nargs() == 1) {
                        // single cell/part of cell
@@ -1351,15 +1374,15 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd,
 {
        switch (cmd.action) {
        case LFUN_TABULAR_FEATURE: {
-               string const s = to_utf8(cmd.argument());
+               string const s = cmd.getArg(0);
                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;
                }
@@ -1367,7 +1390,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;
                }
@@ -1376,14 +1399,24 @@ 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 == 'm'));
+               }
+               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" ||
@@ -1391,20 +1424,13 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd,
                    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);
+                       status.setEnabled(true);
                else {
-                       status.enabled(false);
+                       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!
@@ -1422,18 +1448,18 @@ bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd,
                        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(true);
                return true;
 
        case LFUN_CELL_BACKWARD:
        case LFUN_CELL_FORWARD:
-               status.enabled(true);
+               status.setEnabled(true);
                return true;
 
        default: