]> git.lyx.org Git - lyx.git/blobdiff - src/insets/insettabular.C
The speed patch: redraw only rows that have changed
[lyx.git] / src / insets / insettabular.C
index 7e3cd21e284d302ca933c6b10852e17071913c37..4d7b3085fe6b5ad303d303f2b39538607a103222 100644 (file)
@@ -16,6 +16,7 @@
 #include "bufferparams.h"
 #include "BufferView.h"
 #include "cursor.h"
+#include "CutAndPaste.h"
 #include "coordcache.h"
 #include "debug.h"
 #include "dispatchresult.h"
@@ -45,6 +46,8 @@
 #include <iostream>
 #include <limits>
 
+using lyx::cap::tabularStackDirty;
+
 using lyx::graphics::PreviewLoader;
 
 using lyx::support::ltrim;
@@ -242,10 +245,16 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                int maxDesc = 0;
                for (col_type j = 0; j < tabular.columns(); ++j) {
                        if (tabular.isPartOfMultiColumn(i, j))
+                               // Multicolumn cell, but not first one
                                continue;
                        Dimension dim;
                        MetricsInfo m = mi;
-                       LyXLength p_width = tabular.column_info[j].p_width;
+                       LyXLength p_width;
+                       if (tabular.cell_info[i][j].multicolumn == 
+                           LyXTabular::CELL_BEGIN_OF_MULTICOLUMN)
+                               p_width = tabular.cellinfo_of_cell(cell).p_width;
+                       else
+                               p_width = tabular.column_info[j].p_width;
                        if (!p_width.zero())
                                m.base.textwidth = p_width.inPixels(mi.base.textwidth);
                        tabular.getCellInset(cell)->metrics(m, dim);
@@ -301,10 +310,10 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
                            || y + d < 0
                            || y - a > bv->workHeight()) {
                                cell(idx)->draw(nullpi, cx, y);
-                               drawCellLines(nop, nx, y, i, idx);
+                               drawCellLines(nop, nx, y, i, idx, pi.erased_);
                        } else {
                                cell(idx)->draw(pi, cx, y);
-                               drawCellLines(pi.pain, nx, y, i, idx);
+                               drawCellLines(pi.pain, nx, y, i, idx, pi.erased_);
                        }
                        nx += tabular.getWidthOfColumn(idx);
                        ++idx;
@@ -363,28 +372,35 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
 
 
 void InsetTabular::drawCellLines(Painter & pain, int x, int y,
-                                row_type row, idx_type cell) const
+                                row_type row, idx_type cell, bool erased) const
 {
        int x2 = x + tabular.getWidthOfColumn(cell);
        bool on_off = false;
+       LColor::color col = LColor::tabularline;
+       LColor::color onoffcol = LColor::tabularonoffline;
+
+       if (erased) {
+               col = LColor::strikeout;
+               onoffcol = LColor::strikeout;
+       }
 
        if (!tabular.topAlreadyDrawn(cell)) {
                on_off = !tabular.topLine(cell);
                pain.line(x, y - tabular.getAscentOfRow(row),
                          x2, y -  tabular.getAscentOfRow(row),
-                         on_off ? LColor::tabularonoffline : LColor::tabularline,
+                         on_off ? onoffcol : col,
                          on_off ? Painter::line_onoffdash : Painter::line_solid);
        }
        on_off = !tabular.bottomLine(cell);
        pain.line(x, y + tabular.getDescentOfRow(row),
                  x2, y + tabular.getDescentOfRow(row),
-                 on_off ? LColor::tabularonoffline : LColor::tabularline,
+                 on_off ? onoffcol : col,
                  on_off ? Painter::line_onoffdash : Painter::line_solid);
        if (!tabular.leftAlreadyDrawn(cell)) {
                on_off = !tabular.leftLine(cell);
                pain.line(x, y -  tabular.getAscentOfRow(row),
                          x, y +  tabular.getDescentOfRow(row),
-                         on_off ? LColor::tabularonoffline : LColor::tabularline,
+                         on_off ? onoffcol : col,
                          on_off ? Painter::line_onoffdash : Painter::line_solid);
        }
        on_off = !tabular.rightLine(cell);
@@ -392,7 +408,7 @@ void InsetTabular::drawCellLines(Painter & pain, int x, int y,
                  y -  tabular.getAscentOfRow(row),
                  x2 - tabular.getAdditionalWidth(cell),
                  y +  tabular.getDescentOfRow(row),
-                 on_off ? LColor::tabularonoffline : LColor::tabularline,
+                 on_off ? onoffcol : col,
                  on_off ? Painter::line_onoffdash : Painter::line_solid);
 }
 
@@ -432,8 +448,8 @@ void InsetTabular::edit(LCursor & cur, bool left)
 
 void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
 {
-       //lyxerr << "# InsetTabular::dispatch: cmd: " << cmd << endl;
-       //lyxerr << "  cur:\n" << cur << endl;
+       lyxerr[Debug::DEBUG] << "# InsetTabular::doDispatch: cmd: " << cmd 
+                            << "\n  cur:" << cur << endl;
        CursorSlice sl = cur.top();
        LCursor & bvcur = cur.bv().cursor();
 
@@ -495,24 +511,24 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_RIGHTSEL:
        case LFUN_RIGHT:
                cell(cur.idx())->dispatch(cur, cmd);
-               cur.dispatched(); // override the cell's decision
-               if (sl == cur.top())
+               if (!cur.result().dispatched()) {
                        isRightToLeft(cur) ? movePrevCell(cur) : moveNextCell(cur);
-               if (sl == cur.top()) {
-                       cmd = FuncRequest(LFUN_FINISHED_RIGHT);
-                       cur.undispatched();
+                       if (sl == cur.top()) 
+                               cmd = FuncRequest(LFUN_FINISHED_RIGHT);
+                       else
+                               cur.dispatched();
                }
                break;
 
        case LFUN_LEFTSEL:
        case LFUN_LEFT:
                cell(cur.idx())->dispatch(cur, cmd);
-               cur.dispatched(); // override the cell's decision
-               if (sl == cur.top())
+               if (!cur.result().dispatched()) {
                        isRightToLeft(cur) ? moveNextCell(cur) : movePrevCell(cur);
-               if (sl == cur.top()) {
-                       cmd = FuncRequest(LFUN_FINISHED_LEFT);
-                       cur.undispatched();
+                       if (sl == cur.top()) 
+                               cmd = FuncRequest(LFUN_FINISHED_LEFT);
+                       else
+                               cur.dispatched();
                }
                break;
 
@@ -621,7 +637,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
        case LFUN_CUT:
                if (tablemode(cur)) {
                        if (copySelection(cur)) {
-                               recordUndo(cur, Undo::DELETE);
+                               recordUndoInset(cur, Undo::DELETE);
                                cutSelection(cur);
                        }
                }
@@ -631,9 +647,10 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
 
        case LFUN_BACKSPACE:
        case LFUN_DELETE:
-               recordUndo(cur, Undo::DELETE);
-               if (tablemode(cur))
+               if (tablemode(cur)) {
+                       recordUndoInset(cur, Undo::DELETE);
                        cutSelection(cur);
+               }
                else
                        cell(cur.idx())->dispatch(cur, cmd);
                break;
@@ -719,8 +736,8 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_PASTE:
-               if (hasPasteBuffer()) {
-                       recordUndo(cur, Undo::INSERT);
+               if (hasPasteBuffer() && tabularStackDirty()) {
+                       recordUndoInset(cur, Undo::INSERT);
                        pasteSelection(cur);
                        break;
                }
@@ -1003,7 +1020,20 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd,
                if (tablemode(cur)) {
                        status.enabled(false);
                        return true;
-               }
+               } else
+                       return cell(cur.idx())->getStatus(cur, cmd, status);
+       }
+
+       // disable in non-fixed-width cells
+       case LFUN_BREAKLINE:
+       case LFUN_BREAKPARAGRAPH:
+       case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
+       case LFUN_BREAKPARAGRAPH_SKIP: {
+               if (tabular.getPWidth(cur.idx()).zero()) {
+                       status.enabled(false);
+                       return true;
+               } else
+                       return cell(cur.idx())->getStatus(cur, cmd, status);
        }
 
        case LFUN_INSET_MODIFY:
@@ -1169,7 +1199,6 @@ void InsetTabular::setCursorFromCoordinates(LCursor & cur, int x, int y) const
 {
        cur.idx() = getNearestCell(x, y);
        cell(cur.idx())->text_.setCursorFromCoordinates(cur, x, y);
-       resetPos(cur);
 }
 
 
@@ -1177,7 +1206,7 @@ InsetTabular::idx_type InsetTabular::getNearestCell(int x, int y) const
 {
        idx_type idx_min = 0;
        int dist_min = std::numeric_limits<int>::max();
-       for (idx_type i = 0; i < nargs(); ++i) {
+       for (idx_type i = 0, n = nargs(); i != n; ++i) {
                if (theCoords.getInsets().has(tabular.getCellInset(i).get())) {
                        int const d = dist(i, x, y);
                        if (d < dist_min) {
@@ -1381,7 +1410,7 @@ void InsetTabular::tabularFeatures(LCursor & cur,
                break;
        }
 
-       recordUndo(cur, Undo::ATOMIC);
+       recordUndoInset(cur, Undo::ATOMIC);
 
        getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end);
        row_type const row = tabular.row_of_cell(cur.idx());
@@ -1393,18 +1422,15 @@ void InsetTabular::tabularFeatures(LCursor & cur,
 
        case LyXTabular::SET_PWIDTH: {
                LyXLength const len(value);
-               tabular.setColumnPWidth(cur.idx(), len);
+               tabular.setColumnPWidth(cur, cur.idx(), len);
                if (len.zero()
                    && tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_BLOCK)
                        tabularFeatures(cur, LyXTabular::ALIGN_CENTER, string());
-               else if (!len.zero()
-                        && tabular.getAlignment(cur.idx(), true) != LYX_ALIGN_BLOCK)
-                       tabularFeatures(cur, LyXTabular::ALIGN_BLOCK, string());
                break;
        }
 
        case LyXTabular::SET_MPWIDTH:
-               tabular.setMColumnPWidth(cur.idx(), LyXLength(value));
+               tabular.setMColumnPWidth(cur, cur.idx(), LyXLength(value));
                break;
 
        case LyXTabular::SET_SPECIAL_COLUMN:
@@ -1707,6 +1733,11 @@ bool InsetTabular::copySelection(LCursor & cur)
        OutputParams const runparams;
        paste_tabular->plaintext(cur.buffer(), os, runparams, 0, true, '\t');
        cur.bv().stuffClipboard(os.str());
+       // mark tabular stack dirty
+       // FIXME: this is a workaround for bug 1919. Should be removed for 1.5, 
+       // when we (hopefully) have a one-for-all paste mechanism.
+       lyx::cap::dirtyTabularStack(true);
+
        return true;
 }
 
@@ -1750,13 +1781,19 @@ void InsetTabular::cutSelection(LCursor & cur)
        if (!cur.selection())
                return;
 
-       bool const track = cur.buffer().params().tracking_changes;
        row_type rs, re;
        col_type cs, ce;
        getSelection(cur, rs, re, cs, ce);
-       for (row_type i = rs; i <= re; ++i)
-               for (col_type j = cs; j <= ce; ++j)
-                       cell(tabular.getCellNumber(i, j))->clear(track);
+       for (row_type i = rs; i <= re; ++i) {
+               for (col_type j = cs; j <= ce; ++j) {
+                       shared_ptr<InsetText> t
+                               = cell(tabular.getCellNumber(i, j));
+                       if (cur.buffer().params().tracking_changes)
+                               t->markErased(true);
+                       else
+                               t->clear();
+               }
+       }
 
        // cursor position might be invalid now
        cur.pos() = cur.lastpos();
@@ -1795,46 +1832,22 @@ void InsetTabular::getSelection(LCursor & cur,
 }
 
 
-size_t InsetTabular::nargs() const
-{
-       return tabular.getNumberOfCells();
-}
-
-
 LyXText * InsetTabular::getText(int idx) const
 {
        return size_t(idx) < nargs() ? cell(idx)->getText(0) : 0;
 }
 
 
-void InsetTabular::markErased()
+void InsetTabular::markErased(bool erased)
 {
        for (idx_type idx = 0; idx < nargs(); ++idx)
-               cell(idx)->markErased();
+               cell(idx)->markErased(erased);
 }
 
 
-bool InsetTabular::forceDefaultParagraphs(InsetBase const *) const
+bool InsetTabular::forceDefaultParagraphs(idx_type cell) const
 {
-#if 0
-       idx_type const cell = tabular.getCellFromInset(in);
-       // FIXME: getCellFromInset() returns now always a valid cell, so
-       // the stuff below can be deleted, and instead we have:
        return tabular.getPWidth(cell).zero();
-
-       if (cell != npos)
-               return tabular.getPWidth(cell).zero();
-
-       // this is a workaround for a crash (New, Insert->Tabular,
-       // Insert->FootNote)
-       if (!owner())
-               return false;
-
-       // well we didn't obviously find it so maybe our owner knows more
-       BOOST_ASSERT(owner());
-       return owner()->forceDefaultParagraphs(in);
-#endif
-       return false;
 }