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

Reply via email to