]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetTabular.cpp
Stupid bug fix.
[lyx.git] / src / insets / InsetTabular.cpp
index 19583ecbf64a17c79918f136adfa6b992d1c27b0..959fc257d81633c0574484a20f8f930cf8ede1fd 100644 (file)
@@ -3,7 +3,6 @@
  * This file is part of LyX, the document processor.
  * Licence details can be found in the file COPYING.
  *
- * \author Jürgen Vigna
  * \author Lars Gullik Bjønnes
  * \author Matthias Ettrich
  * \author José Matos
@@ -35,6 +34,7 @@
 #include "LaTeXFeatures.h"
 #include "Lexer.h"
 #include "LyXFunc.h"
+#include "LyXRC.h"
 #include "MetricsInfo.h"
 #include "OutputParams.h"
 #include "paragraph_funcs.h"
 #include "TextClass.h"
 #include "TextMetrics.h"
 
+#include "frontends/Application.h"
 #include "frontends/alert.h"
 #include "frontends/Clipboard.h"
 #include "frontends/Painter.h"
 #include "frontends/Selection.h"
 
-
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/docstream.h"
 #include "support/FileName.h"
 #include "support/gettext.h"
+#include "support/lassert.h"
 #include "support/lstrings.h"
 
 #include <boost/scoped_ptr.hpp>
@@ -70,6 +71,7 @@ using namespace lyx::support;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
+
 namespace lyx {
 
 using cap::dirtyTabularStack;
@@ -85,10 +87,10 @@ namespace Alert = frontend::Alert;
 
 namespace {
 
-int const ADD_TO_HEIGHT = 2;
-int const ADD_TO_TABULAR_WIDTH = 2;
-int const default_line_space = 10;
-int const WIDTH_OF_LINE = 5;
+int const ADD_TO_HEIGHT = 2; // in cell
+int const ADD_TO_TABULAR_WIDTH = 6; // horiz space before and after the table
+int const default_line_space = 10; // ?
+int const WIDTH_OF_LINE = 5; // space between double lines
 
 
 ///
@@ -120,10 +122,6 @@ TabularFeature tabularFeature[] =
        { Tabular::VALIGN_TOP, "valign-top" },
        { Tabular::VALIGN_BOTTOM, "valign-bottom" },
        { Tabular::VALIGN_MIDDLE, "valign-middle" },
-       { Tabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
-       { Tabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
-       { Tabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
-       { Tabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
        { Tabular::M_ALIGN_LEFT, "m-align-left" },
        { Tabular::M_ALIGN_RIGHT, "m-align-right" },
        { Tabular::M_ALIGN_CENTER, "m-align-center" },
@@ -153,6 +151,7 @@ TabularFeature tabularFeature[] =
        { Tabular::SET_LTLASTFOOT, "set-ltlastfoot" },
        { Tabular::UNSET_LTLASTFOOT, "unset-ltlastfoot" },
        { Tabular::SET_LTNEWPAGE, "set-ltnewpage" },
+       { Tabular::TOGGLE_LTCAPTION, "toggle-ltcaption" },
        { Tabular::SET_SPECIAL_COLUMN, "set-special-column" },
        { Tabular::SET_SPECIAL_MULTI, "set-special-multi" },
        { Tabular::SET_BOOKTABS, "set-booktabs" },
@@ -160,6 +159,7 @@ TabularFeature tabularFeature[] =
        { Tabular::SET_TOP_SPACE, "set-top-space" },
        { Tabular::SET_BOTTOM_SPACE, "set-bottom-space" },
        { Tabular::SET_INTERLINE_SPACE, "set-interline-space" },
+       { Tabular::SET_BORDER_LINES, "set-border-lines" },
        { Tabular::LAST_ACTION, "" }
 };
 
@@ -472,22 +472,22 @@ string const featureAsString(Tabular::Feature feature)
 /////////////////////////////////////////////////////////////////////
 
 
-Tabular::CellData::CellData(Buffer const & buffer)
+Tabular::CellData::CellData(Buffer & buf)
        : cellno(0),
          width(0),
          multicolumn(Tabular::CELL_NORMAL),
          alignment(LYX_ALIGN_CENTER),
          valignment(LYX_VALIGN_TOP),
-         top_line(true),
+         top_line(false),
          bottom_line(false),
-         left_line(true),
+         left_line(false),
          right_line(false),
          usebox(BOX_NONE),
          rotate(false),
-         inset(new InsetText(buffer.params()))
+         inset(new InsetTableCell(buf))
 {
-       inset->setBuffer(const_cast<Buffer &>(buffer));
-       inset->paragraphs().back().setLayout(buffer.params().textClass().emptyLayout());
+       inset->setBuffer(const_cast<Buffer &>(buf));
+       inset->paragraphs().back().setLayout(buf.params().documentClass().emptyLayout());
 }
 
 
@@ -505,9 +505,9 @@ Tabular::CellData::CellData(CellData const & cs)
          rotate(cs.rotate),
          align_special(cs.align_special),
          p_width(cs.p_width),
-         inset(dynamic_cast<InsetText*>(cs.inset->clone()))
-{}
-
+         inset(dynamic_cast<InsetTableCell *>(cs.inset->clone()))
+{
+}
 
 Tabular::CellData & Tabular::CellData::operator=(CellData cs)
 {
@@ -515,7 +515,6 @@ Tabular::CellData & Tabular::CellData::operator=(CellData cs)
        return *this;
 }
 
-
 void Tabular::CellData::swap(CellData & rhs)
 {
        std::swap(cellno, rhs.cellno);
@@ -538,8 +537,6 @@ void Tabular::CellData::swap(CellData & rhs)
 Tabular::RowData::RowData()
        : ascent(0),
          descent(0),
-         top_line(true),
-         bottom_line(false),
          top_space_default(false),
          bottom_space_default(false),
          interline_space_default(false),
@@ -547,15 +544,14 @@ Tabular::RowData::RowData()
          endfirsthead(false),
          endfoot(false),
          endlastfoot(false),
-         newpage(false)
+         newpage(false),
+         caption(false)
 {}
 
 
 Tabular::ColumnData::ColumnData()
        : alignment(LYX_ALIGN_CENTER),
          valignment(LYX_VALIGN_TOP),
-         left_line(true),
-         right_line(false),
          width(0)
 {
 }
@@ -568,20 +564,26 @@ Tabular::ltType::ltType()
 {}
 
 
-Tabular::Tabular()
+Tabular::Tabular(Buffer & buffer, row_type rows_arg, col_type columns_arg)
 {
-       // unusable now!
+       init(buffer, rows_arg, columns_arg);
 }
 
 
-Tabular::Tabular(Buffer const & buffer, row_type rows_arg, col_type columns_arg)
+void Tabular::setBuffer(Buffer & buffer)
 {
-       init(buffer, rows_arg, columns_arg);
+       buffer_ = &buffer;
+       size_t row_count = row_info.size();
+       size_t column_count = column_info.size();
+       // set silly default lines
+       for (row_type i = 0; i < row_count; ++i)
+               for (col_type j = 0; j < column_count; ++j)
+                       cell_info[i][j].inset->setBuffer(*buffer_);
 }
 
 
 // activates all lines and sets all widths to 0
-void Tabular::init(Buffer const & buf, row_type rows_arg,
+void Tabular::init(Buffer & buf, row_type rows_arg,
                      col_type columns_arg)
 {
        buffer_ = &buf;
@@ -591,32 +593,21 @@ void Tabular::init(Buffer const & buf, row_type rows_arg,
        row_info.reserve(10);
        column_info.reserve(10);
        cell_info.reserve(100);
-       fixCellNums();
-       for (row_type i = 0; i < rows_arg; ++i)
-               cell_info[i].back().right_line = true;
-       row_info.back().bottom_line = true;
-       row_info.front().bottom_line = true;
-       column_info.back().right_line = true;
+       updateIndexes();
        is_long_tabular = false;
        rotate = false;
        use_booktabs = false;
-}
-
-
-void Tabular::fixCellNums()
-{
-       idx_type cellno = 0;
-       for (row_type i = 0; i < rowCount(); ++i) {
-               for (col_type j = 0; j < columnCount(); ++j) {
-                       // When debugging it can be nice to set
-                       // this to true.
-                       cell_info[i][j].inset->setDrawFrame(false);
-                       cell_info[i][j].cellno = cellno++;
+       size_t row_count = row_info.size();
+       size_t column_count = column_info.size();
+       // set silly default lines
+       for (row_type i = 0; i < row_count; ++i)
+               for (col_type j = 0; j < column_count; ++j) {
+                       cell_info[i][j].inset->setBuffer(*buffer_);
+                       cell_info[i][j].top_line = true;
+                       cell_info[i][j].left_line = true;
+                       cell_info[i][j].bottom_line = i == 0 || i == row_count - 1;
+                       cell_info[i][j].right_line = j == column_count - 1;
                }
-               cell_info[i].back().right_line = true;
-       }
-
-       updateIndexes();
 }
 
 
@@ -630,8 +621,8 @@ void Tabular::appendRow(idx_type const cell)
        // now set the values of the row before
        row_info[row] = row_info[row + 1];
 
-       row_type const nrows = rowCount();
-       col_type const ncols = columnCount();
+       row_type const nrows = row_info.size();
+       col_type const ncols = column_info.size();
 
        cell_vvector old(nrows - 1);
        for (row_type i = 0; i < nrows - 1; ++i)
@@ -644,23 +635,34 @@ void Tabular::appendRow(idx_type const cell)
        for (row_type i = row + 2; i < nrows; ++i)
                swap(cell_info[i], old[i - 1]);
 
-       if (bp.trackChanges)
-               for (col_type j = 0; j < ncols; ++j)
-                       cell_info[row + 1][j].inset->setChange(Change(Change::INSERTED));
-
        updateIndexes();
+       for (col_type c = 0; c < ncols; ++c) {
+               // inherit line settings
+               idx_type const i = cellIndex(row + 1, c);
+               idx_type const j = cellIndex(row, c);
+               setLeftLine(i, leftLine(j));
+               setRightLine(i, rightLine(j));
+               setTopLine(i, topLine(j));
+               if (topLine(j) && bottomLine(j)) {
+                       setBottomLine(i, true);
+                       setBottomLine(j, false);
+               }
+               // mark track changes
+               if (bp.trackChanges)
+                       cellInfo(i).inset->setChange(Change(Change::INSERTED));
+       }
 }
 
 
 void Tabular::deleteRow(row_type const row)
 {
        // Not allowed to delete last row
-       if (rowCount() == 1)
+       if (row_info.size() == 1)
                return;
 
        row_info.erase(row_info.begin() + row);
        cell_info.erase(cell_info.begin() + row);
-       fixCellNums();
+       updateIndexes();
 }
 
 
@@ -670,7 +672,7 @@ void Tabular::copyRow(row_type const row)
        cell_info.insert(cell_info.begin() + row, cell_info[row]);
 
        if (buffer().params().trackChanges)
-               for (col_type j = 0; j < columnCount(); ++j)
+               for (col_type j = 0; j < column_info.size(); ++j)
                        cell_info[row + 1][j].inset->setChange(Change(Change::INSERTED));
 
        updateIndexes();
@@ -679,52 +681,59 @@ void Tabular::copyRow(row_type const row)
 
 void Tabular::appendColumn(idx_type const cell)
 {
-       col_type const column = cellColumn(cell);
-       col_type const ncols = columnCount();
-       column_vector::iterator cit = column_info.begin() + column + 1;
+       col_type const c = cellColumn(cell);
+       column_vector::iterator cit = column_info.begin() + c + 1;
        column_info.insert(cit, ColumnData());
+       row_type const nrows = row_info.size();
        // set the column values of the column before
-       column_info[column + 1] = column_info[column];
+       column_info[c + 1] = column_info[c];
 
-       BufferParams const & bp = buffer().params();
-       for (row_type i = 0; i < rowCount(); ++i) {
-               cell_info[i].insert(cell_info[i].begin() + column + 1, CellData(buffer()));
-
-               // care about multicolumns
-               if (cell_info[i][column + 1].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
-                       cell_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
-
-               if (column + 2 >= ncols
-                   || cell_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
-                       cell_info[i][column + 1].multicolumn = Tabular::CELL_NORMAL;
+       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;
        }
-       //++column;
-       for (row_type i = 0; i < rowCount(); ++i) {
-               cell_info[i][column + 1].inset->clear();
-               if (bp.trackChanges)
-                       cell_info[i][column + 1].inset->setChange(Change(Change::INSERTED));
+       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);
+               }
+               //
+               cellInfo(i).inset->clear();
+               if (buffer().params().trackChanges)
+                       cellInfo(i).inset->setChange(Change(Change::INSERTED));
        }
-       fixCellNums();
 }
 
 
 void Tabular::deleteColumn(col_type const column)
 {
        // Not allowed to delete last column
-       if (columnCount() == 1)
+       if (column_info.size() == 1)
                return;
 
        column_info.erase(column_info.begin() + column);
-       for (row_type i = 0; i < rowCount(); ++i) {
+       size_t row_count = row_info.size();
+       for (row_type i = 0; i < row_count; ++i) {
                // Care about multicolumn cells
-               if (column + 1 < columnCount() &&
+               if (column + 1 < column_info.size() &&
                    cell_info[i][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN &&
                    cell_info[i][column + 1].multicolumn == CELL_PART_OF_MULTICOLUMN) {
                        cell_info[i][column + 1].multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
                }
                cell_info[i].erase(cell_info[i].begin() + column);
        }
-       fixCellNums();
+       updateIndexes();
 }
 
 
@@ -733,68 +742,41 @@ void Tabular::copyColumn(col_type const column)
        BufferParams const & bp = buffer().params();
        column_info.insert(column_info.begin() + column, column_info[column]);
 
-       for (row_type i = 0; i < rowCount(); ++i)
+       size_t row_count = row_info.size();
+       for (row_type i = 0; i < row_count; ++i)
                cell_info[i].insert(cell_info[i].begin() + column, cell_info[i][column]);
 
        if (bp.trackChanges)
-               for (row_type i = 0; i < rowCount(); ++i)
+               for (row_type i = 0; i < row_count; ++i)
                        cell_info[i][column + 1].inset->setChange(Change(Change::INSERTED));
-       fixCellNums();
+       updateIndexes();
 }
 
 
 void Tabular::updateIndexes()
 {
+       col_type ncols = column_info.size();
+       row_type nrows = row_info.size();
        numberofcells = 0;
-       // Count only non-multicol cells plus begin multicol
-       // cells, ignore non-begin multicol cells:
-       for (row_type row = 0; row < rowCount(); ++row) {
-               for (col_type column = 0; column < columnCount(); ++column) {
-                       if (cell_info[row][column].multicolumn
-                               != Tabular::CELL_PART_OF_MULTICOLUMN)
+       for (row_type row = 0; row < nrows; ++row)
+               for (col_type column = 0; column < ncols; ++column) {
+                       if (!isPartOfMultiColumn(row, column))
                                ++numberofcells;
-                       BOOST_ASSERT(numberofcells != 0);
-                       cell_info[row][column].cellno =
-                               numberofcells - 1;
+                       cell_info[row][column].cellno = numberofcells - 1;
                }
-       }
 
        rowofcell.resize(numberofcells);
        columnofcell.resize(numberofcells);
-
-       row_type row = 0;
-       col_type column = 0;
-       for (idx_type c = 0;
-                c < numberofcells && row < rowCount() && column < columnCount();) {
-               rowofcell[c] = row;
-               columnofcell[c] = column;
-               ++c;
-               do {
-                       ++column;
-               } while (column < columnCount() &&
-                                cell_info[row][column].multicolumn
-                                == Tabular::CELL_PART_OF_MULTICOLUMN);
-
-               if (column == columnCount()) {
-                       column = 0;
-                       ++row;
-               }
-       }
-
-       for (row_type row = 0; row < rowCount(); ++row) {
-               for (col_type column = 0; column < columnCount(); ++column) {
-                       if (isPartOfMultiColumn(row,column))
+       idx_type i = 0;
+       for (row_type row = 0; row < nrows; ++row)
+               for (col_type column = 0; column < ncols; ++column) {
+                       if (isPartOfMultiColumn(row, column))
                                continue;
-                       cell_info[row][column].inset->setAutoBreakRows(
-                               !getPWidth(cellIndex(row, column)).zero());
+                       rowofcell[i] = row;
+                       columnofcell[i] = column;
+                       setFixedWidth(row, column);
+                       ++i;
                }
-       }
-}
-
-
-Tabular::idx_type Tabular::cellCount() const
-{
-       return numberofcells;
 }
 
 
@@ -802,124 +784,76 @@ Tabular::idx_type Tabular::numberOfCellsInRow(idx_type const cell) const
 {
        row_type const row = cellRow(cell);
        idx_type result = 0;
-       for (col_type i = 0; i < columnCount(); ++i)
+       for (col_type i = 0; i < column_info.size(); ++i)
                if (cell_info[row][i].multicolumn != Tabular::CELL_PART_OF_MULTICOLUMN)
                        ++result;
        return result;
 }
 
 
-bool Tabular::topLine(idx_type const cell, bool const wholerow) const
+bool Tabular::topLine(idx_type const cell) const
 {
-       if (!wholerow && isMultiColumn(cell) &&
-           !(use_booktabs && cellRow(cell) == 0))
-               return cellinfo_of_cell(cell).top_line;
-       return row_info[cellRow(cell)].top_line;
+       return cellInfo(cell).top_line;
 }
 
 
-bool Tabular::bottomLine(idx_type const cell, bool wholerow) const
+bool Tabular::bottomLine(idx_type const cell) const
 {
-       if (!wholerow && isMultiColumn(cell) &&
-           !(use_booktabs && isLastRow(cell)))
-               return cellinfo_of_cell(cell).bottom_line;
-       return row_info[cellRow(cell)].bottom_line;
+       return cellInfo(cell).bottom_line;
 }
 
 
-bool Tabular::leftLine(idx_type cell, bool wholecolumn) const
+bool Tabular::leftLine(idx_type cell) const
 {
        if (use_booktabs)
                return false;
-       if (!wholecolumn && isMultiColumn(cell) &&
-               (isFirstCellInRow(cell) || isMultiColumn(cell-1)))
-               return cellinfo_of_cell(cell).left_line;
-       return column_info[cellColumn(cell)].left_line;
+       return cellInfo(cell).left_line;
 }
 
 
-bool Tabular::rightLine(idx_type cell, bool wholecolumn) const
+bool Tabular::rightLine(idx_type cell) const
 {
        if (use_booktabs)
                return false;
-       if (!wholecolumn && isMultiColumn(cell) &&
-               (isLastCellInRow(cell) || isMultiColumn(cell + 1)))
-               return cellinfo_of_cell(cell).right_line;
-       return column_info[cellRightColumn(cell)].right_line;
+       return cellInfo(cell).right_line;
 }
 
 
 bool Tabular::topAlreadyDrawn(idx_type cell) const
 {
        row_type row = cellRow(cell);
-       if (row > 0 && !getAdditionalHeight(row)) {
-               col_type column = cellColumn(cell);
-               --row;
-               while (column
-                          && cell_info[row][column].multicolumn
-                          == Tabular::CELL_PART_OF_MULTICOLUMN)
-                       --column;
-               if (cell_info[row][column].multicolumn == Tabular::CELL_NORMAL)
-                       return row_info[row].bottom_line;
-               else
-                       return cell_info[row][column].bottom_line;
-       }
-       return false;
+       if (row == 0)
+               return false;
+       idx_type i = cellIndex(row - 1, cellColumn(cell));
+       return !rowTopLine(row) && bottomLine(i);
 }
 
 
 bool Tabular::leftAlreadyDrawn(idx_type cell) const
 {
-       col_type column = cellColumn(cell);
-       if (column > 0) {
-               row_type row = cellRow(cell);
-               while (--column &&
-                          (cell_info[row][column].multicolumn ==
-                               Tabular::CELL_PART_OF_MULTICOLUMN)) { }
-               if (getAdditionalWidth(cell_info[row][column].cellno))
-                       return false;
-               return rightLine(cell_info[row][column].cellno);
-       }
-       return false;
+       col_type col = cellColumn(cell);
+       if (col == 0)
+               return false;
+       idx_type i = cellIndex(cellRow(cell), col - 1);
+       return rightLine(i) && !leftLine(cell);
 }
 
 
 bool Tabular::isLastRow(idx_type cell) const
 {
-       return cellRow(cell) == rowCount() - 1;
+       return cellRow(cell) == row_info.size() - 1;
 }
 
 
 int Tabular::getAdditionalHeight(row_type row) const
 {
-       if (!row || row >= rowCount())
+       if (!row || row >= row_info.size())
                return 0;
 
-       bool top = true;
-       bool bottom = true;
-
-       for (col_type column = 0; column < columnCount() && bottom; ++column) {
-               switch (cell_info[row - 1][column].multicolumn) {
-               case Tabular::CELL_BEGIN_OF_MULTICOLUMN:
-                       bottom = cell_info[row - 1][column].bottom_line;
-                       break;
-               case Tabular::CELL_NORMAL:
-                       bottom = row_info[row - 1].bottom_line;
-               }
-       }
-       for (col_type column = 0; column < columnCount() && top; ++column) {
-               switch (cell_info[row][column].multicolumn) {
-               case Tabular::CELL_BEGIN_OF_MULTICOLUMN:
-                       top = cell_info[row][column].top_line;
-                       break;
-               case Tabular::CELL_NORMAL:
-                       top = row_info[row].top_line;
-               }
-       }
        int const interline_space = row_info[row - 1].interline_space_default ?
                default_line_space :
                row_info[row - 1].interline_space.inPixels(width());
-       if (top && bottom)
+       if (rowTopLine(row) && rowBottomLine(row - 1))
                return interline_space + WIDTH_OF_LINE;
        return interline_space;
 }
@@ -927,131 +861,80 @@ int Tabular::getAdditionalHeight(row_type row) const
 
 int Tabular::getAdditionalWidth(idx_type cell) const
 {
-       // internally already set in setCellWidth
-       // used to get it back in text.cpp
-       col_type const col = cellRightColumn(cell);
-       row_type const row = cellRow(cell);
-       if (col < columnCount() - 1 && rightLine(cell) &&
-               leftLine(cell_info[row][col+1].cellno)) // column_info[col+1].left_line)
-       {
+       col_type const nextcol = cellColumn(cell) + columnSpan(cell);
+       if (rightLine(cell) 
+               && nextcol < column_info.size() && leftLine(cellIndex(cellRow(cell), nextcol)))
                return WIDTH_OF_LINE;
-       }
        return 0;
 }
 
 
-// returns the maximum over all rows
 int Tabular::columnWidth(idx_type cell) const
 {
-       col_type const column1 = cellColumn(cell);
-       col_type const column2 = cellRightColumn(cell);
-       int result = 0;
-       for (col_type i = column1; i <= column2; ++i)
-               result += column_info[i].width;
-       return result;
+       int w = 0;
+       col_type const span = columnSpan(cell);
+       col_type const col = cellColumn(cell);
+       for(col_type c = col; c < col + span ; ++c)
+               w += column_info[c].width;
+       return w;
 }
 
 
-int Tabular::width() const
+bool Tabular::updateColumnWidths()
 {
-       int width = 0;
-       for (col_type i = 0; i < columnCount(); ++i)
-               width += column_info[i].width;
-       return width;
-}
+       col_type const ncols = column_info.size();
+       row_type const nrows = row_info.size();
+       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 (column_info[c].width != new_width) {
+                       column_info[c].width = new_width;
+                       update = true;
+               }
+       }
+       // update col widths to fit merged cells
+       for(col_type c = 0; c < ncols; ++c)
+               for(row_type r = 0; r < nrows; ++r) {
+                       idx_type const i = cellIndex(r, c);
+                       int const span = columnSpan(i);
+                       if (span == 1 || c > cellColumn(i))
+                               continue;
 
-// returns true if a complete update is necessary, otherwise false
-bool Tabular::setWidthOfMulticolCell(idx_type cell, int new_width)
-{
-       if (!isMultiColumn(cell))
-               return false;
+                       int old_width = 0;
+                       for(col_type j = c; j < c + span ; ++j)
+                               old_width += column_info[j].width;
 
-       row_type const row = cellRow(cell);
-       col_type const column1 = cellColumn(cell);
-       col_type const column2 = cellRightColumn(cell);
-       int const old_val = cell_info[row][column2].width;
+                       if (cellInfo(i).width > old_width) {
+                               column_info[c + span - 1].width += cellInfo(i).width - old_width;
+                               update = true;
+                       }
+               }
 
-       // first set columns to 0 so we can calculate the right width
-       for (col_type i = column1; i <= column2; ++i) {
-               cell_info[row][i].width = 0;
-       }
-       // set the width to MAX_WIDTH until width > 0
-       int width = new_width + 2 * WIDTH_OF_LINE;
-       col_type i = column1;
-       for (; i < column2 && width > column_info[i].width; ++i) {
-               cell_info[row][i].width = column_info[i].width;
-               width -= column_info[i].width;
-       }
-       if (width > 0) {
-               cell_info[row][i].width = width;
-       }
-       if (old_val != cell_info[row][column2].width) {
-               // in this case we have to recalculate all multicolumn cells which
-               // have this column as one of theirs but not as last one
-               calculate_width_of_column_NMC(i);
-               recalculateMulticolumnsOfColumn(i);
-               calculate_width_of_column(i);
-       }
-       return true;
+       return update;
 }
 
 
-void Tabular::recalculateMulticolumnsOfColumn(col_type column)
+int Tabular::width() const
 {
-       // the last column does not have to be recalculated because all
-       // multicolumns will have here there last multicolumn cell which
-       // always will have the whole rest of the width of the cell.
-       if (columnCount() < 2 || column > (columnCount() - 2))
-               return;
-       for (row_type row = 0; row < rowCount(); ++row) {
-               int mc = cell_info[row][column].multicolumn;
-               int nmc = cell_info[row][column+1].multicolumn;
-               // we only have to update multicolumns which do not have this
-               // column as their last column!
-               if (mc == CELL_BEGIN_OF_MULTICOLUMN ||
-                         (mc == CELL_PART_OF_MULTICOLUMN &&
-                          nmc == CELL_PART_OF_MULTICOLUMN))
-               {
-                       idx_type const cellno = cell_info[row][column].cellno;
-                       setWidthOfMulticolCell(cellno,
-                                              cellWidth(cellno) - 2 * WIDTH_OF_LINE);
-               }
-       }
+       col_type const ncols = column_info.size();
+       int width = 0;
+       for (col_type i = 0; i < ncols; ++i)
+               width += column_info[i].width;
+       return width;
 }
 
 
 void Tabular::setCellWidth(idx_type cell, int new_width)
 {
-       row_type const row = cellRow(cell);
-       col_type const column1 = cellColumn(cell);
-       bool tmp = false;
-       int width = 0;
-       int add_width = 0;
-
-       if (rightLine(cell_info[row][column1].cellno, true) &&
-               column1 < columnCount() - 1 &&
-               leftLine(cell_info[row][column1+1].cellno, true))
-       {
-               add_width = WIDTH_OF_LINE;
-       }
-
-       if (cellWidth(cell) == new_width + 2 * WIDTH_OF_LINE + add_width)
-               return;
-
-       if (isMultiColumnReal(cell)) {
-               tmp = setWidthOfMulticolCell(cell, new_width);
-       } else {
-               width = new_width + 2 * WIDTH_OF_LINE + add_width;
-               cell_info[row][column1].width = width;
-               tmp = calculate_width_of_column_NMC(column1);
-               if (tmp)
-                       recalculateMulticolumnsOfColumn(column1);
-       }
-       if (tmp) {
-               for (col_type i = 0; i < columnCount(); ++i)
-                       calculate_width_of_column(i);
-       }
+       cellInfo(cell).width = new_width + 2 * WIDTH_OF_LINE 
+               + getAdditionalWidth(cell);
 }
 
 
@@ -1061,7 +944,7 @@ void Tabular::setAlignment(idx_type cell, LyXAlignment align,
        if (!isMultiColumn(cell) || onlycolumn)
                column_info[cellColumn(cell)].alignment = align;
        if (!onlycolumn)
-               cellinfo_of_cell(cell).alignment = align;
+               cellInfo(cell).alignment = align;
 }
 
 
@@ -1071,7 +954,7 @@ void Tabular::setVAlignment(idx_type cell, VAlignment align,
        if (!isMultiColumn(cell) || onlycolumn)
                column_info[cellColumn(cell)].valignment = align;
        if (!onlycolumn)
-               cellinfo_of_cell(cell).valignment = align;
+               cellInfo(cell).valignment = align;
 }
 
 
@@ -1082,9 +965,10 @@ namespace {
  * merge cell paragraphs and reset layout to standard for variable width
  * cells.
  */
-void toggleFixedWidth(Cursor & cur, InsetText * inset, bool fixedWidth)
+void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth)
 {
        inset->setAutoBreakRows(fixedWidth);
+       inset->toggleFixedWidth(fixedWidth);
        if (fixedWidth)
                return;
 
@@ -1097,7 +981,7 @@ void toggleFixedWidth(Cursor & cur, InsetText * inset, bool fixedWidth)
        cur.push(*inset);
        // undo information has already been recorded
        inset->getText(0)->setLayout(cur.bv().buffer(), 0, cur.lastpit() + 1,
-                       bp.textClass().emptyLayoutName());
+                       bp.documentClass().emptyLayoutName());
        cur.pop();
 }
 
@@ -1110,10 +994,10 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell,
        col_type const j = cellColumn(cell);
 
        column_info[j].p_width = width;
-       for (row_type i = 0; i < rowCount(); ++i) {
+       for (row_type i = 0; i < row_info.size(); ++i) {
                idx_type const cell = cellIndex(i, j);
                // because of multicolumns
-               toggleFixedWidth(cur, getCellInset(cell).get(),
+               toggleFixedWidth(cur, cellInset(cell).get(),
                                 !getPWidth(cell).zero());
        }
        // cur paragraph can become invalid after paragraphs were merged
@@ -1125,14 +1009,26 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell,
 }
 
 
+bool Tabular::setFixedWidth(row_type r, col_type c)
+{
+       if (!column_info[c].p_width.zero() ||
+                               (cell_info[r][c].multicolumn != CELL_NORMAL && 
+                               !cell_info[r][c].p_width.zero())) {
+               cell_info[r][c].inset->toggleFixedWidth(true);
+               return true;
+       }
+       return false;
+}
+
+
 bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell,
                Length const & width)
 {
        if (!isMultiColumn(cell))
                return false;
 
-       cellinfo_of_cell(cell).p_width = width;
-       toggleFixedWidth(cur, getCellInset(cell).get(), !width.zero());
+       cellInfo(cell).p_width = width;
+       toggleFixedWidth(cur, cellInset(cell).get(), !width.zero());
        // cur paragraph can become invalid after paragraphs were merged
        if (cur.pit() > cur.lastpit())
                cur.pit() = cur.lastpit();
@@ -1147,7 +1043,7 @@ void Tabular::setAlignSpecial(idx_type cell, docstring const & special,
                                 Tabular::Feature what)
 {
        if (what == SET_SPECIAL_MULTI)
-               cellinfo_of_cell(cell).align_special = special;
+               cellInfo(cell).align_special = special;
        else
                column_info[cellColumn(cell)].align_special = special;
 }
@@ -1162,99 +1058,123 @@ void Tabular::setAllLines(idx_type cell, bool line)
 }
 
 
-void Tabular::setTopLine(idx_type cell, bool line, bool wholerow)
+void Tabular::setTopLine(idx_type i, bool line)
 {
-       row_type const row = cellRow(cell);
-       if (wholerow || !isMultiColumn(cell))
-               row_info[row].top_line = line;
-       else
-               cellinfo_of_cell(cell).top_line = line;
+       cellInfo(i).top_line = line;
 }
 
 
-void Tabular::setBottomLine(idx_type cell, bool line, bool wholerow)
+void Tabular::setBottomLine(idx_type i, bool line)
 {
-       if (wholerow || !isMultiColumn(cell))
-               row_info[cellRow(cell)].bottom_line = line;
-       else
-               cellinfo_of_cell(cell).bottom_line = line;
+       cellInfo(i).bottom_line = line;
 }
 
 
-void Tabular::setLeftLine(idx_type cell, bool line, bool wholecolumn)
+void Tabular::setLeftLine(idx_type cell, bool line)
 {
-       if (wholecolumn || !isMultiColumn(cell))
-               column_info[cellColumn(cell)].left_line = line;
-       else
-               cellinfo_of_cell(cell).left_line = line;
+       cellInfo(cell).left_line = line;
 }
 
 
-void Tabular::setRightLine(idx_type cell, bool line, bool wholecolumn)
+void Tabular::setRightLine(idx_type cell, bool line)
 {
-       if (wholecolumn || !isMultiColumn(cell))
-               column_info[cellRightColumn(cell)].right_line = line;
-       else
-               cellinfo_of_cell(cell).right_line = line;
+       cellInfo(cell).right_line = line;
 }
 
+bool Tabular::rowTopLine(row_type r) const
+{
+       idx_type i0 = getFirstCellInRow(r);
+       idx_type i1 = getLastCellInRow(r);
+       bool all_rows_set = true;
+       for (idx_type j = i0; all_rows_set && j <= i1; ++j)
+               all_rows_set = cellInfo(j).top_line;
+       return all_rows_set;
+}
 
-LyXAlignment Tabular::getAlignment(idx_type cell, bool onlycolumn) const
+
+bool Tabular::rowBottomLine(row_type r) const
 {
-       if (!onlycolumn && isMultiColumn(cell))
-               return cellinfo_of_cell(cell).alignment;
-       return column_info[cellColumn(cell)].alignment;
+       idx_type i0 = getFirstCellInRow(r);
+       idx_type i1 = getLastCellInRow(r);
+       bool all_rows_set = true;
+       for (idx_type j = i0; all_rows_set && j <= i1; ++j)
+               all_rows_set = cellInfo(j).bottom_line;
+       return all_rows_set;
 }
 
 
-Tabular::VAlignment
-Tabular::getVAlignment(idx_type cell, bool onlycolumn) const
+bool Tabular::columnLeftLine(col_type c) const
 {
-       if (!onlycolumn && isMultiColumn(cell))
-               return cellinfo_of_cell(cell).valignment;
-       return column_info[cellColumn(cell)].valignment;
+       if (use_booktabs)
+               return false;
+
+       int nrows_left = 0;
+       int total = 0;
+       row_type const nrows = row_info.size();
+       for (row_type r = 0; r < nrows; ++r) {
+               idx_type i = cellIndex(r, c);
+               if (c == cellColumn(i)) {
+                       ++total;
+                       bool right = c > 0 && cellInfo(cellIndex(r, c - 1)).right_line;
+                       if (cellInfo(i).left_line || right)
+                               ++nrows_left;
+               }
+       }
+       return 2 * nrows_left >= total;
 }
 
 
-Length const Tabular::getPWidth(idx_type cell) const
+bool Tabular::columnRightLine(col_type c) const
 {
-       if (isMultiColumn(cell))
-               return cellinfo_of_cell(cell).p_width;
-       return column_info[cellColumn(cell)].p_width;
+       if (use_booktabs)
+               return false;
+
+       int nrows_right = 0;
+       int total = 0;
+       row_type const nrows = row_info.size();
+       for (row_type r = 0; r < nrows; ++r) {
+               idx_type i = cellIndex(r, c);
+               if (c == cellColumn(i) + columnSpan(i) - 1) {
+                       ++total;
+                       bool left = c + 1 < column_info.size() 
+                               && cellInfo(cellIndex(r, c + 1)).left_line
+                               || c + 1 == column_info.size();
+                       if (cellInfo(i).right_line && left)
+                               ++nrows_right;
+               }
+       }
+       return 2 * nrows_right >= total;
 }
 
 
-Length const Tabular::getColumnPWidth(idx_type cell) const
+LyXAlignment Tabular::getAlignment(idx_type cell, bool onlycolumn) const
 {
-       return column_info[cellColumn(cell)].p_width;
+       if (!onlycolumn && isMultiColumn(cell))
+               return cellInfo(cell).alignment;
+       return column_info[cellColumn(cell)].alignment;
 }
 
 
-Length const Tabular::getMColumnPWidth(idx_type cell) const
+Tabular::VAlignment
+Tabular::getVAlignment(idx_type cell, bool onlycolumn) const
 {
-       if (isMultiColumn(cell))
-               return cellinfo_of_cell(cell).p_width;
-       return Length();
+       if (!onlycolumn && isMultiColumn(cell))
+               return cellInfo(cell).valignment;
+       return column_info[cellColumn(cell)].valignment;
 }
 
 
-docstring const Tabular::getAlignSpecial(idx_type cell, int what) const
+Length const Tabular::getPWidth(idx_type cell) const
 {
-       if (what == SET_SPECIAL_MULTI)
-               return cellinfo_of_cell(cell).align_special;
-       return column_info[cellColumn(cell)].align_special;
+       if (isMultiColumn(cell))
+               return cellInfo(cell).p_width;
+       return column_info[cellColumn(cell)].p_width;
 }
 
 
 int Tabular::cellWidth(idx_type cell) const
 {
-       row_type const row = cellRow(cell);
-       col_type const column1 = cellColumn(cell);
-       col_type const column2 = cellRightColumn(cell);
-       int result = 0;
-       for (col_type i = column1; i <= column2; ++i)
-               result += cell_info[row][i].width;
-       return result;
+       return cellInfo(cell).width;
 }
 
 
@@ -1289,63 +1209,30 @@ bool Tabular::isFirstCellInRow(idx_type cell) const
 
 Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const
 {
-       if (row > rowCount() - 1)
-               row = rowCount() - 1;
+       if (row > row_info.size() - 1)
+               row = row_info.size() - 1;
        return cell_info[row][0].cellno;
 }
 
 
 bool Tabular::isLastCellInRow(idx_type cell) const
 {
-       return cellRightColumn(cell) == columnCount() - 1;
+       return cellRightColumn(cell) == column_info.size() - 1;
 }
 
 
 Tabular::idx_type Tabular::getLastCellInRow(row_type row) const
 {
-       if (row > rowCount() - 1)
-               row = rowCount() - 1;
-       return cell_info[row][columnCount() - 1].cellno;
-}
-
-
-void Tabular::calculate_width_of_column(col_type column)
-{
-       int maximum = 0;
-       for (row_type i = 0; i < rowCount(); ++i)
-               maximum = max(cell_info[i][column].width, maximum);
-       column_info[column].width = maximum;
-}
-
-
-//
-// Calculate the columns regarding ONLY the normal cells and if this
-// column is inside a multicolumn cell then use it only if its the last
-// column of this multicolumn cell as this gives an added width to the
-// column, all the rest should be adapted!
-//
-bool Tabular::calculate_width_of_column_NMC(col_type column)
-{
-       int const old_column_width = column_info[column].width;
-       int max = 0;
-       for (row_type i = 0; i < rowCount(); ++i) {
-               idx_type cell = cellIndex(i, column);
-               bool ismulti = isMultiColumnReal(cell);
-               if ((!ismulti || column == cellRightColumn(cell)) &&
-                       cell_info[i][column].width > max)
-               {
-                       max = cell_info[i][column].width;
-               }
-       }
-       column_info[column].width = max;
-       return column_info[column].width != old_column_width;
+       if (row > row_info.size() - 1)
+               row = row_info.size() - 1;
+       return cell_info[row][column_info.size() - 1].cellno;
 }
 
 
 Tabular::row_type Tabular::cellRow(idx_type cell) const
 {
-       if (cell >= cellCount())
-               return rowCount() - 1;
+       if (cell >= numberofcells)
+               return row_info.size() - 1;
        if (cell == npos)
                return 0;
        return rowofcell[cell];
@@ -1354,10 +1241,10 @@ Tabular::row_type Tabular::cellRow(idx_type cell) const
 
 Tabular::col_type Tabular::cellColumn(idx_type cell) const
 {
-       if (cell >= cellCount())
-               return columnCount() - 1;
+       if (cell >= numberofcells)
+               return column_info.size() - 1;
        if (cell == npos)
-               return 0;
+               return 0;       
        return columnofcell[cell];
 }
 
@@ -1366,8 +1253,8 @@ Tabular::col_type Tabular::cellRightColumn(idx_type cell) const
 {
        row_type const row = cellRow(cell);
        col_type column = cellColumn(cell);
-       while (column < columnCount() - 1 &&
-                  cell_info[row][column + 1].multicolumn == Tabular::CELL_PART_OF_MULTICOLUMN)
+       while (column < column_info.size() - 1 &&
+                  cell_info[row][column + 1].multicolumn == CELL_PART_OF_MULTICOLUMN)
                ++column;
        return column;
 }
@@ -1378,8 +1265,8 @@ void Tabular::write(ostream & os) const
        // header line
        os << "<lyxtabular"
           << write_attribute("version", 3)
-          << write_attribute("rows", rowCount())
-          << write_attribute("columns", columnCount())
+          << write_attribute("rows", row_info.size())
+          << write_attribute("columns", column_info.size())
           << ">\n";
        // global longtable options
        os << "<features"
@@ -1397,21 +1284,17 @@ void Tabular::write(ostream & os) const
           << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
           << write_attribute("lastFootEmpty", endlastfoot.empty)
           << ">\n";
-       for (col_type j = 0; j < columnCount(); ++j) {
+       for (col_type j = 0; j < column_info.size(); ++j) {
                os << "<column"
                   << write_attribute("alignment", column_info[j].alignment)
                   << write_attribute("valignment", column_info[j].valignment)
-                  << write_attribute("leftline", column_info[j].left_line)
-                  << write_attribute("rightline", column_info[j].right_line)
                   << write_attribute("width", column_info[j].p_width.asString())
                   << write_attribute("special", column_info[j].align_special)
                   << ">\n";
        }
-       for (row_type i = 0; i < rowCount(); ++i) {
-               os << "<row"
-                  << write_attribute("topline", row_info[i].top_line)
-                  << write_attribute("bottomline", row_info[i].bottom_line);
+       for (row_type i = 0; i < row_info.size(); ++i) {
                static const string def("default");
+               os << "<row";
                if (row_info[i].top_space_default)
                        os << write_attribute("topspace", def);
                else
@@ -1429,8 +1312,9 @@ void Tabular::write(ostream & os) const
                   << write_attribute("endfoot", row_info[i].endfoot)
                   << write_attribute("endlastfoot", row_info[i].endlastfoot)
                   << write_attribute("newpage", row_info[i].newpage)
+                  << write_attribute("caption", row_info[i].caption)
                   << ">\n";
-               for (col_type j = 0; j < columnCount(); ++j) {
+               for (col_type j = 0; j < column_info.size(); ++j) {
                        os << "<cell"
                           << write_attribute("multicolumn", cell_info[i][j].multicolumn)
                           << write_attribute("alignment", cell_info[i][j].alignment)
@@ -1462,14 +1346,14 @@ void Tabular::read(Lexer & lex)
 
        l_getline(is, line);
        if (!prefixIs(line, "<lyxtabular ") && !prefixIs(line, "<Tabular ")) {
-               BOOST_ASSERT(false);
+               LASSERT(false, /**/);
                return;
        }
 
        int version;
        if (!getTokenValue(line, "version", version))
                return;
-       BOOST_ASSERT(version >= 2);
+       LASSERT(version >= 2, /**/);
 
        int rows_arg;
        if (!getTokenValue(line, "rows", rows_arg))
@@ -1498,7 +1382,7 @@ void Tabular::read(Lexer & lex)
        getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
        getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
 
-       for (col_type j = 0; j < columnCount(); ++j) {
+       for (col_type j = 0; j < column_info.size(); ++j) {
                l_getline(is,line);
                if (!prefixIs(line,"<column")) {
                        lyxerr << "Wrong tabular format (expected <column ...> got"
@@ -1507,21 +1391,17 @@ void Tabular::read(Lexer & lex)
                }
                getTokenValue(line, "alignment", column_info[j].alignment);
                getTokenValue(line, "valignment", column_info[j].valignment);
-               getTokenValue(line, "leftline", column_info[j].left_line);
-               getTokenValue(line, "rightline", column_info[j].right_line);
                getTokenValue(line, "width", column_info[j].p_width);
                getTokenValue(line, "special", column_info[j].align_special);
        }
 
-       for (row_type i = 0; i < rowCount(); ++i) {
+       for (row_type i = 0; i < row_info.size(); ++i) {
                l_getline(is, line);
                if (!prefixIs(line, "<row")) {
                        lyxerr << "Wrong tabular format (expected <row ...> got"
                               << line << ')' << endl;
                        return;
                }
-               getTokenValue(line, "topline", row_info[i].top_line);
-               getTokenValue(line, "bottomline", row_info[i].bottom_line);
                getTokenValue(line, "topspace", row_info[i].top_space,
                              row_info[i].top_space_default);
                getTokenValue(line, "bottomspace", row_info[i].bottom_space,
@@ -1533,7 +1413,8 @@ void Tabular::read(Lexer & lex)
                getTokenValue(line, "endfoot", row_info[i].endfoot);
                getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
                getTokenValue(line, "newpage", row_info[i].newpage);
-               for (col_type j = 0; j < columnCount(); ++j) {
+               getTokenValue(line, "caption", row_info[i].caption);
+               for (col_type j = 0; j < column_info.size(); ++j) {
                        l_getline(is, line);
                        if (!prefixIs(line, "<cell")) {
                                lyxerr << "Wrong tabular format (expected <cell ...> got"
@@ -1550,9 +1431,11 @@ void Tabular::read(Lexer & lex)
                        getTokenValue(line, "rotate", cell_info[i][j].rotate);
                        getTokenValue(line, "usebox", cell_info[i][j].usebox);
                        getTokenValue(line, "width", cell_info[i][j].p_width);
+                       setFixedWidth(i,j);
                        getTokenValue(line, "special", cell_info[i][j].align_special);
                        l_getline(is, line);
                        if (prefixIs(line, "\\begin_inset")) {
+                               cell_info[i][j].inset->setBuffer(*buffer_);
                                cell_info[i][j].inset->read(lex);
                                l_getline(is, line);
                        }
@@ -1578,18 +1461,18 @@ void Tabular::read(Lexer & lex)
 
 bool Tabular::isMultiColumn(idx_type cell) const
 {
-       return cellinfo_of_cell(cell).multicolumn != Tabular::CELL_NORMAL;
+       return cellInfo(cell).multicolumn != CELL_NORMAL;
 }
 
 
 bool Tabular::isMultiColumnReal(idx_type cell) const
 {
        return cellColumn(cell) != cellRightColumn(cell) &&
-                       cellinfo_of_cell(cell).multicolumn != Tabular::CELL_NORMAL;
+                       cellInfo(cell).multicolumn != CELL_NORMAL;
 }
 
 
-Tabular::CellData & Tabular::cellinfo_of_cell(idx_type cell) const
+Tabular::CellData & Tabular::cellInfo(idx_type cell) const
 {
        return cell_info[cellRow(cell)][cellColumn(cell)];
 }
@@ -1597,15 +1480,12 @@ Tabular::CellData & Tabular::cellinfo_of_cell(idx_type cell) const
 
 void Tabular::setMultiColumn(idx_type cell, idx_type number)
 {
-       CellData & cs = cellinfo_of_cell(cell);
+       CellData & cs = cellInfo(cell);
        cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
        cs.alignment = column_info[cellColumn(cell)].alignment;
-       cs.top_line = row_info[cellRow(cell)].top_line;
-       cs.bottom_line = row_info[cellRow(cell)].bottom_line;
-       cs.left_line = column_info[cellColumn(cell)].left_line;
-       cs.right_line = column_info[cellColumn(cell+number-1)].right_line;
+       setRightLine(cell, rightLine(cell + number - 1));
        for (idx_type i = 1; i < number; ++i) {
-               CellData & cs1 = cellinfo_of_cell(cell + i);
+               CellData & cs1 = cellInfo(cell + i);
                cs1.multicolumn = CELL_PART_OF_MULTICOLUMN;
                cs.inset->appendParagraphs(cs1.inset->paragraphs());
                cs1.inset->clear();
@@ -1614,15 +1494,13 @@ void Tabular::setMultiColumn(idx_type cell, idx_type number)
 }
 
 
-Tabular::idx_type Tabular::cells_in_multicolumn(idx_type cell) const
+Tabular::idx_type Tabular::columnSpan(idx_type cell) const
 {
        row_type const row = cellRow(cell);
-       col_type column = cellColumn(cell);
+       col_type const ncols = column_info.size();
        idx_type result = 1;
-       ++column;
-       while (column < columnCount() &&
-                  cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
-       {
+       col_type column = cellColumn(cell) + 1;
+       while (column < ncols && isPartOfMultiColumn(row, column)) {
                ++result;
                ++column;
        }
@@ -1640,7 +1518,7 @@ Tabular::idx_type Tabular::unsetMultiColumn(idx_type cell)
        if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
                cell_info[row][column].multicolumn = CELL_NORMAL;
                ++column;
-               while (column < columnCount() &&
+               while (column < column_info.size() &&
                           cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
                {
                        cell_info[row][column].multicolumn = CELL_NORMAL;
@@ -1653,51 +1531,15 @@ Tabular::idx_type Tabular::unsetMultiColumn(idx_type cell)
 }
 
 
-void Tabular::setBookTabs(bool what)
-{
-       use_booktabs = what;
-}
-
-
-bool Tabular::useBookTabs() const
-{
-       return use_booktabs;
-}
-
-
-void Tabular::setLongTabular(bool what)
-{
-       is_long_tabular = what;
-}
-
-
-bool Tabular::isLongTabular() const
-{
-       return is_long_tabular;
-}
-
-
-void Tabular::setRotateTabular(bool flag)
-{
-       rotate = flag;
-}
-
-
-bool Tabular::getRotateTabular() const
-{
-       return rotate;
-}
-
-
 void Tabular::setRotateCell(idx_type cell, bool flag)
 {
-       cellinfo_of_cell(cell).rotate = flag;
+       cellInfo(cell).rotate = flag;
 }
 
 
 bool Tabular::getRotateCell(idx_type cell) const
 {
-       return cellinfo_of_cell(cell).rotate;
+       return cellInfo(cell).rotate;
 }
 
 
@@ -1705,8 +1547,8 @@ bool Tabular::needRotating() const
 {
        if (rotate)
                return true;
-       for (row_type i = 0; i < rowCount(); ++i)
-               for (col_type j = 0; j < columnCount(); ++j)
+       for (row_type i = 0; i < row_info.size(); ++i)
+               for (col_type j = 0; j < column_info.size(); ++j)
                        if (cell_info[i][j].rotate)
                                return true;
        return false;
@@ -1715,13 +1557,13 @@ bool Tabular::needRotating() const
 
 bool Tabular::isLastCell(idx_type cell) const
 {
-       if (cell + 1 < cellCount())
+       if (cell + 1 < numberofcells)
                return false;
        return true;
 }
 
 
-Tabular::idx_type Tabular::getCellAbove(idx_type cell) const
+Tabular::idx_type Tabular::cellAbove(idx_type cell) const
 {
        if (cellRow(cell) > 0)
                return cell_info[cellRow(cell)-1][cellColumn(cell)].cellno;
@@ -1729,56 +1571,38 @@ Tabular::idx_type Tabular::getCellAbove(idx_type cell) const
 }
 
 
-Tabular::idx_type Tabular::getCellBelow(idx_type cell) const
+Tabular::idx_type Tabular::cellBelow(idx_type cell) const
 {
-       if (cellRow(cell) + 1 < rowCount())
+       if (cellRow(cell) + 1 < row_info.size())
                return cell_info[cellRow(cell)+1][cellColumn(cell)].cellno;
        return cell;
 }
 
 
-Tabular::idx_type Tabular::getLastCellAbove(idx_type cell) const
-{
-       if (cellRow(cell) == 0)
-               return cell;
-       if (!isMultiColumn(cell))
-               return getCellAbove(cell);
-       return cell_info[cellRow(cell) - 1][cellRightColumn(cell)].cellno;
-}
-
-
-Tabular::idx_type Tabular::getLastCellBelow(idx_type cell) const
-{
-       if (cellRow(cell) + 1 >= rowCount())
-               return cell;
-       if (!isMultiColumn(cell))
-               return getCellBelow(cell);
-       return cell_info[cellRow(cell) + 1][cellRightColumn(cell)].cellno;
-}
-
-
 Tabular::idx_type Tabular::cellIndex(row_type row,
                                               col_type column) const
 {
-       BOOST_ASSERT(column != npos && column < columnCount() &&
-                    row    != npos && row    < rowCount());
+       BOOST_ASSERT(column != npos && column < column_info.size()
+               && row != npos && row < row_info.size());
        return cell_info[row][column].cellno;
 }
 
 
 void Tabular::setUsebox(idx_type cell, BoxType type)
 {
-       cellinfo_of_cell(cell).usebox = type;
+       cellInfo(cell).usebox = type;
 }
 
 
+// FIXME: Remove this routine because we cannot insert \parboxes when the user
+// adds line breaks, see bug 4886.
 Tabular::BoxType Tabular::getUsebox(idx_type cell) const
 {
-       if (column_info[cellColumn(cell)].p_width.zero() &&
-               !(isMultiColumn(cell) && !cellinfo_of_cell(cell).p_width.zero()))
+       if ((!column_info[cellColumn(cell)].p_width.zero() && !isMultiColumn(cell)) ||
+               (isMultiColumn(cell) && !cellInfo(cell).p_width.zero()))
                return BOX_NONE;
-       if (cellinfo_of_cell(cell).usebox > 1)
-               return cellinfo_of_cell(cell).usebox;
+       if (cellInfo(cell).usebox > 1)
+               return cellInfo(cell).usebox;
        return useParbox(cell);
 }
 
@@ -1862,7 +1686,7 @@ bool Tabular::getLTNewPage(row_type row) const
 
 bool Tabular::haveLTHead() const
 {
-       for (row_type i = 0; i < rowCount(); ++i)
+       for (row_type i = 0; i < row_info.size(); ++i)
                if (row_info[i].endhead)
                        return true;
        return false;
@@ -1873,7 +1697,7 @@ bool Tabular::haveLTFirstHead() const
 {
        if (endfirsthead.empty)
                return false;
-       for (row_type i = 0; i < rowCount(); ++i)
+       for (row_type i = 0; i < row_info.size(); ++i)
                if (row_info[i].endfirsthead)
                        return true;
        return false;
@@ -1882,7 +1706,7 @@ bool Tabular::haveLTFirstHead() const
 
 bool Tabular::haveLTFoot() const
 {
-       for (row_type i = 0; i < rowCount(); ++i)
+       for (row_type i = 0; i < row_info.size(); ++i)
                if (row_info[i].endfoot)
                        return true;
        return false;
@@ -1893,18 +1717,40 @@ bool Tabular::haveLTLastFoot() const
 {
        if (endlastfoot.empty)
                return false;
-       for (row_type i = 0; i < rowCount(); ++i)
+       for (row_type i = 0; i < row_info.size(); ++i)
                if (row_info[i].endlastfoot)
                        return true;
        return false;
 }
 
 
+Tabular::idx_type Tabular::setLTCaption(row_type row, bool what)
+{
+       idx_type i = getFirstCellInRow(row);
+       if (what) {
+               setMultiColumn(i, column_info.size());
+               setTopLine(i, false);
+               setBottomLine(i, false);
+               setLeftLine(i, false);
+               setRightLine(i, false);
+       } else
+               unsetMultiColumn(i);
+       row_info[row].caption = what;
+       return i;
+}
+
+
+bool Tabular::ltCaption(row_type row) const
+{
+       return row_info[row].caption;
+}
+
+
 // end longtable support functions
 
 void Tabular::setRowAscent(row_type row, int height)
 {
-       if (row >= rowCount() || row_info[row].ascent == height)
+       if (row >= row_info.size() || row_info[row].ascent == height)
                return;
        row_info[row].ascent = height;
 }
@@ -1912,7 +1758,7 @@ void Tabular::setRowAscent(row_type row, int height)
 
 void Tabular::setRowDescent(row_type row, int height)
 {
-       if (row >= rowCount() || row_info[row].descent == height)
+       if (row >= row_info.size() || row_info[row].descent == height)
                return;
        row_info[row].descent = height;
 }
@@ -1920,7 +1766,7 @@ void Tabular::setRowDescent(row_type row, int height)
 
 int Tabular::rowAscent(row_type row) const
 {
-       if (row >= rowCount())
+       if (row >= row_info.size())
                return 0;
        return row_info[row].ascent;
 }
@@ -1928,7 +1774,7 @@ int Tabular::rowAscent(row_type row) const
 
 int Tabular::rowDescent(row_type row) const
 {
-       BOOST_ASSERT(row < rowCount());
+       LASSERT(row < row_info.size(), /**/);
        return row_info[row].descent;
 }
 
@@ -1936,7 +1782,7 @@ int Tabular::rowDescent(row_type row) const
 int Tabular::height() const
 {
        int height = 0;
-       for (row_type row = 0; row < rowCount(); ++row)
+       for (row_type row = 0; row < row_info.size(); ++row)
                height += rowAscent(row) + rowDescent(row) +
                        getAdditionalHeight(row);
        return height;
@@ -1945,8 +1791,8 @@ int Tabular::height() const
 
 bool Tabular::isPartOfMultiColumn(row_type row, col_type column) const
 {
-       BOOST_ASSERT(row < rowCount());
-       BOOST_ASSERT(column < columnCount());
+       LASSERT(row < row_info.size(), /**/);
+       LASSERT(column < column_info.size(), /**/);
        return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN;
 }
 
@@ -1954,8 +1800,8 @@ bool Tabular::isPartOfMultiColumn(row_type row, col_type column) const
 int Tabular::TeXTopHLine(odocstream & os, row_type row) const
 {
        // FIXME: assert or return 0 as in TeXBottomHLine()?
-       BOOST_ASSERT(row != npos);
-       BOOST_ASSERT(row < rowCount());
+       LASSERT(row != npos, /**/);
+       LASSERT(row < row_info.size(), /**/);
 
        idx_type const fcell = getFirstCellInRow(row);
        idx_type const n = numberOfCellsInRow(fcell) + fcell;
@@ -1991,7 +1837,7 @@ int Tabular::TeXTopHLine(odocstream & os, row_type row) const
 int Tabular::TeXBottomHLine(odocstream & os, row_type row) const
 {
        // FIXME: return 0 or assert as in TeXTopHLine()?
-       if (row == npos || row >= rowCount())
+       if (row == npos || row >= row_info.size())
                return 0;
 
        idx_type const fcell = getFirstCellInRow(row);
@@ -2002,7 +1848,7 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row) const
                if (bottomLine(i))
                        ++tmp;
        }
-       if (use_booktabs && row == rowCount() - 1) {
+       if (use_booktabs && row == row_info.size() - 1) {
                if (bottomLine(fcell))
                        os << "\\bottomrule";
        } else if (tmp == n - fcell) {
@@ -2025,26 +1871,40 @@ int Tabular::TeXBottomHLine(odocstream & os, row_type row) const
 }
 
 
-int Tabular::TeXCellPreamble(odocstream & os, idx_type cell) const
+int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, bool & ismulticol) const
 {
        int ret = 0;
-
-       if (getRotateCell(cell)) {
-               os << "\\begin{sideways}\n";
-               ++ret;
-       }
-       if (isMultiColumn(cell)) {
-               os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
-               if (leftLine(cell) &&
-                       (isFirstCellInRow(cell) ||
-                        (!isMultiColumn(cell - 1) && !leftLine(cell, true) &&
-                         !rightLine(cell - 1, true))))
+       row_type const r = cellRow(cell);
+       if (is_long_tabular && row_info[r].caption)
+               return ret;
+
+       Tabular::VAlignment valign =  getVAlignment(cell, !isMultiColumn(cell));
+       LyXAlignment align = getAlignment(cell, !isMultiColumn(cell));
+       // figure out how to set the lines
+       // we always set double lines to the right of the cell
+       col_type const c = cellColumn(cell);
+       col_type const nextcol = c + columnSpan(cell);
+       bool colright = columnRightLine(c);
+       bool colleft = columnLeftLine(c);
+       bool nextcolleft = nextcol < column_info.size() && columnLeftLine(nextcol);
+       bool nextcellleft = nextcol < column_info.size() 
+               && leftLine(cellIndex(r, nextcol));
+       bool coldouble = colright && nextcolleft;
+       bool celldouble = rightLine(cell) && nextcellleft;
+       ismulticol = isMultiColumn(cell) 
+               || (c == 0 && colleft != leftLine(cell))
+               || ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft)
+               || (!colright && !nextcolleft && (rightLine(cell) || nextcellleft))
+               || (coldouble != celldouble);
+       if (ismulticol) {
+               os << "\\multicolumn{" << columnSpan(cell) << "}{";
+               if (c ==0 && leftLine(cell))
                        os << '|';
-               if (!cellinfo_of_cell(cell).align_special.empty()) {
-                       os << cellinfo_of_cell(cell).align_special;
+               if (!cellInfo(cell).align_special.empty()) {
+                       os << cellInfo(cell).align_special;
                } else {
                        if (!getPWidth(cell).zero()) {
-                               switch (getVAlignment(cell)) {
+                               switch (valign) {
                                case LYX_VALIGN_TOP:
                                        os << 'p';
                                        break;
@@ -2059,7 +1919,7 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell) const
                                   << from_ascii(getPWidth(cell).asLatexString())
                                   << '}';
                        } else {
-                               switch (getAlignment(cell)) {
+                               switch (align) {
                                case LYX_ALIGN_LEFT:
                                        os << 'l';
                                        break;
@@ -2072,16 +1932,20 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell) const
                                }
                        } // end if else !getPWidth
                } // end if else !cellinfo_of_cell
-               if (rightLine(cell))
+               if (rightLine(cell) || nextcellleft)
                        os << '|';
-               if (((cell + 1) < cellCount()) && !isFirstCellInRow(cell+1) &&
-                       leftLine(cell+1))
+               if (celldouble)
+                       // add extra vertical line if we want a double one
                        os << '|';
                os << "}{";
                }
+       if (getRotateCell(cell)) {
+               os << "\\begin{sideways}\n";
+               ++ret;
+       }
        if (getUsebox(cell) == BOX_PARBOX) {
                os << "\\parbox[";
-               switch (getVAlignment(cell)) {
+               switch (valign) {
                case LYX_VALIGN_TOP:
                        os << 't';
                        break;
@@ -2096,7 +1960,7 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell) const
                   << "}{";
        } else if (getUsebox(cell) == BOX_MINIPAGE) {
                os << "\\begin{minipage}[";
-               switch (getVAlignment(cell)) {
+               switch (valign) {
                case LYX_VALIGN_TOP:
                        os << 't';
                        break;
@@ -2115,9 +1979,12 @@ int Tabular::TeXCellPreamble(odocstream & os, idx_type cell) const
 }
 
 
-int Tabular::TeXCellPostamble(odocstream & os, idx_type cell) const
+int Tabular::TeXCellPostamble(odocstream & os, idx_type cell, bool ismulticol) const
 {
        int ret = 0;
+       row_type const r = cellRow(cell);
+       if (is_long_tabular && row_info[r].caption)
+               return ret;
 
        // usual cells
        if (getUsebox(cell) == BOX_PARBOX)
@@ -2126,13 +1993,13 @@ int Tabular::TeXCellPostamble(odocstream & os, idx_type cell) const
                os << "%\n\\end{minipage}";
                ret += 2;
        }
-       if (isMultiColumn(cell)) {
-               os << '}';
-       }
        if (getRotateCell(cell)) {
                os << "%\n\\end{sideways}";
                ++ret;
        }
+       if (ismulticol) {
+               os << '}';
+       }
        return ret;
 }
 
@@ -2150,7 +2017,7 @@ int Tabular::TeXLongtableHeaderFooter(odocstream & os,
                        os << "\\hline\n";
                        ++ret;
                }
-               for (row_type i = 0; i < rowCount(); ++i) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
                        if (row_info[i].endhead) {
                                ret += TeXRow(os, i, runparams);
                        }
@@ -2172,7 +2039,7 @@ int Tabular::TeXLongtableHeaderFooter(odocstream & os,
                        os << "\\hline\n";
                        ++ret;
                }
-               for (row_type i = 0; i < rowCount(); ++i) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
                        if (row_info[i].endfirsthead) {
                                ret += TeXRow(os, i, runparams);
                        }
@@ -2190,7 +2057,7 @@ int Tabular::TeXLongtableHeaderFooter(odocstream & os,
                        os << "\\hline\n";
                        ++ret;
                }
-               for (row_type i = 0; i < rowCount(); ++i) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
                        if (row_info[i].endfoot) {
                                ret += TeXRow(os, i, runparams);
                        }
@@ -2212,7 +2079,7 @@ int Tabular::TeXLongtableHeaderFooter(odocstream & os,
                        os << "\\hline\n";
                        ++ret;
                }
-               for (row_type i = 0; i < rowCount(); ++i) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
                        if (row_info[i].endlastfoot) {
                                ret += TeXRow(os, i, runparams);
                        }
@@ -2260,12 +2127,12 @@ int Tabular::TeXRow(odocstream & os, row_type i,
                }
                ++ret;
        }
-
-       for (col_type j = 0; j < columnCount(); ++j) {
+       bool ismulticol = false;
+       for (col_type j = 0; j < column_info.size(); ++j) {
                if (isPartOfMultiColumn(i, j))
                        continue;
-               ret += TeXCellPreamble(os, cell);
-               shared_ptr<InsetText> inset = getCellInset(cell);
+               ret += TeXCellPreamble(os, cell, ismulticol);
+               shared_ptr<InsetTableCell> inset = cellInset(cell);
 
                Paragraph const & par = inset->paragraphs().front();
                bool rtl = par.isRTL(buffer().params())
@@ -2286,7 +2153,7 @@ int Tabular::TeXRow(odocstream & os, row_type i,
                if (rtl)
                        os << '}';
 
-               ret += TeXCellPostamble(os, cell);
+               ret += TeXCellPostamble(os, cell, ismulticol);
                if (!isLastCellInRow(cell)) { // not last cell in row
                        os << " & ";
                }
@@ -2345,8 +2212,9 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
                os << "\\begin{longtable}{";
        else
                os << "\\begin{tabular}{";
-       for (col_type i = 0; i < columnCount(); ++i) {
-               if (!use_booktabs && column_info[i].left_line)
+
+       for (col_type i = 0; i < column_info.size(); ++i) {
+               if (columnLeftLine(i))
                        os << '|';
                if (!column_info[i].align_special.empty()) {
                        os << column_info[i].align_special;
@@ -2397,7 +2265,7 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
                                }
                        } // end if else !column_info[i].p_width
                } // end if else !column_info[i].align_special
-               if (!use_booktabs && column_info[i].right_line)
+               if (columnRightLine(i))
                        os << '|';
        }
        os << "}\n";
@@ -2409,7 +2277,7 @@ int Tabular::latex(odocstream & os, OutputParams const & runparams) const
        //+                      the single row and columns (cells)            +
        //+---------------------------------------------------------------------
 
-       for (row_type i = 0; i < rowCount(); ++i) {
+       for (row_type i = 0; i < row_info.size(); ++i) {
                if (isValidRow(i)) {
                        ret += TeXRow(os, i, runparams);
                        if (is_long_tabular && row_info[i].newpage) {
@@ -2443,7 +2311,7 @@ int Tabular::docbookRow(odocstream & os, row_type row,
        idx_type cell = getFirstCellInRow(row);
 
        os << "<row>\n";
-       for (col_type j = 0; j < columnCount(); ++j) {
+       for (col_type j = 0; j < column_info.size(); ++j) {
                if (isPartOfMultiColumn(row, j))
                        continue;
 
@@ -2475,11 +2343,11 @@ int Tabular::docbookRow(odocstream & os, row_type row,
 
                if (isMultiColumn(cell)) {
                        os << " namest=\"col" << j << "\" ";
-                       os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
+                       os << "nameend=\"col" << j + columnSpan(cell) - 1<< '"';
                }
 
                os << '>';
-               ret += getCellInset(cell)->docbook(os, runparams);
+               ret += cellInset(cell)->docbook(os, runparams);
                os << "</entry>\n";
                ++cell;
        }
@@ -2496,10 +2364,10 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
        //+                      first the opening preamble                    +
        //+---------------------------------------------------------------------
 
-       os << "<tgroup cols=\"" << columnCount()
+       os << "<tgroup cols=\"" << column_info.size()
           << "\" colsep=\"1\" rowsep=\"1\">\n";
 
-       for (col_type i = 0; i < columnCount(); ++i) {
+       for (col_type i = 0; i < column_info.size(); ++i) {
                os << "<colspec colname=\"col" << i << "\" align=\"";
                switch (column_info[i].alignment) {
                case LYX_ALIGN_LEFT:
@@ -2527,7 +2395,7 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
        if (haveLTHead() || haveLTFirstHead()) {
                os << "<thead>\n";
                ++ret;
-               for (row_type i = 0; i < rowCount(); ++i) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
                        if (row_info[i].endhead || row_info[i].endfirsthead) {
                                ret += docbookRow(os, i, runparams);
                        }
@@ -2539,7 +2407,7 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
        if (haveLTFoot() || haveLTLastFoot()) {
                os << "<tfoot>\n";
                ++ret;
-               for (row_type i = 0; i < rowCount(); ++i) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
                        if (row_info[i].endfoot || row_info[i].endlastfoot) {
                                ret += docbookRow(os, i, runparams);
                        }
@@ -2554,7 +2422,7 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
 
        os << "<tbody>\n";
        ++ret;
-       for (row_type i = 0; i < rowCount(); ++i) {
+       for (row_type i = 0; i < row_info.size(); ++i) {
                if (isValidRow(i)) {
                        ret += docbookRow(os, i, runparams);
                }
@@ -2602,7 +2470,7 @@ bool Tabular::plaintextTopHLine(odocstream & os, row_type row,
                }
                col_type column = cellColumn(i);
                int len = clen[column];
-               while (column < columnCount() - 1
+               while (column < column_info.size() - 1
                       && isPartOfMultiColumn(row, ++column))
                        len += clen[column] + 4;
                os << docstring(len, ch);
@@ -2650,7 +2518,7 @@ bool Tabular::plaintextBottomHLine(odocstream & os, row_type row,
                }
                col_type column = cellColumn(i);
                int len = clen[column];
-               while (column < columnCount() -1
+               while (column < column_info.size() -1
                       && isPartOfMultiColumn(row, ++column))
                        len += clen[column] + 4;
                os << docstring(len, ch);
@@ -2675,7 +2543,7 @@ void Tabular::plaintextPrintCell(odocstream & os,
                               bool onlydata) const
 {
        odocstringstream sstr;
-       getCellInset(cell)->plaintext(sstr, runparams);
+       cellInset(cell)->plaintext(sstr, runparams);
 
        if (onlydata) {
                os << sstr.str();
@@ -2689,7 +2557,7 @@ void Tabular::plaintextPrintCell(odocstream & os,
 
        unsigned int len1 = sstr.str().length();
        unsigned int len2 = clen[column];
-       while (column < columnCount() -1
+       while (column < column_info.size() -1
               && isPartOfMultiColumn(row, ++column))
                len2 += clen[column] + 4;
        len2 -= len1;
@@ -2724,32 +2592,32 @@ void Tabular::plaintext(odocstream & os,
                           bool onlydata, char_type delim) const
 {
        // first calculate the width of the single columns
-       vector<unsigned int> clen(columnCount());
+       vector<unsigned int> clen(column_info.size());
 
        if (!onlydata) {
                // first all non (real) multicolumn cells!
-               for (col_type j = 0; j < columnCount(); ++j) {
+               for (col_type j = 0; j < column_info.size(); ++j) {
                        clen[j] = 0;
-                       for (row_type i = 0; i < rowCount(); ++i) {
+                       for (row_type i = 0; i < row_info.size(); ++i) {
                                idx_type cell = cellIndex(i, j);
                                if (isMultiColumnReal(cell))
                                        continue;
                                odocstringstream sstr;
-                               getCellInset(cell)->plaintext(sstr, runparams);
+                               cellInset(cell)->plaintext(sstr, runparams);
                                if (clen[j] < sstr.str().length())
                                        clen[j] = sstr.str().length();
                        }
                }
                // then all (real) multicolumn cells!
-               for (col_type j = 0; j < columnCount(); ++j) {
-                       for (row_type i = 0; i < rowCount(); ++i) {
+               for (col_type j = 0; j < column_info.size(); ++j) {
+                       for (row_type i = 0; i < row_info.size(); ++i) {
                                idx_type cell = cellIndex(i, j);
                                if (!isMultiColumnReal(cell) || isPartOfMultiColumn(i, j))
                                        continue;
                                odocstringstream sstr;
-                               getCellInset(cell)->plaintext(sstr, runparams);
+                               cellInset(cell)->plaintext(sstr, runparams);
                                int len = int(sstr.str().length());
-                               idx_type const n = cells_in_multicolumn(cell);
+                               idx_type const n = columnSpan(cell);
                                for (col_type k = j; len > 0 && k < j + n - 1; ++k)
                                        len -= clen[k];
                                if (len > int(clen[j + n - 1]))
@@ -2758,10 +2626,10 @@ void Tabular::plaintext(odocstream & os,
                }
        }
        idx_type cell = 0;
-       for (row_type i = 0; i < rowCount(); ++i) {
+       for (row_type i = 0; i < row_info.size(); ++i) {
                if (!onlydata && plaintextTopHLine(os, i, clen))
                        os << docstring(depth * 2, ' ');
-               for (col_type j = 0; j < columnCount(); ++j) {
+               for (col_type j = 0; j < column_info.size(); ++j) {
                        if (isPartOfMultiColumn(i, j))
                                continue;
                        if (onlydata && j > 0)
@@ -2781,13 +2649,13 @@ void Tabular::plaintext(odocstream & os,
 }
 
 
-shared_ptr<InsetText> Tabular::getCellInset(idx_type cell) const
+shared_ptr<InsetTableCell> Tabular::cellInset(idx_type cell) const
 {
        return cell_info[cellRow(cell)][cellColumn(cell)].inset;
 }
 
 
-shared_ptr<InsetText> Tabular::getCellInset(row_type row,
+shared_ptr<InsetTableCell> Tabular::cellInset(row_type row,
                                               col_type column) const
 {
        return cell_info[row][column].inset;
@@ -2795,58 +2663,34 @@ shared_ptr<InsetText> Tabular::getCellInset(row_type row,
 
 
 void Tabular::setCellInset(row_type row, col_type column,
-                             shared_ptr<InsetText> ins) const
+                             shared_ptr<InsetTableCell> ins) const
 {
-       cell_info[row][column].inset = ins;
-}
-
-
-Tabular::idx_type
-Tabular::getCellFromInset(Inset const * inset) const
-{
-       // is this inset part of the tabular?
-       if (!inset) {
-               lyxerr << "Error: this is not a cell of the tabular!" << endl;
-               BOOST_ASSERT(false);
-       }
-
-       for (idx_type cell = 0, n = cellCount(); cell < n; ++cell)
-               if (getCellInset(cell).get() == inset) {
-                       LYXERR(Debug::INSETTEXT, "Tabular::getCellFromInset: "
-                               << "cell=" << cell);
-                       return cell;
-               }
-
-       // We should have found a cell at this point
-       lyxerr << "Tabular::getCellFromInset: Cell of inset "
-               << inset << " not found!" << endl;
-       BOOST_ASSERT(false);
-       // shut up compiler
-       return 0;
+       CellData & cd = cell_info[row][column];
+       cd.inset = ins;
 }
 
 
 void Tabular::validate(LaTeXFeatures & features) const
 {
        features.require("NeedTabularnewline");
-       if (useBookTabs())
+       if (use_booktabs)
                features.require("booktabs");
-       if (isLongTabular())
+       if (is_long_tabular)
                features.require("longtable");
        if (needRotating())
                features.require("rotating");
-       for (idx_type cell = 0; cell < cellCount(); ++cell) {
+       for (idx_type cell = 0; cell < numberofcells; ++cell) {
                if (getVAlignment(cell) != LYX_VALIGN_TOP ||
                     (!getPWidth(cell).zero() && !isMultiColumn(cell)))
                        features.require("array");
-               getCellInset(cell)->validate(features);
+               cellInset(cell)->validate(features);
        }
 }
 
 
 Tabular::BoxType Tabular::useParbox(idx_type cell) const
 {
-       ParagraphList const & parlist = getCellInset(cell)->paragraphs();
+       ParagraphList const & parlist = cellInset(cell)->paragraphs();
        ParagraphList::const_iterator cit = parlist.begin();
        ParagraphList::const_iterator end = parlist.end();
 
@@ -2859,36 +2703,69 @@ Tabular::BoxType Tabular::useParbox(idx_type cell) const
 }
 
 
+/////////////////////////////////////////////////////////////////////
+//
+// InsetTableCell
+//
+/////////////////////////////////////////////////////////////////////
+
+InsetTableCell::InsetTableCell(Buffer & buf)
+       : InsetText(buf), isFixedWidth(false)
+{}
+
+
+bool InsetTableCell::forcePlainLayout(idx_type) const
+{
+       return !isFixedWidth;
+}
+
+bool InsetTableCell::allowParagraphCustomization(idx_type) const
+{
+       return isFixedWidth;
+}
+
+bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd,
+       FuncStatus & status) const
+{
+       bool enabled;
+       switch (cmd.action) {
+       case LFUN_LAYOUT:
+               enabled = !forcePlainLayout();
+               break;
+       case LFUN_LAYOUT_PARAGRAPH:
+               enabled = allowParagraphCustomization();
+               break;
+       default:
+               return InsetText::getStatus(cur, cmd, status);
+       }
+       status.setEnabled(enabled);
+       return true;
+}
+
 /////////////////////////////////////////////////////////////////////
 //
 // InsetTabular
 //
 /////////////////////////////////////////////////////////////////////
 
-InsetTabular::InsetTabular(Buffer const & buf, row_type rows,
+InsetTabular::InsetTabular(Buffer & buf, row_type rows,
                           col_type columns)
-       : tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), scx_(0)
+       : tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), scx_(0), 
+       rowselect_(false), colselect_(false)
 {
-       setBuffer(const_cast<Buffer &>(buf)); // FIXME: remove later
+       setBuffer(buf); // FIXME: remove later
 }
 
 
 InsetTabular::InsetTabular(InsetTabular const & tab)
        : Inset(tab), tabular(tab.tabular),  scx_(0)
 {
-       setBuffer(const_cast<Buffer &>(tab.buffer())); // FIXME: remove later
 }
 
 
 InsetTabular::~InsetTabular()
 {
-       InsetTabularMailer(*this).hideDialog();
-}
-
-
-Inset * InsetTabular::clone() const
-{
-       return new InsetTabular(*this);
+       hideDialogs("tabular", this);
 }
 
 
@@ -2908,14 +2785,21 @@ void InsetTabular::write(ostream & os) const
 }
 
 
+docstring InsetTabular::contextMenu(BufferView const &, int, int) const
+{
+       // FIXME: depending on the selection state, we could offer a different menu.
+       return from_ascii("context-tabular");
+}
+
+
 void InsetTabular::read(Lexer & lex)
 {
-       bool const old_format = (lex.getString() == "\\LyXTable");
+       //bool const old_format = (lex.getString() == "\\LyXTable");
 
        tabular.read(lex);
 
-       if (old_format)
-               return;
+       //if (old_format)
+       //      return;
 
        lex.next();
        string token = lex.getString();
@@ -2923,10 +2807,35 @@ void InsetTabular::read(Lexer & lex)
                lex.next();
                token = lex.getString();
        }
-       if (!lex) {
-               lex.printError("Missing \\end_inset at this point. "
-                              "Read: `$$Token'");
+       if (!lex)
+               lex.printError("Missing \\end_inset at this point. ");
+}
+
+
+int InsetTabular::rowFromY(Cursor & cur, int y) const
+{
+       // top y coordinate of tabular
+       int h = yo(cur.bv()) - tabular.rowAscent(0);
+       size_t nrows = tabular.row_info.size();
+       row_type r = 0;
+       for (; r < nrows && y > h; ++r) {
+               h += tabular.rowAscent(r);
+               h += tabular.rowDescent(r);
+               h += tabular.getAdditionalHeight(r);
        }
+       return r - 1;
+}
+
+
+int InsetTabular::columnFromX(Cursor & cur, int x) const
+{
+       // left x coordinate of tabular
+       int w = xo(cur.bv()) + ADD_TO_TABULAR_WIDTH;
+       size_t ncols = tabular.column_info.size();
+       col_type c = 0;
+       for (; c < ncols && x > w; ++c)
+               w += tabular.columnWidth(c);
+       return c - 1;
 }
 
 
@@ -2935,15 +2844,15 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
        //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
        //      mi.base.textwidth << "\n";
        if (!mi.base.bv) {
-               lyxerr << "InsetTabular::metrics: need bv" << endl;
-               BOOST_ASSERT(false);
+               LYXERR0("need bv");
+               LASSERT(false, /**/);
        }
 
        row_type i = 0;
-       for (idx_type cell = 0; i < tabular.rowCount(); ++i) {
+       for (idx_type cell = 0; i < tabular.row_info.size(); ++i) {
                int maxAsc = 0;
                int maxDesc = 0;
-               for (col_type j = 0; j < tabular.columnCount(); ++j) {
+               for (col_type j = 0; j < tabular.column_info.size(); ++j) {
                        if (tabular.isPartOfMultiColumn(i, j))
                                // Multicolumn cell, but not first one
                                continue;
@@ -2951,22 +2860,16 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                        MetricsInfo m = mi;
                        Length p_width;
                        if (tabular.cell_info[i][j].multicolumn ==
-                           Tabular::CELL_BEGIN_OF_MULTICOLUMN)
-                               p_width = tabular.cellinfo_of_cell(cell).p_width;
+                               Tabular::CELL_BEGIN_OF_MULTICOLUMN)
+                               p_width = tabular.cellInfo(cell).p_width;
                        else
                                p_width = tabular.column_info[j].p_width;
                        if (!p_width.zero())
                                m.base.textwidth = p_width.inPixels(mi.base.textwidth);
-                       tabular.getCellInset(cell)->metrics(m, dim);
+                       tabular.cellInset(cell)->metrics(m, dim);
                        if (!p_width.zero())
                                dim.wid = m.base.textwidth;
                        tabular.setCellWidth(cell, dim.wid);
-                       if (p_width.zero()) {
-                               m.base.textwidth = dim.wid + 2 * ADD_TO_TABULAR_WIDTH;
-                               // FIXME there must be a way to get rid of
-                               // the second metrics call
-                               tabular.getCellInset(cell)->metrics(m, dim);
-                       }
                        maxAsc  = max(maxAsc, dim.asc);
                        maxDesc = max(maxDesc, dim.des);
                        ++cell;
@@ -2980,7 +2883,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                        tabular.row_info[i].bottom_space.inPixels(mi.base.textwidth);
                tabular.setRowDescent(i, maxDesc + ADD_TO_HEIGHT + bottom_space);
        }
-
+       tabular.updateColumnWidths();
        dim.asc = tabular.rowAscent(0);
        dim.des = tabular.height() - dim.asc;
        dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH;
@@ -3005,12 +2908,12 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
 
        idx_type idx = 0;
        first_visible_cell = Tabular::npos;
-       for (row_type i = 0; i < tabular.rowCount(); ++i) {
+       for (row_type i = 0; i < tabular.row_info.size(); ++i) {
                int nx = x;
                int const a = tabular.rowAscent(i);
                int const d = tabular.rowDescent(i);
                idx = tabular.cellIndex(i, 0);
-               for (col_type j = 0; j < tabular.columnCount(); ++j) {
+               for (col_type j = 0; j < tabular.column_info.size(); ++j) {
                        if (tabular.isPartOfMultiColumn(i, j))
                                continue;
                        if (first_visible_cell == Tabular::npos)
@@ -3035,7 +2938,7 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
                        ++idx;
                }
 
-               if (i + 1 < tabular.rowCount())
+               if (i + 1 < tabular.row_info.size())
                        y += d + tabular.rowAscent(i + 1) +
                                tabular.getAdditionalHeight(i + 1);
        }
@@ -3070,12 +2973,12 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
                col_type cs, ce;
                getSelection(cur, rs, re, cs, ce);
                y -= tabular.rowAscent(0);
-               for (row_type j = 0; j < tabular.rowCount(); ++j) {
+               for (row_type j = 0; j < tabular.row_info.size(); ++j) {
                        int const a = tabular.rowAscent(j);
                        int const h = a + tabular.rowDescent(j);
                        int xx = x;
                        y += tabular.getAdditionalHeight(j);
-                       for (col_type i = 0; i < tabular.columnCount(); ++i) {
+                       for (col_type i = 0; i < tabular.column_info.size(); ++i) {
                                if (tabular.isPartOfMultiColumn(j, i))
                                        continue;
                                idx_type const cell =
@@ -3090,7 +2993,7 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
                }
 
        } else {
-               x += getCellXPos(cur.idx());
+               x += cellXPos(cur.idx());
                x += tabular.getBeginningOfTextInCell(cur.idx());
                cell(cur.idx())->drawSelection(pi, x, 0 /* ignored */);
        }
@@ -3160,9 +3063,9 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection)
                cur.pos() = 0;
        } else {
                if (isRightToLeft(cur))
-                       cur.idx() = tabular.getFirstCellInRow(tabular.rowCount() - 1);
+                       cur.idx() = tabular.getFirstCellInRow(tabular.row_info.size() - 1);
                else
-                       cur.idx() = tabular.cellCount() - 1;
+                       cur.idx() = tabular.numberofcells - 1;
                cur.pit() = 0;
                cur.pos() = cur.lastpos(); // FIXME crude guess
        }
@@ -3175,9 +3078,9 @@ void InsetTabular::edit(Cursor & cur, bool front, EntryDirection)
 void InsetTabular::updateLabels(ParIterator const & it)
 {
        // In a longtable, tell captions what the current float is
-       Counters & cnts = buffer().params().textClass().counters();
+       Counters & cnts = buffer().params().documentClass().counters();
        string const saveflt = cnts.current_float();
-       if (tabular.isLongTabular())
+       if (tabular.is_long_tabular)
                cnts.current_float("table");
 
        ParIterator it2 = it;
@@ -3187,7 +3090,7 @@ void InsetTabular::updateLabels(ParIterator const & it)
                lyx::updateLabels(buffer(), it2);
 
        //reset afterwards
-       if (tabular.isLongTabular())
+       if (tabular.is_long_tabular)
                cnts.current_float(saveflt);
 }
 
@@ -3201,9 +3104,37 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        switch (cmd.action) {
 
-       case LFUN_MOUSE_PRESS:
+       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);
+                       cur.idx() = tabular.getFirstCellInRow(r);
+                       cur.pos() = 0;
+                       cur.resetAnchor();
+                       cur.idx() = tabular.getLastCellInRow(r);
+                       cur.pos() = cur.lastpos();
+                       cur.selection() = true;
+                       bvcur = cur; 
+                       rowselect_ = true;
+                       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);
+                       cur.idx() = tabular.cellIndex(0, c);
+                       cur.pos() = 0;
+                       cur.resetAnchor();
+                       cur.idx() = tabular.cellIndex(tabular.row_info.size() - 1, c);
+                       cur.pos() = cur.lastpos();
+                       cur.selection() = true;
+                       bvcur = cur; 
+                       colselect_ = true;
+                       break;
+               }
                // do not reset cursor/selection if we have selected
                // some cells (bug 2715).
                if (cmd.button() == mouse_button::button3
@@ -3211,30 +3142,47 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                    && tablemode(bvcur)) 
                        ;
                else
-                       // Let InsetText do it
+                       // Let InsetTableCell do it
                        cell(cur.idx())->dispatch(cur, cmd);
                break;
+       }
        case LFUN_MOUSE_MOTION:
                //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)) {
-                               // 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);
+                       if (!bvcur.anchor_.hasPart(cur)) {
+                               cur.undispatched();
+                               break;
+                       }
+                       // select (additional) row
+                       if (rowselect_) {
+                               row_type r = rowFromY(cur, cmd.y);
+                               cur.idx() = tabular.getLastCellInRow(r);
                                bvcur.setCursor(cur);
                                bvcur.selection() = true;
-                       } else
-                               cur.undispatched();
+                               break;
+                       }
+                       // select (additional) column
+                       if (colselect_) {
+                               col_type c = columnFromX(cur, cmd.x);
+                               cur.idx() = tabular.cellIndex(tabular.row_info.size() - 1, c);
+                               bvcur.setCursor(cur);
+                               bvcur.selection() = true;
+                               break;
+                       }
+                       // only update if selection changes
+                       if (bvcur.idx() == cur.idx() &&
+                               !(bvcur.anchor_.idx() == cur.idx() && bvcur.pos() != cur.pos()))
+                               cur.noUpdate();
+                       setCursorFromCoordinates(cur, cmd.x, cmd.y);
+                       bvcur.setCursor(cur);
+                       bvcur.selection() = true;
                }
                break;
 
        case LFUN_MOUSE_RELEASE:
-               //lyxerr << "# InsetTabular::MouseRelease\n" << bvcur << endl;
-               if (cmd.button() == mouse_button::button3)
-                       InsetTabularMailer(*this).showDialog(&cur.bv());
+               rowselect_ = false;
+               colselect_ = false;
                break;
 
        case LFUN_CELL_BACKWARD:
@@ -3246,56 +3194,69 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                moveNextCell(cur);
                cur.selection() = false;
                break;
-
        case LFUN_CHAR_FORWARD_SELECT:
        case LFUN_CHAR_FORWARD:
-               cell(cur.idx())->dispatch(cur, cmd);
-               if (!cur.result().dispatched()) {
-                       moveNextCell(cur);
-                       if (sl == cur.top())
-                               cmd = FuncRequest(LFUN_FINISHED_FORWARD);
+       case LFUN_CHAR_BACKWARD_SELECT:
+       case LFUN_CHAR_BACKWARD:
+       case LFUN_CHAR_RIGHT_SELECT:
+       case LFUN_CHAR_RIGHT:
+       case LFUN_CHAR_LEFT_SELECT:
+       case LFUN_CHAR_LEFT: {
+
+               // 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:
+               bool next_cell;
+               EntryDirection entry_from = ENTRY_DIRECTION_IGNORE;
+               FuncCode finish_lfun;
+
+               if (cmd.action == LFUN_CHAR_FORWARD 
+                               || cmd.action == LFUN_CHAR_FORWARD_SELECT) {
+                       next_cell = true;
+                       finish_lfun = LFUN_FINISHED_FORWARD;
+               }
+               else if (cmd.action == LFUN_CHAR_BACKWARD
+                               || cmd.action == LFUN_CHAR_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 right = (cmd.action == LFUN_CHAR_RIGHT
+                                                       || cmd.action == LFUN_CHAR_RIGHT_SELECT);
+                       next_cell = (isRightToLeft(cur) != right);
+                       
+                       if (lyxrc.visual_cursor) {
+                               entry_from = right ? ENTRY_DIRECTION_LEFT:ENTRY_DIRECTION_RIGHT;
+                       }
+
+                       if (right)
+                               finish_lfun = LFUN_FINISHED_RIGHT;
                        else
-                               cur.dispatched();
+                               finish_lfun = LFUN_FINISHED_LEFT;
                }
-               break;
+               
 
-       case LFUN_CHAR_BACKWARD_SELECT:
-       case LFUN_CHAR_BACKWARD:
+               // finally, now that we know what we want to do, do it!
                cell(cur.idx())->dispatch(cur, cmd);
                if (!cur.result().dispatched()) {
-                       movePrevCell(cur);
+                       // move to next/prev cell, as appropriate
+                       LYXERR(Debug::RTL, "entering " << (next_cell ? "next" : "previous")
+                               << " cell from: " << int(entry_from));
+                       if (next_cell)
+                               moveNextCell(cur, entry_from);
+                       else
+                               movePrevCell(cur, entry_from);
+                       // if we're exiting the table, call the appropriate FINISHED lfun
                        if (sl == cur.top())
-                               cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
+                               cmd = FuncRequest(finish_lfun);
                        else
                                cur.dispatched();
                }
                break;
 
-       case LFUN_CHAR_RIGHT_SELECT:
-       case LFUN_CHAR_RIGHT:
-               //FIXME: for visual cursor, really move right
-               if (isRightToLeft(cur))
-                       lyx::dispatch(FuncRequest(
-                               cmd.action == LFUN_CHAR_RIGHT_SELECT ?
-                                       LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD));
-               else
-                       lyx::dispatch(FuncRequest(
-                               cmd.action == LFUN_CHAR_RIGHT_SELECT ?
-                                       LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD));
-               break;
-
-       case LFUN_CHAR_LEFT_SELECT:
-       case LFUN_CHAR_LEFT:
-               //FIXME: for visual cursor, really move left
-               if (isRightToLeft(cur))
-                       lyx::dispatch(FuncRequest(
-                               cmd.action == LFUN_CHAR_LEFT_SELECT ?
-                                       LFUN_CHAR_FORWARD_SELECT : LFUN_CHAR_FORWARD));
-               else
-                       lyx::dispatch(FuncRequest(
-                               cmd.action == LFUN_CHAR_LEFT_SELECT ?
-                                       LFUN_CHAR_BACKWARD_SELECT : LFUN_CHAR_BACKWARD));
-               break;
+       }
 
        case LFUN_DOWN_SELECT:
        case LFUN_DOWN:
@@ -3305,8 +3266,8 @@ 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.
-                       if (tabular.cellRow(cur.idx()) != tabular.rowCount() - 1) {
-                               cur.idx() = tabular.getCellBelow(cur.idx());
+                       if (tabular.cellRow(cur.idx()) != tabular.row_info.size() - 1) {
+                               cur.idx() = tabular.cellBelow(cur.idx());
                                cur.pit() = 0;
                                TextMetrics const & tm =
                                        cur.bv().textMetrics(cell(cur.idx())->getText(0));
@@ -3329,7 +3290,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        // then we try to put the cursor into the cell above
                        // setting also the right targetX.
                        if (tabular.cellRow(cur.idx()) != 0) {
-                               cur.idx() = tabular.getCellAbove(cur.idx());
+                               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);
@@ -3350,7 +3311,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 //             int const t =   cur.bv().top_y() + cur.bv().height();
 //             if (t < yo() + tabular.getHeightOfTabular()) {
 //                     cur.bv().scrollDocView(t);
-//                     cur.idx() = tabular.getCellBelow(first_visible_cell) + col;
+//                     cur.idx() = tabular.cellBelow(first_visible_cell) + col;
 //             } else {
 //                     cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col;
 //             }
@@ -3369,7 +3330,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 //                     if (yo() > 0)
 //                             cur.idx() = col;
 //                     else
-//                             cur.idx() = tabular.getCellBelow(first_visible_cell) + col;
+//                             cur.idx() = tabular.cellBelow(first_visible_cell) + col;
 //             } else {
 //                     cur.idx() = col;
 //             }
@@ -3379,11 +3340,11 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 //     }
 
        case LFUN_LAYOUT_TABULAR:
-               InsetTabularMailer(*this).showDialog(&cur.bv());
+               cur.bv().showDialog("tabular", params2string(*this), this);
                break;
 
        case LFUN_INSET_DIALOG_UPDATE:
-               InsetTabularMailer(*this).updateDialog(&cur.bv());
+               cur.bv().updateDialog("tabular", params2string(*this));
                break;
 
        case LFUN_TABULAR_FEATURE:
@@ -3468,13 +3429,15 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
        }
 
        case LFUN_PASTE:
-               if (tabularStackDirty() && theClipboard().isInternal() ||
+               if (!tabularStackDirty()) {
+                       cell(cur.idx())->dispatch(cur, cmd);
+                       break;
+               }
+               if (theClipboard().isInternal() ||
                    !theClipboard().hasInternal() && theClipboard().hasLyXContents()) {
                        cur.recordUndoInset(INSERT_UNDO);
                        pasteClipboard(cur);
-                       break;
                }
-               cell(cur.idx())->dispatch(cur, cmd);
                break;
 
        case LFUN_FONT_EMPH:
@@ -3485,8 +3448,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_FONT_FRAK:
        case LFUN_FONT_TYPEWRITER:
        case LFUN_FONT_SANS:
-       case LFUN_FONT_FREE_APPLY:
-       case LFUN_FONT_FREE_UPDATE:
+       case LFUN_TEXTSTYLE_APPLY:
+       case LFUN_TEXTSTYLE_UPDATE:
        case LFUN_FONT_SIZE:
        case LFUN_FONT_UNDERLINE:
        case LFUN_LANGUAGE:
@@ -3572,8 +3535,6 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                case Tabular::DELETE_COLUMN:
                case Tabular::COPY_ROW:
                case Tabular::COPY_COLUMN:
-               case Tabular::SET_ALL_LINES:
-               case Tabular::UNSET_ALL_LINES:
                case Tabular::SET_TOP_SPACE:
                case Tabular::SET_BOTTOM_SPACE:
                case Tabular::SET_INTERLINE_SPACE:
@@ -3581,31 +3542,34 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        return true;
 
                case Tabular::MULTICOLUMN:
+                       status.setEnabled(sel_row_start == sel_row_end);
                        status.setOnOff(tabular.isMultiColumn(cur.idx()));
                        break;
 
-               case Tabular::M_TOGGLE_LINE_TOP:
-                       flag = false;
+               case Tabular::SET_ALL_LINES:
+               case Tabular::UNSET_ALL_LINES:
+               case Tabular::SET_BORDER_LINES:
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       break;
+
                case Tabular::TOGGLE_LINE_TOP:
-                       status.setOnOff(tabular.topLine(cur.idx(), flag));
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       status.setOnOff(tabular.topLine(cur.idx()));
                        break;
 
-               case Tabular::M_TOGGLE_LINE_BOTTOM:
-                       flag = false;
                case Tabular::TOGGLE_LINE_BOTTOM:
-                       status.setOnOff(tabular.bottomLine(cur.idx(), flag));
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       status.setOnOff(tabular.bottomLine(cur.idx()));
                        break;
 
-               case Tabular::M_TOGGLE_LINE_LEFT:
-                       flag = false;
                case Tabular::TOGGLE_LINE_LEFT:
-                       status.setOnOff(tabular.leftLine(cur.idx(), flag));
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       status.setOnOff(tabular.leftLine(cur.idx()));
                        break;
 
-               case Tabular::M_TOGGLE_LINE_RIGHT:
-                       flag = false;
                case Tabular::TOGGLE_LINE_RIGHT:
-                       status.setOnOff(tabular.rightLine(cur.idx(), flag));
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       status.setOnOff(tabular.rightLine(cur.idx()));
                        break;
 
                case Tabular::M_ALIGN_LEFT:
@@ -3627,7 +3591,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                case Tabular::ALIGN_BLOCK:
-                       status.enabled(!tabular.getPWidth(cur.idx()).zero());
+                       status.setEnabled(!tabular.getPWidth(cur.idx()).zero());
                        status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_BLOCK);
                        break;
 
@@ -3653,20 +3617,20 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                case Tabular::SET_LONGTABULAR:
-                       status.setOnOff(tabular.isLongTabular());
+                       status.setOnOff(tabular.is_long_tabular);
                        break;
 
                case Tabular::UNSET_LONGTABULAR:
-                       status.setOnOff(!tabular.isLongTabular());
+                       status.setOnOff(!tabular.is_long_tabular);
                        break;
 
                case Tabular::TOGGLE_ROTATE_TABULAR:
                case Tabular::SET_ROTATE_TABULAR:
-                       status.setOnOff(tabular.getRotateTabular());
+                       status.setOnOff(tabular.rotate);
                        break;
 
                case Tabular::UNSET_ROTATE_TABULAR:
-                       status.setOnOff(!tabular.getRotateTabular());
+                       status.setOnOff(!tabular.rotate);
                        break;
 
                case Tabular::TOGGLE_ROTATE_CELL:
@@ -3720,17 +3684,22 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.setOnOff(tabular.getLTNewPage(sel_row_start));
                        break;
 
+               case Tabular::TOGGLE_LTCAPTION:
+                       status.setEnabled(sel_row_start == sel_row_end);
+                       status.setOnOff(tabular.ltCaption(sel_row_start));
+                       break;
+
                case Tabular::SET_BOOKTABS:
-                       status.setOnOff(tabular.useBookTabs());
+                       status.setOnOff(tabular.use_booktabs);
                        break;
 
                case Tabular::UNSET_BOOKTABS:
-                       status.setOnOff(!tabular.useBookTabs());
+                       status.setOnOff(!tabular.use_booktabs);
                        break;
 
                default:
                        status.clear();
-                       status.enabled(false);
+                       status.setEnabled(false);
                        break;
                }
                return true;
@@ -3739,7 +3708,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
        // These are only enabled inside tabular
        case LFUN_CELL_BACKWARD:
        case LFUN_CELL_FORWARD:
-               status.enabled(true);
+               status.setEnabled(true);
                return true;
 
        // disable these with multiple cells selected
@@ -3761,18 +3730,17 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
        case LFUN_WRAP_INSERT:
        case LFUN_ERT_INSERT: {
                if (tablemode(cur)) {
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                } else
                        return cell(cur.idx())->getStatus(cur, cmd, status);
        }
 
        // disable in non-fixed-width cells
-       case LFUN_NEW_LINE:
-       case LFUN_BREAK_PARAGRAPH:
-       case LFUN_BREAK_PARAGRAPH_SKIP: {
+       case LFUN_NEWLINE_INSERT:
+       case LFUN_BREAK_PARAGRAPH: {
                if (tabular.getPWidth(cur.idx()).zero()) {
-                       status.enabled(false);
+                       status.setEnabled(false);
                        return true;
                } else
                        return cell(cur.idx())->getStatus(cur, cmd, status);
@@ -3780,14 +3748,14 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
 
        case LFUN_PASTE:
                if (tabularStackDirty() && theClipboard().isInternal()) {
-                       status.enabled(true);
+                       status.setEnabled(true);
                        return true;
                } else
                        return cell(cur.idx())->getStatus(cur, cmd, status);
 
        case LFUN_INSET_MODIFY:
                if (insetCode(cmd.getArg(0)) == TABULAR_CODE) {
-                       status.enabled(true);
+                       status.setEnabled(true);
                        return true;
                }
                // Fall through
@@ -3847,15 +3815,15 @@ void InsetTabular::validate(LaTeXFeatures & features) const
 }
 
 
-shared_ptr<InsetText const> InsetTabular::cell(idx_type idx) const
+shared_ptr<InsetTableCell const> InsetTabular::cell(idx_type idx) const
 {
-       return tabular.getCellInset(idx);
+       return tabular.cellInset(idx);
 }
 
 
-shared_ptr<InsetText> InsetTabular::cell(idx_type idx)
+shared_ptr<InsetTableCell> InsetTabular::cell(idx_type idx)
 {
-       return tabular.getCellInset(idx);
+       return tabular.cellInset(idx);
 }
 
 
@@ -3894,7 +3862,7 @@ int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const
 {
        int xx = 0;
        int yy = 0;
-       Inset const & inset = *tabular.getCellInset(cell);
+       Inset const & inset = *tabular.cellInset(cell);
        Point o = bv.coordCache().getInsets().xy(&inset);
        int const xbeg = o.x_ - tabular.getBeginningOfTextInCell(cell);
        int const xend = xbeg + tabular.columnWidth(cell);
@@ -3944,7 +3912,7 @@ InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int
        idx_type idx_min = 0;
        int dist_min = numeric_limits<int>::max();
        for (idx_type i = 0, n = nargs(); i != n; ++i) {
-               if (bv.coordCache().getInsets().has(tabular.getCellInset(i).get())) {
+               if (bv.coordCache().getInsets().has(tabular.cellInset(i).get())) {
                        int const d = dist(bv, i, x, y);
                        if (d < dist_min) {
                                dist_min = d;
@@ -3956,7 +3924,7 @@ InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int
 }
 
 
-int InsetTabular::getCellXPos(idx_type const cell) const
+int InsetTabular::cellXPos(idx_type const cell) const
 {
        idx_type c = cell;
 
@@ -3981,7 +3949,7 @@ void InsetTabular::resetPos(Cursor & cur) const
                int const X1 = 0;
                int const X2 = maxwidth;
                int const offset = ADD_TO_TABULAR_WIDTH + 2;
-               int const x1 = xo(cur.bv()) + getCellXPos(cur.idx()) + offset;
+               int const x1 = xo(cur.bv()) + cellXPos(cur.idx()) + offset;
                int const x2 = x1 + tabular.columnWidth(cur.idx());
 
                if (x1 < X1)
@@ -3996,14 +3964,14 @@ void InsetTabular::resetPos(Cursor & cur) const
 }
 
 
-void InsetTabular::moveNextCell(Cursor & cur)
+void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from)
 {
        if (isRightToLeft(cur)) {
                if (tabular.isFirstCellInRow(cur.idx())) {
                        row_type const row = tabular.cellRow(cur.idx());
-                       if (row == tabular.rowCount() - 1)
+                       if (row == tabular.row_info.size() - 1)
                                return;
-                       cur.idx() = tabular.getCellBelow(tabular.getLastCellInRow(row));
+                       cur.idx() = tabular.cellBelow(tabular.getLastCellInRow(row));
                } else {
                        if (cur.idx() == 0)
                                return;
@@ -4016,11 +3984,29 @@ void InsetTabular::moveNextCell(Cursor & cur)
        }
        cur.pit() = 0;
        cur.pos() = 0;
+       cur.boundary(false);
+
+       // in visual mode, place cursor at extreme left or right
+       
+       switch(entry_from) {
+
+       case ENTRY_DIRECTION_RIGHT:
+               cur.posVisToRowExtremity(false /* !left */);
+               break;
+       case ENTRY_DIRECTION_LEFT:
+               cur.posVisToRowExtremity(true /* left */);
+               break;
+       case ENTRY_DIRECTION_IGNORE:
+               // nothing to do in this case
+               break;
+
+       }
+
        resetPos(cur);
 }
 
 
-void InsetTabular::movePrevCell(Cursor & cur)
+void InsetTabular::movePrevCell(Cursor & cur, EntryDirection entry_from)
 {
        if (isRightToLeft(cur)) {
                if (tabular.isLastCellInRow(cur.idx())) {
@@ -4028,7 +4014,7 @@ void InsetTabular::movePrevCell(Cursor & cur)
                        if (row == 0)
                                return;
                        cur.idx() = tabular.getFirstCellInRow(row);
-                       cur.idx() = tabular.getCellAbove(cur.idx());
+                       cur.idx() = tabular.cellAbove(cur.idx());
                } else {
                        if (tabular.isLastCell(cur.idx()))
                                return;
@@ -4042,6 +4028,22 @@ void InsetTabular::movePrevCell(Cursor & cur)
        cur.pit() = cur.lastpit();
        cur.pos() = cur.lastpos();
 
+       // in visual mode, place cursor at extreme left or right
+       
+       switch(entry_from) {
+
+       case ENTRY_DIRECTION_RIGHT:
+               cur.posVisToRowExtremity(false /* !left */);
+               break;
+       case ENTRY_DIRECTION_LEFT:
+               cur.posVisToRowExtremity(true /* left */);
+               break;
+       case ENTRY_DIRECTION_IGNORE:
+               // nothing to do in this case
+               break;
+
+       }
+
        // FIXME: this accesses the position cache before it is initialized
        //resetPos(cur);
 }
@@ -4198,7 +4200,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        case Tabular::DELETE_ROW:
                for (row_type i = sel_row_start; i <= sel_row_end; ++i)
                        tabular.deleteRow(sel_row_start);
-               if (sel_row_start >= tabular.rowCount())
+               if (sel_row_start >= tabular.row_info.size())
                        --sel_row_start;
                cur.idx() = tabular.cellIndex(sel_row_start, column);
                cur.pit() = 0;
@@ -4209,7 +4211,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        case Tabular::DELETE_COLUMN:
                for (col_type i = sel_col_start; i <= sel_col_end; ++i)
                        tabular.deleteColumn(sel_col_start);
-               if (sel_col_start >= tabular.columnCount())
+               if (sel_col_start >= tabular.column_info.size())
                        --sel_col_start;
                cur.idx() = tabular.cellIndex(row, sel_col_start);
                cur.pit() = 0;
@@ -4226,51 +4228,35 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                cur.idx() = tabular.cellIndex(row, column);
                break;
 
-       case Tabular::M_TOGGLE_LINE_TOP:
-               flag = false;
        case Tabular::TOGGLE_LINE_TOP: {
-               bool lineSet = !tabular.topLine(cur.idx(), flag);
+               bool lineSet = !tabular.topLine(cur.idx());
                for (row_type i = sel_row_start; i <= sel_row_end; ++i)
                        for (col_type j = sel_col_start; j <= sel_col_end; ++j)
-                               tabular.setTopLine(
-                                       tabular.cellIndex(i, j),
-                                       lineSet, flag);
+                               tabular.setTopLine(tabular.cellIndex(i, j), lineSet);
                break;
        }
 
-       case Tabular::M_TOGGLE_LINE_BOTTOM:
-               flag = false;
        case Tabular::TOGGLE_LINE_BOTTOM: {
-               bool lineSet = !tabular.bottomLine(cur.idx(), flag);
+               bool lineSet = !tabular.bottomLine(cur.idx());
                for (row_type i = sel_row_start; i <= sel_row_end; ++i)
                        for (col_type j = sel_col_start; j <= sel_col_end; ++j)
-                               tabular.setBottomLine(
-                                       tabular.cellIndex(i, j),
-                                       lineSet,
-                                       flag);
+                               tabular.setBottomLine(tabular.cellIndex(i, j), lineSet);
                break;
        }
 
-       case Tabular::M_TOGGLE_LINE_LEFT:
-               flag = false;
        case Tabular::TOGGLE_LINE_LEFT: {
-               bool lineSet = !tabular.leftLine(cur.idx(), flag);
+               bool lineSet = !tabular.leftLine(cur.idx());
                for (row_type i = sel_row_start; i <= sel_row_end; ++i)
                        for (col_type j = sel_col_start; j <= sel_col_end; ++j)
-                               tabular.setLeftLine(
-                                       tabular.cellIndex(i,j),
-                                       lineSet,
-                                       flag);
+                               tabular.setLeftLine(tabular.cellIndex(i, j), lineSet);
                break;
        }
 
-       case Tabular::M_TOGGLE_LINE_RIGHT:
-               flag = false;
        case Tabular::TOGGLE_LINE_RIGHT: {
-               bool lineSet = !tabular.rightLine(cur.idx(), flag);
+               bool lineSet = !tabular.rightLine(cur.idx());
                for (row_type i = sel_row_start; i <= sel_row_end; ++i)
                        for (col_type j = sel_col_start; j <= sel_col_end; ++j)
-                               tabular.setRightLine(tabular.cellIndex(i,j), lineSet, flag);
+                               tabular.setRightLine(tabular.cellIndex(i, j), lineSet);
                break;
        }
 
@@ -4300,13 +4286,6 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
 
        case Tabular::MULTICOLUMN: {
-               if (sel_row_start != sel_row_end) {
-                       // FIXME: Need I say it ? This is horrible.
-                       // FIXME UNICODE
-                       Alert::error(_("Error setting multicolumn"),
-                                    _("You cannot set multicolumn vertically."));
-                       return;
-               }
                if (!cur.selection()) {
                        // just multicol for one single cell
                        // check whether we are completely in a multicol
@@ -4337,24 +4316,35 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                                        tabular.cellIndex(i,j), setLines);
                break;
 
+       case Tabular::SET_BORDER_LINES:
+               for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
+                       tabular.setLeftLine(tabular.cellIndex(i, sel_col_start), true);
+                       tabular.setRightLine(tabular.cellIndex(i, sel_col_end), true);
+               }
+               for (col_type j = sel_col_start; j <= sel_col_end; ++j) {
+                       tabular.setTopLine(tabular.cellIndex(sel_row_start, j), true);
+                       tabular.setBottomLine(tabular.cellIndex(sel_row_end, j), true);
+               }
+               break;
+
        case Tabular::SET_LONGTABULAR:
-               tabular.setLongTabular(true);
+               tabular.is_long_tabular = true;
                break;
 
        case Tabular::UNSET_LONGTABULAR:
-               tabular.setLongTabular(false);
+               tabular.is_long_tabular = false;
                break;
 
        case Tabular::SET_ROTATE_TABULAR:
-               tabular.setRotateTabular(true);
+               tabular.rotate = true;
                break;
 
        case Tabular::UNSET_ROTATE_TABULAR:
-               tabular.setRotateTabular(false);
+               tabular.rotate = false;
                break;
 
        case Tabular::TOGGLE_ROTATE_TABULAR:
-               tabular.setRotateTabular(!tabular.getRotateTabular());
+               tabular.rotate = !tabular.rotate;
                break;
 
        case Tabular::SET_ROTATE_CELL:
@@ -4428,12 +4418,19 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                tabular.setLTNewPage(row, !tabular.getLTNewPage(row));
                break;
 
+       case Tabular::TOGGLE_LTCAPTION:
+               cur.idx() = tabular.setLTCaption(row, !tabular.ltCaption(row));
+               cur.pit() = 0;
+               cur.pos() = 0;
+               cur.selection() = false;
+               break;
+
        case Tabular::SET_BOOKTABS:
-               tabular.setBookTabs(true);
+               tabular.use_booktabs = true;
                break;
 
        case Tabular::UNSET_BOOKTABS:
-               tabular.setBookTabs(false);
+               tabular.use_booktabs = false;
                break;
 
        case Tabular::SET_TOP_SPACE: {
@@ -4499,14 +4496,16 @@ void InsetTabular::tabularFeatures(Cursor & cur,
 
 bool InsetTabular::showInsetDialog(BufferView * bv) const
 {
-       InsetTabularMailer(*this).showDialog(bv);
+       bv->showDialog("tabular", params2string(*this),
+               const_cast<InsetTabular *>(this));
        return true;
 }
 
 
 void InsetTabular::openLayoutDialog(BufferView * bv) const
 {
-       InsetTabularMailer(*this).showDialog(bv);
+       bv->showDialog("tabular", params2string(*this),
+               const_cast<InsetTabular *>(this));
 }
 
 
@@ -4525,23 +4524,17 @@ bool InsetTabular::copySelection(Cursor & cur)
                paste_tabular->deleteRow(0);
 
        row_type const rows = re - rs + 1;
-       while (paste_tabular->rowCount() > rows)
+       while (paste_tabular->row_info.size() > rows)
                paste_tabular->deleteRow(rows);
 
-       paste_tabular->setTopLine(0, true, true);
-       paste_tabular->setBottomLine(paste_tabular->getFirstCellInRow(rows - 1),
-                                    true, true);
-
        for (col_type i = 0; i < cs; ++i)
                paste_tabular->deleteColumn(0);
 
        col_type const columns = ce - cs + 1;
-       while (paste_tabular->columnCount() > columns)
+       while (paste_tabular->column_info.size() > columns)
                paste_tabular->deleteColumn(columns);
 
-       paste_tabular->setLeftLine(0, true, true);
-       paste_tabular->setRightLine(paste_tabular->getLastCellInRow(0),
-                                   true, true);
+       paste_tabular->setBuffer(tabular.buffer());
 
        odocstringstream os;
        OutputParams const runparams(0);
@@ -4566,10 +4559,10 @@ bool InsetTabular::pasteClipboard(Cursor & cur)
        col_type const actcol = tabular.cellColumn(cur.idx());
        row_type const actrow = tabular.cellRow(cur.idx());
        for (row_type r1 = 0, r2 = actrow;
-            r1 < paste_tabular->rowCount() && r2 < tabular.rowCount();
+            r1 < paste_tabular->row_info.size() && r2 < tabular.row_info.size();
             ++r1, ++r2) {
                for (col_type c1 = 0, c2 = actcol;
-                   c1 < paste_tabular->columnCount() && c2 < tabular.columnCount();
+                   c1 < paste_tabular->column_info.size() && c2 < tabular.column_info.size();
                    ++c1, ++c2) {
                        if (paste_tabular->isPartOfMultiColumn(r1, c1) &&
                            tabular.isPartOfMultiColumn(r2, c2))
@@ -4582,8 +4575,8 @@ bool InsetTabular::pasteClipboard(Cursor & cur)
                                --c1;
                                continue;
                        }
-                       shared_ptr<InsetText> inset(
-                               new InsetText(*paste_tabular->getCellInset(r1, c1)));
+                       shared_ptr<InsetTableCell> inset(
+                               new InsetTableCell(*paste_tabular->cellInset(r1, c1)));
                        tabular.setCellInset(r2, c2, inset);
                        // FIXME: change tracking (MG)
                        inset->setChange(Change(cur.buffer().params().trackChanges ?
@@ -4605,7 +4598,7 @@ void InsetTabular::cutSelection(Cursor & cur)
        getSelection(cur, rs, re, cs, ce);
        for (row_type i = rs; i <= re; ++i) {
                for (col_type j = cs; j <= ce; ++j) {
-                       shared_ptr<InsetText> t
+                       shared_ptr<InsetTableCell> t
                                = cell(tabular.cellIndex(i, j));
                        if (cur.buffer().params().trackChanges)
                                // FIXME: Change tracking (MG)
@@ -4626,7 +4619,7 @@ void InsetTabular::cutSelection(Cursor & cur)
 
 bool InsetTabular::isRightToLeft(Cursor & cur) const
 {
-       BOOST_ASSERT(cur.depth() > 1);
+       LASSERT(cur.depth() > 1, /**/);
        Paragraph const & parentpar = cur[cur.depth() - 2].paragraph();
        pos_type const parentpos = cur[cur.depth() - 2].pos();
        return parentpar.getFontSettings(cur.bv().buffer().params(),
@@ -4688,6 +4681,12 @@ bool InsetTabular::allowParagraphCustomization(idx_type cell) const
 }
 
 
+bool InsetTabular::forcePlainLayout(idx_type cell) const
+{
+       return !tabular.getPWidth(cell).zero();
+}
+
+
 bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf,
                                     bool usePaste)
 {
@@ -4733,11 +4732,11 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf,
        }
 
        size_t op = 0;
-       idx_type const cells = loctab->cellCount();
+       idx_type const cells = loctab->numberofcells;
        p = 0;
        cols = ocol;
-       rows = loctab->rowCount();
-       col_type const columns = loctab->columnCount();
+       rows = loctab->row_info.size();
+       col_type const columns = loctab->column_info.size();
 
        while (cell < cells && p < len && row < rows &&
               (p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos)
@@ -4748,7 +4747,7 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf,
                case '\t':
                        // we can only set this if we are not too far right
                        if (cols < columns) {
-                               shared_ptr<InsetText> inset = loctab->getCellInset(cell);
+                               shared_ptr<InsetTableCell> inset = loctab->cellInset(cell);
                                Font const font = bv.textMetrics(&inset->text_).
                                        displayFont(0, 0);
                                inset->setText(buf.substr(op, p - op), font,
@@ -4760,7 +4759,7 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf,
                case '\n':
                        // we can only set this if we are not too far right
                        if (cols < columns) {
-                               shared_ptr<InsetText> inset = tabular.getCellInset(cell);
+                               shared_ptr<InsetTableCell> inset = tabular.cellInset(cell);
                                Font const font = bv.textMetrics(&inset->text_).
                                        displayFont(0, 0);
                                inset->setText(buf.substr(op, p - op), font,
@@ -4777,7 +4776,7 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf,
        }
        // check for the last cell if there is no trailing '\n'
        if (cell < cells && op < len) {
-               shared_ptr<InsetText> inset = loctab->getCellInset(cell);
+               shared_ptr<InsetTableCell> inset = loctab->cellInset(cell);
                Font const font = bv.textMetrics(&inset->text_).displayFont(0, 0);
                inset->setText(buf.substr(op, len - op), font,
                        buffer().params().trackChanges);
@@ -4788,11 +4787,11 @@ bool InsetTabular::insertPlaintextString(BufferView & bv, docstring const & buf,
 
 void InsetTabular::addPreview(PreviewLoader & loader) const
 {
-       row_type const rows = tabular.rowCount();
-       col_type const columns = tabular.columnCount();
+       row_type const rows = tabular.row_info.size();
+       col_type const columns = tabular.column_info.size();
        for (row_type i = 0; i < rows; ++i) {
                for (col_type j = 0; j < columns; ++j)
-                       tabular.getCellInset(i, j)->addPreview(loader);
+                       tabular.cellInset(i, j)->addPreview(loader);
        }
 }
 
@@ -4803,25 +4802,74 @@ bool InsetTabular::tablemode(Cursor & cur) const
 }
 
 
+bool InsetTabular::completionSupported(Cursor const & cur) const
+{
+       Cursor const & bvCur = cur.bv().cursor();
+       if (&bvCur.inset() != this)
+               return false;
+       return cur.text()->completionSupported(cur);
+}
 
 
-string const InsetTabularMailer::name_("tabular");
+bool InsetTabular::inlineCompletionSupported(Cursor const & cur) const
+{
+       return completionSupported(cur);
+}
 
-InsetTabularMailer::InsetTabularMailer(InsetTabular const & inset)
-       : inset_(const_cast<InsetTabular &>(inset))
-{}
+
+bool InsetTabular::automaticInlineCompletion() const
+{
+       return lyxrc.completion_inline_text;
+}
 
 
-string const InsetTabularMailer::inset2string(Buffer const &) const
+bool InsetTabular::automaticPopupCompletion() const
 {
-       return params2string(inset_);
+       return lyxrc.completion_popup_text;
 }
 
 
-void InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
+bool InsetTabular::showCompletionCursor() const
+{
+       return lyxrc.completion_cursor_text;
+}
+
+
+CompletionList const * InsetTabular::createCompletionList(Cursor const & cur) const
+{
+       return completionSupported(cur) ? cur.text()->createCompletionList(cur) : 0;
+}
+
+
+docstring InsetTabular::completionPrefix(Cursor const & cur) const
+{
+       if (!completionSupported(cur))
+               return docstring();
+       return cur.text()->completionPrefix(cur);
+}
+
+
+bool InsetTabular::insertCompletion(Cursor & cur, docstring const & s, bool finished)
+{
+       if (!completionSupported(cur))
+               return false;
+
+       return cur.text()->insertCompletion(cur, s, finished);
+}
+
+
+void InsetTabular::completionPosAndDim(Cursor const & cur, int & x, int & y, 
+                                   Dimension & dim) const
+{
+       TextMetrics const & tm = cur.bv().textMetrics(cur.text());
+       tm.completionPosAndDim(cur, x, y, dim);
+}
+
+
+void InsetTabular::string2params(string const & in, InsetTabular & inset)
 {
        istringstream data(in);
-       Lexer lex(0,0);
+       Lexer lex;
        lex.setStream(data);
 
        if (in.empty())
@@ -4829,24 +4877,27 @@ void InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
 
        string token;
        lex >> token;
-       if (!lex || token != name_)
-               return print_mailer_error("InsetTabularMailer", in, 1,
-                                         name_);
+       if (!lex || token != "tabular") {
+               LYXERR0("Expected arg 1 to be \"tabular\" in " << in);
+               return;
+       }
 
        // This is part of the inset proper that is usually swallowed
        // by Buffer::readInset
        lex >> token;
-       if (!lex || token != "Tabular")
-               return print_mailer_error("InsetTabularMailer", in, 2, "Tabular");
+       if (!lex || token != "Tabular") {
+               LYXERR0("Expected arg 2 to be \"Tabular\" in " << in);
+               return;
+       }
 
        inset.read(lex);
 }
 
 
-string const InsetTabularMailer::params2string(InsetTabular const & inset)
+string InsetTabular::params2string(InsetTabular const & inset)
 {
        ostringstream data;
-       data << name_ << ' ';
+       data << "tabular" << ' ';
        inset.write(data);
        data << "\\end_inset\n";
        return data.str();