On Fri, Dec 21, 2012 at 10:07 AM, Richard Heck <rgh...@lyx.org> wrote: > On 12/21/2012 03:11 AM, Scott Kostyshak wrote:
> Wrong patch. Sorry about that. Correct patch attached. Thanks, Scott
From 43c8594ac5ac0eba2c2dcc224dd8921b19498a25 Mon Sep 17 00:00:00 2001 From: Scott Kostyshak <skost...@lyx.org> Date: Wed, 19 Dec 2012 05:28:16 -0500 Subject: [PATCH] Implement move row/column in tabular inset This patch implements 'move row' and 'move column' features for tabular. The purpose is to provide a useful behavior in tabular that is consistent with PARAGRAPH_MOVE_UP and PARAGRAPH_MOVE_DOWN so that the user can, for example, do alt-<up> to move a row up. If there is any selection, the feature is disabled. This is consistent with how PARAGRAPH_MOVE_UP works in other contexts. Additionally, 'move row' is disabled if there is a multi-row in the current or target row; and 'move column' is disabled if there is a multi-column in the current or target column. 'move row' moves only the left and right borders of a cell along with the row and does not move the top and bottom borders. Similarly, 'move column' moves only the the top and bottom borders. --- lib/bind/cua.bind | 3 +- lib/bind/emacs.bind | 2 + lib/bind/mac.bind | 2 + lib/bind/sciword.bind | 2 + lib/bind/xemacs.bind | 6 +- src/LyXAction.cpp | 2 + src/insets/InsetTabular.cpp | 256 ++++++++++++++++++++++++++++++++++++++++++- src/insets/InsetTabular.h | 31 ++++++ 8 files changed, 300 insertions(+), 4 deletions(-) diff --git a/lib/bind/cua.bind b/lib/bind/cua.bind index 4d6c286..44bfcf6 100644 --- a/lib/bind/cua.bind +++ b/lib/bind/cua.bind @@ -134,6 +134,8 @@ Format 1 \bind "M-Up" "paragraph-move-up" \bind "M-Down" "paragraph-move-down" +\bind "M-Right" "inset-modify tabular move-column-right" +\bind "M-Left" "inset-modify tabular move-column-left" \bind "C-Right" "word-right" \bind "C-Left" "word-left" \bind "C-Up" "paragraph-up" @@ -146,7 +148,6 @@ Format 1 \bind "C-~S-greater" "label-goto" \bind "C-~S-less" "bookmark-goto 0" - # # Motion + select group # diff --git a/lib/bind/emacs.bind b/lib/bind/emacs.bind index fd7123f..b9b4ec6 100644 --- a/lib/bind/emacs.bind +++ b/lib/bind/emacs.bind @@ -149,6 +149,8 @@ Format 1 \bind "M-Up" "paragraph-move-up" \bind "M-Down" "paragraph-move-down" +\bind "M-Right" "inset-modify tabular move-column-right" +\bind "M-Left" "inset-modify tabular move-column-left" \bind "C-Right" "word-right" \bind "C-Left" "word-left" \bind "C-Up" "paragraph-up" diff --git a/lib/bind/mac.bind b/lib/bind/mac.bind index c85ec8d..da12d8e 100644 --- a/lib/bind/mac.bind +++ b/lib/bind/mac.bind @@ -360,6 +360,8 @@ Format 1 \bind "Escape" "cancel" \bind "C-M-Up" "paragraph-move-up" \bind "C-M-Down" "paragraph-move-down" +\bind "C-M-Right" "inset-modify tabular move-column-right" +\bind "C-M-Left" "inset-modify tabular move-column-left" #\bind "F9" "meta-prefix" # Include menu and math bindings diff --git a/lib/bind/sciword.bind b/lib/bind/sciword.bind index 3367c4e..ccf4cb7 100644 --- a/lib/bind/sciword.bind +++ b/lib/bind/sciword.bind @@ -219,6 +219,8 @@ Format 1 \bind "M-Up" "paragraph-move-up" \bind "M-Down" "paragraph-move-down" +\bind "M-Right" "inset-modify tabular move-column-right" +\bind "M-Left" "inset-modify tabular move-column-left" \bind "S-KP_Right" "char-right-select" \bind "S-KP_Left" "char-left-select" \bind "S-KP_Up" "up-select" diff --git a/lib/bind/xemacs.bind b/lib/bind/xemacs.bind index 90ada4f..996f2c5 100644 --- a/lib/bind/xemacs.bind +++ b/lib/bind/xemacs.bind @@ -146,8 +146,10 @@ Format 1 # Motion group # -\bind "M-Up" "paragraph-move-up" -\bind "M-Down" "paragraph-move-down" +\bind "M-Up" "paragraph-move-up" +\bind "M-Down" "paragraph-move-down" +\bind "M-Right" "inset-modify tabular move-column-right" +\bind "M-Left" "inset-modify tabular move-column-left" \bind "C-Right" "word-right" \bind "C-Left" "word-left" \bind "C-Up" "paragraph-up" diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 68ce15d..5289a31 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -1931,6 +1931,7 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_PARAGRAPH_MOVE_DOWN * \li Action: Moves the current paragraph downwards in the document. + If in a table, move the current row downwards. * \li Syntax: paragraph-move-down * \li Origin: Edwin, 8 Apr 2006 * \endvar @@ -1939,6 +1940,7 @@ void LyXAction::init() /*! * \var lyx::FuncCode lyx::LFUN_PARAGRAPH_MOVE_UP * \li Action: Moves the current paragraph upwards in the document. + If in a table, move the current row upwards. * \li Notion: Movement through the document will possibly break the paragraph-depth (e.g. itemize structure). * \li Syntax: paragraph-move-up diff --git a/src/insets/InsetTabular.cpp b/src/insets/InsetTabular.cpp index f8d8686..0845ca5 100644 --- a/src/insets/InsetTabular.cpp +++ b/src/insets/InsetTabular.cpp @@ -13,6 +13,7 @@ * \author Jürgen Vigna * \author Uwe Stöhr * \author Edwin Leuven + * \author Scott Kostyshak * * Full author contact details are available in file CREDITS. */ @@ -114,6 +115,10 @@ TabularFeature tabularFeature[] = { Tabular::DELETE_COLUMN, "delete-column", false }, { Tabular::COPY_ROW, "copy-row", false }, { Tabular::COPY_COLUMN, "copy-column", false }, + { Tabular::MOVE_COLUMN_RIGHT, "move-column-right", false }, + { Tabular::MOVE_COLUMN_LEFT, "move-column-left", false }, + { Tabular::MOVE_ROW_DOWN, "move-row-down", false }, + { Tabular::MOVE_ROW_UP, "move-row-up", false }, { Tabular::SET_LINE_TOP, "set-line-top", true }, { Tabular::SET_LINE_BOTTOM, "set-line-bottom", true }, { Tabular::SET_LINE_LEFT, "set-line-left", true }, @@ -769,6 +774,125 @@ void Tabular::insertRow(row_type const row, bool copy) } +void Tabular::moveColumn(col_type col, Tabular::ColDirection const direction) +{ + if (direction == Tabular::LEFT) + col = col -1; + + swapColumns(col, col + 1); + updateIndexes(); + + // Note that the names refer to the positions after the swap. + map< pair<row_type, col_type>, pair<bool, bool> > cMap; + map< pair<row_type, col_type>, pair<bool, bool> > cplus1Map; + + // Could potentially do everything in one loop, but would have to be + // careful with multi-row cells. Currently the first loop reads the + // borders and the second loop writes them. + for (row_type r = 0; r < nrows(); ++r) { + + // Cells part of a multi-row will write to the same idx. + { + idx_type const i = cellIndex(r, col); + cMap[make_pair(r, col)] = + make_pair(leftLine(i), rightLine(i)); + } + { + idx_type const j = cellIndex(r, col + 1); + cplus1Map[make_pair(r, col + 1)] = + make_pair(leftLine(j), rightLine(j)); + } + } + + for (row_type r = 0; r < nrows(); ++r) { + idx_type const i = cellIndex(r, col); + idx_type const j = cellIndex(r, col + 1); + + pair<bool, bool> const j_lines = + cplus1Map[make_pair(r, col + 1)]; + setLeftLine(i, j_lines.first); + setRightLine(i, j_lines.second); + + pair<bool, bool> const i_lines = + cMap[make_pair(r, col)]; + setLeftLine(j, i_lines.first); + setRightLine(j, i_lines.second); + + if (buffer().params().trackChanges) { + cellInfo(i).inset->setChange(Change(Change::INSERTED)); + cellInfo(j).inset->setChange(Change(Change::INSERTED)); + } + } +} + + +void Tabular::swapColumns(col_type const & c1, col_type const & c2) +{ + for (row_type r = 0; r < nrows(); ++r) { + std::swap(cell_info[r][c1], cell_info[r][c2]); + } +} + + +void Tabular::moveRow(row_type row, Tabular::RowDirection const direction) +{ + if (direction == Tabular::UP) + row = row - 1; + + swapRows(row, row + 1); + + updateIndexes(); + + // Note that the names refer to the positions after the swap. + map< pair<row_type, col_type>, pair<bool, bool> > rMap; + map< pair<row_type, col_type>, pair<bool, bool> > rplus1Map; + + // Could potentially do everything in one loop, but would have to be + // careful with multi-column cells. Currently the first loop reads the + // borders and the second loop writes them. + for (col_type c = 0; c < ncols(); ++c) { + + // Cells part of a multi-column will write to the same idx. + { + idx_type const i = cellIndex(row, c); + rMap[make_pair(row, c)] = + make_pair(topLine(i), bottomLine(i)); + } + { + idx_type const j = cellIndex(row + 1, c); + rplus1Map[make_pair(row + 1, c)] = + make_pair(topLine(j), bottomLine(j)); + } + } + + for (col_type c = 0; c < ncols(); ++c) { + idx_type const i = cellIndex(row, c); + idx_type const j = cellIndex(row + 1, c); + + pair<bool, bool> const j_lines = + rplus1Map[make_pair(row + 1, c)]; + setTopLine(i, j_lines.first); + setBottomLine(i, j_lines.second); + + pair<bool, bool> const i_lines = + rMap[make_pair(row, c)]; + setTopLine(j, i_lines.first); + setBottomLine(j, i_lines.second); + + if (buffer().params().trackChanges) { + cellInfo(i).inset->setChange(Change(Change::INSERTED)); + cellInfo(j).inset->setChange(Change(Change::INSERTED)); + } + } +} + + +void Tabular::swapRows(row_type const & r1, row_type const & r2) +{ + std::swap(cell_info[r1], cell_info[r2]); +} + + void Tabular::deleteColumn(col_type const col) { // Not allowed to delete last column @@ -1603,6 +1727,16 @@ bool Tabular::isMultiColumn(idx_type cell) const } +bool Tabular::hasMultiColumn(col_type c) const +{ + for (row_type r = 0; r < nrows(); ++r) { + if(isMultiColumn(cellIndex(r, c))) + return(true); + } + return(false); +} + + Tabular::CellData & Tabular::cellInfo(idx_type cell) const { return cell_info[cellRow(cell)][cellColumn(cell)]; @@ -1643,6 +1777,14 @@ bool Tabular::isMultiRow(idx_type cell) const || cellInfo(cell).multirow == CELL_PART_OF_MULTIROW); } +bool Tabular::hasMultiRow(row_type r) const +{ + for (col_type c = 0; c < ncols(); ++c) { + if(isMultiRow(cellIndex(r, c))) + return(true); + } + return(false); +} Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number, bool const bottom_border) @@ -4174,6 +4316,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd) // break; // } + case LFUN_PARAGRAPH_MOVE_DOWN: + tabularFeatures(cur, Tabular::MOVE_ROW_DOWN); + break; + + case LFUN_PARAGRAPH_MOVE_UP: + tabularFeatures(cur, Tabular::MOVE_ROW_UP); + break; + case LFUN_LAYOUT_TABULAR: cur.bv().showDialog("tabular"); break; @@ -4410,6 +4560,84 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, status.setEnabled(!tabular.rotate && !tabular.is_long_tabular && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE); break; + case Tabular::MOVE_COLUMN_RIGHT: + if (cur.selection()) { + status.message(_("Selections not supported.")); + status.setEnabled(false); + break; + } + if (tabular.ncols() == tabular.cellColumn(cur.idx()) + 1) { + status.setEnabled(false); + break; + } + if (tabular.hasMultiColumn(tabular.cellColumn(cur.idx())) || + tabular.hasMultiColumn(tabular.cellColumn(cur.idx()) + 1)) { + status.message(_("Multi-column in current or" + " destination column.")); + status.setEnabled(false); + break; + } + status.setEnabled(true); + break; + case Tabular::MOVE_COLUMN_LEFT: + if (cur.selection()) { + status.message(_("Selections not supported.")); + status.setEnabled(false); + break; + } + if (tabular.cellColumn(cur.idx()) == 0) { + status.setEnabled(false); + break; + } + if (tabular.hasMultiColumn(tabular.cellColumn(cur.idx())) || + tabular.hasMultiColumn(tabular.cellColumn(cur.idx()) - 1)) { + status.message(_("Multi-column in current or" + " destination column.")); + status.setEnabled(false); + break; + } + status.setEnabled(true); + break; + + case Tabular::MOVE_ROW_DOWN: + if (cur.selection()) { + status.message(_("Selections not supported.")); + status.setEnabled(false); + break; + } + if (tabular.nrows() == tabular.cellRow(cur.idx()) + 1) { + status.setEnabled(false); + break; + } + if (tabular.hasMultiRow(tabular.cellRow(cur.idx())) || + tabular.hasMultiRow(tabular.cellRow(cur.idx()) + 1)) { + status.message(_("Multi-row in current or" + " destination row.")); + status.setEnabled(false); + break; + } + status.setEnabled(true); + break; + + case Tabular::MOVE_ROW_UP: + if (cur.selection()) { + status.message(_("Selections not supported.")); + status.setEnabled(false); + break; + } + if (tabular.cellRow(cur.idx()) == 0) { + status.setEnabled(false); + break; + } + if (tabular.hasMultiRow(tabular.cellRow(cur.idx())) || + tabular.hasMultiRow(tabular.cellRow(cur.idx()) - 1)) { + status.message(_("Multi-row in current or" + " destination row.")); + status.setEnabled(false); + break; + } + status.setEnabled(true); + break; case Tabular::SET_DECIMAL_POINT: status.setEnabled( @@ -4731,6 +4959,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd, return cell(cur.idx())->getStatus(cur, cmd, status); } + case LFUN_PARAGRAPH_MOVE_DOWN: + return getStatus(cur, FuncRequest(LFUN_INSET_MODIFY, "tabular move-row-down"), status); + + case LFUN_PARAGRAPH_MOVE_UP: + return getStatus(cur, FuncRequest(LFUN_INSET_MODIFY, "tabular move-row-up"), status); + // disable in non-fixed-width cells case LFUN_PARAGRAPH_BREAK: // multirow does not allow paragraph breaks @@ -5361,6 +5595,26 @@ void InsetTabular::tabularFeatures(Cursor & cur, cur.idx() = tabular.cellIndex(row, column); break; + case Tabular::MOVE_COLUMN_RIGHT: + tabular.moveColumn(column, Tabular::RIGHT); + cur.idx() = tabular.cellIndex(row, column + 1); + break; + + case Tabular::MOVE_COLUMN_LEFT: + tabular.moveColumn(column, Tabular::LEFT); + cur.idx() = tabular.cellIndex(row, column - 1); + break; + + case Tabular::MOVE_ROW_DOWN: + tabular.moveRow(row, Tabular::DOWN); + cur.idx() = tabular.cellIndex(row + 1, column); + break; + + case Tabular::MOVE_ROW_UP: + tabular.moveRow(row, Tabular::UP); + cur.idx() = tabular.cellIndex(row - 1, column); + break; + case Tabular::SET_LINE_TOP: case Tabular::TOGGLE_LINE_TOP: { bool lineSet = (feature == Tabular::SET_LINE_TOP) @@ -5436,7 +5690,7 @@ void InsetTabular::tabularFeatures(Cursor & cur, tabular.rightLine(cur.idx())); break; } - // we have a selection so this means we just add all this + // we have a selection so this means we just add all these // cells to form a multicolumn cell idx_type const s_start = cur.selBegin().idx(); row_type const col_start = tabular.cellColumn(s_start); diff --git a/src/insets/InsetTabular.h b/src/insets/InsetTabular.h index 80958cc..5dc0b3e 100644 --- a/src/insets/InsetTabular.h +++ b/src/insets/InsetTabular.h @@ -10,6 +10,7 @@ * \author Jürgen Vigna * \author Edwin Leuven * \author Uwe Stöhr + * \author Scott Kostyshak * * Full author contact details are available in file CREDITS. */ @@ -136,6 +137,14 @@ public: /// COPY_COLUMN, /// + MOVE_COLUMN_RIGHT, + /// + MOVE_COLUMN_LEFT, + /// + MOVE_ROW_DOWN, + /// + MOVE_ROW_UP, + /// SET_LINE_TOP, /// SET_LINE_BOTTOM, @@ -331,6 +340,16 @@ public: CAPTION_ANY }; + enum RowDirection { + UP = 0, + DOWN + }; + + enum ColDirection { + RIGHT = 0, + LEFT + }; + class ltType { public: // constructor @@ -453,6 +472,14 @@ public: /// void insertRow(row_type row, bool copy); /// + void moveColumn(col_type col, Tabular::ColDirection direction); + /// + void swapColumns(col_type const & c1, col_type const & c2); + /// + void moveRow(row_type row, Tabular::RowDirection direction); + /// + void swapRows(row_type const & r1, row_type const & r2); + /// void appendColumn(col_type column); /// void deleteColumn(col_type column); @@ -483,6 +510,8 @@ public: /// bool isMultiColumn(idx_type cell) const; /// + bool hasMultiColumn(col_type cell) const; + /// idx_type setMultiColumn(idx_type cell, idx_type number, bool const right_border); /// @@ -494,6 +523,8 @@ public: /// bool isMultiRow(idx_type cell) const; /// + bool hasMultiRow(row_type r) const; + /// idx_type setMultiRow(idx_type cell, idx_type number, bool const bottom_border); /// -- 1.7.9.5