]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetTabular.cpp
Comments.
[lyx.git] / src / insets / InsetTabular.cpp
index 2fdd162bb1939a6df9e9b342ea42b903ef27660f..3cd8213b3a130d7d3501213015c488a3e008d432 100644 (file)
@@ -188,62 +188,6 @@ TabularFeature tabularFeature[] =
 };
 
 
-template <class T>
-string const write_attribute(string const & name, T const & t)
-{
-       string const s = tostr(t);
-       return s.empty() ? s : " " + name + "=\"" + s + "\"";
-}
-
-template <>
-string const write_attribute(string const & name, string const & t)
-{
-       return t.empty() ? t : " " + name + "=\"" + t + "\"";
-}
-
-
-template <>
-string const write_attribute(string const & name, docstring const & t)
-{
-       return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\"";
-}
-
-
-template <>
-string const write_attribute(string const & name, bool const & b)
-{
-       // we write only true attribute values so we remove a bit of the
-       // file format bloat for tabulars.
-       return b ? write_attribute(name, convert<string>(b)) : string();
-}
-
-
-template <>
-string const write_attribute(string const & name, int const & i)
-{
-       // we write only true attribute values so we remove a bit of the
-       // file format bloat for tabulars.
-       return i ? write_attribute(name, convert<string>(i)) : string();
-}
-
-
-template <>
-string const write_attribute(string const & name, Tabular::idx_type const & i)
-{
-       // we write only true attribute values so we remove a bit of the
-       // file format bloat for tabulars.
-       return i ? write_attribute(name, convert<string>(i)) : string();
-}
-
-
-template <>
-string const write_attribute(string const & name, Length const & value)
-{
-       // we write only the value if we really have one same reson as above.
-       return value.zero() ? string() : write_attribute(name, value.asString());
-}
-
-
 string const tostr(LyXAlignment const & num)
 {
        switch (num) {
@@ -503,6 +447,61 @@ void l_getline(istream & is, string & str)
        }
 }
 
+template <class T>
+string const write_attribute(string const & name, T const & t)
+{
+       string const s = tostr(t);
+       return s.empty() ? s : " " + name + "=\"" + s + "\"";
+}
+
+template <>
+string const write_attribute(string const & name, string const & t)
+{
+       return t.empty() ? t : " " + name + "=\"" + t + "\"";
+}
+
+
+template <>
+string const write_attribute(string const & name, docstring const & t)
+{
+       return t.empty() ? string() : " " + name + "=\"" + to_utf8(t) + "\"";
+}
+
+
+template <>
+string const write_attribute(string const & name, bool const & b)
+{
+       // we write only true attribute values so we remove a bit of the
+       // file format bloat for tabulars.
+       return b ? write_attribute(name, convert<string>(b)) : string();
+}
+
+
+template <>
+string const write_attribute(string const & name, int const & i)
+{
+       // we write only true attribute values so we remove a bit of the
+       // file format bloat for tabulars.
+       return i ? write_attribute(name, convert<string>(i)) : string();
+}
+
+
+template <>
+string const write_attribute(string const & name, Tabular::idx_type const & i)
+{
+       // we write only true attribute values so we remove a bit of the
+       // file format bloat for tabulars.
+       return i ? write_attribute(name, convert<string>(i)) : string();
+}
+
+
+template <>
+string const write_attribute(string const & name, Length const & value)
+{
+       // we write only the value if we really have one same reson as above.
+       return value.zero() ? string() : write_attribute(name, value.asString());
+}
+
 } // namespace
 
 
@@ -516,19 +515,25 @@ string const featureAsString(Tabular::Feature action)
 }
 
 
-InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep)
+DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d)
 {
-       InsetTableCell tail = InsetTableCell(head);
-
-       DocIterator dit = doc_iterator_begin(&head.buffer(), &head);
+       DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell);
        for (; dit; dit.forwardChar())
-               if (dit.inTexted() && dit.depth()==1
+               if (dit.inTexted() && dit.depth() == 1
                        && dit.paragraph().find(align_d, false, false, dit.pos()))
                        break;
 
-       pit_type const psize = head.paragraphs().front().size();
+       return dit;
+}
+
+
+InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep)
+{
+       InsetTableCell tail = InsetTableCell(head);
+       DocIterator const dit = separatorPos(&head, align_d);
        hassep = dit;
        if (hassep) {
+               pit_type const psize = head.paragraphs().front().size();
                head.paragraphs().front().eraseChars(dit.pos(), psize, false);
                tail.paragraphs().front().eraseChars(0, 
                        dit.pos() < psize ? dit.pos() + 1 : psize, false);
@@ -1333,7 +1338,13 @@ int Tabular::textVOffset(idx_type cell) const
 Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const
 {
        col_type c = 0;
-       while (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW)
+       idx_type const numcells = numberOfCellsInRow(row);
+       // we check against numcells to make sure we do not crash if all the
+       // cells are multirow (bug #7535), but in that case our return value
+       // is really invalid, i.e., it is NOT the first cell in the row. but
+       // i do not know what to do here. (rgh)
+       while (c < numcells - 1
+              && cell_info[row][c].multirow == CELL_PART_OF_MULTIROW)
                ++c;
        return cell_info[row][c].cellno;
 }
@@ -1342,6 +1353,9 @@ Tabular::idx_type Tabular::getFirstCellInRow(row_type row) const
 Tabular::idx_type Tabular::getLastCellInRow(row_type row) const
 {
        col_type c = ncols() - 1;
+       // of course we check against 0 so we don't crash. but we have the same
+       // problem as in the previous routine: if all the cells are part of a
+       // multirow or part of a multi column, then our return value is invalid.
        while (c > 0
               && (cell_info[row][c].multirow == CELL_PART_OF_MULTIROW
                   || cell_info[row][c].multicolumn == CELL_PART_OF_MULTICOLUMN))
@@ -1600,7 +1614,8 @@ Tabular::CellData & Tabular::cellInfo(idx_type cell) const
 }
 
 
-Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number)
+Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number,
+                                         bool const right_border)
 {
        idx_type const col = cellColumn(cell);
        idx_type const row = cellRow(cell);
@@ -1614,7 +1629,7 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number)
        if (column_info[col].alignment != LYX_ALIGN_DECIMAL)
                cs.alignment = column_info[col].alignment;
        if (col > 0)
-               setRightLine(cell, rightLine(cellIndex(row, col - 1)));
+               setRightLine(cell, right_border);
 
        for (idx_type i = 1; i < number; ++i) {
                CellData & cs1 = cellInfo(cell + i);
@@ -1634,7 +1649,8 @@ bool Tabular::isMultiRow(idx_type cell) const
 }
 
 
-Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number)
+Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number,
+                                      bool const bottom_border)
 {
        idx_type const col = cellColumn(cell);
        idx_type const row = cellRow(cell);
@@ -1653,10 +1669,10 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number)
        // this feature would be a fileformat change
        // until LyX supports this, use the deault alignment of multirow
        // cells: left
-       cs.alignment = LYX_ALIGN_LEFT; 
+       cs.alignment = LYX_ALIGN_LEFT;
 
-       // set the bottom row of the last selected cell
-       setBottomLine(cell, bottomLine(cell + (number - 1)*ncols()));
+       // set the bottom line of the last selected cell
+       setBottomLine(cell, bottom_border);
 
        for (idx_type i = 1; i < number; ++i) {
                CellData & cs1 = cell_info[row + i][col];
@@ -1938,7 +1954,7 @@ Tabular::idx_type Tabular::setLTCaption(row_type row, bool what)
 {
        idx_type i = getFirstCellInRow(row);
        if (what) {
-               setMultiColumn(i, numberOfCellsInRow(row));
+               setMultiColumn(i, numberOfCellsInRow(row), false);
                setTopLine(i, false);
                setBottomLine(i, false);
                setLeftLine(i, false);
@@ -2042,8 +2058,8 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, string const lang) cons
                // multirow, no line must be drawn.
                if (row != 0)
                        if (isMultiRow(cellIndex(row, c))
-                               && isMultiRow(cellIndex(row - 1, c)))
-                                       topline[c] = false;
+                           && cell_info[row][c].multirow != CELL_BEGIN_OF_MULTIROW)
+                               topline[c] = false;
                if (topline[c])
                        ++nset;
        }
@@ -2102,13 +2118,14 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const lang) c
        for (col_type c = 0; c < ncols(); ++c) {
                bottomline.push_back(bottomLine(cellIndex(row, c)));
                topline.push_back(!lastrow && topLine(cellIndex(row + 1, c)));
-               // If cell is part of a multirow and not the last or first cell of the
+               // If cell is part of a multirow and not the last cell of the
                // multirow, no line must be drawn.
                if (!lastrow)
                        if (isMultiRow(cellIndex(row, c))
-                               && isMultiRow(cellIndex(row + 1, c))) {
-                                       bottomline[c] = false;
-                                       topline[c] = false;
+                           && isMultiRow(cellIndex(row + 1, c))
+                           && cell_info[row + 1][c].multirow != CELL_BEGIN_OF_MULTIROW) {
+                               bottomline[c] = false;
+                               topline[c] = false;
                                }
                nextrowset &= topline[c];
        }
@@ -2190,8 +2207,11 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
                || (coldouble != celldouble);
 
        // we center in multicol when no decimal point
-       ismulticol |= ((column_info[c].alignment == LYX_ALIGN_DECIMAL)
-               && (cellInfo(cell).decimal_width == 0));
+       if (column_info[c].alignment == LYX_ALIGN_DECIMAL) {
+               docstring const align_d = column_info[c].decimal_point;
+               DocIterator const dit = separatorPos(cellInset(cell).get(), align_d);
+               ismulticol |= !dit;
+       }
 
        // up counter by 1 for each decimally aligned col since they use 2 latex cols
        int latexcolspan = columnSpan(cell);
@@ -2480,21 +2500,25 @@ void Tabular::TeXRow(otexstream & os, row_type row,
                                    ? OutputParams::PLAIN
                                    : OutputParams::ALIGNED;
 
-               if (getAlignment(cell) == LYX_ALIGN_DECIMAL
-                       && cellInfo(cell).decimal_width != 0) {
+               if (getAlignment(cell) == LYX_ALIGN_DECIMAL) {
                        // copy cell and split in 2
                        InsetTableCell head = InsetTableCell(*cellInset(cell).get());
-                       head.getText(0)->setMacrocontextPosition(
-                               cellInset(cell)->getText(0)->macrocontextPosition());
                        head.setBuffer(buffer());
+                       DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition();
+                       dit.pop_back();
+                       dit.push_back(CursorSlice(head));
+                       head.setMacrocontextPositionRecursive(dit);
                        bool hassep = false;
                        InsetTableCell tail = splitCell(head, column_info[c].decimal_point, hassep);
-                       tail.getText(0)->setMacrocontextPosition(
-                               head.getText(0)->macrocontextPosition());
-                       tail.setBuffer(head.buffer());
                        head.latex(os, newrp);
-                       os << '&';
-                       tail.latex(os, newrp);
+                       if (hassep) {
+                               os << '&';
+                               tail.setBuffer(head.buffer());
+                               dit.pop_back();
+                               dit.push_back(CursorSlice(tail));
+                               tail.setMacrocontextPositionRecursive(dit);
+                               tail.latex(os, newrp);
+                       }
                } else if (!isPartOfMultiRow(row, c)) {
                        if (!runparams.nice)
                                os.texrow().start(par.id(), 0);
@@ -2854,7 +2878,7 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row,
 
        xs << html::StartTag("tr");
        for (col_type c = 0; c < ncols(); ++c) {
-               if (isPartOfMultiColumn(row, c))
+               if (isPartOfMultiColumn(row, c) || isPartOfMultiRow(row, c))
                        continue;
 
                stringstream attr;
@@ -2886,12 +2910,12 @@ docstring Tabular::xhtmlRow(XHTMLStream & xs, row_type row,
 
                if (isMultiColumn(cell))
                        attr << " colspan='" << columnSpan(cell) << "'";
+               else if (isMultiRow(cell))
+                       attr << " rowspan='" << rowSpan(cell) << "'";
 
-               xs << html::StartTag(celltag, attr.str());
-               xs.cr();
+               xs << html::StartTag(celltag, attr.str()) << html::CR();
                ret += cellInset(cell)->xhtml(xs, runparams);
-               xs << html::EndTag(celltag);
-               xs.cr();
+               xs << html::EndTag(celltag) << html::CR();
                ++cell;
        }
        xs << html::EndTag("tr");
@@ -2917,17 +2941,19 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
                        align = "right";
                        break;
                }
-               xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'");
+               xs << html::StartTag("div", "class='longtable' style='text-align: " + align + ";'")
+                  << html::CR();
                if (haveLTCaption()) {
-                       xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'");
+                       xs << html::StartTag("div", "class='longtable-caption' style='text-align: " + align + ";'")
+                          << html::CR();
                        for (row_type r = 0; r < nrows(); ++r)
                                if (row_info[r].caption)
                                        ret += xhtmlRow(xs, r, runparams);
-                       xs << html::EndTag("div");
+                       xs << html::EndTag("div") << html::CR();
                }
        }
 
-       xs << html::StartTag("table");
+       xs << html::StartTag("table") << html::CR();
 
        // output header info
        bool const havefirsthead = haveLTFirstHead();
@@ -2936,40 +2962,42 @@ docstring Tabular::xhtml(XHTMLStream & xs, OutputParams const & runparams) const
        // in XHTML. this test accomplishes that.
        bool const havehead = !havefirsthead && haveLTHead();
        if (havehead || havefirsthead) {
-               xs << html::StartTag("thead");
+               xs << html::StartTag("thead") << html::CR();
                for (row_type r = 0; r < nrows(); ++r) {
                        if ((havefirsthead && row_info[r].endfirsthead)
                            || (havehead && row_info[r].endhead)) {
                                ret += xhtmlRow(xs, r, runparams, true);
                        }
                }
-               xs << html::EndTag("thead");
+               xs << html::EndTag("thead") << html::CR();
        }
        // output footer info
        bool const havelastfoot = haveLTLastFoot();
        // as before.
        bool const havefoot = !havelastfoot && haveLTFoot();
        if (havefoot || havelastfoot) {
-               xs << html::StartTag("tfoot");
+               xs << html::StartTag("tfoot") << html::CR();
                for (row_type r = 0; r < nrows(); ++r) {
                        if ((havelastfoot && row_info[r].endlastfoot)
                            || (havefoot && row_info[r].endfoot)) {
                                ret += xhtmlRow(xs, r, runparams);
                        }
                }
-               xs << html::EndTag("tfoot");
+               xs << html::EndTag("tfoot") << html::CR();
        }
 
-       xs << html::StartTag("tbody");
+       xs << html::StartTag("tbody") << html::CR();
        for (row_type r = 0; r < nrows(); ++r) {
                if (isValidRow(r)) {
                        ret += xhtmlRow(xs, r, runparams);
                }
        }
        xs << html::EndTag("tbody")
-          << html::EndTag("table");
+          << html::CR()
+          << html::EndTag("table")
+          << html::CR();
        if (is_long_tabular)
-               xs << html::EndTag("div");
+               xs << html::EndTag("div") << html::CR();
        return ret;
 }
 
@@ -3162,7 +3190,7 @@ void Tabular::plaintext(odocstream & os,
                if (!onlydata && plaintextTopHLine(os, r, clen))
                        os << docstring(depth * 2, ' ');
                for (col_type c = 0; c < ncols(); ++c) {
-                       if (isPartOfMultiColumn(r, c))
+                       if (isPartOfMultiColumn(r, c) || isPartOfMultiRow(r,c))
                                continue;
                        if (onlydata && c > 0)
                                // we don't use operator<< for single UCS4 character.
@@ -3371,7 +3399,7 @@ void InsetTabular::write(ostream & os) const
 }
 
 
-docstring InsetTabular::contextMenu(BufferView const &, int, int) const
+string InsetTabular::contextMenu(BufferView const &, int, int) const
 {
        // FIXME: depending on the selection state,
        // we could offer a different menu.
@@ -3379,9 +3407,9 @@ docstring InsetTabular::contextMenu(BufferView const &, int, int) const
 }
 
 
-docstring InsetTabular::contextMenuName() const
+string InsetTabular::contextMenuName() const
 {
-       return from_ascii("context-tabular");
+       return "context-tabular";
 }
 
 
@@ -3463,30 +3491,32 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                                mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0));
 
                        // determine horizontal offset because of decimal align (if necessary)
-                       int decimal_hoffset = 0;
                        int decimal_width = 0;
                        if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) {
-                               // make a copy which we will split in 2
-                               InsetTableCell head = InsetTableCell(*tabular.cellInset(cell).get());
-                               head.getText(0)->setMacrocontextPosition(
-                                       tabular.cellInset(cell)->getText(0)->macrocontextPosition());
-                               head.setBuffer(tabular.buffer());
-                               // split in 2 and calculate width of each part
-                               bool hassep = false;
-                               InsetTableCell tail = 
-                                       splitCell(head, tabular.column_info[c].decimal_point, hassep);
-                               tail.getText(0)->setMacrocontextPosition(
-                                       head.getText(0)->macrocontextPosition());
-                               tail.setBuffer(head.buffer());
-                               Dimension dim1;
-                               head.metrics(m, dim1);
-                               decimal_hoffset = dim1.width();
-                               if (hassep) {
+                               InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell).get());
+                               tail.setBuffer(tabular.buffer());
+                               // we need to set macrocontext position everywhere
+                               // otherwise we crash with nested insets (e.g. footnotes)
+                               // after decimal point
+                               DocIterator dit = tabular.cellInset(cell)->getText(0)->macrocontextPosition();
+                               dit.pop_back();
+                               dit.push_back(CursorSlice(tail));
+                               tail.setMacrocontextPositionRecursive(dit);
+
+                               // remove text leading decimal point
+                               docstring const align_d = tabular.column_info[c].decimal_point;
+                               dit = separatorPos(&tail, align_d);
+
+                               pit_type const psize = tail.paragraphs().front().size();
+                               if (dit) {
+                                       tail.paragraphs().front().eraseChars(0,
+                                               dit.pos() < psize ? dit.pos() + 1 : psize, false);
+                                       Dimension dim1;
                                        tail.metrics(m, dim1);
                                        decimal_width = dim1.width();
                                }
                        }
-                       tabular.cell_info[r][c].decimal_hoffset = decimal_hoffset;
+                       tabular.cell_info[r][c].decimal_hoffset = tm.width() - decimal_width;
                        tabular.cell_info[r][c].decimal_width = decimal_width;
 
                        // with LYX_VALIGN_BOTTOM the descent is relative to the last par
@@ -4025,11 +4055,15 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        // setting also the right targetX.
                        cur.selHandle(act == LFUN_DOWN_SELECT);
                        if (tabular.cellRow(cur.idx()) != tabular.nrows() - 1) {
+                               int const xtarget = cur.targetX();
+                               // WARNING: Once cur.idx() has been reset, the cursor is in
+                               // an inconsistent state until pos() has been set. Be careful
+                               // what you do with it!
                                cur.idx() = tabular.cellBelow(cur.idx());
                                cur.pit() = 0;
                                TextMetrics const & tm =
                                        cur.bv().textMetrics(cell(cur.idx())->getText(0));
-                               cur.pos() = tm.x2pos(cur.pit(), 0, cur.targetX());
+                               cur.pos() = tm.x2pos(cur.pit(), 0, xtarget);
                                cur.setCurrentFont();
                        }
                }
@@ -4059,13 +4093,17 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        // setting also the right targetX.
                        cur.selHandle(act == LFUN_UP_SELECT);
                        if (tabular.cellRow(cur.idx()) != 0) {
+                               int const xtarget = cur.targetX();
+                               // WARNING: Once cur.idx() has been reset, the cursor is in
+                               // an inconsistent state until pos() has been set. Be careful
+                               // what you do with it!
                                cur.idx() = tabular.cellAbove(cur.idx());
                                cur.pit() = cur.lastpit();
                                Text const * text = cell(cur.idx())->getText(0);
                                TextMetrics const & tm = cur.bv().textMetrics(text);
                                ParagraphMetrics const & pm =
                                        tm.parMetrics(cur.lastpit());
-                               cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, cur.targetX());
+                               cur.pos() = tm.x2pos(cur.pit(), pm.rows().size()-1, xtarget);
                                cur.setCurrentFont();
                        }
                }
@@ -5326,7 +5364,8 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                        // just multicol for one single cell
                        // check whether we are completely in a multicol
                        if (!tabular.isMultiColumn(cur.idx()))
-                               tabular.setMultiColumn(cur.idx(), 1);
+                               tabular.setMultiColumn(cur.idx(), 1,
+                                       tabular.rightLine(cur.idx()));
                        break;
                }
                // we have a selection so this means we just add all this
@@ -5334,7 +5373,8 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                idx_type const s_start = cur.selBegin().idx();
                row_type const col_start = tabular.cellColumn(s_start);
                row_type const col_end = tabular.cellColumn(cur.selEnd().idx());
-               cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1);
+               cur.idx() = tabular.setMultiColumn(s_start, col_end - col_start + 1,
+                                                  tabular.rightLine(cur.selEnd().idx()));
                cur.pit() = 0;
                cur.pos() = 0;
                cur.setSelection(false);
@@ -5350,10 +5390,27 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        }
 
        case Tabular::MULTICOLUMN: {
-               if (tabular.isMultiColumn(cur.idx()))
-                       tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN);
-               else
+               if (!cur.selection()) {
+                       if (tabular.isMultiColumn(cur.idx()))
+                               tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN);
+                       else
+                               tabularFeatures(cur, Tabular::SET_MULTICOLUMN);
+                       break;
+               }
+               bool merge = false;
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                       row_type const r = sel_row_start;
+                       if (!tabular.isMultiColumn(tabular.cellIndex(r, c))
+                           || (r > sel_row_start && !tabular.isPartOfMultiColumn(r, c)))
+                               merge = true;
+               }
+               // If the selection contains at least one singlecol cell
+               // or multiple multicol cells,
+               // we assume the user will merge is to a single multicol
+               if (merge)
                        tabularFeatures(cur, Tabular::SET_MULTICOLUMN);
+               else
+                       tabularFeatures(cur, Tabular::UNSET_MULTICOLUMN);
                break;
        }
 
@@ -5362,7 +5419,8 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                        // just multirow for one single cell
                        // check whether we are completely in a multirow
                        if (!tabular.isMultiRow(cur.idx()))
-                               tabular.setMultiRow(cur.idx(), 1);
+                               tabular.setMultiRow(cur.idx(), 1,
+                                                   tabular.bottomLine(cur.idx()));
                        break;
                }
                // we have a selection so this means we just add all this
@@ -5370,7 +5428,8 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                idx_type const s_start = cur.selBegin().idx();
                row_type const row_start = tabular.cellRow(s_start);
                row_type const row_end = tabular.cellRow(cur.selEnd().idx());
-               cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1);
+               cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1,
+                                               tabular.bottomLine(cur.selEnd().idx()));
                cur.pit() = 0;
                cur.pos() = 0;
                cur.setSelection(false);
@@ -5386,10 +5445,27 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        }
 
        case Tabular::MULTIROW: {
-               if (tabular.isMultiRow(cur.idx()))
-                       tabularFeatures(cur, Tabular::UNSET_MULTIROW);
-               else
+               if (!cur.selection()) {
+                       if (tabular.isMultiRow(cur.idx()))
+                               tabularFeatures(cur, Tabular::UNSET_MULTIROW);
+                       else
+                               tabularFeatures(cur, Tabular::SET_MULTIROW);
+                       break;
+               }
+               bool merge = false;
+               for (row_type r = sel_row_start; r <= sel_row_end; ++r) {
+                       col_type const c = sel_col_start;
+                       if (!tabular.isMultiRow(tabular.cellIndex(r, c))
+                           || (r > sel_row_start && !tabular.isPartOfMultiRow(r, c)))
+                               merge = true;
+               }
+               // If the selection contains at least one singlerow cell
+               // or multiple multirow cells,
+               // we assume the user will merge is to a single multirow
+               if (merge)
                        tabularFeatures(cur, Tabular::SET_MULTIROW);
+               else
+                       tabularFeatures(cur, Tabular::UNSET_MULTIROW);
                break;
        }