]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetTabular.cpp
Fix crash after undo following replacement of a multicell selection (#8973).
[lyx.git] / src / insets / InsetTabular.cpp
index fca719853f8b518071811216d5ba5fb78787bd43..b12474344606c04db87920a5ca81e3f92c5408a4 100644 (file)
@@ -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.
  */
@@ -32,6 +33,7 @@
 #include "DispatchResult.h"
 #include "FuncRequest.h"
 #include "FuncStatus.h"
+#include "InsetList.h"
 #include "Language.h"
 #include "LaTeXFeatures.h"
 #include "Lexer.h"
 
 #include <boost/scoped_ptr.hpp>
 
-#include <sstream>
+#include <cstring>
 #include <iostream>
 #include <limits>
-#include <cstring>
+#include <sstream>
 
 using namespace std;
 using namespace lyx::support;
 
-using boost::shared_ptr;
 
 
 namespace lyx {
@@ -89,7 +90,7 @@ namespace Alert = frontend::Alert;
 namespace {
 
 int const ADD_TO_HEIGHT = 2; // in cell
-int const ADD_TO_TABULAR_WIDTH = 6; // horiz space before and after the table
+int const ADD_TO_TABULAR_WIDTH = 6; // horizontal space before and after the table
 int const default_line_space = 10; // ?
 int const WIDTH_OF_LINE = 5; // space between double lines
 
@@ -107,17 +108,22 @@ struct TabularFeature {
 
 TabularFeature tabularFeature[] =
 {
+       // the SET/UNSET actions are used by the table dialog,
+       // the TOGGLE actions by the table toolbar buttons
        { Tabular::APPEND_ROW, "append-row", false },
        { Tabular::APPEND_COLUMN, "append-column", false },
        { Tabular::DELETE_ROW, "delete-row", false },
        { 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 },
        { Tabular::SET_LINE_RIGHT, "set-line-right", true },
-       //FIXME: get rid of those 4 TOGGLE actions in favor of the 4 above.
        { Tabular::TOGGLE_LINE_TOP, "toggle-line-top", false },
        { Tabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom", false },
        { Tabular::TOGGLE_LINE_LEFT, "toggle-line-left", false },
@@ -126,6 +132,7 @@ TabularFeature tabularFeature[] =
        { Tabular::ALIGN_RIGHT, "align-right", false },
        { Tabular::ALIGN_CENTER, "align-center", false },
        { Tabular::ALIGN_BLOCK, "align-block", false },
+       { Tabular::ALIGN_DECIMAL, "align-decimal", false },
        { Tabular::VALIGN_TOP, "valign-top", false },
        { Tabular::VALIGN_BOTTOM, "valign-bottom", false },
        { Tabular::VALIGN_MIDDLE, "valign-middle", false },
@@ -136,19 +143,24 @@ TabularFeature tabularFeature[] =
        { Tabular::M_VALIGN_BOTTOM, "m-valign-bottom", false },
        { Tabular::M_VALIGN_MIDDLE, "m-valign-middle", false },
        { Tabular::MULTICOLUMN, "multicolumn", false },
+       { Tabular::SET_MULTICOLUMN, "set-multicolumn", false },
+       { Tabular::UNSET_MULTICOLUMN, "unset-multicolumn", false },
        { Tabular::MULTIROW, "multirow", false },
+       { Tabular::SET_MULTIROW, "set-multirow", false },
+       { Tabular::UNSET_MULTIROW, "unset-multirow", false },
+       { Tabular::SET_MROFFSET, "set-mroffset", true },
        { Tabular::SET_ALL_LINES, "set-all-lines", false },
        { Tabular::UNSET_ALL_LINES, "unset-all-lines", false },
        { Tabular::SET_LONGTABULAR, "set-longtabular", false },
        { Tabular::UNSET_LONGTABULAR, "unset-longtabular", false },
        { Tabular::SET_PWIDTH, "set-pwidth", true },
        { Tabular::SET_MPWIDTH, "set-mpwidth", true },
-       { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular", false },
-       { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular", false },
-       { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular", false },
-       { Tabular::SET_ROTATE_CELL, "set-rotate-cell", false },
-       { Tabular::UNSET_ROTATE_CELL, "unset-rotate-cell", false },
-       { Tabular::TOGGLE_ROTATE_CELL, "toggle-rotate-cell", false },
+       { Tabular::SET_ROTATE_TABULAR, "set-rotate-tabular", true },
+       { Tabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular", true },
+       { Tabular::TOGGLE_ROTATE_TABULAR, "toggle-rotate-tabular", true },
+       { Tabular::SET_ROTATE_CELL, "set-rotate-cell", true },
+       { Tabular::UNSET_ROTATE_CELL, "unset-rotate-cell", true },
+       { Tabular::TOGGLE_ROTATE_CELL, "toggle-rotate-cell", true },
        { Tabular::SET_USEBOX, "set-usebox", true },
        { Tabular::SET_LTHEAD, "set-lthead", true },
        { Tabular::UNSET_LTHEAD, "unset-lthead", true },
@@ -159,10 +171,12 @@ TabularFeature tabularFeature[] =
        { Tabular::SET_LTLASTFOOT, "set-ltlastfoot", true },
        { Tabular::UNSET_LTLASTFOOT, "unset-ltlastfoot", true },
        { Tabular::SET_LTNEWPAGE, "set-ltnewpage", false },
+       { Tabular::UNSET_LTNEWPAGE, "unset-ltnewpage", false },
        { Tabular::TOGGLE_LTCAPTION, "toggle-ltcaption", false },
+       { Tabular::SET_LTCAPTION, "set-ltcaption", false },
+       { Tabular::UNSET_LTCAPTION, "unset-ltcaption", false },
        { Tabular::SET_SPECIAL_COLUMN, "set-special-column", true },
        { Tabular::SET_SPECIAL_MULTICOLUMN, "set-special-multicolumn", true },
-       { Tabular::SET_SPECIAL_MULTIROW, "set-special-multirow", false },
        { Tabular::SET_BOOKTABS, "set-booktabs", false },
        { Tabular::UNSET_BOOKTABS, "unset-booktabs", false },
        { Tabular::SET_TOP_SPACE, "set-top-space", true },
@@ -175,66 +189,12 @@ TabularFeature tabularFeature[] =
        { Tabular::LONGTABULAR_ALIGN_LEFT, "longtabular-align-left", false },
        { Tabular::LONGTABULAR_ALIGN_CENTER, "longtabular-align-center", false },
        { Tabular::LONGTABULAR_ALIGN_RIGHT, "longtabular-align-right", false },
+       { Tabular::SET_DECIMAL_POINT, "set-decimal-point", true },
+       { Tabular::SET_TABULAR_WIDTH, "set-tabular-width", true },
        { Tabular::LAST_ACTION, "", false }
 };
 
 
-template <class T>
-string const write_attribute(string const & name, T const & t)
-{
-       string const s = tostr(t);
-       return s.empty() ? s : " " + name + "=\"" + s + "\"";
-}
-
-template <>
-string const write_attribute(string const & name, string const & t)
-{
-       return t.empty() ? t : " " + name + "=\"" + t + "\"";
-}
-
-
-template <>
-string const write_attribute(string const & name, docstring const & t)
-{
-       return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\"";
-}
-
-
-template <>
-string const write_attribute(string const & name, bool const & b)
-{
-       // we write only true attribute values so we remove a bit of the
-       // file format bloat for tabulars.
-       return b ? write_attribute(name, convert<string>(b)) : string();
-}
-
-
-template <>
-string const write_attribute(string const & name, int const & i)
-{
-       // we write only true attribute values so we remove a bit of the
-       // file format bloat for tabulars.
-       return i ? write_attribute(name, convert<string>(i)) : string();
-}
-
-
-template <>
-string const write_attribute(string const & name, Tabular::idx_type const & i)
-{
-       // we write only true attribute values so we remove a bit of the
-       // file format bloat for tabulars.
-       return i ? write_attribute(name, convert<string>(i)) : string();
-}
-
-
-template <>
-string const write_attribute(string const & name, Length const & value)
-{
-       // we write only the value if we really have one same reson as above.
-       return value.zero() ? string() : write_attribute(name, value.asString());
-}
-
-
 string const tostr(LyXAlignment const & num)
 {
        switch (num) {
@@ -252,6 +212,8 @@ string const tostr(LyXAlignment const & num)
                return "layout";
        case LYX_ALIGN_SPECIAL:
                return "special";
+       case LYX_ALIGN_DECIMAL:
+               return "decimal";
        }
        return string();
 }
@@ -312,6 +274,8 @@ bool string2type(string const str, LyXAlignment & num)
                num = LYX_ALIGN_CENTER;
        else if (str == "right")
                num = LYX_ALIGN_RIGHT;
+       else if (str == "decimal")
+               num = LYX_ALIGN_DECIMAL;
        else
                return false;
        return true;
@@ -490,6 +454,61 @@ void l_getline(istream & is, string & str)
        }
 }
 
+template <class T>
+string const write_attribute(string const & name, T const & t)
+{
+       string const s = tostr(t);
+       return s.empty() ? s : " " + name + "=\"" + s + "\"";
+}
+
+template <>
+string const write_attribute(string const & name, string const & t)
+{
+       return t.empty() ? t : " " + name + "=\"" + t + "\"";
+}
+
+
+template <>
+string const write_attribute(string const & name, docstring const & t)
+{
+       return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\"";
+}
+
+
+template <>
+string const write_attribute(string const & name, bool const & b)
+{
+       // we write only true attribute values so we remove a bit of the
+       // file format bloat for tabulars.
+       return b ? write_attribute(name, convert<string>(b)) : string();
+}
+
+
+template <>
+string const write_attribute(string const & name, int const & i)
+{
+       // we write only true attribute values so we remove a bit of the
+       // file format bloat for tabulars.
+       return i ? write_attribute(name, convert<string>(i)) : string();
+}
+
+
+template <>
+string const write_attribute(string const & name, Tabular::idx_type const & i)
+{
+       // we write only true attribute values so we remove a bit of the
+       // file format bloat for tabulars.
+       return i ? write_attribute(name, convert<string>(i)) : string();
+}
+
+
+template <>
+string const write_attribute(string const & name, Length const & value)
+{
+       // we write only the value if we really have one same reson as above.
+       return value.zero() ? string() : write_attribute(name, value.asString());
+}
+
 } // namespace
 
 
@@ -503,6 +522,33 @@ string const featureAsString(Tabular::Feature action)
 }
 
 
+DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d)
+{
+       DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell);
+       for (; dit; dit.forwardChar())
+               if (dit.inTexted() && dit.depth() == 1
+                       && dit.paragraph().find(align_d, false, false, dit.pos()))
+                       break;
+
+       return dit;
+}
+
+
+InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep)
+{
+       InsetTableCell tail = InsetTableCell(head);
+       DocIterator const dit = separatorPos(&head, align_d);
+       hassep = dit;
+       if (hassep) {
+               pit_type const psize = head.paragraphs().front().size();
+               head.paragraphs().front().eraseChars(dit.pos(), psize, false);
+               tail.paragraphs().front().eraseChars(0, 
+                       dit.pos() < psize ? dit.pos() + 1 : psize, false);
+       }
+
+       return tail;
+}
+
 
 /////////////////////////////////////////////////////////////////////
 //
@@ -518,12 +564,15 @@ Tabular::CellData::CellData(Buffer * buf)
          multirow(Tabular::CELL_NORMAL),
          alignment(LYX_ALIGN_CENTER),
          valignment(LYX_VALIGN_TOP),
+         decimal_hoffset(0),
+         decimal_width(0),
+         voffset(0),
          top_line(false),
          bottom_line(false),
          left_line(false),
          right_line(false),
          usebox(BOX_NONE),
-         rotate(false),
+         rotate(0),
          inset(new InsetTableCell(buf))
 {
        inset->setBuffer(*buf);
@@ -535,8 +584,12 @@ Tabular::CellData::CellData(CellData const & cs)
          width(cs.width),
          multicolumn(cs.multicolumn),
          multirow(cs.multirow),
+         mroffset(cs.mroffset),
          alignment(cs.alignment),
          valignment(cs.valignment),
+         decimal_hoffset(cs.decimal_hoffset),
+         decimal_width(cs.decimal_width),
+         voffset(cs.voffset),
          top_line(cs.top_line),
          bottom_line(cs.bottom_line),
          left_line(cs.left_line),
@@ -545,7 +598,7 @@ Tabular::CellData::CellData(CellData const & cs)
          rotate(cs.rotate),
          align_special(cs.align_special),
          p_width(cs.p_width),
-         inset(dynamic_cast<InsetTableCell *>(cs.inset->clone()))
+         inset(static_cast<InsetTableCell *>(cs.inset->clone()))
 {
 }
 
@@ -561,8 +614,12 @@ void Tabular::CellData::swap(CellData & rhs)
        std::swap(width, rhs.width);
        std::swap(multicolumn, rhs.multicolumn);
        std::swap(multirow, rhs.multirow);
+       std::swap(mroffset, rhs.mroffset);
        std::swap(alignment, rhs.alignment);
        std::swap(valignment, rhs.valignment);
+       std::swap(decimal_hoffset, rhs.decimal_hoffset);
+       std::swap(decimal_width, rhs.decimal_width);
+       std::swap(voffset, rhs.voffset);
        std::swap(top_line, rhs.top_line);
        std::swap(bottom_line, rhs.bottom_line);
        std::swap(left_line, rhs.left_line);
@@ -634,8 +691,9 @@ void Tabular::init(Buffer * buf, row_type rows_arg,
        updateIndexes();
        is_long_tabular = false;
        tabular_valignment = LYX_VALIGN_MIDDLE;
+       tabular_width = Length();
        longtabular_alignment = LYX_LONGTABULAR_ALIGN_CENTER;
-       rotate = false;
+       rotate = 0;
        use_booktabs = false;
        // set silly default lines
        for (row_type r = 0; r < nrows(); ++r)
@@ -649,23 +707,54 @@ void Tabular::init(Buffer * buf, row_type rows_arg,
 }
 
 
-void Tabular::appendRow(idx_type const cell)
+void Tabular::deleteRow(row_type const row)
 {
-       row_type const row = cellRow(cell);
+       // Not allowed to delete last row
+       if (nrows() == 1)
+               return;
 
-       row_info.insert(row_info.begin() + row + 1, RowData());
-       row_info[row + 1] = row_info[row];
+       for (col_type c = 0; c < ncols(); ++c) {
+               // Care about multirow cells
+               if (row + 1 < nrows() &&
+                   cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW &&
+                   cell_info[row + 1][c].multirow == CELL_PART_OF_MULTIROW) {
+                               cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW;
+               }
+       }
+       row_info.erase(row_info.begin() + row);
+       cell_info.erase(cell_info.begin() + row);
+       updateIndexes();
+}
+
+
+void Tabular::copyRow(row_type const row)
+{
+       insertRow(row, true);
+}
 
-       cell_info.insert(cell_info.begin() + row + 1,
-               cell_vector(ncols(), CellData(buffer_)));
+
+void Tabular::appendRow(row_type row)
+{
+       insertRow(row, false);
+}
+
+
+void Tabular::insertRow(row_type const row, bool copy)
+{
+       row_info.insert(row_info.begin() + row + 1, RowData(row_info[row]));
+       cell_info.insert(cell_info.begin() + row + 1, 
+               cell_vector(0, CellData(buffer_)));
+       
        for (col_type c = 0; c < ncols(); ++c) {
+               cell_info[row + 1].insert(cell_info[row + 1].begin() + c,
+                       copy ? CellData(cell_info[row][c]) : CellData(buffer_));
+               if (buffer().params().trackChanges)
+                       cell_info[row + 1][c].inset->setChange(Change(Change::INSERTED));
                if (cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW)
                        cell_info[row + 1][c].multirow = CELL_PART_OF_MULTIROW;
-               else
-                       cell_info[row + 1][c].multirow = cell_info[row][c].multirow;
        }
+       
        updateIndexes();
-
        for (col_type c = 0; c < ncols(); ++c) {
                if (isPartOfMultiRow(row, c))
                        continue;
@@ -686,69 +775,51 @@ void Tabular::appendRow(idx_type const cell)
 }
 
 
-void Tabular::deleteRow(row_type const row)
+void Tabular::moveColumn(col_type col, ColDirection direction)
 {
-       // Not allowed to delete last row
-       if (nrows() == 1)
-               return;
+       if (direction == Tabular::LEFT)
+               col = col - 1;
 
-       for (col_type c = 0; c < ncols(); ++c) {
-               // Care about multirow cells
-               if (row + 1 < nrows() &&
-                   cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW &&
-                   cell_info[row + 1][c].multirow == CELL_PART_OF_MULTIROW) {
-                               cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW;
+       std::swap(column_info[col], column_info[col + 1]);
+
+       for (row_type r = 0; r < nrows(); ++r) {
+               std::swap(cell_info[r][col], cell_info[r][col + 1]);
+               std::swap(cell_info[r][col].left_line, cell_info[r][col + 1].left_line);
+               std::swap(cell_info[r][col].right_line, cell_info[r][col + 1].right_line);
+
+               // FIXME track changes is broken for tabular features (#8469)
+               idx_type const i = cellIndex(r, col);
+               idx_type const j = cellIndex(r, col + 1);
+               if (buffer().params().trackChanges) {
+                       cellInfo(i).inset->setChange(Change(Change::INSERTED));
+                       cellInfo(j).inset->setChange(Change(Change::INSERTED));
                }
        }
-       row_info.erase(row_info.begin() + row);
-       cell_info.erase(cell_info.begin() + row);
        updateIndexes();
 }
 
 
-void Tabular::copyRow(row_type const row)
+void Tabular::moveRow(row_type row, RowDirection direction)
 {
-       row_info.insert(row_info.begin() + row, row_info[row]);
-       cell_info.insert(cell_info.begin() + row, cell_info[row]);
+       if (direction == Tabular::UP)
+               row = row - 1;
 
-       if (buffer().params().trackChanges)
-               for (col_type c = 0; c < ncols(); ++c)
-                       cell_info[row + 1][c].inset->setChange(Change(Change::INSERTED));
+       std::swap(row_info[row], row_info[row + 1]);
 
-       updateIndexes();
-}
-
-
-void Tabular::appendColumn(idx_type const cell)
-{
-       col_type const c = cellColumn(cell);
-       
-       column_info.insert(column_info.begin() + c + 1, ColumnData());
-       column_info[c + 1] = column_info[c];
-
-       for (row_type r = 0; r < nrows(); ++r) {
-               cell_info[r].insert(cell_info[r].begin() + c + 1, 
-                       CellData(buffer_));
-               if (cell_info[r][c].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
-                       cell_info[r][c + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
-               else
-                       cell_info[r][c + 1].multicolumn = cell_info[r][c].multicolumn;
-       }
-       updateIndexes();
-       for (row_type r = 0; r < nrows(); ++r) {
-               // inherit line settings
-               idx_type const i = cellIndex(r, c + 1);
-               idx_type const j = cellIndex(r, c);
-               setBottomLine(i, bottomLine(j));
-               setTopLine(i, topLine(j));
-               setLeftLine(i, leftLine(j));
-               if (rightLine(j) && rightLine(j)) {
-                       setRightLine(i, true);
-                       setRightLine(j, false);
-               }
-               if (buffer().params().trackChanges)
+       for (col_type c = 0; c < ncols(); ++c) {
+               std::swap(cell_info[row][c], cell_info[row + 1][c]);
+               std::swap(cell_info[row][c].top_line, cell_info[row + 1][c].top_line);
+               std::swap(cell_info[row][c].bottom_line, cell_info[row + 1][c].bottom_line);
+
+               // FIXME track changes is broken for tabular features (#8469)
+               idx_type const i = cellIndex(row, c);
+               idx_type const j = cellIndex(row + 1, c);
+               if (buffer().params().trackChanges) {
                        cellInfo(i).inset->setChange(Change(Change::INSERTED));
+                       cellInfo(j).inset->setChange(Change(Change::INSERTED));
+               }
        }
+       updateIndexes();
 }
 
 
@@ -773,16 +844,45 @@ void Tabular::deleteColumn(col_type const col)
 
 
 void Tabular::copyColumn(col_type const col)
+{
+       insertColumn(col, true);
+}
+
+
+void Tabular::appendColumn(col_type col)
+{      
+       insertColumn(col, false);
+}
+
+
+void Tabular::insertColumn(col_type const col, bool copy)
 {
        BufferParams const & bp = buffer().params();
-       column_info.insert(column_info.begin() + col, column_info[col]);
+       column_info.insert(column_info.begin() + col + 1, ColumnData(column_info[col]));
 
        for (row_type r = 0; r < nrows(); ++r) {
-               cell_info[r].insert(cell_info[r].begin() + col, cell_info[r][col]);
+               cell_info[r].insert(cell_info[r].begin() + col + 1,
+                       copy ? CellData(cell_info[r][col]) : CellData(buffer_));
                if (bp.trackChanges)
                        cell_info[r][col + 1].inset->setChange(Change(Change::INSERTED));
+               if (cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
+                       cell_info[r][col + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
        }
        updateIndexes();
+       for (row_type r = 0; r < nrows(); ++r) {
+               // inherit line settings
+               idx_type const i = cellIndex(r, col + 1);
+               idx_type const j = cellIndex(r, col);
+               setBottomLine(i, bottomLine(j));
+               setTopLine(i, topLine(j));
+               setLeftLine(i, leftLine(j));
+               if (rightLine(j) && rightLine(j)) {
+                       setRightLine(i, true);
+                       setRightLine(j, false);
+               }
+               if (buffer().params().trackChanges)
+                       cellInfo(i).inset->setChange(Change(Change::INSERTED));
+       }
 }
 
 
@@ -790,6 +890,7 @@ void Tabular::updateIndexes()
 {
        setBuffer(buffer());
        numberofcells = 0;
+       // reset cell number
        for (row_type row = 0; row < nrows(); ++row)
                for (col_type column = 0; column < ncols(); ++column) {
                        if (!isPartOfMultiColumn(row, column)
@@ -804,15 +905,22 @@ void Tabular::updateIndexes()
        rowofcell.resize(numberofcells);
        columnofcell.resize(numberofcells);
        idx_type i = 0;
+       // reset column and row of cells and update their width and alignment
        for (row_type row = 0; row < nrows(); ++row)
                for (col_type column = 0; column < ncols(); ++column) {
-                       if (isPartOfMultiColumn(row, column)
-                               || isPartOfMultiRow(row, column))
+                       if (isPartOfMultiColumn(row, column))
                                continue;
-                       rowofcell[i] = row;
-                       columnofcell[i] = column;
+                       // columnofcell needs to be called before setting width and aligment
+                       // multirow cells inherit the width from the column width
+                       if (!isPartOfMultiRow(row, column)) {
+                               columnofcell[i] = column;
+                               rowofcell[i] = row;
+                       }
                        setFixedWidth(row, column);
-                       updateContentAlignment(row, column);
+                       if (isPartOfMultiRow(row, column))
+                               continue;
+                       cell_info[row][column].inset->setContentAlignment(
+                               getAlignment(cellIndex(row, column)));
                        ++i;
                }
 }
@@ -880,7 +988,7 @@ int Tabular::interColumnSpace(idx_type cell) const
 }
 
 
-int Tabular::columnWidth(idx_type cell) const
+int Tabular::cellWidth(idx_type cell) const
 {
        int w = 0;
        col_type const span = columnSpan(cell);
@@ -908,14 +1016,28 @@ int Tabular::cellHeight(idx_type cell) const
 
 bool Tabular::updateColumnWidths()
 {
+       vector<int> max_dwidth(ncols(), 0);
+       for(col_type c = 0; c < ncols(); ++c)
+               for(row_type r = 0; r < nrows(); ++r) {
+                       idx_type const i = cellIndex(r, c);
+                       if (getAlignment(i) == LYX_ALIGN_DECIMAL)
+                               max_dwidth[c] = max(max_dwidth[c], cell_info[r][c].decimal_width);
+               }
+
        bool update = false;
        // for each col get max of single col cells
        for(col_type c = 0; c < ncols(); ++c) {
                int new_width = 0;
                for(row_type r = 0; r < nrows(); ++r) {
                        idx_type const i = cellIndex(r, c);
-                       if (columnSpan(i) == 1)
-                               new_width = max(new_width, cellInfo(i).width);
+                       if (columnSpan(i) == 1) {
+                               if (getAlignment(i) == LYX_ALIGN_DECIMAL
+                                       && cell_info[r][c].decimal_width!=0)
+                                       new_width = max(new_width, cellInfo(i).width 
+                                               + max_dwidth[c] - cellInfo(i).decimal_width);
+                               else
+                                       new_width = max(new_width, cellInfo(i).width);
+                       }
                }
 
                if (column_info[c].width != new_width) {
@@ -954,21 +1076,35 @@ int Tabular::width() const
 }
 
 
-void Tabular::setCellWidth(idx_type cell, int new_width)
-{
-       cellInfo(cell).width = new_width + 2 * WIDTH_OF_LINE 
-               + interColumnSpace(cell);
-}
-
-
 void Tabular::setAlignment(idx_type cell, LyXAlignment align,
-                             bool onlycolumn)
+                             bool has_width)
 {
-       if (!isMultiColumn(cell) || onlycolumn)
-               column_info[cellColumn(cell)].alignment = align;
-       if (!onlycolumn)
-               cellInfo(cell).alignment = align;
-       cellInset(cell).get()->setContentAlignment(align);
+       col_type const col = cellColumn(cell);
+       // set alignment for the whole row if we are not in a multicolumn cell,
+       // exclude possible multicolumn cells in the row
+       if (!isMultiColumn(cell)) {
+               for (row_type r = 0; r < nrows(); ++r) {
+                       // only if the column has no width the multirow inherits the
+                       // alignment of the column, otherwise it is left aligned
+                       if (!(isMultiRow(cellIndex(r, col)) && has_width)
+                               && !isMultiColumn(cellIndex(r, col))) {
+                               cell_info[r][col].alignment = align;
+                               cell_info[r][col].inset->setContentAlignment(align);
+                       }
+                       if ((isMultiRow(cellIndex(r, col)) && has_width)
+                               && !isMultiColumn(cellIndex(r, col))) {
+                               cell_info[r][col].alignment = LYX_ALIGN_LEFT;
+                               cell_info[r][col].inset->setContentAlignment(LYX_ALIGN_LEFT);
+                       }
+               }
+               column_info[col].alignment = align;
+               docstring & dpoint = column_info[col].decimal_point;
+               if (align == LYX_ALIGN_DECIMAL && dpoint.empty())
+                       dpoint = from_utf8(lyxrc.default_decimal_point);
+       } else {
+               cellInfo(cell).alignment = align; 
+               cellInset(cell).get()->setContentAlignment(align); 
+       }
 }
 
 
@@ -1048,13 +1184,6 @@ bool Tabular::setFixedWidth(row_type r, col_type c)
 }
 
 
-void Tabular::updateContentAlignment(row_type r, col_type c)
-{
-       cell_info[r][c].inset->setContentAlignment(
-               getAlignment(cellIndex(r, c)));
-}
-
-
 bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell,
                Length const & width)
 {
@@ -1073,6 +1202,13 @@ bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell,
 }
 
 
+bool Tabular::setMROffset(Cursor &, idx_type cell, Length const & mroffset)
+{
+       cellInfo(cell).mroffset = mroffset;
+       return true;
+}
+
+
 void Tabular::setAlignSpecial(idx_type cell, docstring const & special,
                                 Tabular::Feature what)
 {
@@ -1168,8 +1304,9 @@ bool Tabular::columnRightLine(col_type c) const
 
 LyXAlignment Tabular::getAlignment(idx_type cell, bool onlycolumn) const
 {
-       if (!onlycolumn && isMultiColumn(cell))
+       if (!onlycolumn && (isMultiColumn(cell) || isMultiRow(cell)))
                return cellInfo(cell).alignment;
+       
        return column_info[cellColumn(cell)].alignment;
 }
 
@@ -1191,9 +1328,9 @@ Length const Tabular::getPWidth(idx_type cell) const
 }
 
 
-int Tabular::cellWidth(idx_type cell) const
+Length const Tabular::getMROffset(idx_type cell) const
 {
-       return cellInfo(cell).width;
+       return cellInfo(cell).mroffset;
 }
 
 
@@ -1202,14 +1339,31 @@ int Tabular::textHOffset(idx_type cell) const
        // the LaTeX Way :-(
        int x = WIDTH_OF_LINE;
 
+       int const w = cellWidth(cell) - cellInfo(cell).width;
+
        switch (getAlignment(cell)) {
        case LYX_ALIGN_CENTER:
-               x += (columnWidth(cell) - cellWidth(cell)) / 2;
+               x += w / 2;
                break;
        case LYX_ALIGN_RIGHT:
-               x += columnWidth(cell) - cellWidth(cell);
-               // + interColumnSpace(cell);
+               x += w;
                break;
+       case LYX_ALIGN_DECIMAL: {
+               // we center when no decimal point
+               if (cellInfo(cell).decimal_width == 0) {
+                       x += w / 2;
+                       break;
+               }
+               col_type const c = cellColumn(cell);
+               int max_dhoffset = 0;
+               for(row_type r = 0; r < row_info.size() ; ++r) {
+                       idx_type const i = cellIndex(r, c);
+                       if (getAlignment(i) == LYX_ALIGN_DECIMAL
+                               && cellInfo(i).decimal_width != 0)
+                               max_dhoffset = max(max_dhoffset, cellInfo(i).decimal_hoffset);
+               }
+               x += max_dhoffset - cellInfo(cell).decimal_hoffset;
+       }
        default:
                // LYX_ALIGN_LEFT: nothing :-)
                break;
@@ -1221,27 +1375,25 @@ int Tabular::textHOffset(idx_type cell) const
 
 int Tabular::textVOffset(idx_type cell) const
 {
-       row_type const r = cellRow(cell);
-       int y = cellHeight(cell) - rowDescent(r) - rowAscent(r);
-       switch (getVAlignment(cell)) {
-          case LYX_VALIGN_TOP:
-                  y = 0;
-                  break;
-          case LYX_VALIGN_MIDDLE:
-                  y = y/2;
-                  break;
-          case LYX_VALIGN_BOTTOM:
-                  break;
+       int voffset = cellInfo(cell).voffset;
+       if (isMultiRow(cell)) {
+               row_type const row = cellRow(cell);
+               voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2; 
        }
-
-       return y;
+       return voffset;
 }
 
 
 Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const
 {
        col_type c = 0;
-       while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW)
+       idx_type const numcells = numberOfCellsInRow(row);
+       // we check against numcells to make sure we do not crash if all the
+       // cells are multirow (bug #7535), but in that case our return value
+       // is really invalid, i.e., it is NOT the first cell in the row. but
+       // i do not know what to do here. (rgh)
+       while (c < numcells - 1
+              && cell_info[row][c].multirow == CELL_PART_OF_MULTIROW)
                ++c;
        return cell_info[row][c].cellno;
 }
@@ -1250,8 +1402,12 @@ Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const
 Tabular::idx_type Tabular::getLastCellInRow(row_type row) const
 {
        col_type c = ncols() - 1;
-       while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW
-               || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN)
+       // of course we check against 0 so we don't crash. but we have the same
+       // problem as in the previous routine: if all the cells are part of a
+       // multirow or part of a multi column, then our return value is invalid.
+       while (c > 0
+              && (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW
+                  || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN))
                --c;
        return cell_info[row][c].cellno;
 }
@@ -1272,7 +1428,7 @@ Tabular::col_type Tabular::cellColumn(idx_type cell) const
        if (cell >= numberofcells)
                return ncols() - 1;
        if (cell == npos)
-               return 0;       
+               return 0;
        return columnofcell[cell];
 }
 
@@ -1287,7 +1443,7 @@ void Tabular::write(ostream & os) const
           << ">\n";
        // global longtable options
        os << "<features"
-          << write_attribute("rotate", rotate)
+          << write_attribute("rotate", convert<string>(rotate))
           << write_attribute("booktabs", use_booktabs)
           << write_attribute("islongtable", is_long_tabular)
           << write_attribute("firstHeadTopDL", endfirsthead.topDL)
@@ -1301,16 +1457,20 @@ void Tabular::write(ostream & os) const
           << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
           << write_attribute("lastFootEmpty", endlastfoot.empty);
        // longtables cannot be aligned vertically
-       if (!is_long_tabular)
+       if (!is_long_tabular) {
           os << write_attribute("tabularvalignment", tabular_valignment);
+          os << write_attribute("tabularwidth", tabular_width);
+       }
        if (is_long_tabular)
           os << write_attribute("longtabularalignment",
                                 longtabular_alignment);
        os << ">\n";
        for (col_type c = 0; c < ncols(); ++c) {
                os << "<column"
-                  << write_attribute("alignment", column_info[c].alignment)
-                  << write_attribute("valignment", column_info[c].valignment)
+                  << write_attribute("alignment", column_info[c].alignment);
+               if (column_info[c].alignment == LYX_ALIGN_DECIMAL)
+                  os << write_attribute("decimal_point", column_info[c].decimal_point);
+               os << write_attribute("valignment", column_info[c].valignment)
                   << write_attribute("width", column_info[c].p_width.asString())
                   << write_attribute("special", column_info[c].align_special)
                   << ">\n";
@@ -1341,6 +1501,7 @@ void Tabular::write(ostream & os) const
                        os << "<cell"
                           << write_attribute("multicolumn", cell_info[r][c].multicolumn)
                           << write_attribute("multirow", cell_info[r][c].multirow)
+                          << write_attribute("mroffset", cell_info[r][c].mroffset)
                           << write_attribute("alignment", cell_info[r][c].alignment)
                           << write_attribute("valignment", cell_info[r][c].valignment)
                           << write_attribute("topline", cell_info[r][c].top_line)
@@ -1370,14 +1531,13 @@ void Tabular::read(Lexer & lex)
 
        l_getline(is, line);
        if (!prefixIs(line, "<lyxtabular ") && !prefixIs(line, "<Tabular ")) {
-               LASSERT(false, /**/);
-               return;
+               LASSERT(false, return);
        }
 
        int version;
        if (!getTokenValue(line, "version", version))
                return;
-       LASSERT(version >= 2, /**/);
+       LATTEST(version >= 2);
 
        int rows_arg;
        if (!getTokenValue(line, "rows", rows_arg))
@@ -1396,6 +1556,7 @@ void Tabular::read(Lexer & lex)
        getTokenValue(line, "booktabs", use_booktabs);
        getTokenValue(line, "islongtable", is_long_tabular);
        getTokenValue(line, "tabularvalignment", tabular_valignment);
+       getTokenValue(line, "tabularwidth", tabular_width);
        getTokenValue(line, "longtabularalignment", longtabular_alignment);
        getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
        getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
@@ -1416,6 +1577,7 @@ void Tabular::read(Lexer & lex)
                        return;
                }
                getTokenValue(line, "alignment", column_info[c].alignment);
+               getTokenValue(line, "decimal_point", column_info[c].decimal_point);
                getTokenValue(line, "valignment", column_info[c].valignment);
                getTokenValue(line, "width", column_info[c].p_width);
                getTokenValue(line, "special", column_info[c].align_special);
@@ -1449,6 +1611,7 @@ void Tabular::read(Lexer & lex)
                        }
                        getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
                        getTokenValue(line, "multirow", cell_info[i][j].multirow);
+                       getTokenValue(line, "mroffset", cell_info[i][j].mroffset);
                        getTokenValue(line, "alignment", cell_info[i][j].alignment);
                        getTokenValue(line, "valignment", cell_info[i][j].valignment);
                        getTokenValue(line, "topline", cell_info[i][j].top_line);
@@ -1493,13 +1656,24 @@ 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)];
 }
 
 
-Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number)
+Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number,
+                                         bool const right_border)
 {
        idx_type const col = cellColumn(cell);
        idx_type const row = cellRow(cell);
@@ -1510,9 +1684,9 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number)
        cell = cellIndex(row, col);
        CellData & cs = cellInfo(cell);
        cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
-       cs.alignment = column_info[col].alignment;
-       if (col > 0)
-               setRightLine(cell, rightLine(cellIndex(row, col - 1)));
+       if (column_info[col].alignment != LYX_ALIGN_DECIMAL)
+               cs.alignment = column_info[col].alignment;
+       setRightLine(cell, right_border);
 
        for (idx_type i = 1; i < number; ++i) {
                CellData & cs1 = cellInfo(cell + i);
@@ -1531,29 +1705,39 @@ 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)
+Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number,
+                                      bool const bottom_border)
 {
        idx_type const col = cellColumn(cell);
        idx_type const row = cellRow(cell);
        for (idx_type i = 0; i < number; ++i)
                unsetMultiColumn(cellIndex(row + i, col));
 
-       // unsetting of multicol may have invalidated cell index
+       // unsetting of multirow may have invalidated cell index
        cell = cellIndex(row, col);
        CellData & cs = cellInfo(cell);
        cs.multirow = CELL_BEGIN_OF_MULTIROW;
        cs.valignment = LYX_VALIGN_MIDDLE;
-       // FIXME: the horizontal alignment of multirow cells can only
-       // be changed for the whole table,
-       // support for this needs to be implemented but us a fileformat
-       // change (assigning this to uwestoehr)
+       // the horizontal alignment of multirow cells can only
+       // be changed for the whole table row,
+       // support changing this only for the multirow cell can be done via
+       // \multirowsetup
+       // this feature would be a fileformat change
        // until LyX supports this, use the deault alignment of multirow
        // cells: left
-       cs.alignment = LYX_ALIGN_LEFT; 
+       cs.alignment = LYX_ALIGN_LEFT;
 
-       // set the bottom row of the last selected cell
-       setBottomLine(cell, bottomLine(cell + (number - 1)*ncols()));
+       // set the bottom line of the last selected cell
+       setBottomLine(cell, bottom_border);
 
        for (idx_type i = 1; i < number; ++i) {
                CellData & cs1 = cell_info[row + i][col];
@@ -1569,11 +1753,12 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number)
 Tabular::idx_type Tabular::columnSpan(idx_type cell) const
 {
        row_type const row = cellRow(cell);
-       col_type column = cellColumn(cell) + 1;
-       while (column < ncols() && isPartOfMultiColumn(row, column))
-               ++column;
+       col_type const col = cellColumn(cell);
+       int span = 1;
+       while (col + span < ncols() && isPartOfMultiColumn(row, col + span))
+               ++span;
 
-       return column - cellColumn(cell);
+       return span;
 }
 
 
@@ -1596,8 +1781,17 @@ void Tabular::unsetMultiColumn(idx_type cell)
        row_type const row = cellRow(cell);
        col_type const col = cellColumn(cell);
        row_type const span = columnSpan(cell);
-       for (col_type c = 0; c < span; ++c)
+       for (col_type c = 0; c < span; ++c) {
+               // in the table dialog the lines are set in every case
+               // when unsetting a multicolumn this leads to an additional right
+               // line for every cell that was part of the former multicolumn cell,
+               // except if the cell is in the last column
+               // therefore remove this line
+               if (cell_info[row][col + c].multicolumn == CELL_BEGIN_OF_MULTICOLUMN
+                       && (col + c) < (col + span - 1))
+                       cell_info[row][col + c].right_line = false;
                cell_info[row][col + c].multicolumn = CELL_NORMAL;
+       }
        updateIndexes();
 }
 
@@ -1618,13 +1812,13 @@ void Tabular::unsetMultiRow(idx_type cell)
 }
 
 
-void Tabular::setRotateCell(idx_type cell, bool flag)
+void Tabular::setRotateCell(idx_type cell, int value)
 {
-       cellInfo(cell).rotate = flag;
+       cellInfo(cell).rotate = value;
 }
 
 
-bool Tabular::getRotateCell(idx_type cell) const
+int Tabular::getRotateCell(idx_type cell) const
 {
        return cellInfo(cell).rotate;
 }
@@ -1636,7 +1830,7 @@ bool Tabular::needRotating() const
                return true;
        for (row_type r = 0; r < nrows(); ++r)
                for (col_type c = 0; c < ncols(); ++c)
-                       if (cell_info[r][c].rotate)
+                       if (cell_info[r][c].rotate != 0)
                                return true;
        return false;
 }
@@ -1675,8 +1869,8 @@ Tabular::idx_type Tabular::cellBelow(idx_type cell) const
 
 Tabular::idx_type Tabular::cellIndex(row_type row, col_type column) const
 {
-       LASSERT(column != npos && column < ncols()
-               && row != npos && row < nrows(), /**/);
+       LASSERT(column != npos && column < ncols(), column = 0);
+       LASSERT(row != npos && row < nrows(), row = 0);
        return cell_info[row][column].cellno;
 }
 
@@ -1777,41 +1971,49 @@ bool Tabular::getLTNewPage(row_type row) const
 }
 
 
-bool Tabular::haveLTHead() const
+bool Tabular::haveLTHead(bool withcaptions) const
 {
+       if (!is_long_tabular)
+               return false;
        for (row_type i = 0; i < nrows(); ++i)
-               if (row_info[i].endhead)
+               if (row_info[i].endhead &&
+                   (withcaptions || !row_info[i].caption))
                        return true;
        return false;
 }
 
 
-bool Tabular::haveLTFirstHead() const
+bool Tabular::haveLTFirstHead(bool withcaptions) const
 {
-       if (endfirsthead.empty)
+       if (!is_long_tabular || endfirsthead.empty)
                return false;
        for (row_type r = 0; r < nrows(); ++r)
-               if (row_info[r].endfirsthead)
+               if (row_info[r].endfirsthead &&
+                   (withcaptions || !row_info[r].caption))
                        return true;
        return false;
 }
 
 
-bool Tabular::haveLTFoot() const
+bool Tabular::haveLTFoot(bool withcaptions) const
 {
+       if (!is_long_tabular)
+               return false;
        for (row_type r = 0; r < nrows(); ++r)
-               if (row_info[r].endfoot)
+               if (row_info[r].endfoot &&
+                   (withcaptions || !row_info[r].caption))
                        return true;
        return false;
 }
 
 
-bool Tabular::haveLTLastFoot() const
+bool Tabular::haveLTLastFoot(bool withcaptions) const
 {
-       if (endlastfoot.empty)
+       if (!is_long_tabular || endlastfoot.empty)
                return false;
        for (row_type r = 0; r < nrows(); ++r)
-               if (row_info[r].endlastfoot)
+               if (row_info[r].endlastfoot &&
+                   (withcaptions || !row_info[r].caption))
                        return true;
        return false;
 }
@@ -1821,11 +2023,16 @@ Tabular::idx_type Tabular::setLTCaption(row_type row, bool what)
 {
        idx_type i = getFirstCellInRow(row);
        if (what) {
-               setMultiColumn(i, numberOfCellsInRow(row));
+               setMultiColumn(i, numberOfCellsInRow(row), false);
                setTopLine(i, false);
                setBottomLine(i, false);
                setLeftLine(i, false);
                setRightLine(i, false);
+               if (!row_info[row].endfirsthead && !row_info[row].endhead &&
+                   !row_info[row].endfoot && !row_info[row].endlastfoot) {
+                       setLTHead(row, true, endfirsthead, true);
+                       row_info[row].endfirsthead = true;
+               }
        } else {
                unsetMultiColumn(i);
                // When unsetting a caption row, also all existing
@@ -1842,11 +2049,34 @@ bool Tabular::ltCaption(row_type row) const
 }
 
 
-bool Tabular::haveLTCaption() const
+bool Tabular::haveLTCaption(CaptionType captiontype) const
 {
-       for (row_type r = 0; r < nrows(); ++r)
-               if (row_info[r].caption)
-                       return true;
+       if (!is_long_tabular)
+               return false;
+       for (row_type r = 0; r < nrows(); ++r) {
+               if (row_info[r].caption) {
+                       switch (captiontype) {
+                       case CAPTION_FIRSTHEAD:
+                               if (row_info[r].endfirsthead)
+                                       return true;
+                               break;
+                       case CAPTION_HEAD:
+                               if (row_info[r].endhead)
+                                       return true;
+                               break;
+                       case CAPTION_FOOT:
+                               if (row_info[r].endfoot)
+                                       return true;
+                               break;
+                       case CAPTION_LASTFOOT:
+                               if (row_info[r].endlastfoot)
+                                       return true;
+                               break;
+                       case CAPTION_ANY:
+                               return true;
+                       }
+               }
+       }
        return false;
 }
 
@@ -1871,14 +2101,14 @@ void Tabular::setRowDescent(row_type row, int height)
 
 int Tabular::rowAscent(row_type row) const
 {
-       LASSERT(row < nrows(), /**/);
+       LASSERT(row < nrows(), row = 0);
        return row_info[row].ascent;
 }
 
 
 int Tabular::rowDescent(row_type row) const
 {
-       LASSERT(row < nrows(), /**/);
+       LASSERT(row < nrows(), row = 0);
        return row_info[row].descent;
 }
 
@@ -1895,21 +2125,21 @@ int Tabular::height() const
 
 bool Tabular::isPartOfMultiColumn(row_type row, col_type column) const
 {
-       LASSERT(row < nrows(), /**/);
-       LASSERT(column < ncols(), /**/);
+       LASSERT(row < nrows(), return false);
+       LASSERT(column < ncols(), return false);
        return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN;
 }
 
 
 bool Tabular::isPartOfMultiRow(row_type row, col_type column) const
 {
-       LASSERT(row < nrows(), /**/);
-       LASSERT(column < ncols(), /**/);
+       LASSERT(row < nrows(), return false);
+       LASSERT(column < ncols(), return false);
        return cell_info[row][column].multirow == CELL_PART_OF_MULTIROW;
 }
 
 
-int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const
+void Tabular::TeXTopHLine(otexstream & os, row_type row, string const lang) const
 {
        // we only output complete row lines and the 1st row here, the rest
        // is done in Tabular::TeXBottomHLine(...)
@@ -1923,15 +2153,15 @@ int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const
                // multirow, no line must be drawn.
                if (row != 0)
                        if (isMultiRow(cellIndex(row, c))
-                               && isMultiRow(cellIndex(row - 1, c)))
-                                       topline[c] = false;
+                           && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW)
+                               topline[c] = false;
                if (topline[c])
                        ++nset;
        }
 
        // do nothing if empty first row, or incomplete row line after
        if ((row == 0 && nset == 0) || (row > 0 && nset != ncols()))
-               return 0;
+               return;
 
        // only output complete row lines and the 1st row's clines
        if (nset == ncols()) {
@@ -1943,27 +2173,35 @@ int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const
        } else if (row == 0) {
                for (col_type c = 0; c < ncols(); ++c) {
                        if (topline[c]) {
+                               col_type offset = 0;
+                               for (col_type j = 0 ; j < c; ++j)
+                                       if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
+                                               ++offset;
+                               
                                //babel makes the "-" character an active one, so we have to suppress this here
                                //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289#
                                if (lang == "slovak" || lang == "czech")
-                                       os << (use_booktabs ? "\\expandafter\\cmidrule\\expandafter{\\expandafter" :
-                                                             "\\expandafter\\cline\\expandafter{\\expandafter")
-                                                                                 << c + 1 << "\\string-";
+                                       os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline") 
+                                       << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-";
                                else
-                                       os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 << '-';
-                               // get to last column of line span
-                               while (c < ncols() && topline[c])
-                                       ++c;
-                               os << c << "} ";
+                                       os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-';
+                               
+                               col_type cstart = c;
+                               for ( ; c < ncols() && topline[c]; ++c) {}
+                               
+                               for (col_type j = cstart ; j < c ; ++j)
+                                       if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
+                                               ++offset;
+                               
+                               os << c + offset << "} ";
                        }
                }
        }
        os << "\n";
-       return 1;
 }
 
 
-int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) const
+void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const lang) const
 {
        // we output bottomlines of row r and the toplines of row r+1
        // if the latter do not span the whole tabular
@@ -1975,13 +2213,14 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) co
        for (col_type c = 0; c < ncols(); ++c) {
                bottomline.push_back(bottomLine(cellIndex(row, c)));
                topline.push_back(!lastrow && topLine(cellIndex(row + 1, c)));
-               // If cell is part of a multirow and not the last or first cell of the
+               // If cell is part of a multirow and not the last cell of the
                // multirow, no line must be drawn.
                if (!lastrow)
                        if (isMultiRow(cellIndex(row, c))
-                               && isMultiRow(cellIndex(row + 1, c))) {
-                                       bottomline[c] = false;
-                                       topline[c] = false;
+                           && isMultiRow(cellIndex(row + 1, c))
+                           && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) {
+                               bottomline[c] = false;
+                               topline[c] = false;
                                }
                nextrowset &= topline[c];
        }
@@ -1997,7 +2236,7 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) co
 
        // do nothing if empty, OR incomplete row line with a topline in next row
        if (nset == 0 || (nextrowset && nset != ncols()))
-               return 0;
+               return;
 
        if (nset == ncols()) {
                if (use_booktabs)
@@ -2007,33 +2246,40 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row, string const lang) co
        } else {
                for (col_type c = 0; c < ncols(); ++c) {
                        if (bottomline[c]) {
+                               col_type offset = 0;
+                               for (col_type j = 0 ; j < c; ++j)
+                                       if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
+                                               ++offset;
+                               
                                //babel makes the "-" character an active one, so we have to suppress this here
                                //see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289#
                                if (lang == "slovak" || lang == "czech")
-                                       os << (use_booktabs ? "\\expandafter\\cmidrule\\expandafter{\\expandafter" :
-                                                             "\\expandafter\\cline\\expandafter{\\expandafter")
-                                                                                 << c + 1 << "\\string-";
+                                       os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline")
+                                       << "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-";
                                else
-                                       os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 << '-';
-                               // get to last column of line span
-                               while (c < ncols() && bottomline[c])
-                                       ++c;
-                               os << c << "} ";
+                                       os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-';
+                               
+                               col_type cstart = c;
+                               for ( ; c < ncols() && bottomline[c]; ++c) {}
+                               
+                               for (col_type j = cstart ; j < c ; ++j)
+                                       if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
+                                               ++offset;
+                               
+                               os << c + offset << "} ";
                        }
                }
        }
        os << "\n";
-       return 1;
 }
 
 
-int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
-                                                        bool & ismulticol, bool & ismultirow) const
+void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
+                             bool & ismulticol, bool & ismultirow) const
 {
-       int ret = 0;
        row_type const r = cellRow(cell);
        if (is_long_tabular && row_info[r].caption)
-               return ret;
+               return;
 
        Tabular::VAlignment valign =  getVAlignment(cell, !isMultiColumn(cell));
        LyXAlignment align = getAlignment(cell, !isMultiColumn(cell));
@@ -2054,8 +2300,22 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
                || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft)
                || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft))
                || (coldouble != celldouble);
+
+       // we center in multicol when no decimal point
+       if (column_info[c].alignment == LYX_ALIGN_DECIMAL) {
+               docstring const align_d = column_info[c].decimal_point;
+               DocIterator const dit = separatorPos(cellInset(cell).get(), align_d);
+               ismulticol |= !dit;
+       }
+
+       // up counter by 1 for each decimally aligned col since they use 2 latex cols
+       int latexcolspan = columnSpan(cell);
+       for(col_type col = c; col < c + columnSpan(cell); ++col)
+               if (column_info[col].alignment == LYX_ALIGN_DECIMAL)
+                       ++latexcolspan;
+
        if (ismulticol) {
-               os << "\\multicolumn{" << columnSpan(cell) << "}{";
+               os << "\\multicolumn{" << latexcolspan << "}{";
                if (c ==0 && leftLine(cell))
                        os << '|';
                if (!cellInfo(cell).align_special.empty()) {
@@ -2109,7 +2369,7 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
                        // add extra vertical line if we want a double one
                        os << '|';
                os << "}{";
-               } // end if ismulticol
+       } // end if ismulticol
 
        // we only need code for the first multirow cell
        ismultirow = isMultiRow(cell);
@@ -2119,15 +2379,16 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
                        os << from_ascii(getPWidth(cell).asLatexString());
                else
                        // we need to set a default value
-                       // needs to be discussed
                        os << "*";
-               os << "}{";
-               } // end if ismultirow
+               os << "}";
+               if (!getMROffset(cell).zero())
+                       os << "[" << from_ascii(getMROffset(cell).asLatexString()) << "]";
+               os << "{";
+       } // end if ismultirow
+
+       if (getRotateCell(cell) != 0)
+               os << "\\begin{turn}{" << convert<string>(getRotateCell(cell)) << "}\n";
 
-       if (getRotateCell(cell)) {
-               os << "\\begin{sideways}\n";
-               ++ret;
-       }
        if (getUsebox(cell) == BOX_PARBOX) {
                os << "\\parbox[";
                switch (valign) {
@@ -2158,137 +2419,99 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
                }
                os << "]{" << from_ascii(getPWidth(cell).asLatexString())
                   << "}\n";
-               ++ret;
        }
-       return ret;
 }
 
 
-int Tabular::TeXCellPostamble(odocstream & os, idx_type cell,
-                                                         bool ismulticol, bool ismultirow) const
+void Tabular::TeXCellPostamble(otexstream & os, idx_type cell,
+                              bool ismulticol, bool ismultirow) const
 {
-       int ret = 0;
        row_type const r = cellRow(cell);
        if (is_long_tabular && row_info[r].caption)
-               return ret;
+               return;
 
        // usual cells
        if (getUsebox(cell) == BOX_PARBOX)
                os << '}';
-       else if (getUsebox(cell) == BOX_MINIPAGE) {
-               os << "%\n\\end{minipage}";
-               ret += 2;
-       }
-       if (getRotateCell(cell)) {
-               os << "%\n\\end{sideways}";
-               ++ret;
-       }
-       if (ismulticol || ismultirow) {
+       else if (getUsebox(cell) == BOX_MINIPAGE)
+               os << breakln << "\\end{minipage}";
+       if (getRotateCell(cell) != 0)
+               os << breakln << "\\end{turn}";
+       if (ismultirow)
+               os << '}';
+       if (ismulticol)
                os << '}';
-       }
-       return ret;
 }
 
 
-int Tabular::TeXLongtableHeaderFooter(odocstream & os,
-                                        OutputParams const & runparams) const
+void Tabular::TeXLongtableHeaderFooter(otexstream & os,
+                                       OutputParams const & runparams) const
 {
        if (!is_long_tabular)
-               return 0;
+               return;
 
-       int ret = 0;
        // caption handling
-       // the caption must be output before the headers
+       // output caption which is in no header or footer
        if (haveLTCaption()) {
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].caption) {
-                               ret += TeXRow(os, r, runparams);
-                       }
+                       if (row_info[r].caption &&
+                           !row_info[r].endfirsthead && !row_info[r].endhead &&
+                           !row_info[r].endfoot && !row_info[r].endlastfoot)
+                               TeXRow(os, r, runparams);
                }
        }
        // output first header info
-       // first header must be output before the header, otherwise the
-       // correct caption placement becomes really weird
        if (haveLTFirstHead()) {
-               if (endfirsthead.topDL) {
+               if (endfirsthead.topDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].endfirsthead) {
-                               ret += TeXRow(os, r, runparams);
-                       }
+                       if (row_info[r].endfirsthead)
+                               TeXRow(os, r, runparams);
                }
-               if (endfirsthead.bottomDL) {
+               if (endfirsthead.bottomDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                os << "\\endfirsthead\n";
-               ++ret;
        }
        // output header info
        if (haveLTHead()) {
-               if (endfirsthead.empty && !haveLTFirstHead()) {
+               if (endfirsthead.empty && !haveLTFirstHead())
                        os << "\\endfirsthead\n";
-                       ++ret;
-               }
-               if (endhead.topDL) {
+               if (endhead.topDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].endhead) {
-                               ret += TeXRow(os, r, runparams);
-                       }
+                       if (row_info[r].endhead)
+                               TeXRow(os, r, runparams);
                }
-               if (endhead.bottomDL) {
+               if (endhead.bottomDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                os << "\\endhead\n";
-               ++ret;
        }
        // output footer info
        if (haveLTFoot()) {
-               if (endfoot.topDL) {
+               if (endfoot.topDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].endfoot) {
-                               ret += TeXRow(os, r, runparams);
-                       }
+                       if (row_info[r].endfoot)
+                               TeXRow(os, r, runparams);
                }
-               if (endfoot.bottomDL) {
+               if (endfoot.bottomDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                os << "\\endfoot\n";
-               ++ret;
-               if (endlastfoot.empty && !haveLTLastFoot()) {
+               if (endlastfoot.empty && !haveLTLastFoot())
                        os << "\\endlastfoot\n";
-                       ++ret;
-               }
        }
        // output lastfooter info
        if (haveLTLastFoot()) {
-               if (endlastfoot.topDL) {
+               if (endlastfoot.topDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].endlastfoot) {
-                               ret += TeXRow(os, r, runparams);
-                       }
+                       if (row_info[r].endlastfoot)
+                               TeXRow(os, r, runparams);
                }
-               if (endlastfoot.bottomDL) {
+               if (endlastfoot.bottomDL)
                        os << "\\hline\n";
-                       ++ret;
-               }
                os << "\\endlastfoot\n";
-               ++ret;
        }
-       return ret;
 }
 
 
@@ -2302,8 +2525,8 @@ bool Tabular::isValidRow(row_type row) const
 }
 
 
-int Tabular::TeXRow(odocstream & os, row_type row,
-                      OutputParams const & runparams) const
+void Tabular::TeXRow(otexstream & os, row_type row,
+                    OutputParams const & runparams) const
 {
        idx_type cell = cellIndex(row, 0);
        shared_ptr<InsetTableCell> inset = cellInset(cell);
@@ -2311,14 +2534,13 @@ int Tabular::TeXRow(odocstream & os, row_type row,
        string const lang = par.getParLanguage(buffer().params())->lang();
 
        //output the top line
-       int ret = TeXTopHLine(os, row, lang);
+       TeXTopHLine(os, row, lang);
 
        if (row_info[row].top_space_default) {
                if (use_booktabs)
                        os << "\\addlinespace\n";
                else
                        os << "\\noalign{\\vskip\\doublerulesep}\n";
-               ++ret;
        } else if(!row_info[row].top_space.zero()) {
                if (use_booktabs)
                        os << "\\addlinespace["
@@ -2329,23 +2551,30 @@ int Tabular::TeXRow(odocstream & os, row_type row,
                           << from_ascii(row_info[row].top_space.asLatexString())
                           << "}\n";
                }
-               ++ret;
        }
        bool ismulticol = false;
        bool ismultirow = false;
        for (col_type c = 0; c < ncols(); ++c) {
-               if (isPartOfMultiRow(row, c))
-                       os << " & "; // we need to add a further column
-               if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c))
+               if (isPartOfMultiColumn(row, c))
                        continue;
+
                cell = cellIndex(row, c);
-               ret += TeXCellPreamble(os, cell, ismulticol, ismultirow);
+
+               if (isPartOfMultiRow(row, c)
+                   && column_info[c].alignment != LYX_ALIGN_DECIMAL) {
+                       if (cell != getLastCellInRow(row))
+                               os << " & "; 
+                       continue;
+               }
+
+               TeXCellPreamble(os, cell, ismulticol, ismultirow);
                shared_ptr<InsetTableCell> inset = cellInset(cell);
 
                Paragraph const & par = inset->paragraphs().front();
                bool rtl = par.isRTL(buffer().params())
                        && !par.empty()
-                       && getPWidth(cell).zero();
+                       && getPWidth(cell).zero()
+                       && !runparams.use_polyglossia;
 
                if (rtl) {
                        string const lang =
@@ -2354,7 +2583,7 @@ int Tabular::TeXRow(odocstream & os, row_type row,
                                os << "\\textFR{";
                        else if (lang == "arabic_arabi")
                                os << "\\textAR{";
-                       // currently, remaning RTL languages are
+                       // currently, remaining RTL languages are
                        // arabic_arabtex and hebrew
                        else
                                os << "\\R{";
@@ -2366,23 +2595,45 @@ int Tabular::TeXRow(odocstream & os, row_type row,
                newrp.inTableCell = (getAlignment(cell) == LYX_ALIGN_BLOCK)
                                    ? OutputParams::PLAIN
                                    : OutputParams::ALIGNED;
-               ret += inset->latex(os, newrp);
+
+               if (getAlignment(cell) == LYX_ALIGN_DECIMAL) {
+                       // copy cell and split in 2
+                       InsetTableCell head = InsetTableCell(*cellInset(cell).get());
+                       head.setBuffer(buffer());
+                       DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition();
+                       dit.pop_back();
+                       dit.push_back(CursorSlice(head));
+                       head.setMacrocontextPositionRecursive(dit);
+                       bool hassep = false;
+                       InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep);
+                       head.latex(os, newrp);
+                       if (hassep) {
+                               os << '&';
+                               tail.setBuffer(head.buffer());
+                               dit.pop_back();
+                               dit.push_back(CursorSlice(tail));
+                               tail.setMacrocontextPositionRecursive(dit);
+                               tail.latex(os, newrp);
+                       }
+               } else if (!isPartOfMultiRow(row, c)) {
+                       if (!runparams.nice)
+                               os.texrow().start(par.id(), 0);
+                       inset->latex(os, newrp);
+               }
+
                runparams.encoding = newrp.encoding;
                if (rtl)
                        os << '}';
 
-               ret += TeXCellPostamble(os, cell, ismulticol, ismultirow);
+               TeXCellPostamble(os, cell, ismulticol, ismultirow);
                if (cell != getLastCellInRow(row)) { // not last cell in row
-                       os << " & ";
+                       if (runparams.nice)
+                               os << " & ";
+                       else
+                               os << " &\n";
                }
        }
-       if (row_info[row].caption && !endfirsthead.empty && !haveLTFirstHead())
-               // if no first header and no empty first header is used,
-               // the caption needs to be terminated by \endfirsthead
-               // (bug 6057)
-               os << "\\endfirsthead";
-       else
-               os << "\\tabularnewline";
+       os << "\\tabularnewline";
        if (row_info[row].bottom_space_default) {
                if (use_booktabs)
                        os << "\\addlinespace";
@@ -2396,17 +2647,15 @@ int Tabular::TeXRow(odocstream & os, row_type row,
                   << ']';
        }
        os << '\n';
-       ++ret;
 
        //output the bottom line
-       ret += TeXBottomHLine(os, row, lang);
+       TeXBottomHLine(os, row, lang);
 
        if (row_info[row].interline_space_default) {
                if (use_booktabs)
                        os << "\\addlinespace\n";
                else
                        os << "\\noalign{\\vskip\\doublerulesep}\n";
-               ++ret;
        } else if (!row_info[row].interline_space.zero()) {
                if (use_booktabs)
                        os << "\\addlinespace["
@@ -2416,24 +2665,25 @@ int Tabular::TeXRow(odocstream & os, row_type row,
                        os << "\\noalign{\\vskip"
                           << from_ascii(row_info[row].interline_space.asLatexString())
                           << "}\n";
-               ++ret;
        }
-       return ret;
 }
 
 
-int Tabular::latex(odocstream & os, OutputParams const & runparams) const
+void Tabular::latex(otexstream & os, OutputParams const & runparams) const
 {
-       int ret = 0;
+       bool const is_tabular_star = !tabular_width.zero();
 
        //+---------------------------------------------------------------------
        //+                      first the opening preamble                    +
        //+---------------------------------------------------------------------
 
-       if (rotate) {
-               os << "\\begin{sideways}\n";
-               ++ret;
-       }
+       os << safebreakln;
+       if (runparams.lastid != -1)
+               os.texrow().start(runparams.lastid, runparams.lastpos);
+
+       if (rotate != 0)
+               os << "\\begin{turn}{" << convert<string>(rotate) << "}\n";
+
        if (is_long_tabular) {
                os << "\\begin{longtable}";
                switch (longtabular_alignment) {
@@ -2447,7 +2697,10 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
                        break;
                }
        } else {
-               os << "\\begin{tabular}";
+               if (is_tabular_star)
+                       os << "\\begin{tabular*}{" << from_ascii(tabular_width.asLatexString()) << "}";
+               else
+                       os << "\\begin{tabular}";
                switch (tabular_valignment) {
                case LYX_VALIGN_TOP:
                        os << "[t]";
@@ -2462,6 +2715,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
        
        os << "{";
 
+       if (is_tabular_star)
+               os << "@{\\extracolsep{\\fill}}";
+
        for (col_type c = 0; c < ncols(); ++c) {
                if (columnLeftLine(c))
                        os << '|';
@@ -2483,6 +2739,7 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
                                case LYX_ALIGN_BLOCK:
                                case LYX_ALIGN_LAYOUT:
                                case LYX_ALIGN_SPECIAL:
+                               case LYX_ALIGN_DECIMAL:
                                        break;
                                }
 
@@ -2508,6 +2765,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
                                case LYX_ALIGN_RIGHT:
                                        os << 'r';
                                        break;
+                               case LYX_ALIGN_DECIMAL:
+                                       os << "r@{\\extracolsep{0pt}" << column_info[c].decimal_point << "}l";
+                                       break;
                                default:
                                        os << 'c';
                                        break;
@@ -2518,9 +2778,8 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
                        os << '|';
        }
        os << "}\n";
-       ++ret;
 
-       ret += TeXLongtableHeaderFooter(os, runparams);
+       TeXLongtableHeaderFooter(os, runparams);
 
        //+---------------------------------------------------------------------
        //+                      the single row and columns (cells)            +
@@ -2528,11 +2787,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
 
        for (row_type r = 0; r < nrows(); ++r) {
                if (isValidRow(r)) {
-                       ret += TeXRow(os, r, runparams);
-                       if (is_long_tabular && row_info[r].newpage) {
+                       TeXRow(os, r, runparams);
+                       if (is_long_tabular && row_info[r].newpage)
                                os << "\\newpage\n";
-                               ++ret;
-                       }
                }
        }
 
@@ -2542,14 +2799,15 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
 
        if (is_long_tabular)
                os << "\\end{longtable}";
-       else
-               os << "\\end{tabular}";
-       if (rotate) {
-               os << "\n\\end{sideways}";
-               ++ret;
+       else {
+               if (is_tabular_star)
+                       os << "\\end{tabular*}";
+               else
+                       os << "\\end{tabular}";
        }
 
-       return ret;
+       if (rotate != 0)
+               os << breakln << "\\end{turn}";
 }
 
 
@@ -2641,6 +2899,7 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
        //+---------------------------------------------------------------------
 
        // output caption info
+       // The caption flag wins over head/foot
        if (haveLTCaption()) {
                os << "<caption>\n";
                ++ret;
@@ -2653,11 +2912,12 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
                ++ret;
        }
        // output header info
-       if (haveLTHead() || haveLTFirstHead()) {
+       if (haveLTHead(false) || haveLTFirstHead(false)) {
                os << "<thead>\n";
                ++ret;
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].endhead || row_info[r].endfirsthead) {
+                       if ((row_info[r].endhead || row_info[r].endfirsthead) &&
+                           !row_info[r].caption) {
                                ret += docbookRow(os, r, runparams);
                        }
                }
@@ -2665,11 +2925,12 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
                ++ret;
        }
        // output footer info
-       if (haveLTFoot() || haveLTLastFoot()) {
+       if (haveLTFoot(false) || haveLTLastFoot(false)) {
                os << "<tfoot>\n";
                ++ret;
                for (row_type r = 0; r < nrows(); ++r) {
-                       if (row_info[r].endfoot || row_info[r].endlastfoot) {
+                       if ((row_info[r].endfoot || row_info[r].endlastfoot) &&
+                           !row_info[r].caption) {
                                ret += docbookRow(os, r, runparams);
                        }
                }
@@ -2702,14 +2963,15 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
 
 
 docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row,
-                          OutputParams const & runparams) const
+                          OutputParams const & runparams, bool header) const
 {
        docstring ret;
+       string const celltag = header ? "th" : "td";
        idx_type cell = getFirstCellInRow(row);
 
        xs << html::StartTag("tr");
        for (col_type c = 0; c < ncols(); ++c) {
-               if (isPartOfMultiColumn(row, c))
+               if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c))
                        continue;
 
                stringstream attr;
@@ -2741,35 +3003,102 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row,
 
                if (isMultiColumn(cell))
                        attr << " colspan='" << columnSpan(cell) << "'";
+               else if (isMultiRow(cell))
+                       attr << " rowspan='" << rowSpan(cell) << "'";
 
-               xs << html::StartTag("td", attr.str());
+               xs << html::StartTag(celltag, attr.str()) << html::CR();
                ret += cellInset(cell)->xhtml(xs, runparams);
-               xs << html::EndTag("td");
+               xs << html::EndTag(celltag) << html::CR();
                ++cell;
        }
-       xs << html::EndTag("tr");
-       return ret;
-}
+       xs << html::EndTag("tr");
+       return ret;
+}
+
+
+docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
+{
+       docstring ret;
+
+       if (is_long_tabular) {
+               // we'll wrap it in a div, so as to deal with alignment
+               string align;
+               switch (longtabular_alignment) {
+               case LYX_LONGTABULAR_ALIGN_LEFT:
+                       align = "left";
+                       break;
+               case LYX_LONGTABULAR_ALIGN_CENTER:
+                       align = "center";
+                       break;
+               case LYX_LONGTABULAR_ALIGN_RIGHT:
+                       align = "right";
+                       break;
+               }
+               xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'")
+                  << html::CR();
+               // The caption flag wins over head/foot
+               if (haveLTCaption()) {
+                       xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'")
+                          << html::CR();
+                       for (row_type r = 0; r < nrows(); ++r)
+                               if (row_info[r].caption)
+                                       ret += xhtmlRow(xs, r, runparams);
+                       xs << html::EndTag("div") << html::CR();
+               }
+       }
 
+       xs << html::StartTag("table") << html::CR();
 
-docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
-{
-       docstring ret;
-       // It's unclear to me if we need to mess with the long table stuff. 
-       // We can borrow that too from docbook, if so.
+       // output header info
+       bool const havefirsthead = haveLTFirstHead(false);
+       // if we have a first head, then we are going to ignore the
+       // headers for the additional pages, since there aren't any
+       // in XHTML. this test accomplishes that.
+       bool const havehead = !havefirsthead && haveLTHead(false);
+       if (havehead || havefirsthead) {
+               xs << html::StartTag("thead") << html::CR();
+               for (row_type r = 0; r < nrows(); ++r) {
+                       if (((havefirsthead && row_info[r].endfirsthead) ||
+                            (havehead && row_info[r].endhead)) &&
+                           !row_info[r].caption) {
+                               ret += xhtmlRow(xs, r, runparams, true);
+                       }
+               }
+               xs << html::EndTag("thead") << html::CR();
+       }
+       // output footer info
+       bool const havelastfoot = haveLTLastFoot(false);
+       // as before.
+       bool const havefoot = !havelastfoot && haveLTFoot(false);
+       if (havefoot || havelastfoot) {
+               xs << html::StartTag("tfoot") << html::CR();
+               for (row_type r = 0; r < nrows(); ++r) {
+                       if (((havelastfoot && row_info[r].endlastfoot) ||
+                            (havefoot && row_info[r].endfoot)) &&
+                           !row_info[r].caption) {
+                               ret += xhtmlRow(xs, r, runparams);
+                       }
+               }
+               xs << html::EndTag("tfoot") << html::CR();
+       }
 
-       xs << html::StartTag("tbody");
+       xs << html::StartTag("tbody") << html::CR();
        for (row_type r = 0; r < nrows(); ++r) {
                if (isValidRow(r)) {
                        ret += xhtmlRow(xs, r, runparams);
                }
        }
-       xs << html::EndTag("tbody");
+       xs << html::EndTag("tbody")
+          << html::CR()
+          << html::EndTag("table")
+          << html::CR();
+       if (is_long_tabular)
+               xs << html::EndTag("div") << html::CR();
        return ret;
 }
 
 
-bool Tabular::plaintextTopHLine(odocstream & os, row_type row,
+bool Tabular::plaintextTopHLine(odocstringstream & os, row_type row,
                                   vector<unsigned int> const & clen) const
 {
        idx_type const fcell = getFirstCellInRow(row);
@@ -2817,7 +3146,7 @@ bool Tabular::plaintextTopHLine(odocstream & os, row_type row,
 }
 
 
-bool Tabular::plaintextBottomHLine(odocstream & os, row_type row,
+bool Tabular::plaintextBottomHLine(odocstringstream & os, row_type row,
                                      vector<unsigned int> const & clen) const
 {
        idx_type const fcell = getFirstCellInRow(row);
@@ -2864,14 +3193,14 @@ bool Tabular::plaintextBottomHLine(odocstream & os, row_type row,
 }
 
 
-void Tabular::plaintextPrintCell(odocstream & os,
+void Tabular::plaintextPrintCell(odocstringstream & os,
                               OutputParams const & runparams,
                               idx_type cell, row_type row, col_type column,
                               vector<unsigned int> const & clen,
-                              bool onlydata) const
+                              bool onlydata, size_t max_length) const
 {
        odocstringstream sstr;
-       cellInset(cell)->plaintext(sstr, runparams);
+       cellInset(cell)->plaintext(sstr, runparams, max_length);
 
        if (onlydata) {
                os << sstr.str();
@@ -2914,9 +3243,9 @@ void Tabular::plaintextPrintCell(odocstream & os,
 }
 
 
-void Tabular::plaintext(odocstream & os,
+void Tabular::plaintext(odocstringstream & os,
                           OutputParams const & runparams, int const depth,
-                          bool onlydata, char_type delim) const
+                          bool onlydata, char_type delim, size_t max_length) const
 {
        // first calculate the width of the single columns
        vector<unsigned int> clen(ncols());
@@ -2930,7 +3259,7 @@ void Tabular::plaintext(odocstream & os,
                                if (isMultiColumn(cell))
                                        continue;
                                odocstringstream sstr;
-                               cellInset(cell)->plaintext(sstr, runparams);
+                               cellInset(cell)->plaintext(sstr, runparams, max_length);
                                if (clen[c] < sstr.str().length())
                                        clen[c] = sstr.str().length();
                        }
@@ -2942,7 +3271,7 @@ void Tabular::plaintext(odocstream & os,
                                if (cell_info[r][c].multicolumn != CELL_BEGIN_OF_MULTICOLUMN)
                                        continue;
                                odocstringstream sstr;
-                               cellInset(cell)->plaintext(sstr, runparams);
+                               cellInset(cell)->plaintext(sstr, runparams, max_length);
                                int len = int(sstr.str().length());
                                idx_type const n = columnSpan(cell);
                                for (col_type k = c; len > 0 && k < c + n - 1; ++k)
@@ -2957,14 +3286,16 @@ void Tabular::plaintext(odocstream & os,
                if (!onlydata && plaintextTopHLine(os, r, clen))
                        os << docstring(depth * 2, ' ');
                for (col_type c = 0; c < ncols(); ++c) {
-                       if (isPartOfMultiColumn(r, c))
+                       if (isPartOfMultiColumn(r, c) || isPartOfMultiRow(r,c))
                                continue;
                        if (onlydata && c > 0)
                                // we don't use operator<< for single UCS4 character.
                                // see explanation in docstream.h
                                os.put(delim);
-                       plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata);
+                       plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata, max_length);
                        ++cell;
+                       if (os.str().size() > max_length)
+                               break;
                }
                os << endl;
                if (!onlydata) {
@@ -2972,6 +3303,8 @@ void Tabular::plaintext(odocstream & os,
                        if (plaintextBottomHLine(os, r, clen))
                                os << docstring(depth * 2, ' ');
                }
+               if (os.str().size() > max_length)
+                       break;
        }
 }
 
@@ -3059,14 +3392,20 @@ bool InsetTableCell::allowParagraphCustomization(idx_type) const
 bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd,
        FuncStatus & status) const
 {
-       bool enabled;
-       switch (cmd.action) {
+       bool enabled = true;
+       switch (cmd.action()) {
        case LFUN_LAYOUT:
                enabled = !forcePlainLayout();
                break;
        case LFUN_LAYOUT_PARAGRAPH:
                enabled = allowParagraphCustomization();
                break;
+
+       case LFUN_MATH_DISPLAY:
+               if (!hasFixedWidth()) {
+                       enabled = false;
+                       break;
+               } //fall-through
        default:
                return InsetText::getStatus(cur, cmd, status);
        }
@@ -3093,6 +3432,12 @@ docstring InsetTableCell::asString(bool intoInsets)
 }
 
 
+void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const
+{
+       InsetText::iterateForToc(di, output_active);
+}
+
+
 docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const
 {
        if (!isFixedWidth)
@@ -3137,11 +3482,26 @@ void InsetTabular::setBuffer(Buffer & buf)
 
 bool InsetTabular::insetAllowed(InsetCode code) const
 {
-       if (code == MATHMACRO_CODE
-               || (code == CAPTION_CODE && !tabular.is_long_tabular))
+       switch (code) {
+       case FLOAT_CODE:
+       case MARGIN_CODE:
+       case MATHMACRO_CODE:
+       case WRAP_CODE:
                return false;
 
-       return true;
+       case CAPTION_CODE:
+               return tabular.is_long_tabular;
+
+       default:
+               return true;
+       }
+}
+
+
+bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const
+{
+       return tabular.is_long_tabular &&
+               (newtype == "Standard" || newtype == "LongTableNoNumber");
 }
 
 
@@ -3152,10 +3512,17 @@ void InsetTabular::write(ostream & os) const
 }
 
 
-docstring InsetTabular::contextMenu(BufferView const &, int, int) const
+string InsetTabular::contextMenu(BufferView const &, int, int) const
+{
+       // FIXME: depending on the selection state,
+       // we could offer a different menu.
+       return cell(0)->contextMenuName() + ";" + contextMenuName();
+}
+
+
+string InsetTabular::contextMenuName() const
 {
-       // FIXME: depending on the selection state, we could offer a different menu.
-       return from_ascii("context-tabular");
+       return "context-tabular";
 }
 
 
@@ -3182,11 +3549,11 @@ void InsetTabular::read(Lexer & lex)
 int InsetTabular::rowFromY(Cursor & cur, int y) const
 {
        // top y coordinate of tabular
-       int h = yo(cur.bv()) - tabular.rowAscent(0);
+       int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_;
        row_type r = 0;
        for (; r < tabular.nrows() && y > h; ++r)
                h += tabular.rowAscent(r) + tabular.rowDescent(r)
-               + tabular.interRowSpace(r);
+                       + tabular.interRowSpace(r);
 
        return r - 1;
 }
@@ -3198,7 +3565,7 @@ int InsetTabular::columnFromX(Cursor & cur, int x) const
        int w = xo(cur.bv()) + ADD_TO_TABULAR_WIDTH;
        col_type c = 0;
        for (; c < tabular.ncols() && x > w; ++c)
-               w += tabular.columnWidth(c);
+               w += tabular.cellWidth(c);
        return c - 1;
 }
 
@@ -3207,14 +3574,11 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
 {
        //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
        //      mi.base.textwidth << "\n";
-       if (!mi.base.bv) {
-               LYXERR0("need bv");
-               LASSERT(false, /**/);
-       }
+       LBUFERR(mi.base.bv);
 
        for (row_type r = 0; r < tabular.nrows(); ++r) {
-               int maxAsc = 0;
-               int maxDesc = 0;
+               int maxasc = 0;
+               int maxdes = 0;
                for (col_type c = 0; c < tabular.ncols(); ++c) {
                        if (tabular.isPartOfMultiColumn(r, c)
                                || tabular.isPartOfMultiRow(r, c))
@@ -3223,36 +3587,99 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                        idx_type const cell = tabular.cellIndex(r, c);
                        Dimension dim;
                        MetricsInfo m = mi;
-                       Length p_width;
-                       if (tabular.cell_info[r][c].multicolumn ==
-                               Tabular::CELL_BEGIN_OF_MULTICOLUMN)
-                               p_width = tabular.cellInfo(cell).p_width;
-                       else
-                               p_width = tabular.column_info[c].p_width;
+                       Length const p_width = tabular.getPWidth(cell);
                        if (!p_width.zero())
                                m.base.textwidth = p_width.inPixels(mi.base.textwidth);
                        tabular.cellInset(cell)->metrics(m, dim);
                        if (!p_width.zero())
                                dim.wid = m.base.textwidth;
-                       tabular.setCellWidth(cell, dim.wid);
-                       maxAsc  = max(maxAsc, dim.asc);
-                       maxDesc = max(maxDesc, dim.des);
+                       tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE 
+                               + tabular.interColumnSpace(cell);
+
+                       // FIXME(?): do we need a second metrics call?
+                       TextMetrics const & tm = 
+                               mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0));
+
+                       // determine horizontal offset because of decimal align (if necessary)
+                       int decimal_width = 0;
+                       if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) {
+                               InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell).get());
+                               tail.setBuffer(tabular.buffer());
+                               // we need to set macrocontext position everywhere
+                               // otherwise we crash with nested insets (e.g. footnotes)
+                               // after decimal point
+                               DocIterator dit = tabular.cellInset(cell)->getText(0)->macrocontextPosition();
+                               dit.pop_back();
+                               dit.push_back(CursorSlice(tail));
+                               tail.setMacrocontextPositionRecursive(dit);
+
+                               // remove text leading decimal point
+                               docstring const align_d = tabular.column_info[c].decimal_point;
+                               dit = separatorPos(&tail, align_d);
+
+                               pit_type const psize = tail.paragraphs().front().size();
+                               if (dit) {
+                                       tail.paragraphs().front().eraseChars(0,
+                                               dit.pos() < psize ? dit.pos() + 1 : psize, false);
+                                       Dimension dim1;
+                                       tail.metrics(m, dim1);
+                                       decimal_width = dim1.width();
+                               }
+                       }
+                       tabular.cell_info[r][c].decimal_hoffset = tm.width() - decimal_width;
+                       tabular.cell_info[r][c].decimal_width = decimal_width;
+
+                       // with LYX_VALIGN_BOTTOM the descent is relative to the last par
+                       // = descent of text in last par + TEXT_TO_INSET_OFFSET:
+                       int const lastpardes = tm.last().second->descent()
+                               + TEXT_TO_INSET_OFFSET;
+                       int offset = 0;
+                       switch (tabular.getVAlignment(cell)) { 
+                               case Tabular::LYX_VALIGN_TOP:
+                                       break; 
+                               case Tabular::LYX_VALIGN_MIDDLE:
+                                       offset = -(dim.des - lastpardes)/2; 
+                                       break; 
+                               case Tabular::LYX_VALIGN_BOTTOM:
+                                       offset = -(dim.des - lastpardes); 
+                                       break;
+                       }
+                       tabular.cell_info[r][c].voffset = offset;
+                       maxasc = max(maxasc, dim.asc - offset);
+                       maxdes = max(maxdes, dim.des + offset);
                }
                int const top_space = tabular.row_info[r].top_space_default ?
                        default_line_space :
                        tabular.row_info[r].top_space.inPixels(mi.base.textwidth);
-               tabular.setRowAscent(r, maxAsc + ADD_TO_HEIGHT + top_space);
+               tabular.setRowAscent(r, maxasc + ADD_TO_HEIGHT + top_space);
                int const bottom_space = tabular.row_info[r].bottom_space_default ?
                        default_line_space :
                        tabular.row_info[r].bottom_space.inPixels(mi.base.textwidth);
-               tabular.setRowDescent(r, maxDesc + ADD_TO_HEIGHT + bottom_space);
+               tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space);
+       }
+
+       // for top-alignment the first horizontal table line must be exactly at
+       // the position of the base line of the surrounding text line
+       // for bottom alignment, the same is for the last table line
+       switch (tabular.tabular_valignment) {
+       case Tabular::LYX_VALIGN_BOTTOM:
+               offset_valign_ = tabular.rowAscent(0) - tabular.height();
+               break;
+       case Tabular::LYX_VALIGN_MIDDLE:
+               offset_valign_ = (- tabular.height()) / 2 + tabular.rowAscent(0);
+               break;
+       case Tabular::LYX_VALIGN_TOP:
+               offset_valign_ = tabular.rowAscent(0);
+               break;
        }
+
        tabular.updateColumnWidths();
-       dim.asc = tabular.rowAscent(0);
+       dim.asc = tabular.rowAscent(0) - offset_valign_;        
        dim.des = tabular.height() - dim.asc;
        dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH;
 }
 
+
 bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) 
        const
 {
@@ -3292,7 +3719,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
        Cursor & cur = pi.base.bv->cursor();
        resetPos(cur);
 
-       // FIXME: As the full background is painted in drawSelection(),
+       // FIXME: As the full background is painted in drawBackground(),
        // we have no choice but to do a full repaint for the Text cells.
        pi.full_repaint = true;
 
@@ -3300,6 +3727,8 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
 
        idx_type idx = 0;
        first_visible_cell = Tabular::npos;
+
+       int yy = y + offset_valign_;
        for (row_type r = 0; r < tabular.nrows(); ++r) {
                int nx = x;
                for (col_type c = 0; c < tabular.ncols(); ++c) {
@@ -3309,7 +3738,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
                        idx = tabular.cellIndex(r, c);
                        
                        if (tabular.isPartOfMultiRow(r, c)) {
-                               nx += tabular.columnWidth(idx);
+                               nx += tabular.cellWidth(idx);
                                continue;
                        }
 
@@ -3318,22 +3747,31 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
 
                        pi.selected |= isCellSelected(cur, r, c);
                        int const cx = nx + tabular.textHOffset(idx);
-                       int const cy = y  + tabular.textVOffset(idx);
+                       int const cy = yy + tabular.textVOffset(idx);
                        // Cache the Inset position.
                        bv->coordCache().insets().add(cell(idx).get(), cx, cy);
                        cell(idx)->draw(pi, cx, cy);
-                       drawCellLines(pi.pain, nx, y, r, idx, pi.change_);
-                       nx += tabular.columnWidth(idx);
+                       drawCellLines(pi, nx, yy, r, idx);
+                       nx += tabular.cellWidth(idx);
                        pi.selected = original_selection_state;
                }
 
                if (r + 1 < tabular.nrows())
-                       y += tabular.rowDescent(r) + tabular.rowAscent(r + 1) 
+                       yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1) 
                                + tabular.interRowSpace(r + 1);
        }
 }
 
 
+void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const
+{
+       x += scx_ + ADD_TO_TABULAR_WIDTH;
+       y += offset_valign_ - tabular.rowAscent(0);
+       pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(),
+               pi.backgroundColor(this));
+}
+
+
 void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
 {
        Cursor & cur = pi.base.bv->cursor();
@@ -3341,15 +3779,6 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
 
        x += scx_ + ADD_TO_TABULAR_WIDTH;
 
-       // FIXME: it is wrong to completely paint the background
-       // if we want to do single row painting.
-
-       // Paint background of current tabular
-       int const w = tabular.width();
-       int const h = tabular.height();
-       int yy = y - tabular.rowAscent(0);
-       pi.pain.fillRectangle(x, yy, w, h, pi.backgroundColor(this));
-
        if (!cur.selection())
                return;
        if (&cur.inset() != this)
@@ -3370,12 +3799,12 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
                                idx_type const cell = tabular.cellIndex(r, c);
 
                                if (tabular.isPartOfMultiRow(r, c)) {
-                                       xx += tabular.columnWidth(cell);
+                                       xx += tabular.cellWidth(cell);
                                        continue;
                                }
-                               int const w = tabular.columnWidth(cell);
+                               int const w = tabular.cellWidth(cell);
                                int const h = tabular.cellHeight(cell);
-                               int const yy = y - tabular.rowAscent(r);
+                               int const yy = y - tabular.rowAscent(r) + offset_valign_;
                                if (isCellSelected(cur, r, c))
                                        pi.pain.fillRectangle(xx, yy, w, h, Color_selection);
                                xx += w;
@@ -3385,33 +3814,36 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
                                     + tabular.interRowSpace(r + 1);
                }
 
-       } else {
-               x += cellXPos(cur.idx());
-               x += tabular.textHOffset(cur.idx());
-               cell(cur.idx())->drawSelection(pi, x, 0 /* ignored */);
-       }
+       } 
+       // FIXME: This code has no effect because InsetTableCell does not handle
+       // drawSelection other than the trivial implementation in Inset.
+       //else {
+       //      x += cellXPos(cur.idx());
+       //      x += tabular.textHOffset(cur.idx());
+       //      cell(cur.idx())->drawSelection(pi, x, 0 /* ignored */);
+       //}
 }
 
 
-void InsetTabular::drawCellLines(Painter & pain, int x, int y,
-                                                                row_type row, idx_type cell, Change const & change) const
+void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y,
+                                row_type row, idx_type cell) const
 {
        y -= tabular.rowAscent(row);
-       int const w = tabular.columnWidth(cell);
+       int const w = tabular.cellWidth(cell);
        int const h = tabular.cellHeight(cell);
-       Color linecolor = change.changed() ? change.color() : Color_tabularline;
-       Color gridcolor = change.changed() ? change.color() : Color_tabularonoffline;
+       Color const linecolor = pi.textColor(Color_tabularline);
+       Color const gridcolor = pi.textColor(Color_tabularonoffline);
 
        // Top
        bool drawline = tabular.topLine(cell)
                || (row > 0 && tabular.bottomLine(tabular.cellAbove(cell)));
-       pain.line(x, y, x + w, y,
+       pi.pain.line(x, y, x + w, y,
                drawline ? linecolor : gridcolor,
                drawline ? Painter::line_solid : Painter::line_onoffdash);
 
        // Bottom
        drawline = tabular.bottomLine(cell);
-       pain.line(x, y + h, x + w, y + h,
+       pi.pain.line(x, y + h, x + w, y + h,
                drawline ? linecolor : gridcolor,
                drawline ? Painter::line_solid : Painter::line_onoffdash);
 
@@ -3419,16 +3851,20 @@ void InsetTabular::drawCellLines(Painter & pain, int x, int y,
        col_type const col = tabular.cellColumn(cell);
        drawline = tabular.leftLine(cell)
                || (col > 0 && tabular.rightLine(tabular.cellIndex(row, col - 1)));
-       pain.line(x, y, x, y + h,
+       pi.pain.line(x, y, x, y + h,
                drawline ? linecolor : gridcolor,
                drawline ? Painter::line_solid : Painter::line_onoffdash);
 
        // Right
        x -= tabular.interColumnSpace(cell);
+       col_type next_cell_col = col + 1;
+       while (next_cell_col < tabular.ncols() 
+               && tabular.isMultiColumn(tabular.cellIndex(row, next_cell_col)))
+               next_cell_col++;
        drawline = tabular.rightLine(cell)
-                  || (col + 1 < tabular.ncols()
-                      && tabular.leftLine(tabular.cellIndex(row, col + 1)));
-       pain.line(x + w, y, x + w, y + h,
+                  || (next_cell_col < tabular.ncols()
+                      && tabular.leftLine(tabular.cellIndex(row, next_cell_col)));
+       pi.pain.line(x + w, y, x + w, y + h,
                drawline ? linecolor : gridcolor,
                drawline ? Painter::line_solid : Painter::line_onoffdash);
 }
@@ -3467,8 +3903,12 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype)
        // In a longtable, tell captions what the current float is
        Counters & cnts = buffer().masterBuffer()->params().documentClass().counters();
        string const saveflt = cnts.current_float();
-       if (tabular.is_long_tabular)
+       if (tabular.is_long_tabular) {
                cnts.current_float("table");
+               // in longtables, we only step the counter once
+               cnts.step(from_ascii("table"), utype);
+               cnts.isLongtable(true);
+       }
 
        ParIterator it2 = it;
        it2.forwardPos();
@@ -3477,18 +3917,20 @@ void InsetTabular::updateBuffer(ParIterator const & it, UpdateType utype)
                buffer().updateBuffer(it2, utype);
 
        //reset afterwards
-       if (tabular.is_long_tabular)
+       if (tabular.is_long_tabular) {
                cnts.current_float(saveflt);
+               cnts.isLongtable(false);
+       }
 }
 
 
-void InsetTabular::addToToc(DocIterator const & cpit)
+void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const
 {
        DocIterator dit = cpit;
        dit.forwardPos();
        size_t const end = dit.nargs();
        for ( ; dit.idx() < end; dit.top().forwardIdx())
-               cell(dit.idx())->addToToc(dit);
+               cell(dit.idx())->addToToc(dit, output_active);
 }
 
 
@@ -3499,14 +3941,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
        CursorSlice sl = cur.top();
        Cursor & bvcur = cur.bv().cursor();
 
-       switch (cmd.action) {
+       FuncCode const act = cmd.action();
+       
+       switch (act) {
 
        case LFUN_MOUSE_PRESS: {
                //lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl;
                // select row
-               if (cmd.x < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH
-                       || cmd.x > xo(cur.bv()) + tabular.width()) {
-                       row_type r = rowFromY(cur, cmd.y);
+               if (cmd.x() < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH
+                       || cmd.x() > xo(cur.bv()) + tabular.width()) {
+                       row_type r = rowFromY(cur, cmd.y());
                        cur.idx() = tabular.getFirstCellInRow(r);
                        cur.pos() = 0;
                        cur.resetAnchor();
@@ -3518,10 +3962,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        break;
                }
                // select column
-               int const y0 = yo(cur.bv()) - tabular.rowAscent(0);
-               if (cmd.y < y0 + ADD_TO_TABULAR_WIDTH 
-                       || cmd.y > y0 + tabular.height()) {
-                       col_type c = columnFromX(cur, cmd.x);
+               int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_;
+               if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH 
+                       || cmd.y() > y0 + tabular.height()) {
+                       col_type c = columnFromX(cur, cmd.x());
                        cur.idx() = tabular.cellIndex(0, c);
                        cur.pos() = 0;
                        cur.resetAnchor();
@@ -3547,13 +3991,13 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                //lyxerr << "# InsetTabular::MouseMotion\n" << bvcur << endl;
                if (cmd.button() == mouse_button::button1) {
                        // only accept motions to places not deeper nested than the real anchor
-                       if (!bvcur.anchor_.hasPart(cur)) {
+                       if (!bvcur.realAnchor().hasPart(cur)) {
                                cur.undispatched();
                                break;
                        }
                        // select (additional) row
                        if (rowselect_) {
-                               row_type r = rowFromY(cur, cmd.y);
+                               row_type r = rowFromY(cur, cmd.y());
                                cur.idx() = tabular.getLastCellInRow(r);
                                // we need to reset the cursor's pit and pos now, as the old ones
                                // may no longer be valid.
@@ -3565,7 +4009,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        }
                        // select (additional) column
                        if (colselect_) {
-                               col_type c = columnFromX(cur, cmd.x);
+                               col_type c = columnFromX(cur, cmd.x());
                                cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c);
                                // we need to reset the cursor's pit and pos now, as the old ones
                                // may no longer be valid.
@@ -3577,9 +4021,9 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        }
                        // 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.realAnchor().idx() == cur.idx() && bvcur.pos() != cur.pos()))
+                               cur.noScreenUpdate();
+                       setCursorFromCoordinates(cur, cmd.x(), cmd.y());
                        bvcur.setCursor(cur);
                        bvcur.setSelection(true);
                        // if this is a multicell selection, we just set the cursor to
@@ -3613,7 +4057,15 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_CHAR_RIGHT_SELECT:
        case LFUN_CHAR_RIGHT:
        case LFUN_CHAR_LEFT_SELECT:
-       case LFUN_CHAR_LEFT: {
+       case LFUN_CHAR_LEFT: 
+       case LFUN_WORD_FORWARD:
+       case LFUN_WORD_FORWARD_SELECT:
+       case LFUN_WORD_BACKWARD:
+       case LFUN_WORD_BACKWARD_SELECT:
+       case LFUN_WORD_RIGHT:
+       case LFUN_WORD_RIGHT_SELECT:
+       case LFUN_WORD_LEFT:
+       case LFUN_WORD_LEFT_SELECT: {
                // determine whether we move to next or previous cell, where to enter 
                // the new cell from, and which command to "finish" (i.e., exit the
                // inset) with:
@@ -3621,21 +4073,27 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                EntryDirection entry_from = ENTRY_DIRECTION_IGNORE;
                FuncCode finish_lfun;
 
-               if (cmd.action == LFUN_CHAR_FORWARD 
-                               || cmd.action == LFUN_CHAR_FORWARD_SELECT) {
+               if (act == LFUN_CHAR_FORWARD 
+                               || act == LFUN_CHAR_FORWARD_SELECT
+                               || act == LFUN_WORD_FORWARD
+                               || act == LFUN_WORD_FORWARD_SELECT) {
                        next_cell = true;
                        finish_lfun = LFUN_FINISHED_FORWARD;
                }
-               else if (cmd.action == LFUN_CHAR_BACKWARD
-                               || cmd.action == LFUN_CHAR_BACKWARD_SELECT) {
+               else if (act == LFUN_CHAR_BACKWARD
+                               || act == LFUN_CHAR_BACKWARD_SELECT
+                               || act == LFUN_WORD_BACKWARD
+                               || act == LFUN_WORD_BACKWARD_SELECT) {
                        next_cell = false;
                        finish_lfun = LFUN_FINISHED_BACKWARD;
                }
                // LEFT or RIGHT commands --- the interpretation will depend on the 
                // table's direction.
                else {
-                       bool const right = cmd.action == LFUN_CHAR_RIGHT
-                               || cmd.action == LFUN_CHAR_RIGHT_SELECT;
+                       bool const right = act == LFUN_CHAR_RIGHT
+                               || act == LFUN_CHAR_RIGHT_SELECT
+                               || act == LFUN_WORD_RIGHT
+                               || act == LFUN_WORD_RIGHT_SELECT;
                        next_cell = isRightToLeft(cur) != right;
                        
                        if (lyxrc.visual_cursor)
@@ -3644,10 +4102,14 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        finish_lfun = right ? LFUN_FINISHED_RIGHT : LFUN_FINISHED_LEFT;
                }
 
-               bool const select = cmd.action == LFUN_CHAR_FORWARD_SELECT ||
-                   cmd.action == LFUN_CHAR_BACKWARD_SELECT ||
-                   cmd.action == LFUN_CHAR_RIGHT_SELECT ||
-                   cmd.action == LFUN_CHAR_LEFT_SELECT;
+               bool const select =     act == LFUN_CHAR_FORWARD_SELECT 
+                   || act == LFUN_CHAR_BACKWARD_SELECT
+                   || act == LFUN_CHAR_RIGHT_SELECT
+                   || act == LFUN_CHAR_LEFT_SELECT
+                       || act == LFUN_WORD_FORWARD_SELECT
+                       || act == LFUN_WORD_RIGHT_SELECT
+                       || act == LFUN_WORD_BACKWARD_SELECT
+                       || act == LFUN_WORD_LEFT_SELECT;
 
                // If we have a multicell selection or we're 
                // not doing some LFUN_*_SELECT thing anyway...
@@ -3671,6 +4133,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        if (select_whole && !empty_cell){
                                getText(cur.idx())->selectAll(cur);
                                cur.dispatched();
+                               cur.screenUpdateFlags(Update::Force | Update::FitCursor);
                                break;
                        }
 
@@ -3695,6 +4158,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        cmd = FuncRequest(finish_lfun);
                else
                        cur.dispatched();
+
+               cur.screenUpdateFlags(Update::Force | Update::FitCursor);
                break;
 
        }
@@ -3709,13 +4174,17 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        // if our Text didn't do anything to the cursor
                        // then we try to put the cursor into the cell below
                        // setting also the right targetX.
-                       cur.selHandle(cmd.action == LFUN_DOWN_SELECT);
+                       cur.selHandle(act == LFUN_DOWN_SELECT);
                        if (tabular.cellRow(cur.idx()) != tabular.nrows() - 1) {
+                               int const xtarget = cur.targetX();
+                               // WARNING: Once cur.idx() has been reset, the cursor is in
+                               // an inconsistent state until pos() has been set. Be careful
+                               // what you do with it!
                                cur.idx() = tabular.cellBelow(cur.idx());
                                cur.pit() = 0;
                                TextMetrics const & tm =
                                        cur.bv().textMetrics(cell(cur.idx())->getText(0));
-                               cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX());
+                               cur.pos() = tm.x2pos(cur.pit(), 0, xtarget);
                                cur.setCurrentFont();
                        }
                }
@@ -3729,8 +4198,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        cur.pit() = cur.lastpit();
                        cur.pos() = cur.lastpos();
                        cur.setCurrentFont();
+                       cur.screenUpdateFlags(Update::Force | Update::FitCursor);
                        return;
                }
+               cur.screenUpdateFlags(Update::Force | Update::FitCursor);
                break;
 
        case LFUN_UP_SELECT:
@@ -3742,15 +4213,19 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        // if our Text didn't do anything to the cursor
                        // then we try to put the cursor into the cell above
                        // setting also the right targetX.
-                       cur.selHandle(cmd.action == LFUN_UP_SELECT);
+                       cur.selHandle(act == LFUN_UP_SELECT);
                        if (tabular.cellRow(cur.idx()) != 0) {
+                               int const xtarget = cur.targetX();
+                               // WARNING: Once cur.idx() has been reset, the cursor is in
+                               // an inconsistent state until pos() has been set. Be careful
+                               // what you do with it!
                                cur.idx() = tabular.cellAbove(cur.idx());
                                cur.pit() = cur.lastpit();
                                Text const * text = cell(cur.idx())->getText(0);
                                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());
+                               cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, xtarget);
                                cur.setCurrentFont();
                        }
                }
@@ -3762,8 +4237,10 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        cur.pit() = 0;
                        cur.pos() = cur.lastpos();
                        cur.setCurrentFont();
+                       cur.screenUpdateFlags(Update::Force | Update::FitCursor);
                        return;
                }
+               cur.screenUpdateFlags(Update::Force | Update::FitCursor);
                break;
 
 //     case LFUN_SCREEN_DOWN: {
@@ -3772,7 +4249,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 //             col_type const col = tabular.cellColumn(cur.idx());
 //             int const t =   cur.bv().top_y() + cur.bv().height();
 //             if (t < yo() + tabular.getHeightOfTabular()) {
-//                     cur.bv().scrollDocView(t);
+//                     cur.bv().scrollDocView(t, true);
 //                     cur.idx() = tabular.cellBelow(first_visible_cell) + col;
 //             } else {
 //                     cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col;
@@ -3788,7 +4265,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 //             col_type const col = tabular.cellColumn(cur.idx());
 //             int const t =   cur.bv().top_y() + cur.bv().height();
 //             if (yo() < 0) {
-//                     cur.bv().scrollDocView(t);
+//                     cur.bv().scrollDocView(t, true);
 //                     if (yo() > 0)
 //                             cur.idx() = col;
 //                     else
@@ -3805,10 +4282,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                cur.bv().showDialog("tabular");
                break;
 
-       case LFUN_INSET_MODIFY:
-               if (!tabularFeatures(cur, to_utf8(cmd.argument())))
+       case LFUN_INSET_MODIFY: {
+               string arg;
+               if (cmd.getArg(1) == "from-dialog")
+                       arg = cmd.getArg(0) + to_utf8(cmd.argument().substr(19));
+               else
+                       arg = to_utf8(cmd.argument());
+               if (!tabularFeatures(cur, arg))
                        cur.undispatched();
                break;
+       }
 
        // insert file functions
        case LFUN_FILE_INSERT_PLAINTEXT_PARA:
@@ -3845,8 +4328,16 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                if (cur.selIsMultiCell()) {
                        cur.recordUndoInset(DELETE_UNDO);
                        cutSelection(cur);
-               }
-               cell(cur.idx())->dispatch(cur, cmd);
+                       BufferView * bv = &cur.bv();
+                       docstring::const_iterator cit = cmd.argument().begin();
+                       docstring::const_iterator const end = cmd.argument().end();
+                       for (; cit != end; ++cit)
+                               bv->translateAndInsert(*cit, getText(cur.idx()), cur);
+       
+                       cur.resetAnchor();
+                       bv->bookmarkEditPosition();
+               } else
+                       cell(cur.idx())->dispatch(cur, cmd);
                break;
 
        case LFUN_CHAR_DELETE_BACKWARD:
@@ -3870,8 +4361,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_CLIPBOARD_PASTE:
        case LFUN_PRIMARY_SELECTION_PASTE: {
-               docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ?
-                       theClipboard().getAsText() :
+               docstring const clip = (act == LFUN_CLIPBOARD_PASTE) ?
+                       theClipboard().getAsText(Clipboard::PlainTextType) :
                        theSelection().get();
                if (clip.empty())
                        break;
@@ -3899,8 +4390,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                                cell(cur.idx())->dispatch(cur, cmd);
                        break;
                }
-               if (theClipboard().isInternal() ||
-                   (!theClipboard().hasInternal() && theClipboard().hasLyXContents())) {
+               if (theClipboard().isInternal()) {
                        cur.recordUndoInset(INSERT_UNDO);
                        pasteClipboard(cur);
                }
@@ -3920,9 +4410,11 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_FONT_SIZE:
        case LFUN_FONT_UNDERLINE:
        case LFUN_FONT_STRIKEOUT:
-       case LFUN_FONT_UULINE:
-       case LFUN_FONT_UWAVE:
+       case LFUN_FONT_UNDERUNDERLINE:
+       case LFUN_FONT_UNDERWAVE:
        case LFUN_LANGUAGE:
+       case LFUN_PARAGRAPH_PARAMS_APPLY:
+       case LFUN_PARAGRAPH_PARAMS:
        case LFUN_WORD_CAPITALIZE:
        case LFUN_WORD_UPCASE:
        case LFUN_WORD_LOWCASE:
@@ -3971,13 +4463,21 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
        FuncStatus & status) const
 {
-       switch (cmd.action) {
+       switch (cmd.action()) {
        case LFUN_INSET_MODIFY: {
                if (&cur.inset() != this || cmd.getArg(0) != "tabular") 
                        break;
 
-               string const s = cmd.getArg(1);
                // FIXME: We only check for the very first argument...
+               string const s = cmd.getArg(1);
+               // We always enable the lfun if it is coming from the dialog
+               // because the dialog makes sure all the settings are valid,
+               // even though the first argument might not be valid now.
+               if (s == "from-dialog") {
+                       status.setEnabled(true);
+                       return true;
+               }
+
                int action = Tabular::LAST_ACTION;
                int i = 0;
                for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) {
@@ -3988,7 +4488,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                }
                if (action == Tabular::LAST_ACTION) {
                        status.clear();
-                       status.unknown(true);
+                       status.setUnknown(true);
                        return true;
                }
 
@@ -4008,7 +4508,6 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                case Tabular::SET_MPWIDTH:
                case Tabular::SET_SPECIAL_COLUMN:
                case Tabular::SET_SPECIAL_MULTICOLUMN:
-               case Tabular::SET_SPECIAL_MULTIROW:
                case Tabular::APPEND_ROW:
                case Tabular::APPEND_COLUMN:
                case Tabular::DELETE_ROW:
@@ -4021,6 +4520,68 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.clear();
                        return true;
 
+               case Tabular::SET_TABULAR_WIDTH:
+                       status.setEnabled(!tabular.rotate &&  !tabular.is_long_tabular
+                               && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE);
+                       break;
+
+               case Tabular::MOVE_COLUMN_RIGHT:
+               case Tabular::MOVE_COLUMN_LEFT:
+               case Tabular::MOVE_ROW_DOWN:
+               case Tabular::MOVE_ROW_UP: {
+                       if (cur.selection()) {
+                               status.message(_("Selections not supported."));
+                               status.setEnabled(false);
+                               break;
+                       }
+
+                       if ((action == Tabular::MOVE_COLUMN_RIGHT &&
+                               tabular.ncols() == tabular.cellColumn(cur.idx()) + 1) ||
+                           (action == Tabular::MOVE_COLUMN_LEFT &&
+                               tabular.cellColumn(cur.idx()) == 0) ||
+                           (action == Tabular::MOVE_ROW_DOWN &&
+                               tabular.nrows() == tabular.cellRow(cur.idx()) + 1) ||
+                           (action == Tabular::MOVE_ROW_UP &&
+                               tabular.cellRow(cur.idx()) == 0)) {
+                                       status.setEnabled(false);
+                                       break;
+                       }
+
+                       if (action == Tabular::MOVE_COLUMN_RIGHT ||
+                           action == Tabular::MOVE_COLUMN_LEFT) {
+                               if (tabular.hasMultiColumn(tabular.cellColumn(cur.idx())) ||
+                                   tabular.hasMultiColumn(tabular.cellColumn(cur.idx()) +
+                                       (action == Tabular::MOVE_COLUMN_RIGHT ? 1 : -1))) {
+                                       status.message(_("Multi-column in current or"
+                                                        " destination column."));
+                                       status.setEnabled(false);
+                                       break;
+                               }
+                       }
+
+                       if (action == Tabular::MOVE_ROW_DOWN ||
+                           action == Tabular::MOVE_ROW_UP) {
+                               if (tabular.hasMultiRow(tabular.cellRow(cur.idx())) ||
+                                   tabular.hasMultiRow(tabular.cellRow(cur.idx()) +
+                                       (action == Tabular::MOVE_ROW_DOWN ? 1 : -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(
+                               tabular.getAlignment(cur.idx()) == LYX_ALIGN_DECIMAL);
+                       break;
+
+               case Tabular::SET_MULTICOLUMN:
+               case Tabular::UNSET_MULTICOLUMN:
                case Tabular::MULTICOLUMN:
                        // If a row is set as longtable caption, it must not be allowed
                        // to unset that this row is a multicolumn.
@@ -4029,6 +4590,8 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.setOnOff(tabular.isMultiColumn(cur.idx()));
                        break;
 
+               case Tabular::SET_MULTIROW:
+               case Tabular::UNSET_MULTIROW:
                case Tabular::MULTIROW:
                        // If a row is set as longtable caption, it must not be allowed
                        // to unset that this row is a multirow.
@@ -4070,24 +4633,28 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.setOnOff(tabular.rightLine(cur.idx()));
                        break;
 
+               // multirow cells only inherit the alignment of the column if the column has
+               // no width, otherwise they are left-aligned
+               // therefore allow always left but right and center only if there is no width
                case Tabular::M_ALIGN_LEFT:
                        flag = false;
                case Tabular::ALIGN_LEFT:
-                       status.setEnabled(!tabular.isMultiRow(cur.idx()));
                        status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_LEFT);
                        break;
 
                case Tabular::M_ALIGN_RIGHT:
                        flag = false;
                case Tabular::ALIGN_RIGHT:
-                       status.setEnabled(!tabular.isMultiRow(cur.idx()));
+                       status.setEnabled(!(tabular.isMultiRow(cur.idx()) 
+                               && !tabular.getPWidth(cur.idx()).zero()));
                        status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_RIGHT);
                        break;
 
                case Tabular::M_ALIGN_CENTER:
                        flag = false;
                case Tabular::ALIGN_CENTER:
-                       status.setEnabled(!tabular.isMultiRow(cur.idx()));
+                       status.setEnabled(!(tabular.isMultiRow(cur.idx()) 
+                               && !tabular.getPWidth(cur.idx()).zero()));
                        status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_CENTER);
                        break;
 
@@ -4097,6 +4664,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_BLOCK);
                        break;
 
+               case Tabular::ALIGN_DECIMAL:
+                       status.setEnabled(!tabular.isMultiRow(cur.idx()) 
+                               && !tabular.isMultiColumn(cur.idx()));
+                       status.setOnOff(tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_DECIMAL);
+                       break;
+
                case Tabular::M_VALIGN_TOP:
                        flag = false;
                case Tabular::VALIGN_TOP:
@@ -4125,6 +4698,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                case Tabular::SET_LONGTABULAR:
+                       // setting as longtable is not allowed when table is inside a float
+                       if (cur.innerInsetOfType(FLOAT_CODE) != 0
+                               || cur.innerInsetOfType(WRAP_CODE) != 0)
+                               status.setEnabled(false);
+                       else
+                               status.setEnabled(true);
                        status.setOnOff(tabular.is_long_tabular);
                        break;
 
@@ -4134,18 +4713,21 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
 
                case Tabular::TOGGLE_ROTATE_TABULAR:
                case Tabular::SET_ROTATE_TABULAR:
-                       status.setOnOff(tabular.rotate);
+                       status.setOnOff(tabular.rotate != 0);
                        break;
 
                case Tabular::TABULAR_VALIGN_TOP:
+                       status.setEnabled(tabular.tabular_width.zero());
                        status.setOnOff(tabular.tabular_valignment 
                                == Tabular::LYX_VALIGN_TOP);
                        break;
                case Tabular::TABULAR_VALIGN_MIDDLE:
+                       status.setEnabled(tabular.tabular_width.zero());
                        status.setOnOff(tabular.tabular_valignment 
                                == Tabular::LYX_VALIGN_MIDDLE);
                        break;
                case Tabular::TABULAR_VALIGN_BOTTOM:
+                       status.setEnabled(tabular.tabular_width.zero());
                        status.setOnOff(tabular.tabular_valignment 
                                == Tabular::LYX_VALIGN_BOTTOM);
                        break;
@@ -4164,7 +4746,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                case Tabular::UNSET_ROTATE_TABULAR:
-                       status.setOnOff(!tabular.rotate);
+                       status.setOnOff(tabular.rotate == 0);
                        break;
 
                case Tabular::TOGGLE_ROTATE_CELL:
@@ -4183,65 +4765,87 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                // every row can only be one thing:
-               // either a footer or header or caption
+               // either a footer or header
                case Tabular::SET_LTFIRSTHEAD:
-                       status.setEnabled(sel_row_start == sel_row_end
-                               && !tabular.ltCaption(sel_row_start));
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(tabular.getRowOfLTFirstHead(sel_row_start, dummyltt));
                        break;
 
                case Tabular::UNSET_LTFIRSTHEAD:
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt));
                        break;
 
                case Tabular::SET_LTHEAD:
-                       status.setEnabled(sel_row_start == sel_row_end
-                               && !tabular.ltCaption(sel_row_start));
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
                        break;
 
                case Tabular::UNSET_LTHEAD:
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt));
                        break;
 
                case Tabular::SET_LTFOOT:
-                       status.setEnabled(sel_row_start == sel_row_end
-                               && !tabular.ltCaption(sel_row_start));
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
                        break;
 
                case Tabular::UNSET_LTFOOT:
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt));
                        break;
 
                case Tabular::SET_LTLASTFOOT:
-                       status.setEnabled(sel_row_start == sel_row_end
-                               && !tabular.ltCaption(sel_row_start));
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(tabular.getRowOfLTLastFoot(sel_row_start, dummyltt));
                        break;
 
                case Tabular::UNSET_LTLASTFOOT:
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt));
                        break;
 
                case Tabular::SET_LTNEWPAGE:
                        status.setOnOff(tabular.getLTNewPage(sel_row_start));
                        break;
+               case Tabular::UNSET_LTNEWPAGE:
+                       status.setOnOff(!tabular.getLTNewPage(sel_row_start));
+                       break;
 
-               // only one row can be the caption
+               // only one row in head/firsthead/foot/lasthead can be the caption
                // and a multirow cannot be set as caption
-               case Tabular::TOGGLE_LTCAPTION:
+               case Tabular::SET_LTCAPTION:
                        status.setEnabled(sel_row_start == sel_row_end
-                               && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
-                               && !tabular.getRowOfLTHead(sel_row_start, dummyltt)
-                               && !tabular.getRowOfLTFoot(sel_row_start, dummyltt)
-                               && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
-                               && (!tabular.haveLTCaption()
-                                       || tabular.ltCaption(sel_row_start))
+                               && (!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
+                                || !tabular.haveLTCaption(Tabular::CAPTION_FIRSTHEAD))
+                               && (!tabular.getRowOfLTHead(sel_row_start, dummyltt)
+                                || !tabular.haveLTCaption(Tabular::CAPTION_HEAD))
+                               && (!tabular.getRowOfLTFoot(sel_row_start, dummyltt)
+                                || !tabular.haveLTCaption(Tabular::CAPTION_FOOT))
+                               && (!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
+                                || !tabular.haveLTCaption(Tabular::CAPTION_LASTFOOT))
                                && !tabular.isMultiRow(sel_row_start));
                        status.setOnOff(tabular.ltCaption(sel_row_start));
                        break;
 
+               case Tabular::UNSET_LTCAPTION:
+                       status.setEnabled(sel_row_start == sel_row_end && tabular.ltCaption(sel_row_start));
+                       break;
+
+               case Tabular::TOGGLE_LTCAPTION:
+                       status.setEnabled(sel_row_start == sel_row_end && (tabular.ltCaption(sel_row_start)
+                               || ((!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
+                                 || !tabular.haveLTCaption(Tabular::CAPTION_FIRSTHEAD))
+                                && (!tabular.getRowOfLTHead(sel_row_start, dummyltt)
+                                 || !tabular.haveLTCaption(Tabular::CAPTION_HEAD))
+                                && (!tabular.getRowOfLTFoot(sel_row_start, dummyltt)
+                                 || !tabular.haveLTCaption(Tabular::CAPTION_FOOT))
+                                && (!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
+                                 || !tabular.haveLTCaption(Tabular::CAPTION_LASTFOOT)))));
+                       status.setOnOff(tabular.ltCaption(sel_row_start));
+                       break;
+
                case Tabular::SET_BOOKTABS:
                        status.setOnOff(tabular.use_booktabs);
                        break;
@@ -4258,6 +4862,37 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                return true;
        }
 
+       case LFUN_CAPTION_INSERT: {
+               // caption is only allowed in caption cell of longtable
+               if (!tabular.ltCaption(tabular.cellRow(cur.idx()))) {
+                       status.setEnabled(false);
+                       return true;
+               }
+               // only standard caption is allowed
+               string arg = cmd.getArg(0);
+               if (!arg.empty() && arg != "Standard") {
+                       status.setEnabled(false);
+                       return true;
+               }
+               // check if there is already a caption
+               bool have_caption = false;
+               InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get());
+               ParagraphList::const_iterator pit = itc.paragraphs().begin();
+               ParagraphList::const_iterator pend = itc.paragraphs().end();
+               for (; pit != pend; ++pit) {
+                       InsetList::const_iterator it  = pit->insetList().begin();
+                       InsetList::const_iterator end = pit->insetList().end();
+                       for (; it != end; ++it) {
+                               if (it->inset->lyxCode() == CAPTION_CODE) {
+                                       have_caption = true;
+                                       break;
+                               }
+                       }
+               }
+               status.setEnabled(!have_caption);
+               return true;
+       }
+
        // These are only enabled inside tabular
        case LFUN_CELL_BACKWARD:
        case LFUN_CELL_FORWARD:
@@ -4277,11 +4912,12 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_MATH_MUTATE:
        case LFUN_MATH_DISPLAY:
        case LFUN_NOTE_INSERT:
-       case LFUN_OPTIONAL_INSERT:
+       case LFUN_ARGUMENT_INSERT:
        case LFUN_BOX_INSERT:
        case LFUN_BRANCH_INSERT:
        case LFUN_PHANTOM_INSERT:
        case LFUN_WRAP_INSERT:
+       case LFUN_PREVIEW_INSERT:
        case LFUN_ERT_INSERT: {
                if (cur.selIsMultiCell()) {
                        status.setEnabled(false);
@@ -4291,8 +4927,13 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
        }
 
        // disable in non-fixed-width cells
-       case LFUN_NEWLINE_INSERT:
-       case LFUN_BREAK_PARAGRAPH: {
+       case LFUN_PARAGRAPH_BREAK:
+               // multirow does not allow paragraph breaks
+               if (tabular.isMultiRow(cur.idx())) {
+                       status.setEnabled(false);
+                       return true;
+               }
+       case LFUN_NEWLINE_INSERT: {
                if (tabular.getPWidth(cur.idx()).zero()) {
                        status.setEnabled(false);
                        return true;
@@ -4353,17 +4994,18 @@ Inset::DisplayType InsetTabular::display() const
 }
 
 
-int InsetTabular::latex(odocstream & os, OutputParams const & runparams) const
+void InsetTabular::latex(otexstream & os, OutputParams const & runparams) const
 {
-       return tabular.latex(os, runparams);
+       tabular.latex(os, runparams);
 }
 
 
-int InsetTabular::plaintext(odocstream & os, OutputParams const & runparams) const
+int InsetTabular::plaintext(odocstringstream & os,
+        OutputParams const & runparams, size_t max_length) const
 {
        os << '\n'; // output table on a new line
        int const dp = runparams.linelen > 0 ? runparams.depth : 0;
-       tabular.plaintext(os, runparams, dp, false, 0);
+       tabular.plaintext(os, runparams, dp, false, 0, max_length);
        return PLAINTEXT_NEWLINE;
 }
 
@@ -4397,13 +5039,7 @@ int InsetTabular::docbook(odocstream & os, OutputParams const & runparams) const
 
 docstring InsetTabular::xhtml(XHTMLStream & xs, OutputParams const & rp) const
 {
-       // FIXME XHTML
-       // It'd be better to be able to get this from an InsetLayout, but at present
-       // InsetLayouts do not seem really to work for things that aren't InsetTexts.
-       xs << html::StartTag("table");
-       docstring ret = tabular.xhtml(xs, rp);
-       xs << html::EndTag("table");
-       return ret;
+       return tabular.xhtml(xs, rp);
 }
 
 
@@ -4414,10 +5050,9 @@ void InsetTabular::validate(LaTeXFeatures & features) const
        // It'd be better to be able to get this from an InsetLayout, but at present
        // InsetLayouts do not seem really to work for things that aren't InsetTexts.
        if (features.runparams().flavor == OutputParams::HTML)
-               features.addPreambleSnippet("<style type=\"text/css\">\n"
-      "table { border: 1px solid black; display: inline-block; }\n"
-      "td { border: 1px solid black; padding: 0.5ex; }\n"
-      "</style>");
+               features.addCSSSnippet(
+                       "table { border: 1px solid black; display: inline-block; }\n"
+                       "td { border: 1px solid black; padding: 0.5ex; }");
 }
 
 
@@ -4438,20 +5073,13 @@ void InsetTabular::cursorPos(BufferView const & bv,
 {
        cell(sl.idx())->cursorPos(bv, sl, boundary, x, y);
 
-       int const row = tabular.cellRow(sl.idx());
-       int const col = tabular.cellColumn(sl.idx());
-
        // y offset     correction
-       for (int r = 0; r < row; ++r)
-               y += tabular.rowDescent(r) + tabular.rowAscent(r + 1) 
-                       + tabular.interRowSpace(r + 1);
-
+       y += cellYPos(sl.idx());
        y += tabular.textVOffset(sl.idx());
+       y += offset_valign_;
 
        // x offset correction
-       for (int c = 0; c < col; ++c)
-               x += tabular.column_info[c].width;
-       
+       x += cellXPos(sl.idx());
        x += tabular.textHOffset(sl.idx());
        x += ADD_TO_TABULAR_WIDTH;
        x += scx_;
@@ -4465,10 +5093,10 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const
        Inset const & inset = *tabular.cellInset(cell);
        Point o = bv.coordCache().getInsets().xy(&inset);
        int const xbeg = o.x_ - tabular.textHOffset(cell);
-       int const xend = xbeg + tabular.columnWidth(cell);
+       int const xend = xbeg + tabular.cellWidth(cell);
        row_type const row = tabular.cellRow(cell);
        int const ybeg = o.y_ - tabular.rowAscent(row)
-               - tabular.interRowSpace(row);
+               - tabular.interRowSpace(row) - tabular.textVOffset(cell);
        int const yend = ybeg + tabular.cellHeight(cell);
 
        if (x < xbeg)
@@ -4524,13 +5152,23 @@ InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int
 }
 
 
+int InsetTabular::cellYPos(idx_type const cell) const
+{
+       row_type row = tabular.cellRow(cell);
+       int ly = 0;
+       for (row_type r = 0; r < row; ++r)
+               ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1) 
+                       + tabular.interRowSpace(r + 1);
+       return ly;
+}
+
+
 int InsetTabular::cellXPos(idx_type const cell) const
 {
        col_type col = tabular.cellColumn(cell);
        int lx = 0;
        for (col_type c = 0; c < col; ++c)
-               lx += tabular.columnWidth(c);
-
+               lx += tabular.column_info[c].width;
        return lx;
 }
 
@@ -4549,7 +5187,7 @@ void InsetTabular::resetPos(Cursor & cur) const
                int const X2 = maxwidth;
                int const offset = ADD_TO_TABULAR_WIDTH + 2;
                int const x1 = xo(cur.bv()) + cellXPos(cur[i].idx()) + offset;
-               int const x2 = x1 + tabular.columnWidth(cur[i].idx());
+               int const x2 = x1 + tabular.cellWidth(cur[i].idx());
 
                if (x1 < X1)
                        scx_ = X1 + 20 - x1;
@@ -4561,7 +5199,7 @@ void InsetTabular::resetPos(Cursor & cur) const
 
        // only update if offset changed
        if (scx_ != scx_old)
-               cur.updateFlags(Update::Force | Update::FitCursor);
+               cur.screenUpdateFlags(Update::Force | Update::FitCursor);
 }
 
 
@@ -4709,7 +5347,6 @@ bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument)
                for (; tabularFeature[i].action != Tabular::LAST_ACTION; ++i) {
                        if (s != tabularFeature[i].feature)
                                continue;
-
                        action = tabularFeature[i].action;
                        break;
                }
@@ -4752,12 +5389,17 @@ bool InsetTabular::oneCellHasRotationState(bool rotated,
 {
        for (row_type r = row_start; r <= row_end; ++r)
                for (col_type c = col_start; c <= col_end; ++c)
-                       if (tabular.getRotateCell(tabular.cellIndex(r, c)) == rotated)
-                               return true;
-
+                       if (rotated) {
+                               if (tabular.getRotateCell(tabular.cellIndex(r, c)) != 0)
+                                       return true;
+                       } else {
+                               if (tabular.getRotateCell(tabular.cellIndex(r, c)) == 0)
+                                       return true;
+                       }
        return false;
 }
 
+
 void InsetTabular::tabularFeatures(Cursor & cur,
        Tabular::Feature feature, string const & value)
 {
@@ -4790,6 +5432,13 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                setAlign = LYX_ALIGN_BLOCK;
                break;
 
+       case Tabular::ALIGN_DECIMAL:
+               if (tabular.column_info[tabular.cellColumn(cur.idx())].alignment == LYX_ALIGN_DECIMAL)
+                       setAlign = LYX_ALIGN_CENTER;
+               else
+                       setAlign = LYX_ALIGN_DECIMAL;
+               break;
+
        case Tabular::M_VALIGN_TOP:
        case Tabular::VALIGN_TOP:
                setVAlign = Tabular::LYX_VALIGN_TOP;
@@ -4809,7 +5458,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
        }
 
-       cur.recordUndoInset(ATOMIC_UNDO);
+       cur.recordUndoInset(ATOMIC_UNDO, this);
 
        getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end);
        row_type const row = tabular.cellRow(cur.idx());
@@ -4819,6 +5468,10 @@ void InsetTabular::tabularFeatures(Cursor & cur,
 
        switch (feature) {
 
+       case Tabular::SET_TABULAR_WIDTH:
+               tabular.setTabularWidth(Length(value));
+               break;
+
        case Tabular::SET_PWIDTH: {
                Length const len(value);
                tabular.setColumnPWidth(cur, cur.idx(), len);
@@ -4832,6 +5485,10 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                tabular.setMColumnPWidth(cur, cur.idx(), Length(value));
                break;
 
+       case Tabular::SET_MROFFSET:
+               tabular.setMROffset(cur, cur.idx(), Length(value));
+               break;
+
        case Tabular::SET_SPECIAL_COLUMN:
        case Tabular::SET_SPECIAL_MULTICOLUMN:
                if (value == "none")
@@ -4840,22 +5497,24 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                        tabular.setAlignSpecial(cur.idx(), from_utf8(value), feature);
                break;
 
-       case Tabular::SET_SPECIAL_MULTIROW:
-               //FIXME: noting to do here?
-               break;
-
        case Tabular::APPEND_ROW:
                // append the row into the tabular
-               tabular.appendRow(cur.idx());
+               tabular.appendRow(row);
                break;
 
        case Tabular::APPEND_COLUMN:
                // append the column into the tabular
-               tabular.appendColumn(cur.idx());
+               tabular.appendColumn(column);
                cur.idx() = tabular.cellIndex(row, column);
                break;
 
        case Tabular::DELETE_ROW:
+               if (sel_row_end == tabular.nrows() - 1 && sel_row_start != 0) {
+                       for (col_type c = 0; c < tabular.ncols(); c++)
+                               tabular.setBottomLine(tabular.cellIndex(sel_row_start - 1, c),
+                                       tabular.bottomLine(tabular.cellIndex(sel_row_end, c)));
+               }
+
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
                        tabular.deleteRow(sel_row_start);
                if (sel_row_start >= tabular.nrows())
@@ -4867,6 +5526,18 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
 
        case Tabular::DELETE_COLUMN:
+               if (sel_col_end == tabular.ncols() - 1 && sel_col_start != 0) {
+                       for (row_type r = 0; r < tabular.nrows(); r++)
+                               tabular.setRightLine(tabular.cellIndex(r, sel_col_start - 1),
+                                       tabular.rightLine(tabular.cellIndex(r, sel_col_end)));
+               }
+
+               if (sel_col_start == 0 && sel_col_end != tabular.ncols() - 1) {
+                       for (row_type r = 0; r < tabular.nrows(); r++)
+                               tabular.setLeftLine(tabular.cellIndex(r, sel_col_end + 1),
+                                       tabular.leftLine(tabular.cellIndex(r, 0)));
+               }
+
                for (col_type c = sel_col_start; c <= sel_col_end; ++c)
                        tabular.deleteColumn(sel_col_start);
                if (sel_col_start >= tabular.ncols())
@@ -4886,6 +5557,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)
@@ -4929,14 +5620,15 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        case Tabular::M_ALIGN_LEFT:
        case Tabular::M_ALIGN_RIGHT:
        case Tabular::M_ALIGN_CENTER:
-               flag = false;
        case Tabular::ALIGN_LEFT:
        case Tabular::ALIGN_RIGHT:
        case Tabular::ALIGN_CENTER:
        case Tabular::ALIGN_BLOCK:
+       case Tabular::ALIGN_DECIMAL:
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
                        for (col_type c = sel_col_start; c <= sel_col_end; ++c)
-                               tabular.setAlignment(tabular.cellIndex(r, c), setAlign, flag);
+                               tabular.setAlignment(tabular.cellIndex(r, c), setAlign,
+                               !tabular.getPWidth(c).zero());
                break;
 
        case Tabular::M_VALIGN_TOP:
@@ -4951,36 +5643,68 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                                tabular.setVAlignment(tabular.cellIndex(r, c), setVAlign, flag);
                break;
 
-       case Tabular::MULTICOLUMN: {
+       case Tabular::SET_MULTICOLUMN: {
                if (!cur.selection()) {
                        // just multicol for one single cell
                        // check whether we are completely in a multicol
-                       if (tabular.isMultiColumn(cur.idx()))
-                               tabular.unsetMultiColumn(cur.idx());
-                       else
-                               tabular.setMultiColumn(cur.idx(), 1);
+                       if (!tabular.isMultiColumn(cur.idx()))
+                               tabular.setMultiColumn(cur.idx(), 1,
+                                       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);
                row_type const col_end = tabular.cellColumn(cur.selEnd().idx());
-               cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1);
+               cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1,
+                                                  tabular.rightLine(cur.selEnd().idx()));
                cur.pit() = 0;
                cur.pos() = 0;
                cur.setSelection(false);
                break;
        }
-       
-       case Tabular::MULTIROW: {
+
+       case Tabular::UNSET_MULTICOLUMN: {
+               if (!cur.selection()) {
+                       if (tabular.isMultiColumn(cur.idx()))
+                               tabular.unsetMultiColumn(cur.idx());
+               }
+               break;
+       }
+
+       case Tabular::MULTICOLUMN: {
+               if (!cur.selection()) {
+                       if (tabular.isMultiColumn(cur.idx()))
+                               tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN);
+                       else
+                               tabularFeatures(cur, Tabular::SET_MULTICOLUMN);
+                       break;
+               }
+               bool merge = false;
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                       row_type const r = sel_row_start;
+                       if (!tabular.isMultiColumn(tabular.cellIndex(r, c))
+                           || (r > sel_row_start && !tabular.isPartOfMultiColumn(r, c)))
+                               merge = true;
+               }
+               // If the selection contains at least one singlecol cell
+               // or multiple multicol cells,
+               // we assume the user will merge is to a single multicol
+               if (merge)
+                       tabularFeatures(cur, Tabular::SET_MULTICOLUMN);
+               else
+                       tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN);
+               break;
+       }
+
+       case Tabular::SET_MULTIROW: {
                if (!cur.selection()) {
                        // just multirow for one single cell
                        // check whether we are completely in a multirow
-                       if (tabular.isMultiRow(cur.idx()))
-                               tabular.unsetMultiRow(cur.idx());
-                       else
-                               tabular.setMultiRow(cur.idx(), 1);
+                       if (!tabular.isMultiRow(cur.idx()))
+                               tabular.setMultiRow(cur.idx(), 1,
+                                                   tabular.bottomLine(cur.idx()));
                        break;
                }
                // we have a selection so this means we just add all this
@@ -4988,13 +5712,47 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                idx_type const s_start = cur.selBegin().idx();
                row_type const row_start = tabular.cellRow(s_start);
                row_type const row_end = tabular.cellRow(cur.selEnd().idx());
-               cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1);
+               cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1,
+                                               tabular.bottomLine(cur.selEnd().idx()));
                cur.pit() = 0;
                cur.pos() = 0;
                cur.setSelection(false);
                break;
        }
 
+       case Tabular::UNSET_MULTIROW: {
+               if (!cur.selection()) {
+                       if (tabular.isMultiRow(cur.idx()))
+                               tabular.unsetMultiRow(cur.idx());
+               }
+               break;
+       }
+
+       case Tabular::MULTIROW: {
+               if (!cur.selection()) {
+                       if (tabular.isMultiRow(cur.idx()))
+                               tabularFeatures(cur, Tabular::UNSET_MULTIROW);
+                       else
+                               tabularFeatures(cur, Tabular::SET_MULTIROW);
+                       break;
+               }
+               bool merge = false;
+               for (row_type r = sel_row_start; r <= sel_row_end; ++r) {
+                       col_type const c = sel_col_start;
+                       if (!tabular.isMultiRow(tabular.cellIndex(r, c))
+                           || (r > sel_row_start && !tabular.isPartOfMultiRow(r, c)))
+                               merge = true;
+               }
+               // If the selection contains at least one singlerow cell
+               // or multiple multirow cells,
+               // we assume the user will merge is to a single multirow
+               if (merge)
+                       tabularFeatures(cur, Tabular::SET_MULTIROW);
+               else
+                       tabularFeatures(cur, Tabular::UNSET_MULTIROW);
+               break;
+       }
+
        case Tabular::SET_ALL_LINES:
                setLines = true;
        case Tabular::UNSET_ALL_LINES:
@@ -5036,15 +5794,16 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
 
        case Tabular::SET_ROTATE_TABULAR:
-               tabular.rotate = true;
+               tabular.rotate = convert<int>(value);
                break;
 
        case Tabular::UNSET_ROTATE_TABULAR:
-               tabular.rotate = false;
+               tabular.rotate = 0;
                break;
 
        case Tabular::TOGGLE_ROTATE_TABULAR:
-               tabular.rotate = !tabular.rotate;
+               // when pressing the rotate button we default to 90° rotation
+               tabular.rotate != 0 ? tabular.rotate = 0 : tabular.rotate = 90;
                break;
 
        case Tabular::TABULAR_VALIGN_TOP:
@@ -5076,13 +5835,13 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        case Tabular::SET_ROTATE_CELL:
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
                        for (col_type c = sel_col_start; c <= sel_col_end; ++c)
-                               tabular.setRotateCell(tabular.cellIndex(r, c), true);
+                               tabular.setRotateCell(tabular.cellIndex(r, c), convert<int>(value));
                break;
 
        case Tabular::UNSET_ROTATE_CELL:
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
                        for (col_type c = sel_col_start; c <= sel_col_end; ++c)
-                               tabular.setRotateCell(tabular.cellIndex(r, c), false);
+                               tabular.setRotateCell(tabular.cellIndex(r, c), 0);
                break;
 
        case Tabular::TOGGLE_ROTATE_CELL:
@@ -5091,9 +5850,13 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                        sel_row_start, sel_row_end, sel_col_start, sel_col_end);
 
                for (row_type r = sel_row_start; r <= sel_row_end; ++r)
-                       for (col_type c = sel_col_start; c <= sel_col_end; ++c)
-                               tabular.setRotateCell(tabular.cellIndex(r, c),
-                                                                         oneNotRotated);
+                       for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                               // when pressing the rotate cell button we default to 90° rotation
+                               if (oneNotRotated)
+                                       tabular.setRotateCell(tabular.cellIndex(r, c), 90);
+                               else
+                                       tabular.setRotateCell(tabular.cellIndex(r, c), 0);
+                       }
                }
                break;
 
@@ -5139,27 +5902,44 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                tabular.setLTFoot(row, flag, ltt, true);
                break;
 
+       case Tabular::UNSET_LTNEWPAGE:
+               flag = false;
        case Tabular::SET_LTNEWPAGE:
-               tabular.setLTNewPage(row, !tabular.getLTNewPage(row));
+               tabular.setLTNewPage(row, flag);
                break;
 
-       case Tabular::TOGGLE_LTCAPTION: {
-               bool const set = !tabular.ltCaption(row);
-               cur.idx() = tabular.setLTCaption(row, set);
+       case Tabular::SET_LTCAPTION: {
+               if (tabular.ltCaption(row))
+                       break;
+               cur.idx() = tabular.setLTCaption(row, true);
                cur.pit() = 0;
                cur.pos() = 0;
                cur.setSelection(false);
+               // If a row is set as caption, then also insert
+               // a caption. Otherwise the LaTeX output is broken.
+               lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL));
+               lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT));
+               break;
+       }
+       
+       case Tabular::UNSET_LTCAPTION: {
+               if (!tabular.ltCaption(row))
+                       break;
+               cur.idx() = tabular.setLTCaption(row, false);
+               cur.pit() = 0;
+               cur.pos() = 0;
+               cur.setSelection(false);
+               FuncRequest fr(LFUN_INSET_DISSOLVE, "caption");
+               if (lyx::getStatus(fr).enabled())
+                       lyx::dispatch(fr);
+               break;
+       }
 
-               if (set) {
-                       // When a row is set as caption, then also insert
-                       // a caption. Otherwise the LaTeX output is broken.
-                       lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL));
-                       lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT));
-               } else {
-                       FuncRequest fr(LFUN_INSET_DISSOLVE, "caption");
-                       if (lyx::getStatus(fr).enabled())
-                               lyx::dispatch(fr);
-               }
+       case Tabular::TOGGLE_LTCAPTION: {
+               if (tabular.ltCaption(row))
+                       tabularFeatures(cur, Tabular::UNSET_LTCAPTION);
+               else
+                       tabularFeatures(cur, Tabular::SET_LTCAPTION);
                break;
        }
 
@@ -5225,6 +6005,11 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
        }
 
+       case Tabular::SET_DECIMAL_POINT:
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c)
+                       tabular.column_info[c].decimal_point = from_utf8(value);
+               break;
+
        // dummy stuff just to avoid warnings
        case Tabular::LAST_ACTION:
                break;
@@ -5261,7 +6046,7 @@ bool InsetTabular::copySelection(Cursor & cur)
 
        odocstringstream os;
        OutputParams const runparams(0);
-       paste_tabular->plaintext(os, runparams, 0, true, '\t');
+       paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX);
        // Needed for the "Edit->Paste recent" menu and the system clipboard.
        cap::copySelection(cur, os.str());
 
@@ -5352,7 +6137,8 @@ void InsetTabular::cutSelection(Cursor & cur)
 
 bool InsetTabular::isRightToLeft(Cursor & cur) const
 {
-       LASSERT(cur.depth() > 1, /**/);
+       // LASSERT: It might be better to abandon this Buffer.
+       LASSERT(cur.depth() > 1, return false);
        Paragraph const & parentpar = cur[cur.depth() - 2].paragraph();
        pos_type const parentpos = cur[cur.depth() - 2].pos();
        return parentpar.getFontSettings(buffer().params(),