X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Finsets%2Finsettabular.C;h=202ac6fa44bb8495781e2a56dd4919f2a87029ff;hb=e28331ed63062dea10d0a21b9ec12034b4b17b9a;hp=4d7b3085fe6b5ad303d303f2b39538607a103222;hpb=dd6c706cef7f7c29b0a6c988d3a8de22bbf195ac;p=lyx.git diff --git a/src/insets/insettabular.C b/src/insets/insettabular.C index 4d7b3085fe..202ac6fa44 100644 --- a/src/insets/insettabular.C +++ b/src/insets/insettabular.C @@ -37,20 +37,26 @@ #include "support/convert.h" #include "frontends/Alert.h" -#include "frontends/font_metrics.h" -#include "frontends/LyXView.h" +#include "frontends/Clipboard.h" #include "frontends/Painter.h" -#include "frontends/nullpainter.h" +#include "frontends/Selection.h" #include #include #include -using lyx::cap::tabularStackDirty; -using lyx::graphics::PreviewLoader; +namespace lyx { -using lyx::support::ltrim; +using cap::dirtyTabularStack; +using cap::tabularStackDirty; + +using graphics::PreviewLoader; + +using support::ltrim; + +using frontend::Painter; +using frontend::Clipboard; using boost::shared_ptr; @@ -64,11 +70,14 @@ using std::ostringstream; using std::swap; using std::vector; +namespace Alert = frontend::Alert; + namespace { int const ADD_TO_HEIGHT = 2; int const ADD_TO_TABULAR_WIDTH = 2; +int const default_line_space = 10; /// boost::scoped_ptr paste_tabular; @@ -86,6 +95,8 @@ TabularFeature tabularFeature[] = { LyXTabular::APPEND_COLUMN, "append-column" }, { LyXTabular::DELETE_ROW, "delete-row" }, { LyXTabular::DELETE_COLUMN, "delete-column" }, + { LyXTabular::COPY_ROW, "copy-row" }, + { LyXTabular::COPY_COLUMN, "copy-column" }, { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" }, { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" }, { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" }, @@ -130,6 +141,11 @@ TabularFeature tabularFeature[] = { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" }, { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" }, { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" }, + { LyXTabular::SET_BOOKTABS, "set-booktabs" }, + { LyXTabular::UNSET_BOOKTABS, "unset-booktabs" }, + { LyXTabular::SET_TOP_SPACE, "set-top-space" }, + { LyXTabular::SET_BOTTOM_SPACE, "set-bottom-space" }, + { LyXTabular::SET_INTERLINE_SPACE, "set-interline-space" }, { LyXTabular::LAST_ACTION, "" } }; @@ -158,14 +174,8 @@ string const featureAsString(LyXTabular::Feature feature) } -bool InsetTabular::hasPasteBuffer() const -{ - return (paste_tabular.get() != 0); -} - - InsetTabular::InsetTabular(Buffer const & buf, row_type rows, - col_type columns) + col_type columns) : tabular(buf.params(), max(rows, row_type(1)), max(columns, col_type(1))), buffer_(&buf), scx_(0) {} @@ -230,7 +240,7 @@ void InsetTabular::read(Buffer const & buf, LyXLex & lex) } -void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const +bool InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const { //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " << // mi.base.textwidth << "\n"; @@ -250,7 +260,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const Dimension dim; MetricsInfo m = mi; LyXLength p_width; - if (tabular.cell_info[i][j].multicolumn == + if (tabular.cell_info[i][j].multicolumn == LyXTabular::CELL_BEGIN_OF_MULTICOLUMN) p_width = tabular.cellinfo_of_cell(cell).p_width; else @@ -260,19 +270,33 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const tabular.getCellInset(cell)->metrics(m, dim); if (!p_width.zero()) dim.wid = m.base.textwidth; + tabular.setWidthOfCell(cell, dim.wid); + if (p_width.zero()) { + m.base.textwidth = dim.wid + 2 * ADD_TO_TABULAR_WIDTH; + // FIXME there must be a way to get rid of + // the second metrics call + tabular.getCellInset(cell)->metrics(m, dim); + } maxAsc = max(maxAsc, dim.asc); maxDesc = max(maxDesc, dim.des); - tabular.setWidthOfCell(cell, dim.wid); ++cell; } - tabular.setAscentOfRow(i, maxAsc + ADD_TO_HEIGHT); - tabular.setDescentOfRow(i, maxDesc + ADD_TO_HEIGHT); + int const top_space = tabular.row_info[i].top_space_default ? + default_line_space : + tabular.row_info[i].top_space.inPixels(mi.base.textwidth); + tabular.setAscentOfRow(i, maxAsc + ADD_TO_HEIGHT + top_space); + int const bottom_space = tabular.row_info[i].bottom_space_default ? + default_line_space : + tabular.row_info[i].bottom_space.inPixels(mi.base.textwidth); + tabular.setDescentOfRow(i, maxDesc + ADD_TO_HEIGHT + bottom_space); } dim.asc = tabular.getAscentOfRow(0); dim.des = tabular.getHeightOfTabular() - dim.asc; dim.wid = tabular.getWidthOfTabular() + 2 * ADD_TO_TABULAR_WIDTH; + bool const changed = dim_ != dim; dim_ = dim; + return changed; } @@ -283,10 +307,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const //lyxerr << "InsetTabular::draw: " << x << " " << y << endl; BufferView * bv = pi.base.bv; - static NullPainter nop; - static PainterInfo nullpi(bv, nop); - - //resetPos(bv->cursor()); + resetPos(bv->cursor()); x += scx_; x += ADD_TO_TABULAR_WIDTH; @@ -309,8 +330,10 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const || nx > bv->workWidth() || y + d < 0 || y - a > bv->workHeight()) { - cell(idx)->draw(nullpi, cx, y); - drawCellLines(nop, nx, y, i, idx, pi.erased_); + pi.pain.setDrawingEnabled(false); + cell(idx)->draw(pi, cx, y); + drawCellLines(pi.pain, nx, y, i, idx, pi.erased_); + pi.pain.setDrawingEnabled(true); } else { cell(idx)->draw(pi, cx, y); drawCellLines(pi.pain, nx, y, i, idx, pi.erased_); @@ -331,6 +354,15 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const setPosCache(pi, x, y); LCursor & cur = pi.base.bv->cursor(); + + x += scx_ + ADD_TO_TABULAR_WIDTH; + + // Paint background of current tabular + int const w = tabular.getWidthOfTabular(); + int const h = tabular.getHeightOfTabular(); + int yy = y - tabular.getAscentOfRow(0); + pi.pain.fillRectangle(x, yy, w, h, backgroundColor()); + if (!cur.selection()) return; if (!ptr_cmp(&cur.inset(), this)) @@ -338,7 +370,6 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const //resetPos(cur); - x += scx_ + ADD_TO_TABULAR_WIDTH; if (tablemode(cur)) { row_type rs, re; @@ -413,7 +444,7 @@ void InsetTabular::drawCellLines(Painter & pain, int x, int y, } -string const InsetTabular::editMessage() const +docstring const InsetTabular::editMessage() const { return _("Opened table"); } @@ -421,7 +452,7 @@ string const InsetTabular::editMessage() const void InsetTabular::edit(LCursor & cur, bool left) { - lyxerr << "InsetTabular::edit: " << this << endl; + //lyxerr << "InsetTabular::edit: " << this << endl; finishUndo(); cur.selection() = false; cur.push(*this); @@ -440,7 +471,7 @@ void InsetTabular::edit(LCursor & cur, bool left) cur.pit() = 0; cur.pos() = cur.lastpos(); // FIXME crude guess } - // this accesses the position cache before it is initialized + // FIXME: this accesses the position cache before it is initialized //resetPos(cur); //cur.bv().fitCursor(); } @@ -448,7 +479,7 @@ void InsetTabular::edit(LCursor & cur, bool left) void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) { - lyxerr[Debug::DEBUG] << "# InsetTabular::doDispatch: cmd: " << cmd + lyxerr[Debug::DEBUG] << "# InsetTabular::doDispatch: cmd: " << cmd << "\n cur:" << cur << endl; CursorSlice sl = cur.top(); LCursor & bvcur = cur.bv().cursor(); @@ -458,25 +489,31 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) case LFUN_MOUSE_PRESS: //lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl; - if (cmd.button() == mouse_button::button1) { + if (cmd.button() == mouse_button::button1 + || (cmd.button() == mouse_button::button3 + && (&bvcur.selBegin().inset() != this || !tablemode(bvcur)))) { + if (!bvcur.selection() && !cur.bv().mouseSetCursor(cur)) + cur.noUpdate(); cur.selection() = false; setCursorFromCoordinates(cur, cmd.x, cmd.y); - cur.resetAnchor(); - bvcur = cur; + cur.bv().mouseSetCursor(cur); break; } if (cmd.button() == mouse_button::button2) { - // FIXME: pasting multiple cells (with insettabular's own - // LFUN_PASTESELECTION still does not work! (jspitzm) - cmd = FuncRequest(LFUN_PASTESELECTION, "paragraph"); - cell(cur.idx())->dispatch(cur, cmd); - break; + if (bvcur.selection()) { + // See comment in LyXText::dispatch why we + // do this + // FIXME This does not use paste_tabular, + // another reason why paste_tabular should go. + cap::copySelectionToStack(bvcur); + cmd = FuncRequest(LFUN_PASTE, "0"); + } else { + cmd = FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, + "paragraph"); + } + doDispatch(cur, cmd); } - - // we'll pop up the table dialog on release - if (cmd.button() == mouse_button::button3) - break; break; case LFUN_MOUSE_MOTION: @@ -484,6 +521,10 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) if (cmd.button() == mouse_button::button1) { // only accept motions to places not deeper nested than the real anchor if (bvcur.anchor_.hasPart(cur)) { + // only update if selection changes + if (bvcur.idx() == cur.idx() && + !(bvcur.anchor_.idx() == cur.idx() && bvcur.pos() != cur.pos())) + cur.noUpdate(); setCursorFromCoordinates(cur, cmd.x, cmd.y); bvcur.setCursor(cur); bvcur.selection() = true; @@ -494,7 +535,10 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) case LFUN_MOUSE_RELEASE: //lyxerr << "# InsetTabular::MouseRelease\n" << bvcur << endl; - if (cmd.button() == mouse_button::button3) + if (cmd.button() == mouse_button::button1) { + if (bvcur.selection()) + theSelection().haveSelection(true); + } else if (cmd.button() == mouse_button::button3) InsetTabularMailer(*this).showDialog(&cur.bv()); break; @@ -508,31 +552,35 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) cur.selection() = false; break; - case LFUN_RIGHTSEL: - case LFUN_RIGHT: + case LFUN_CHAR_FORWARD_SELECT: + case LFUN_CHAR_FORWARD: cell(cur.idx())->dispatch(cur, cmd); if (!cur.result().dispatched()) { isRightToLeft(cur) ? movePrevCell(cur) : moveNextCell(cur); - if (sl == cur.top()) + if (cmd.action == LFUN_CHAR_FORWARD_SELECT) + theSelection().haveSelection(cur.selection()); + if (sl == cur.top()) cmd = FuncRequest(LFUN_FINISHED_RIGHT); else cur.dispatched(); } break; - case LFUN_LEFTSEL: - case LFUN_LEFT: + case LFUN_CHAR_BACKWARD_SELECT: + case LFUN_CHAR_BACKWARD: cell(cur.idx())->dispatch(cur, cmd); if (!cur.result().dispatched()) { isRightToLeft(cur) ? moveNextCell(cur) : movePrevCell(cur); - if (sl == cur.top()) + if (cmd.action == LFUN_CHAR_BACKWARD_SELECT) + theSelection().haveSelection(cur.selection()); + if (sl == cur.top()) cmd = FuncRequest(LFUN_FINISHED_LEFT); else cur.dispatched(); } break; - case LFUN_DOWNSEL: + case LFUN_DOWN_SELECT: case LFUN_DOWN: cell(cur.idx())->dispatch(cur, cmd); cur.dispatched(); // override the cell's decision @@ -543,8 +591,11 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) if (tabular.row_of_cell(cur.idx()) != tabular.rows() - 1) { cur.idx() = tabular.getCellBelow(cur.idx()); cur.pit() = 0; - cur.pos() = cell(cur.idx())->getText(0)->x2pos( - cur.pit(), 0, cur.targetX()); + TextMetrics const & tm = + cur.bv().textMetrics(cell(cur.idx())->getText(0)); + cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX()); + if (cmd.action == LFUN_DOWN_SELECT) + theSelection().haveSelection(cur.selection()); } if (sl == cur.top()) { // we trick it to go to the RIGHT after leaving the @@ -554,7 +605,7 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) } break; - case LFUN_UPSEL: + case LFUN_UP_SELECT: case LFUN_UP: cell(cur.idx())->dispatch(cur, cmd); cur.dispatched(); // override the cell's decision @@ -566,10 +617,12 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) cur.idx() = tabular.getCellAbove(cur.idx()); cur.pit() = cur.lastpit(); LyXText const * text = cell(cur.idx())->getText(0); - cur.pos() = text->x2pos( - cur.pit(), - text->paragraphs().back().rows().size()-1, - cur.targetX()); + TextMetrics const & tm = cur.bv().textMetrics(text); + ParagraphMetrics const & pm = + tm.parMetrics(cur.lastpit()); + cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, cur.targetX()); + if (cmd.action == LFUN_UP_SELECT) + theSelection().haveSelection(cur.selection()); } if (sl == cur.top()) { cmd = FuncRequest(LFUN_FINISHED_UP); @@ -577,11 +630,11 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) } break; -// case LFUN_NEXT: { +// case LFUN_SCREEN_DOWN: { // //if (hasSelection()) // // cur.selection() = false; // col_type const col = tabular.column_of_cell(cur.idx()); -// int const t = cur.bv().top_y() + cur.bv().painter().paperHeight(); +// int const t = cur.bv().top_y() + cur.bv().height(); // if (t < yo() + tabular.getHeightOfTabular()) { // cur.bv().scrollDocView(t); // cur.idx() = tabular.getCellBelow(first_visible_cell) + col; @@ -593,11 +646,11 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) // break; // } // -// case LFUN_PRIOR: { +// case LFUN_SCREEN_UP: { // //if (hasSelection()) // // cur.selection() = false; // col_type const col = tabular.column_of_cell(cur.idx()); -// int const t = cur.bv().top_y() + cur.bv().painter().paperHeight(); +// int const t = cur.bv().top_y() + cur.bv().height(); // if (yo() < 0) { // cur.bv().scrollDocView(t); // if (yo() > 0) @@ -621,15 +674,17 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) break; case LFUN_TABULAR_FEATURE: - if (!tabularFeatures(cur, cmd.argument)) + if (!tabularFeatures(cur, to_utf8(cmd.argument()))) cur.undispatched(); break; // insert file functions - case LFUN_FILE_INSERT_ASCII_PARA: - case LFUN_FILE_INSERT_ASCII: { - string const tmpstr = getContentsOfAsciiFile(&cur.bv(), cmd.argument, false); - if (!tmpstr.empty() && !insertAsciiString(cur.bv(), tmpstr, false)) + case LFUN_FILE_INSERT_PLAINTEXT_PARA: + case LFUN_FILE_INSERT_PLAINTEXT: { + // FIXME UNICODE + string const tmpstr = getContentsOfPlaintextFile(&cur.bv(), to_utf8(cmd.argument()), false); + // FIXME: We don't know the encoding of the file + if (!tmpstr.empty() && !insertPlaintextString(cur.bv(), from_utf8(tmpstr), false)) cur.undispatched(); break; } @@ -645,8 +700,8 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) cell(cur.idx())->dispatch(cur, cmd); break; - case LFUN_BACKSPACE: - case LFUN_DELETE: + case LFUN_CHAR_DELETE_BACKWARD: + case LFUN_CHAR_DELETE_FORWARD: if (tablemode(cur)) { recordUndoInset(cur, Undo::DELETE); cutSelection(cur); @@ -665,78 +720,31 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) cell(cur.idx())->dispatch(cur, cmd); break; - case LFUN_PASTESELECTION: { - string const clip = cur.bv().getClipboard(); + case LFUN_CLIPBOARD_PASTE: + case LFUN_PRIMARY_SELECTION_PASTE: { + docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ? + theClipboard().getAsText() : + theSelection().get(); if (clip.empty()) break; - if (clip.find('\t') != string::npos) { - col_type cols = 1; - row_type rows = 1; - col_type maxCols = 1; - size_t len = clip.length(); - for (size_t p = 0; p < len; ++p) { - p = clip.find_first_of("\t\n", p); - if (p == string::npos) - break; - switch (clip[p]) { - case '\t': - ++cols; - break; - case '\n': - if (p + 1 < len) - ++rows; - maxCols = max(cols, maxCols); - cols = 1; - break; - } - } - maxCols = max(cols, maxCols); - - paste_tabular.reset( - new LyXTabular(cur.buffer().params(), rows, maxCols)); - - string::size_type op = 0; - idx_type cell = 0; - idx_type const cells = - paste_tabular->getNumberOfCells(); - cols = 0; - LyXFont font; - for (size_t p = 0; cell < cells && p < len; ++p) { - p = clip.find_first_of("\t\n", p); - if (p == string::npos || p >= len) - break; - switch (clip[p]) { - case '\t': - paste_tabular->getCellInset(cell)-> - setText(clip.substr(op, p - op), font); - ++cols; - ++cell; - break; - case '\n': - paste_tabular->getCellInset(cell)-> - setText(clip.substr(op, p - op), font); - while (cols++ < maxCols) - ++cell; - cols = 0; - break; - } - op = p + 1; + // pass to InsertPlaintextString, but + // only if we have multi-cell content + if (clip.find_first_of(from_ascii("\t\n")) != docstring::npos) { + if (insertPlaintextString(cur.bv(), clip, false)) { + // content has been replaced, + // so cursor might be invalid + cur.pos() = cur.lastpos(); + bvcur.setCursor(cur); + break; } - // check for the last cell if there is no trailing '\n' - if (cell < cells && op < len) - paste_tabular->getCellInset(cell)-> - setText(clip.substr(op, len - op), font); - } else if (!insertAsciiString(cur.bv(), clip, true)) { - // so that the clipboard is used and it goes on - // to default - // and executes LFUN_PASTESELECTION in insettext! - paste_tabular.reset(); } - // fall through + // Let the cell handle normal text + cell(cur.idx())->dispatch(cur, cmd); + break; } case LFUN_PASTE: - if (hasPasteBuffer() && tabularStackDirty()) { + if (tabularStackDirty() && theClipboard().isInternal()) { recordUndoInset(cur, Undo::INSERT); pasteSelection(cur); break; @@ -744,48 +752,43 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) cell(cur.idx())->dispatch(cur, cmd); break; - case LFUN_EMPH: - case LFUN_BOLD: - case LFUN_ROMAN: - case LFUN_NOUN: - case LFUN_ITAL: - case LFUN_FRAK: - case LFUN_CODE: - case LFUN_SANS: - case LFUN_FREEFONT_APPLY: - case LFUN_FREEFONT_UPDATE: + case LFUN_FONT_EMPH: + case LFUN_FONT_BOLD: + case LFUN_FONT_ROMAN: + case LFUN_FONT_NOUN: + case LFUN_FONT_ITAL: + case LFUN_FONT_FRAK: + case LFUN_FONT_CODE: + case LFUN_FONT_SANS: + case LFUN_FONT_FREE_APPLY: + case LFUN_FONT_FREE_UPDATE: case LFUN_FONT_SIZE: - case LFUN_UNDERLINE: + case LFUN_FONT_UNDERLINE: case LFUN_LANGUAGE: - case LFUN_CAPITALIZE_WORD: - case LFUN_UPCASE_WORD: - case LFUN_LOWCASE_WORD: - case LFUN_TRANSPOSE_CHARS: + case LFUN_WORD_CAPITALIZE: + case LFUN_WORD_UPCASE: + case LFUN_WORD_LOWCASE: + case LFUN_CHARS_TRANSPOSE: if (tablemode(cur)) { row_type rs, re; col_type cs, ce; getSelection(cur, rs, re, cs, ce); + LCursor tmpcur = cur; for (row_type i = rs; i <= re; ++i) { for (col_type j = cs; j <= ce; ++j) { // cursor follows cell: - cur.idx() = tabular.getCellNumber(i, j); + tmpcur.idx() = tabular.getCellNumber(i, j); // select this cell only: - cur.pos() = 0; - cur.resetAnchor(); - cur.pos() = cur.top().lastpos(); - cur.setCursor(cur); - cur.setSelection(); - cell(cur.idx())->dispatch(cur, cmd); + tmpcur.pit() = 0; + tmpcur.pos() = 0; + tmpcur.resetAnchor(); + tmpcur.pit() = tmpcur.lastpit(); + tmpcur.pos() = tmpcur.top().lastpos(); + tmpcur.setCursor(tmpcur); + tmpcur.setSelection(); + cell(tmpcur.idx())->dispatch(tmpcur, cmd); } } - // Restore original selection - cur.idx() = tabular.getCellNumber(rs, cs); - cur.pos() = 0; - cur.resetAnchor(); - cur.idx() = tabular.getCellNumber(re, ce); - cur.pos() = cur.top().lastpos(); - cur.setCursor(cur); - cur.setSelection(); break; } else { cell(cur.idx())->dispatch(cur, cmd); @@ -797,7 +800,8 @@ void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd) break; } - resetPos(cur); + // FIXME: this accesses the position cache before it is initialized + //resetPos(cur); InsetTabularMailer(*this).updateDialog(&cur.bv()); } @@ -813,7 +817,7 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, int i = 0; for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) { string const tmp = tabularFeature[i].feature; - if (tmp == cmd.argument.substr(0, tmp.length())) { + if (tmp == to_utf8(cmd.argument()).substr(0, tmp.length())) { action = tabularFeature[i].action; break; } @@ -825,7 +829,7 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, } string const argument - = ltrim(cmd.argument.substr(tabularFeature[i].feature.length())); + = ltrim(to_utf8(cmd.argument()).substr(tabularFeature[i].feature.length())); row_type sel_row_start = 0; row_type sel_row_end = 0; @@ -844,8 +848,13 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, case LyXTabular::APPEND_COLUMN: case LyXTabular::DELETE_ROW: case LyXTabular::DELETE_COLUMN: + case LyXTabular::COPY_ROW: + case LyXTabular::COPY_COLUMN: case LyXTabular::SET_ALL_LINES: case LyXTabular::UNSET_ALL_LINES: + case LyXTabular::SET_TOP_SPACE: + case LyXTabular::SET_BOTTOM_SPACE: + case LyXTabular::SET_INTERLINE_SPACE: status.clear(); return true; @@ -985,6 +994,14 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, status.setOnOff(tabular.getLTNewPage(sel_row_start)); break; + case LyXTabular::SET_BOOKTABS: + status.setOnOff(tabular.useBookTabs()); + break; + + case LyXTabular::UNSET_BOOKTABS: + status.setOnOff(!tabular.useBookTabs()); + break; + default: status.clear(); status.enabled(false); @@ -1002,21 +1019,21 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, // disable these with multiple cells selected case LFUN_INSET_INSERT: case LFUN_TABULAR_INSERT: - case LFUN_INSERT_CHARSTYLE: - case LFUN_INSET_FLOAT: - case LFUN_INSET_WIDE_FLOAT: - case LFUN_INSET_FOOTNOTE: - case LFUN_INSET_MARGINAL: - case LFUN_INSERT_MATH: + case LFUN_CHARSTYLE_INSERT: + case LFUN_FLOAT_INSERT: + case LFUN_FLOAT_WIDE_INSERT: + case LFUN_FOOTNOTE_INSERT: + case LFUN_MARGINALNOTE_INSERT: + case LFUN_MATH_INSERT: case LFUN_MATH_MODE: case LFUN_MATH_MUTATE: case LFUN_MATH_DISPLAY: - case LFUN_INSERT_NOTE: - case LFUN_INSET_OPTARG: - case LFUN_INSERT_BOX: - case LFUN_INSERT_BRANCH: - case LFUN_INSET_WRAP: - case LFUN_INSET_ERT: { + case LFUN_NOTE_INSERT: + case LFUN_OPTIONAL_INSERT: + case LFUN_BOX_INSERT: + case LFUN_BRANCH_INSERT: + case LFUN_WRAP_INSERT: + case LFUN_ERT_INSERT: { if (tablemode(cur)) { status.enabled(false); return true; @@ -1025,10 +1042,10 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, } // disable in non-fixed-width cells - case LFUN_BREAKLINE: - case LFUN_BREAKPARAGRAPH: - case LFUN_BREAKPARAGRAPHKEEPLAYOUT: - case LFUN_BREAKPARAGRAPH_SKIP: { + case LFUN_BREAK_LINE: + case LFUN_BREAK_PARAGRAPH: + case LFUN_BREAK_PARAGRAPH_KEEP_LAYOUT: + case LFUN_BREAK_PARAGRAPH_SKIP: { if (tabular.getPWidth(cur.idx()).zero()) { status.enabled(false); return true; @@ -1036,6 +1053,13 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, return cell(cur.idx())->getStatus(cur, cmd, status); } + case LFUN_PASTE: + if (tabularStackDirty() && theClipboard().isInternal()) { + status.enabled(true); + return true; + } else + return cell(cur.idx())->getStatus(cur, cmd, status); + case LFUN_INSET_MODIFY: if (translate(cmd.getArg(0)) == TABULAR_CODE) { status.enabled(true); @@ -1050,14 +1074,14 @@ bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd, } -int InsetTabular::latex(Buffer const & buf, ostream & os, +int InsetTabular::latex(Buffer const & buf, odocstream & os, OutputParams const & runparams) const { return tabular.latex(buf, os, runparams); } -int InsetTabular::plaintext(Buffer const & buf, ostream & os, +int InsetTabular::plaintext(Buffer const & buf, odocstream & os, OutputParams const & runparams) const { int const dp = runparams.linelen ? runparams.depth : 0; @@ -1065,14 +1089,7 @@ int InsetTabular::plaintext(Buffer const & buf, ostream & os, } -int InsetTabular::linuxdoc(Buffer const & buf, ostream & os, - OutputParams const & runparams) const -{ - return tabular.linuxdoc(buf,os, runparams); -} - - -int InsetTabular::docbook(Buffer const & buf, ostream & os, +int InsetTabular::docbook(Buffer const & buf, odocstream & os, OutputParams const & runparams) const { int ret = 0; @@ -1120,10 +1137,10 @@ shared_ptr InsetTabular::cell(idx_type idx) } -void InsetTabular::cursorPos - (CursorSlice const & sl, bool boundary, int & x, int & y) const +void InsetTabular::cursorPos(BufferView const & bv, + CursorSlice const & sl, bool boundary, int & x, int & y) const { - cell(sl.idx())->cursorPos(sl, boundary, x, y); + cell(sl.idx())->cursorPos(bv, sl, boundary, x, y); // y offset correction int const row = tabular.row_of_cell(sl.idx()); @@ -1151,29 +1168,27 @@ void InsetTabular::cursorPos } -int InsetTabular::dist(idx_type const cell, int x, int y) const +int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const { int xx = 0; int yy = 0; InsetBase const & inset = *tabular.getCellInset(cell); - Point o = theCoords.getInsets().xy(&inset); + Point o = bv.coordCache().getInsets().xy(&inset); int const xbeg = o.x_ - tabular.getBeginningOfTextInCell(cell); int const xend = xbeg + tabular.getWidthOfColumn(cell); - int const ybeg = o.y_ - inset.ascent(); row_type const row = tabular.row_of_cell(cell); - int const rowheight = tabular.getAscentOfRow(row) - + tabular.getDescentOfRow(row) - + tabular.getAdditionalHeight(row); - int const yend = ybeg + rowheight; + int const ybeg = o.y_ - tabular.getAscentOfRow(row) - + tabular.getAdditionalHeight(row); + int const yend = o.y_ + tabular.getDescentOfRow(row); if (x < xbeg) xx = xbeg - x; else if (x > xend) xx = x - xend; - if (y < ybeg) + if (y < ybeg) yy = ybeg - y; - else if (y > yend) + else if (y > yend) yy = y - yend; //lyxerr << " xbeg=" << xbeg << " xend=" << xend @@ -1189,7 +1204,7 @@ InsetBase * InsetTabular::editXY(LCursor & cur, int x, int y) //lyxerr << "InsetTabular::editXY: " << this << endl; cur.selection() = false; cur.push(*this); - cur.idx() = getNearestCell(x, y); + cur.idx() = getNearestCell(cur.bv(), x, y); resetPos(cur); return cell(cur.idx())->text_.editXY(cur, x, y); } @@ -1197,18 +1212,18 @@ InsetBase * InsetTabular::editXY(LCursor & cur, int x, int y) void InsetTabular::setCursorFromCoordinates(LCursor & cur, int x, int y) const { - cur.idx() = getNearestCell(x, y); + cur.idx() = getNearestCell(cur.bv(), x, y); cell(cur.idx())->text_.setCursorFromCoordinates(cur, x, y); } -InsetTabular::idx_type InsetTabular::getNearestCell(int x, int y) const +InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int y) const { idx_type idx_min = 0; int dist_min = std::numeric_limits::max(); 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 (bv.coordCache().getInsets().has(tabular.getCellInset(i).get())) { + int const d = dist(bv, i, x, y); if (d < dist_min) { dist_min = d; idx_min = i; @@ -1244,7 +1259,7 @@ void InsetTabular::resetPos(LCursor & cur) const int const X1 = 0; int const X2 = maxwidth; int const offset = ADD_TO_TABULAR_WIDTH + 2; - int const x1 = xo() + getCellXPos(cur.idx()) + offset; + int const x1 = xo(cur.bv()) + getCellXPos(cur.idx()) + offset; int const x2 = x1 + tabular.getWidthOfColumn(cur.idx()); if (x1 < X1) @@ -1255,9 +1270,7 @@ void InsetTabular::resetPos(LCursor & cur) const scx_ = 0; } - cur.needsUpdate(); - - InsetTabularMailer(*this).updateDialog(&bv); + cur.updateFlags(Update::Force | Update::FitCursor); } @@ -1306,7 +1319,9 @@ void InsetTabular::movePrevCell(LCursor & cur) } cur.pit() = cur.lastpit(); cur.pos() = cur.lastpos(); - resetPos(cur); + + // FIXME: this accesses the position cache before it is initialized + //resetPos(cur); } @@ -1435,7 +1450,7 @@ void InsetTabular::tabularFeatures(LCursor & cur, case LyXTabular::SET_SPECIAL_COLUMN: case LyXTabular::SET_SPECIAL_MULTI: - tabular.setAlignSpecial(cur.idx(),value,feature); + tabular.setAlignSpecial(cur.idx(), from_utf8(value), feature); break; case LyXTabular::APPEND_ROW: @@ -1471,6 +1486,15 @@ void InsetTabular::tabularFeatures(LCursor & cur, cur.selection() = false; break; + case LyXTabular::COPY_ROW: + tabular.copyRow(bv.buffer()->params(), row); + break; + + case LyXTabular::COPY_COLUMN: + tabular.copyColumn(bv.buffer()->params(), column); + cur.idx() = tabular.getCellNumber(row, column); + break; + case LyXTabular::M_TOGGLE_LINE_TOP: flag = false; case LyXTabular::TOGGLE_LINE_TOP: { @@ -1557,8 +1581,9 @@ void InsetTabular::tabularFeatures(LCursor & cur, #ifdef WITH_WARNINGS #warning Need I say it ? This is horrible. #endif + // FIXME UNICODE Alert::error(_("Error setting multicolumn"), - _("You cannot set multicolumn vertically.")); + _("You cannot set multicolumn vertically.")); return; } if (!cur.selection()) { @@ -1667,12 +1692,72 @@ void InsetTabular::tabularFeatures(LCursor & cur, tabular.setLTNewPage(row, !tabular.getLTNewPage(row)); break; + case LyXTabular::SET_BOOKTABS: + tabular.setBookTabs(true); + break; + + case LyXTabular::UNSET_BOOKTABS: + tabular.setBookTabs(false); + break; + + case LyXTabular::SET_TOP_SPACE: { + LyXLength len; + if (value == "default") + for (row_type i = sel_row_start; i <= sel_row_end; ++i) + tabular.row_info[i].top_space_default = true; + else if (isValidLength(value, &len)) + for (row_type i = sel_row_start; i <= sel_row_end; ++i) { + tabular.row_info[i].top_space_default = false; + tabular.row_info[i].top_space = len; + } + else + for (row_type i = sel_row_start; i <= sel_row_end; ++i) { + tabular.row_info[i].top_space_default = false; + tabular.row_info[i].top_space = len; + } + break; + } + + case LyXTabular::SET_BOTTOM_SPACE: { + LyXLength len; + if (value == "default") + for (row_type i = sel_row_start; i <= sel_row_end; ++i) + tabular.row_info[i].bottom_space_default = true; + else if (isValidLength(value, &len)) + for (row_type i = sel_row_start; i <= sel_row_end; ++i) { + tabular.row_info[i].bottom_space_default = false; + tabular.row_info[i].bottom_space = len; + } + else + for (row_type i = sel_row_start; i <= sel_row_end; ++i) { + tabular.row_info[i].bottom_space_default = false; + tabular.row_info[i].bottom_space = len; + } + break; + } + + case LyXTabular::SET_INTERLINE_SPACE: { + LyXLength len; + if (value == "default") + for (row_type i = sel_row_start; i <= sel_row_end; ++i) + tabular.row_info[i].interline_space_default = true; + else if (isValidLength(value, &len)) + for (row_type i = sel_row_start; i <= sel_row_end; ++i) { + tabular.row_info[i].interline_space_default = false; + tabular.row_info[i].interline_space = len; + } + else + for (row_type i = sel_row_start; i <= sel_row_end; ++i) { + tabular.row_info[i].interline_space_default = false; + tabular.row_info[i].interline_space = len; + } + break; + } + // dummy stuff just to avoid warnings case LyXTabular::LAST_ACTION: break; } - - InsetTabularMailer(*this).updateDialog(&bv); } @@ -1689,13 +1774,6 @@ void InsetTabular::openLayoutDialog(BufferView * bv) const } -void InsetTabular::getLabelList(Buffer const & buffer, - vector & list) const -{ - tabular.getLabelList(buffer, list); -} - - bool InsetTabular::copySelection(LCursor & cur) { if (!cur.selection()) @@ -1729,14 +1807,17 @@ bool InsetTabular::copySelection(LCursor & cur) paste_tabular->setRightLine(paste_tabular->getLastCellInRow(0), true, true); - ostringstream os; + odocstringstream os; OutputParams const runparams; paste_tabular->plaintext(cur.buffer(), os, runparams, 0, true, '\t'); - cur.bv().stuffClipboard(os.str()); + // Needed for the "Edit->Paste recent" menu and the system clipboard. + cap::copySelection(cur, os.str()); + // mark tabular stack dirty - // FIXME: this is a workaround for bug 1919. Should be removed for 1.5, + // 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); + // This must be called after cap::copySelection. + dirtyTabularStack(true); return true; } @@ -1768,7 +1849,9 @@ bool InsetTabular::pasteSelection(LCursor & cur) shared_ptr inset( new InsetText(*paste_tabular->getCellInset(r1, c1))); tabular.setCellInset(r2, c2, inset); - inset->markNew(); + // FIXME: change tracking (MG) + inset->setChange(Change(cur.buffer().params().trackChanges ? + Change::INSERTED : Change::UNCHANGED)); cur.pos() = 0; } } @@ -1788,16 +1871,21 @@ void InsetTabular::cutSelection(LCursor & cur) for (col_type j = cs; j <= ce; ++j) { shared_ptr t = cell(tabular.getCellNumber(i, j)); - if (cur.buffer().params().tracking_changes) - t->markErased(true); + if (cur.buffer().params().trackChanges) + // FIXME: Change tracking (MG) + t->setChange(Change(Change::DELETED)); else t->clear(); } } // cursor position might be invalid now - cur.pos() = cur.lastpos(); + if (cur.pit() > cur.lastpit()) + cur.pit() = cur.lastpit(); + if (cur.pos() > cur.lastpos()) + cur.pos() = cur.lastpos(); cur.clearSelection(); + theSelection().haveSelection(false); } @@ -1805,9 +1893,9 @@ bool InsetTabular::isRightToLeft(LCursor & cur) const { BOOST_ASSERT(cur.depth() > 1); Paragraph const & parentpar = cur[cur.depth() - 2].paragraph(); - LCursor::pos_type const parentpos = cur[cur.depth() - 2].pos(); + pos_type const parentpos = cur[cur.depth() - 2].pos(); return parentpar.getFontSettings(cur.bv().buffer()->params(), - parentpos).language()->RightToLeft(); + parentpos).language()->rightToLeft(); } @@ -1838,10 +1926,24 @@ LyXText * InsetTabular::getText(int idx) const } -void InsetTabular::markErased(bool erased) +void InsetTabular::setChange(Change const & change) { for (idx_type idx = 0; idx < nargs(); ++idx) - cell(idx)->markErased(erased); + cell(idx)->setChange(change); +} + + +void InsetTabular::acceptChanges() +{ + for (idx_type idx = 0; idx < nargs(); ++idx) + cell(idx)->acceptChanges(); +} + + +void InsetTabular::rejectChanges() +{ + for (idx_type idx = 0; idx < nargs(); ++idx) + cell(idx)->rejectChanges(); } @@ -1851,19 +1953,22 @@ bool InsetTabular::forceDefaultParagraphs(idx_type cell) const } -bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, +bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf, bool usePaste) { if (buf.length() <= 0) return true; + Buffer const & buffer = *bv.buffer(); + col_type cols = 1; row_type rows = 1; col_type maxCols = 1; - string::size_type const len = buf.length(); - string::size_type p = 0; + docstring::size_type const len = buf.length(); + docstring::size_type p = 0; - while (p < len && (p = buf.find_first_of("\t\n", p)) != string::npos) { + while (p < len && + (p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos) { switch (buf[p]) { case '\t': ++cols; @@ -1884,9 +1989,10 @@ bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, row_type row = 0; if (usePaste) { paste_tabular.reset( - new LyXTabular(bv.buffer()->params(), rows, maxCols)); + new LyXTabular(buffer.params(), rows, maxCols)); loctab = paste_tabular.get(); cols = 0; + dirtyTabularStack(true); } else { loctab = &tabular; cell = bv.cursor().idx(); @@ -1894,7 +2000,7 @@ bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, row = tabular.row_of_cell(cell); } - string::size_type op = 0; + docstring::size_type op = 0; idx_type const cells = loctab->getNumberOfCells(); p = 0; cols = ocol; @@ -1902,7 +2008,7 @@ bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, col_type const columns = loctab->columns(); while (cell < cells && p < len && row < rows && - (p = buf.find_first_of("\t\n", p)) != string::npos) + (p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos) { if (p >= len) break; @@ -1912,8 +2018,9 @@ bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, if (cols < columns) { shared_ptr inset = loctab->getCellInset(cell); Paragraph & par = inset->text_.getPar(0); - LyXFont const font = inset->text_.getFont(par, 0); - inset->setText(buf.substr(op, p - op), font); + LyXFont const font = inset->text_.getFont(buffer, par, 0); + inset->setText(buf.substr(op, p - op), font, + buffer.params().trackChanges); ++cols; ++cell; } @@ -1923,8 +2030,9 @@ bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, if (cols < columns) { shared_ptr inset = tabular.getCellInset(cell); Paragraph & par = inset->text_.getPar(0); - LyXFont const font = inset->text_.getFont(par, 0); - inset->setText(buf.substr(op, p - op), font); + LyXFont const font = inset->text_.getFont(buffer, par, 0); + inset->setText(buf.substr(op, p - op), font, + buffer.params().trackChanges); } cols = ocol; ++row; @@ -1939,8 +2047,9 @@ bool InsetTabular::insertAsciiString(BufferView & bv, string const & buf, if (cell < cells && op < len) { shared_ptr inset = loctab->getCellInset(cell); Paragraph & par = inset->text_.getPar(0); - LyXFont const font = inset->text_.getFont(par, 0); - inset->setText(buf.substr(op, len - op), font); + LyXFont const font = inset->text_.getFont(buffer, par, 0); + inset->setText(buf.substr(op, len - op), font, + buffer.params().trackChanges); } return true; } @@ -1992,14 +2101,14 @@ void InsetTabularMailer::string2params(string const & in, InsetTabular & inset) lex >> token; if (!lex || token != name_) return print_mailer_error("InsetTabularMailer", in, 1, - name_); + name_); // This is part of the inset proper that is usually swallowed // by Buffer::readInset lex >> token; if (!lex || token != "Tabular") return print_mailer_error("InsetTabularMailer", in, 2, - "Tabular"); + "Tabular"); Buffer const & buffer = inset.buffer(); inset.read(buffer, lex); @@ -2014,3 +2123,6 @@ string const InsetTabularMailer::params2string(InsetTabular const & inset) data << "\\end_inset\n"; return data.str(); } + + +} // namespace lyx