Attached is what I currently have to support multirows.

There is currently one issue I cannot solve: The metrics and drawing of the cells that are part of a multirow is broken. The drawing of the first multirow cell is however correct. I failed to figure out this problem and therefore ask for help.

Besides this, the copy/paste mechanism is not yet ready for multirows.
The same applies for the plain text output but I have not yet had a look at 
this.

The UI is also not yet feature-complete. I plan to further add support to set the multirow width and the horzontal alignment.

thanks in advance and regards
Uwe

<<attachment: tabular-feature_multirow.png>>

Index: development/scons/scons_manifest.py
===================================================================
--- development/scons/scons_manifest.py	(revision 33077)
+++ development/scons/scons_manifest.py	(working copy)
@@ -1515,6 +1515,7 @@
     tabular-feature_delete-column.png
     tabular-feature_delete-row.png
     tabular-feature_multicolumn.png
+    tabular-feature_multirow.png
     tabular-feature_set-all-lines.png
     tabular-feature_set-border-lines.png
     tabular-feature_set-longtabular.png
Index: lib/images/tabular-feature_multirow.png
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: lib\images\tabular-feature_multirow.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: lib/Makefile.am
===================================================================
--- lib/Makefile.am	(revision 33077)
+++ lib/Makefile.am	(working copy)
@@ -415,6 +415,7 @@
 	images/tabular-feature_delete-column.png \
 	images/tabular-feature_delete-row.png \
 	images/tabular-feature_multicolumn.png \
+	images/tabular-feature_multirow.png \
 	images/tabular-feature_set-all-lines.png \
 	images/tabular-feature_set-longtabular.png \
 	images/tabular-feature_set-rotate-cell.png \
Index: lib/ui/stdtoolbars.inc
===================================================================
--- lib/ui/stdtoolbars.inc	(revision 33077)
+++ lib/ui/stdtoolbars.inc	(working copy)
@@ -151,6 +151,7 @@
 		Item "Rotate cell" "tabular-feature toggle-rotate-cell"
 		Item "Rotate table" "tabular-feature toggle-rotate-tabular"
 		Item "Set multi-column" "tabular-feature multicolumn"
+		Item "Set multi-row" "tabular-feature multirow"
 	End
 	
 	Toolbar "math" "Math"
Index: src/frontends/qt4/GuiTabular.cpp
===================================================================
--- src/frontends/qt4/GuiTabular.cpp	(revision 33077)
+++ src/frontends/qt4/GuiTabular.cpp	(working copy)
@@ -96,6 +96,8 @@
 		this, SLOT(vAlign_changed(int)));
 	connect(multicolumnCB, SIGNAL(clicked()),
 		this, SLOT(multicolumn_clicked()));
+	connect(multirowCB, SIGNAL(clicked()),
+		this, SLOT(multirow_clicked()));
 	connect(newpageCB, SIGNAL(clicked()),
 		this, SLOT(ltNewpage_clicked()));
 	connect(headerStatusCB, SIGNAL(clicked()),
@@ -172,6 +174,7 @@
 	bc().addReadOnly(booktabsRB);
 
 	bc().addReadOnly(multicolumnCB);
+	bc().addReadOnly(multirowCB);
 	bc().addReadOnly(rotateCellCB);
 	bc().addReadOnly(rotateTabularCB);
 	bc().addReadOnly(specialAlignmentED);
@@ -396,7 +399,13 @@
 	changed();
 }
 
+void GuiTabular::multirow_clicked()
+{
+	toggleMultiRow();
+	changed();
+}
 
+
 void GuiTabular::rotateTabular()
 {
 	rotateTabular(rotateTabularCB->isChecked());
@@ -654,7 +663,7 @@
 
 Length getMColumnPWidth(Tabular const & t, size_t cell)
 {
-	if (t.isMultiColumn(cell))
+	if (t.isMultiColumn(cell) || t.isMultiRow(cell))
 		return t.cellInfo(cell).p_width;
 	return Length();
 }
@@ -662,7 +671,8 @@
 
 docstring getAlignSpecial(Tabular const & t, size_t cell, int what)
 {
-	if (what == Tabular::SET_SPECIAL_MULTI)
+	if (what == Tabular::SET_SPECIAL_MULTICOLUMN
+		|| what == Tabular::SET_SPECIAL_MULTIROW)
 		return t.cellInfo(cell).align_special;
 	return t.column_info[t.cellColumn(cell)].align_special;
 }
@@ -670,7 +680,6 @@
 }
 
 
-
 void GuiTabular::updateContents()
 {
 	initialiseParams(string());
@@ -684,9 +693,11 @@
 	tabularColumnED->setText(QString::number(col + 1));
 
 	bool const multicol(tabular_.isMultiColumn(cell));
-
 	multicolumnCB->setChecked(multicol);
 
+	bool const multirow(tabular_.isMultiRow(cell));
+	multirowCB->setChecked(multirow);
+
 	rotateCellCB->setChecked(tabular_.getRotateCell(cell));
 	rotateTabularCB->setChecked(tabular_.rotate);
 
@@ -699,8 +710,12 @@
 
 	if (multicol) {
 		special = getAlignSpecial(tabular_, cell,
-			Tabular::SET_SPECIAL_MULTI);
+			Tabular::SET_SPECIAL_MULTICOLUMN);
 		pwidth = getMColumnPWidth(tabular_, cell);
+	} else if (multirow) {
+		special = getAlignSpecial(tabular_, cell,
+			Tabular::SET_SPECIAL_MULTIROW);
+		pwidth = getMColumnPWidth(tabular_, cell);
 	} else {
 		special = getAlignSpecial(tabular_, cell,
 			Tabular::SET_SPECIAL_COLUMN);
@@ -832,7 +847,8 @@
 	vAlignCB->setCurrentIndex(valign);
 
 	hAlignCB->setEnabled(true);
-	vAlignCB->setEnabled(!pwidth.zero());
+	if (!multirow && !pwidth.zero())
+	vAlignCB->setEnabled(true);
 
 	int tableValign = 1;
 	switch (tabular_.tabular_valignment) {
@@ -927,6 +943,7 @@
 	// When a row is set as longtable caption, it must not be allowed
 	// to unset that this row is a multicolumn.
 	multicolumnCB->setEnabled(funcEnabled(Tabular::MULTICOLUMN));
+	multirowCB->setEnabled(funcEnabled(Tabular::MULTIROW));
 
 	Tabular::ltType ltt;
 	bool use_empty;
@@ -1021,15 +1038,16 @@
 	// apply the fixed width values
 	size_t const cell = getActiveCell();
 	bool const multicol = tabular_.isMultiColumn(cell);
+	bool const multirow = tabular_.isMultiRow(cell);
 	string width = widgetsToLength(widthED, widthUnitCB);
 	string width2;
 
 	Length llen = getColumnPWidth(tabular_, cell);
 	Length llenMulti = getMColumnPWidth(tabular_, cell);
 
-	if (multicol && !llenMulti.zero())
+	if (multicol && multirow && !llenMulti.zero())
 		width2 = llenMulti.asString();
-	else if (!multicol && !llen.zero())
+	else if (!multicol && !multirow && !llen.zero())
 		width2 = llen.asString();
 
 	// apply the special alignment
@@ -1038,14 +1056,19 @@
 
 	if (multicol)
 		sa2 = getAlignSpecial(tabular_, cell,
-			Tabular::SET_SPECIAL_MULTI);
+			Tabular::SET_SPECIAL_MULTICOLUMN);
+	else if (multirow)
+		sa2 = getAlignSpecial(tabular_, cell,
+			Tabular::SET_SPECIAL_MULTIROW);
 	else
 		sa2 = getAlignSpecial(tabular_, cell,
 			Tabular::SET_SPECIAL_COLUMN);
 
 	if (sa1 != sa2) {
 		if (multicol)
-			set(Tabular::SET_SPECIAL_MULTI, to_utf8(sa1));
+			set(Tabular::SET_SPECIAL_MULTICOLUMN, to_utf8(sa1));
+		if (multirow)
+			set(Tabular::SET_SPECIAL_MULTIROW, to_utf8(sa1));
 		else
 			set(Tabular::SET_SPECIAL_COLUMN, to_utf8(sa1));
 	}
@@ -1162,7 +1185,9 @@
 void GuiTabular::setSpecial(string const & special)
 {
 	if (tabular_.isMultiColumn(getActiveCell()))
-		set(Tabular::SET_SPECIAL_MULTI, special);
+		set(Tabular::SET_SPECIAL_MULTICOLUMN, special);
+	else if (tabular_.isMultiRow(getActiveCell()))
+		set(Tabular::SET_SPECIAL_MULTIROW, special);
 	else
 		set(Tabular::SET_SPECIAL_COLUMN, special);
 }
@@ -1186,6 +1211,13 @@
 }
 
 
+void GuiTabular::toggleMultiRow()
+{
+	set(Tabular::MULTIROW);
+	updateView();
+}
+
+
 void GuiTabular::rotateTabular(bool yes)
 {
 	if (yes)
@@ -1255,7 +1287,8 @@
 			break;
 	}
 
-	if (tabular_.isMultiColumn(getActiveCell()))
+	if (tabular_.isMultiColumn(getActiveCell())
+		|| tabular_.isMultiRow(getActiveCell()))
 		set(multi_num);
 	else
 		set(num);
Index: src/frontends/qt4/GuiTabular.h
===================================================================
--- src/frontends/qt4/GuiTabular.h	(revision 33077)
+++ src/frontends/qt4/GuiTabular.h	(working copy)
@@ -45,6 +45,7 @@
 	void topBorder_changed();
 	void bottomBorder_changed();
 	void multicolumn_clicked();
+	void multirow_clicked();
 	void rotateTabular();
 	void rotateCell();
 	void hAlign_changed(int align);
@@ -101,6 +102,7 @@
 	void setWidth(std::string const & width);
 
 	void toggleMultiColumn();
+	void toggleMultiRow();
 
 	void rotateTabular(bool yes);
 	void rotateCell(bool yes);
Index: src/frontends/qt4/ui/TabularUi.ui
===================================================================
--- src/frontends/qt4/ui/TabularUi.ui	(revision 33077)
+++ src/frontends/qt4/ui/TabularUi.ui	(working copy)
@@ -130,8 +130,8 @@
       <attribute name="title">
        <string>&amp;Table Settings</string>
       </attribute>
-      <layout class="QGridLayout" name="gridLayout_6">
-       <item row="0" column="0">
+      <layout class="QGridLayout" name="gridLayout">
+       <item row="0" column="0" colspan="2">
         <widget class="QGroupBox" name="GroupBox12">
          <property name="title">
           <string>Column settings</string>
@@ -283,7 +283,7 @@
           <item row="3" column="0">
            <widget class="QCheckBox" name="multicolumnCB">
             <property name="toolTip">
-             <string>Merge cells</string>
+             <string>Merge cells of different columns</string>
             </property>
             <property name="text">
              <string>&amp;Multicolumn</string>
@@ -296,10 +296,29 @@
        <item row="1" column="0">
         <widget class="QGroupBox" name="groupBox">
          <property name="title">
-          <string>Cell setting</string>
+          <string>Row setting</string>
          </property>
          <layout class="QGridLayout" name="gridLayout_3">
           <item row="0" column="0">
+           <widget class="QCheckBox" name="multirowCB">
+            <property name="toolTip">
+             <string>Merge cells of different rows</string>
+            </property>
+            <property name="text">
+             <string>M&amp;ultirow</string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item row="1" column="1">
+        <widget class="QGroupBox" name="groupBox_2">
+         <property name="title">
+          <string>Cell setting</string>
+         </property>
+         <layout class="QGridLayout" name="gridLayout_6">
+          <item row="0" column="0">
            <widget class="QCheckBox" name="rotateCellCB">
             <property name="toolTip">
              <string>Rotate this cell by 90 degrees</string>
@@ -312,7 +331,7 @@
          </layout>
         </widget>
        </item>
-       <item row="2" column="0">
+       <item row="2" column="0" colspan="2">
         <widget class="QGroupBox" name="tabAlignmentGB">
          <property name="enabled">
           <bool>true</bool>
@@ -388,7 +407,7 @@
          </layout>
         </widget>
        </item>
-       <item row="3" column="0">
+       <item row="3" column="0" colspan="2">
         <layout class="QHBoxLayout" name="horizontalLayout">
          <item>
           <widget class="QLabel" name="specialAlignmentLA">
@@ -409,15 +428,15 @@
          </item>
         </layout>
        </item>
-       <item row="4" column="0">
+       <item row="4" column="1">
         <spacer name="verticalSpacer_2">
          <property name="orientation">
           <enum>Qt::Vertical</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
-           <width>20</width>
-           <height>68</height>
+           <width>17</width>
+           <height>0</height>
           </size>
          </property>
         </spacer>
@@ -1497,6 +1516,7 @@
   <tabstop>vAlignCB</tabstop>
   <tabstop>multicolumnCB</tabstop>
   <tabstop>rotateTabularCB</tabstop>
+  <tabstop>multirowCB</tabstop>
   <tabstop>rotateCellCB</tabstop>
   <tabstop>specialAlignmentED</tabstop>
   <tabstop>closePB</tabstop>
Index: src/insets/InsetTabular.cpp
===================================================================
--- src/insets/InsetTabular.cpp	(revision 33077)
+++ src/insets/InsetTabular.cpp	(working copy)
@@ -130,6 +130,7 @@
 	{ Tabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
 	{ Tabular::M_VALIGN_MIDDLE, "m-valign-middle" },
 	{ Tabular::MULTICOLUMN, "multicolumn" },
+	{ Tabular::MULTIROW, "multirow" },
 	{ Tabular::SET_ALL_LINES, "set-all-lines" },
 	{ Tabular::UNSET_ALL_LINES, "unset-all-lines" },
 	{ Tabular::SET_LONGTABULAR, "set-longtabular" },
@@ -154,7 +155,8 @@
 	{ 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_SPECIAL_MULTICOLUMN, "set-special-multicolumn" },
+	{ Tabular::SET_SPECIAL_MULTIROW, "set-special-multirow" },
 	{ Tabular::SET_BOOKTABS, "set-booktabs" },
 	{ Tabular::UNSET_BOOKTABS, "unset-booktabs" },
 	{ Tabular::SET_TOP_SPACE, "set-top-space" },
@@ -519,6 +521,7 @@
 	: cellno(0),
 	  width(0),
 	  multicolumn(Tabular::CELL_NORMAL),
+	  multirow(Tabular::CELL_NORMAL),
 	  alignment(LYX_ALIGN_CENTER),
 	  valignment(LYX_VALIGN_TOP),
 	  top_line(false),
@@ -537,6 +540,7 @@
 	: cellno(cs.cellno),
 	  width(cs.width),
 	  multicolumn(cs.multicolumn),
+	  multirow(cs.multirow),
 	  alignment(cs.alignment),
 	  valignment(cs.valignment),
 	  top_line(cs.top_line),
@@ -562,6 +566,7 @@
 	std::swap(cellno, rhs.cellno);
 	std::swap(width, rhs.width);
 	std::swap(multicolumn, rhs.multicolumn);
+	std::swap(multirow, rhs.multirow);
 	std::swap(alignment, rhs.alignment);
 	std::swap(valignment, rhs.valignment);
 	std::swap(top_line, rhs.top_line);
@@ -704,6 +709,15 @@
 	if (row_info.size() == 1)
 		return;
 
+	size_t const column_count = column_info.size();
+	for (col_type i = 0; i < column_count; ++i) {
+		// Care about multirow cells
+		if (row + 1 < row_info.size() &&
+		    cell_info[row][i].multirow == CELL_BEGIN_OF_MULTIROW &&
+		    cell_info[row][i + 1].multirow == CELL_PART_OF_MULTIROW) {
+			cell_info[row][i + 1].multirow = CELL_BEGIN_OF_MULTIROW;
+		}
+	}
 	row_info.erase(row_info.begin() + row);
 	cell_info.erase(cell_info.begin() + row);
 	updateIndexes();
@@ -809,7 +823,8 @@
 	numberofcells = 0;
 	for (row_type row = 0; row < nrows; ++row)
 		for (col_type column = 0; column < ncols; ++column) {
-			if (!isPartOfMultiColumn(row, column))
+			if (!isPartOfMultiColumn(row, column)
+				&& !isPartOfMultiRow(row, column))
 				++numberofcells;
 			cell_info[row][column].cellno = numberofcells - 1;
 		}
@@ -819,7 +834,8 @@
 	idx_type i = 0;
 	for (row_type row = 0; row < nrows; ++row)
 		for (col_type column = 0; column < ncols; ++column) {
-			if (isPartOfMultiColumn(row, column))
+			if (isPartOfMultiColumn(row, column)
+				|| isPartOfMultiRow(row, column))
 				continue;
 			rowofcell[i] = row;
 			columnofcell[i] = column;
@@ -1098,7 +1114,7 @@
 void Tabular::setAlignSpecial(idx_type cell, docstring const & special,
 				 Tabular::Feature what)
 {
-	if (what == SET_SPECIAL_MULTI)
+	if (what == SET_SPECIAL_MULTICOLUMN)
 		cellInfo(cell).align_special = special;
 	else
 		column_info[cellColumn(cell)].align_special = special;
@@ -1379,6 +1395,7 @@
 		for (col_type j = 0; j < column_info.size(); ++j) {
 			os << "<cell"
 			   << write_attribute("multicolumn", cell_info[i][j].multicolumn)
+			   << write_attribute("multirow", cell_info[i][j].multirow)
 			   << write_attribute("alignment", cell_info[i][j].alignment)
 			   << write_attribute("valignment", cell_info[i][j].valignment)
 			   << write_attribute("topline", cell_info[i][j].top_line)
@@ -1486,6 +1503,7 @@
 				return;
 			}
 			getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
+			getTokenValue(line, "multirow", cell_info[i][j].multirow);
 			getTokenValue(line, "alignment", cell_info[i][j].alignment);
 			getTokenValue(line, "valignment", cell_info[i][j].valignment);
 			getTokenValue(line, "topline", cell_info[i][j].top_line);
@@ -1525,14 +1543,19 @@
 
 bool Tabular::isMultiColumn(idx_type cell) const
 {
-	return cellInfo(cell).multicolumn != CELL_NORMAL;
+	if (cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN
+		|| cellInfo(cell).multicolumn == CELL_PART_OF_MULTICOLUMN)
+		return true;
+	else
+		return false;
 }
 
 
 bool Tabular::isMultiColumnReal(idx_type cell) const
 {
 	return cellColumn(cell) != cellRightColumn(cell) &&
-			cellInfo(cell).multicolumn != CELL_NORMAL;
+		(cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN
+		 || cellInfo(cell).multicolumn == CELL_PART_OF_MULTICOLUMN);
 }
 
 
@@ -1558,6 +1581,39 @@
 }
 
 
+bool Tabular::isMultiRow(idx_type cell) const
+{
+	if (cellInfo(cell).multirow == CELL_BEGIN_OF_MULTIROW
+		|| cellInfo(cell).multirow == CELL_PART_OF_MULTIROW)
+		return true;
+	else
+		return false;
+}
+
+
+void Tabular::setMultiRow(idx_type cell, idx_type number)
+{
+	idx_type const column = cellColumn(cell);
+	idx_type row = cellRow(cell);
+	idx_type const ncolumns = column_info.size();
+	CellData & cs = cellInfo(cell);
+	cs.multirow = CELL_BEGIN_OF_MULTIROW;
+	// FIXME: the horizontal alignment can only be changed for
+	// the whole table, support for this needs to be implemented
+	// assigning this to uwestoehr
+	cs.valignment = LYX_VALIGN_MIDDLE;
+	// set the bottom row of the last selected cell
+	setBottomLine(cell, bottomLine(cell + (number - 1)*ncolumns));
+	for (idx_type i = 1; i < number; ++i) {
+		CellData & cs1 = cell_info[row+i][column];
+		cs1.multirow = CELL_PART_OF_MULTIROW;
+		cs.inset->appendParagraphs(cs1.inset->paragraphs());
+		cs1.inset->clear();
+	}
+	updateIndexes();
+}
+
+
 Tabular::idx_type Tabular::columnSpan(idx_type cell) const
 {
 	row_type const row = cellRow(cell);
@@ -1572,6 +1628,20 @@
 }
 
 
+Tabular::idx_type Tabular::rowSpan(idx_type cell) const
+{
+	row_type const nrows = row_info.size();
+	col_type const column = cellColumn(cell);
+	idx_type result = 1;
+	col_type row = cellRow(cell) + 1;
+	while (row < nrows && isPartOfMultiRow(row, column)) {
+		++result;
+		++row;
+	}
+	return result;
+}
+
+
 Tabular::idx_type Tabular::unsetMultiColumn(idx_type cell)
 {
 	row_type const row = cellRow(cell);
@@ -1595,6 +1665,29 @@
 }
 
 
+Tabular::idx_type Tabular::unsetMultiRow(idx_type cell)
+{
+	row_type row = cellRow(cell);
+	col_type const column = cellColumn(cell);
+
+	idx_type result = 0;
+
+	if (cell_info[row][column].multirow == CELL_BEGIN_OF_MULTIROW) {
+		cell_info[row][column].multirow = CELL_NORMAL;
+		++row;
+		while (row < row_info.size() &&
+			   cell_info[row][column].multirow == CELL_PART_OF_MULTIROW)
+		{
+			cell_info[row][column].multirow = CELL_NORMAL;
+			++row;
+			++result;
+		}
+	}
+	updateIndexes();
+	return result;
+}
+
+
 void Tabular::setRotateCell(idx_type cell, bool flag)
 {
 	cellInfo(cell).rotate = flag;
@@ -1873,6 +1966,14 @@
 }
 
 
+bool Tabular::isPartOfMultiRow(row_type row, col_type column) const
+{
+	LASSERT(row < row_info.size(), /**/);
+	LASSERT(column < column_info.size(), /**/);
+	return cell_info[row][column].multirow == CELL_PART_OF_MULTIROW;
+}
+
+
 int Tabular::TeXTopHLine(odocstream & os, row_type row, string const lang) const
 {
 	// we only output complete row lines and the 1st row here, the rest
@@ -1979,7 +2080,8 @@
 }
 
 
-int Tabular::TeXCellPreamble(odocstream & os, idx_type cell, bool & ismulticol) const
+int Tabular::TeXCellPreamble(odocstream & os, idx_type cell,
+							 bool & ismulticol, bool & ismultirow) const
 {
 	int ret = 0;
 	row_type const r = cellRow(cell);
@@ -1999,7 +2101,8 @@
 		&& leftLine(cellIndex(r, nextcol));
 	bool coldouble = colright && nextcolleft;
 	bool celldouble = rightLine(cell) && nextcellleft;
-	ismulticol = isMultiColumn(cell) 
+
+	ismulticol = isMultiColumn(cell)
 		|| (c == 0 && colleft != leftLine(cell))
 		|| ((colright || nextcolleft) && !rightLine(cell) && !nextcellleft)
 		|| (!colright && !nextcolleft && (rightLine(cell) || nextcellleft))
@@ -2059,7 +2162,23 @@
 			// add extra vertical line if we want a double one
 			os << '|';
 		os << "}{";
-		}
+		} // end if ismulticol
+
+	// we only need code for the first multirow cell
+	ismultirow = false;
+	if (cellInfo(cell).multirow == CELL_BEGIN_OF_MULTIROW)
+		ismultirow = true;
+	if (ismultirow) {
+		os << "\\multirow{" << rowSpan(cell) << "}{";
+		if (!getPWidth(cell).zero())
+			os << from_ascii(getPWidth(cell).asLatexString());
+		else
+			// we need to set a default value
+			// needs to be discussed
+			os << "2.0cm";
+		os << "}{";
+		} // end if ismultirow
+
 	if (getRotateCell(cell)) {
 		os << "\\begin{sideways}\n";
 		++ret;
@@ -2100,7 +2219,8 @@
 }
 
 
-int Tabular::TeXCellPostamble(odocstream & os, idx_type cell, bool ismulticol) const
+int Tabular::TeXCellPostamble(odocstream & os, idx_type cell,
+							  bool ismulticol, bool ismultirow) const
 {
 	int ret = 0;
 	row_type const r = cellRow(cell);
@@ -2118,7 +2238,7 @@
 		os << "%\n\\end{sideways}";
 		++ret;
 	}
-	if (ismulticol) {
+	if (ismulticol || ismultirow) {
 		os << '}';
 	}
 	return ret;
@@ -2267,10 +2387,11 @@
 		++ret;
 	}
 	bool ismulticol = false;
+	bool ismultirow = false;
 	for (col_type j = 0; j < column_info.size(); ++j) {
-		if (isPartOfMultiColumn(i, j))
+		if (isPartOfMultiColumn(i, j) || isPartOfMultiRow(i, j))
 			continue;
-		ret += TeXCellPreamble(os, cell, ismulticol);
+		ret += TeXCellPreamble(os, cell, ismulticol, ismultirow);
 		shared_ptr<InsetTableCell> inset = cellInset(cell);
 
 		Paragraph const & par = inset->paragraphs().front();
@@ -2302,7 +2423,7 @@
 		if (rtl)
 			os << '}';
 
-		ret += TeXCellPostamble(os, cell, ismulticol);
+		ret += TeXCellPostamble(os, cell, ismulticol, ismultirow);
 		if (!isLastCellInRow(cell)) { // not last cell in row
 			os << " & ";
 		}
@@ -3152,8 +3273,9 @@
 		int maxAsc = 0;
 		int maxDesc = 0;
 		for (col_type j = 0; j < tabular.column_info.size(); ++j) {
-			if (tabular.isPartOfMultiColumn(i, j))
-				// Multicolumn cell, but not first one
+			if (tabular.isPartOfMultiColumn(i, j)
+				|| tabular.isPartOfMultiRow(i, j))
+				// multicolumn or multirow cell, but not first one
 				continue;
 			Dimension dim;
 			MetricsInfo m = mi;
@@ -3250,6 +3372,7 @@
 			int const cx = nx + tabular.getBeginningOfTextInCell(idx);
 			// Cache the Inset position.
 			bv->coordCache().insets().add(cell(idx).get(), cx, y);
+			// FIXME: missing comment what this loop does
 			if (nx + tabular.columnWidth(idx) < 0
 			    || nx > bv->workWidth()
 			    || y + d < 0
@@ -3259,8 +3382,14 @@
 				drawCellLines(pi.pain, nx, y, i, idx, pi.change_);
 				pi.pain.setDrawingEnabled(original_drawing_state);
 			} else {
-				cell(idx)->draw(pi, cx, y);
-				drawCellLines(pi.pain, nx, y, i, idx, pi.change_);
+				// don't draw multirow cells (only their width is
+				// taken into account)
+				if (!tabular.isPartOfMultiRow(i, j)) {
+					cell(idx)->draw(pi, cx, y);
+					drawCellLines(pi.pain, nx, y, i, idx, pi.change_);
+				}
+				// FIXME: the ehight of the forst multiro cell needs to be
+				// calculated correctly
 			}
 			nx += tabular.columnWidth(idx);
 			++idx;
@@ -3934,7 +4063,8 @@
 		case Tabular::SET_PWIDTH:
 		case Tabular::SET_MPWIDTH:
 		case Tabular::SET_SPECIAL_COLUMN:
-		case Tabular::SET_SPECIAL_MULTI:
+		case Tabular::SET_SPECIAL_MULTICOLUMN:
+		case Tabular::SET_SPECIAL_MULTIROW:
 		case Tabular::APPEND_ROW:
 		case Tabular::APPEND_COLUMN:
 		case Tabular::DELETE_ROW:
@@ -3955,6 +4085,14 @@
 			status.setOnOff(tabular.isMultiColumn(cur.idx()));
 			break;
 
+		case Tabular::MULTIROW:
+			// If a row is set as longtable caption, it must not be allowed
+			// to unset that this row is a multirow.
+			status.setEnabled(sel_col_start == sel_col_end
+				&& !tabular.ltCaption(tabular.cellRow(cur.idx())));
+			status.setOnOff(tabular.isMultiRow(cur.idx()));
+			break;
+
 		case Tabular::SET_ALL_LINES:
 		case Tabular::UNSET_ALL_LINES:
 		case Tabular::SET_BORDER_LINES:
@@ -4343,9 +4481,13 @@
 {
 	cell(sl.idx())->cursorPos(bv, sl, boundary, x, y);
 
+	int const row = tabular.cellRow(sl.idx());
+	int const col = tabular.cellColumn(sl.idx());
+
 	// y offset	correction
-	int const row = tabular.cellRow(sl.idx());
 	for (int i = 0;	i <= row; ++i) {
+		if (tabular.isPartOfMultiRow(i, col))
+			continue;
 		if (i != 0) {
 			y += tabular.rowAscent(i);
 			y += tabular.getAdditionalHeight(i);
@@ -4355,7 +4497,6 @@
 	}
 
 	// x offset correction
-	int const col = tabular.cellColumn(sl.idx());
 	int idx = tabular.cellIndex(row, 0);
 	for (int j = 0; j < col; ++j) {
 		if (tabular.isPartOfMultiColumn(row, j))
@@ -4713,7 +4854,7 @@
 		break;
 
 	case Tabular::SET_SPECIAL_COLUMN:
-	case Tabular::SET_SPECIAL_MULTI:
+	case Tabular::SET_SPECIAL_MULTICOLUMN:
 		tabular.setAlignSpecial(cur.idx(), from_utf8(value), feature);
 		break;
 
@@ -4837,6 +4978,32 @@
 		cur.setSelection(false);
 		break;
 	}
+	
+	case Tabular::MULTIROW: {
+		if (!cur.selection()) {
+			// just multirow for one single cell
+			// check whether we are completely in a multirow
+			if (tabular.isMultiRow(cur.idx()))
+				tabular.unsetMultiRow(cur.idx());
+			else
+				tabular.setMultiRow(cur.idx(), 1);
+			break;
+		}
+		// we have a selection so this means we just add all this
+		// cells to form a multirow cell
+		idx_type const s_start = cur.selBegin().idx();
+		idx_type const s_end = cur.selEnd().idx();
+		// the cell index is counted from left to right, we therefore
+		// need to know the number of columns of the table to calculate
+		// the number of selected rows
+		idx_type const ncolumns = tabular.column_info.size();
+		tabular.setMultiRow(s_start, (s_end - s_start)/ncolumns + 1);
+		cur.idx() = s_start;
+		cur.pit() = 0;
+		cur.pos() = 0;
+		cur.setSelection(false);
+		break;
+	}
 
 	case Tabular::SET_ALL_LINES:
 		setLines = true;
Index: src/insets/InsetTabular.h
===================================================================
--- src/insets/InsetTabular.h	(revision 33077)
+++ src/insets/InsetTabular.h	(working copy)
@@ -12,7 +12,6 @@
  * Full author contact details are available in file CREDITS.
  */
 
-
 // This is Juergen's rewrite of the tabular (table) support.
 
 // Things to think of when designing the new tabular support:
@@ -24,14 +23,6 @@
 // - multirow
 // - column styles
 
-// This is what I have written about tabular support in the LyX3-Tasks file:
-//
-//  o rewrite of table code. Should probably be written as some
-//    kind of an inset. [Done]
-// o enhance longtable support
-
-// Lgb
-
 #ifndef INSET_TABULAR_H
 #define INSET_TABULAR_H
 
@@ -120,6 +111,8 @@
 		///
 		MULTICOLUMN,
 		///
+		MULTIROW,
+		///
 		SET_ALL_LINES,
 		///
 		UNSET_ALL_LINES,
@@ -164,8 +157,10 @@
 		///
 		SET_SPECIAL_COLUMN,
 		///
-		SET_SPECIAL_MULTI,
+		SET_SPECIAL_MULTICOLUMN,
 		///
+		SET_SPECIAL_MULTIROW,
+		///
 		SET_BOOKTABS,
 		///
 		UNSET_BOOKTABS,
@@ -199,7 +194,11 @@
 		///
 		CELL_BEGIN_OF_MULTICOLUMN,
 		///
-		CELL_PART_OF_MULTICOLUMN
+		CELL_PART_OF_MULTICOLUMN,
+		///
+		CELL_BEGIN_OF_MULTIROW,
+		///
+		CELL_PART_OF_MULTIROW
 	};
 
 	///
@@ -388,6 +387,14 @@
 	///
 	bool isPartOfMultiColumn(row_type row, col_type column) const;
 	///
+	bool isPartOfMultiRow(row_type row, col_type column) const;
+	///
+	bool isMultiRow(idx_type cell) const;
+	///
+	void setMultiRow(idx_type cell, idx_type number);
+	///
+	idx_type unsetMultiRow(idx_type cell); // returns number of new cells
+	///
 	row_type cellRow(idx_type cell) const;
 	///
 	col_type cellColumn(idx_type cell) const;
@@ -482,6 +489,8 @@
 		///
 		int multicolumn;
 		///
+		int multirow;
+		///
 		LyXAlignment alignment;
 		///
 		VAlignment valignment;
@@ -614,6 +623,8 @@
 	///
 	idx_type columnSpan(idx_type cell) const;
 	///
+	idx_type rowSpan(idx_type cell) const;
+	///
 	BoxType useParbox(idx_type cell) const;
 	///
 	// helper function for Latex returns number of newlines
@@ -622,9 +633,9 @@
 	///
 	int TeXBottomHLine(odocstream &, row_type row, std::string const lang) const;
 	///
-	int TeXCellPreamble(odocstream &, idx_type cell, bool & ismulticol) const;
+	int TeXCellPreamble(odocstream &, idx_type cell, bool & ismulticol, bool & ismultirow) const;
 	///
-	int TeXCellPostamble(odocstream &, idx_type cell, bool ismulticol) const;
+	int TeXCellPostamble(odocstream &, idx_type cell, bool ismulticol, bool ismultirow) const;
 	///
 	int TeXLongtableHeaderFooter(odocstream &, OutputParams const &) const;
 	///
Index: src/LyXAction.cpp
===================================================================
--- src/LyXAction.cpp	(revision 33077)
+++ src/LyXAction.cpp	(working copy)
@@ -2047,9 +2047,10 @@
                        set-rotate-cell|unset-rotate-cell|toggle-rotate-cell|set-usebox|set-lthead|
                        unset-lthead|set-ltfirsthead|unset-ltfirsthead|set-ltfoot|unset-ltfoot|
                        set-ltlastfoot|unset-ltlastfoot|set-ltnewpage|toggle-ltcaption|
-                       set-special-column|set-special-multi|set-booktabs|unset-booktabs|
-                       set-top-space|set-bottom-space|set-interline-space|set-border-lines|
-                       tabular-valign-top|tabular-valign-middle|tabular-valign-bottom \n
+                       set-special-column|set-special-multicolumn|set-special-multirow|
+                       set-booktabs|unset-booktabs|set-top-space|set-bottom-space|
+                       set-interline-space|set-border-lines|tabular-valign-top|
+                       tabular-valign-middle|tabular-valign-bottom \n
                <ARG>: additional argument for some commands, use debug mode to explore its values.
  * \li Origin: Jug, 28 Jul 2000
  * \endvar

Reply via email to