]> git.lyx.org Git - lyx.git/blobdiff - src/insets/InsetTabular.cpp
Fix bug #4952: Multiple cells pasting fails if cells are selected.
[lyx.git] / src / insets / InsetTabular.cpp
index fdd4d3685b2f9c9dd9aed3040ef941fe1bf15935..ba30546a07415df46ed645dff5dc9738b0e1a43f 100644 (file)
@@ -490,7 +490,6 @@ Tabular::CellData::CellData(Buffer & buf)
          inset(new InsetTableCell(buf))
 {
        inset->setBuffer(const_cast<Buffer &>(buf));
-       inset->paragraphs().back().setLayout(buf.params().documentClass().plainLayout());
 }
 
 
@@ -730,8 +729,7 @@ void Tabular::deleteColumn(col_type const column)
        if (column_info.size() == 1)
                return;
 
-       column_info.erase(column_info.begin() + column);
-       size_t row_count = row_info.size();
+       size_t const row_count = row_info.size();
        for (row_type i = 0; i < row_count; ++i) {
                // Care about multicolumn cells
                if (column + 1 < column_info.size() &&
@@ -741,6 +739,7 @@ void Tabular::deleteColumn(col_type const column)
                }
                cell_info[i].erase(cell_info[i].begin() + column);
        }
+       column_info.erase(column_info.begin() + column);
        updateIndexes();
 }
 
@@ -1745,13 +1744,17 @@ Tabular::idx_type Tabular::setLTCaption(row_type row, bool what)
 {
        idx_type i = getFirstCellInRow(row);
        if (what) {
-               setMultiColumn(i, column_info.size());
+               setMultiColumn(i, numberOfCellsInRow(i));
                setTopLine(i, false);
                setBottomLine(i, false);
                setLeftLine(i, false);
                setRightLine(i, false);
-       } else
+       } else {
                unsetMultiColumn(i);
+               // FIXME: when unsetting a caption row, also all existing captions
+               // in this row must be dissolved, see (bug 5754)
+               // dispatch(FuncRequest(LFUN_INSET_DISSOLVE, "caption-insert"));
+       }
        row_info[row].caption = what;
        return i;
 }
@@ -1763,6 +1766,15 @@ bool Tabular::ltCaption(row_type row) const
 }
 
 
+bool Tabular::haveLTCaption() const
+{
+       for (row_type i = 0; i < row_info.size(); ++i)
+               if (row_info[i].caption)
+                       return true;
+       return false;
+}
+
+
 // end longtable support functions
 
 void Tabular::setRowAscent(row_type row, int height)
@@ -2073,44 +2085,55 @@ int Tabular::TeXLongtableHeaderFooter(odocstream & os,
                return 0;
 
        int ret = 0;
-       // output header info
-       if (haveLTHead()) {
-               if (endhead.topDL) {
+       // caption handling
+       // the caption must be output befrore the headers
+       if (haveLTCaption()) {
+               for (row_type i = 0; i < row_info.size(); ++i) {
+                       if (row_info[i].caption) {
+                               ret += TeXRow(os, i, runparams);
+                       }
+               }
+       }
+       // output first header info
+       // first header must be output before the header, otherwise the
+       // correct caption placement becomes really weird
+       if (haveLTFirstHead()) {
+               if (endfirsthead.topDL) {
                        os << "\\hline\n";
                        ++ret;
                }
                for (row_type i = 0; i < row_info.size(); ++i) {
-                       if (row_info[i].endhead) {
+                       if (row_info[i].endfirsthead) {
                                ret += TeXRow(os, i, runparams);
                        }
                }
-               if (endhead.bottomDL) {
+               if (endfirsthead.bottomDL) {
                        os << "\\hline\n";
                        ++ret;
                }
-               os << "\\endhead\n";
+               os << "\\endfirsthead\n";
                ++ret;
-               if (endfirsthead.empty) {
+       }
+       // output header info
+       if (haveLTHead()) {
+               if (endfirsthead.empty && !haveLTFirstHead()) {
                        os << "\\endfirsthead\n";
                        ++ret;
                }
-       }
-       // output firstheader info
-       if (haveLTFirstHead()) {
-               if (endfirsthead.topDL) {
+               if (endhead.topDL) {
                        os << "\\hline\n";
                        ++ret;
                }
                for (row_type i = 0; i < row_info.size(); ++i) {
-                       if (row_info[i].endfirsthead) {
+                       if (row_info[i].endhead) {
                                ret += TeXRow(os, i, runparams);
                        }
                }
-               if (endfirsthead.bottomDL) {
+               if (endhead.bottomDL) {
                        os << "\\hline\n";
                        ++ret;
                }
-               os << "\\endfirsthead\n";
+               os << "\\endhead\n";
                ++ret;
        }
        // output footer info
@@ -2130,7 +2153,7 @@ int Tabular::TeXLongtableHeaderFooter(odocstream & os,
                }
                os << "\\endfoot\n";
                ++ret;
-               if (endlastfoot.empty) {
+               if (endlastfoot.empty && !haveLTLastFoot()) {
                        os << "\\endlastfoot\n";
                        ++ret;
                }
@@ -2161,8 +2184,9 @@ bool Tabular::isValidRow(row_type row) const
 {
        if (!is_long_tabular)
                return true;
-       return !row_info[row].endhead && !row_info[row].endfirsthead &&
-                       !row_info[row].endfoot && !row_info[row].endlastfoot;
+       return !row_info[row].endhead && !row_info[row].endfirsthead
+               && !row_info[row].endfoot && !row_info[row].endlastfoot
+               && !row_info[row].caption;
 }
 
 
@@ -2485,6 +2509,18 @@ int Tabular::docbook(odocstream & os, OutputParams const & runparams) const
        //+                      Long Tabular case                             +
        //+---------------------------------------------------------------------
 
+       // output caption info
+       if (haveLTCaption()) {
+               os << "<caption>\n";
+               ++ret;
+               for (row_type i = 0; i < row_info.size(); ++i) {
+                       if (row_info[i].caption) {
+                               ret += docbookRow(os, i, runparams);
+                       }
+               }
+               os << "</caption>\n";
+               ++ret;
+       }
        // output header info
        if (haveLTHead() || haveLTFirstHead()) {
                os << "<thead>\n";
@@ -2804,7 +2840,7 @@ Tabular::BoxType Tabular::useParbox(idx_type cell) const
 /////////////////////////////////////////////////////////////////////
 
 InsetTableCell::InsetTableCell(Buffer & buf)
-       : InsetText(buf), isFixedWidth(false),
+       : InsetText(buf, InsetText::PlainLayout), isFixedWidth(false),
          contentAlign(LYX_ALIGN_CENTER)
 {}
 
@@ -2895,7 +2931,8 @@ void InsetTabular::setBuffer(Buffer & buf)
 
 bool InsetTabular::insetAllowed(InsetCode code) const
 {
-       if (code == MATHMACRO_CODE)
+       if (code == MATHMACRO_CODE
+               || (code == CAPTION_CODE && !tabular.is_long_tabular))
                return false;
 
        return true;
@@ -3081,11 +3118,11 @@ void InsetTabular::draw(PainterInfo & pi, int x, int y) const
                            || y - a > bv->workHeight()) {
                                pi.pain.setDrawingEnabled(false);
                                cell(idx)->draw(pi, cx, y);
-                               drawCellLines(pi.pain, nx, y, i, idx, pi.erased_);
+                               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.erased_);
+                               drawCellLines(pi.pain, nx, y, i, idx, pi.change_);
                        }
                        nx += tabular.columnWidth(idx);
                        ++idx;
@@ -3154,16 +3191,16 @@ void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
 
 
 void InsetTabular::drawCellLines(Painter & pain, int x, int y,
-                                row_type row, idx_type cell, bool erased) const
+                                row_type row, idx_type cell, Change const & change) const
 {
        int x2 = x + tabular.columnWidth(cell);
        bool on_off = false;
-       ColorCode col = Color_tabularline;
-       ColorCode onoffcol = Color_tabularonoffline;
+       Color col = Color_tabularline;
+       Color onoffcol = Color_tabularonoffline;
 
-       if (erased) {
-               col = Color_deletedtext;
-               onoffcol = Color_deletedtext;
+       if (change.changed()) {
+               col = change.color();
+               onoffcol = change.color();
        }
 
        if (!tabular.topAlreadyDrawn(cell)) {
@@ -3568,23 +3605,24 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        // insert file functions
        case LFUN_FILE_INSERT_PLAINTEXT_PARA:
-       case LFUN_FILE_INSERT_PLAINTEXT: {
+       case LFUN_FILE_INSERT_PLAINTEXT:
                // FIXME UNICODE
-               docstring const tmpstr = cur.bv().contentsOfPlaintextFile(
-                       FileName(to_utf8(cmd.argument())));
-               if (tmpstr.empty())
-                       break;
-               cur.recordUndoInset(INSERT_UNDO);
-               if (insertPlaintextString(cur.bv(), tmpstr, false)) {
-                       // content has been replaced,
-                       // so cursor might be invalid
-                       cur.pos() = cur.lastpos();
-                       cur.pit() = cur.lastpit();
-                       bvcur.setCursor(cur);
-               } else
-                       cur.undispatched();
+               if (FileName::isAbsolute(to_utf8(cmd.argument()))) {
+                       docstring const tmpstr = cur.bv().contentsOfPlaintextFile(
+                               FileName(to_utf8(cmd.argument())));
+                       if (tmpstr.empty())
+                               break;
+                       cur.recordUndoInset(INSERT_UNDO);
+                       if (insertPlaintextString(cur.bv(), tmpstr, false)) {
+                               // content has been replaced,
+                               // so cursor might be invalid
+                               cur.pos() = cur.lastpos();
+                               cur.pit() = cur.lastpit();
+                               bvcur.setCursor(cur);
+                       } else
+                               cur.undispatched();
+               }
                break;
-       }
 
        case LFUN_CUT:
                if (cur.selIsMultiCell()) {
@@ -3592,8 +3630,7 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                                cur.recordUndoInset(DELETE_UNDO);
                                cutSelection(cur);
                        }
-               }
-               else
+               } else
                        cell(cur.idx())->dispatch(cur, cmd);
                break;
 
@@ -3652,7 +3689,8 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
 
        case LFUN_PASTE:
                if (!tabularStackDirty()) {
-                       cell(cur.idx())->dispatch(cur, cmd);
+                       if (!cur.selIsMultiCell())
+                               cell(cur.idx())->dispatch(cur, cmd);
                        break;
                }
                if (theClipboard().isInternal() ||
@@ -3675,6 +3713,9 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
        case LFUN_TEXTSTYLE_UPDATE:
        case LFUN_FONT_SIZE:
        case LFUN_FONT_UNDERLINE:
+       case LFUN_FONT_STRIKEOUT:
+       case LFUN_FONT_UULINE:
+       case LFUN_FONT_UWAVE:
        case LFUN_LANGUAGE:
        case LFUN_WORD_CAPITALIZE:
        case LFUN_WORD_UPCASE:
@@ -3705,6 +3746,12 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                        cell(cur.idx())->dispatch(cur, cmd);
                        break;
                }
+
+       case LFUN_INSET_SETTINGS:
+               // relay this lfun to Inset, not to the cell.
+               Inset::doDispatch(cur, cmd);
+               break;
+
        default:
                // we try to handle this event in the insets dispatch function.
                cell(cur.idx())->dispatch(cur, cmd);
@@ -3765,7 +3812,10 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        return true;
 
                case Tabular::MULTICOLUMN:
-                       status.setEnabled(sel_row_start == sel_row_end);
+                       // When a row is set as longtable caption, it must not be allowed
+                       // to unset that this row is a multicolumn.
+                       status.setEnabled(sel_row_start == sel_row_end
+                               && !tabular.ltCaption(tabular.cellRow(cur.idx())));
                        status.setOnOff(tabular.isMultiColumn(cur.idx()));
                        break;
 
@@ -3884,15 +3934,27 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        status.setOnOff(convert<int>(argument) == tabular.getUsebox(cur.idx()));
                        break;
 
+               // every row can only be one thing:
+               // either a footer or header or caption
                case Tabular::SET_LTFIRSTHEAD:
-                       status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
+                       status.setEnabled(sel_row_start == sel_row_end
+                               && !tabular.getRowOfLTHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTFoot(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
+                               && !tabular.ltCaption(sel_row_start));
+                       status.setOnOff(tabular.getRowOfLTFirstHead(sel_row_start, dummyltt));
                        break;
 
                case Tabular::UNSET_LTFIRSTHEAD:
-                       status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt));
+                       status.setOnOff(!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt));
                        break;
 
                case Tabular::SET_LTHEAD:
+                       status.setEnabled(sel_row_start == sel_row_end
+                               && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTFoot(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
+                               && !tabular.ltCaption(sel_row_start));
                        status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
                        break;
 
@@ -3901,6 +3963,11 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                case Tabular::SET_LTFOOT:
+                       status.setEnabled(sel_row_start == sel_row_end
+                               && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
+                               && !tabular.ltCaption(sel_row_start));
                        status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
                        break;
 
@@ -3909,19 +3976,31 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                        break;
 
                case Tabular::SET_LTLASTFOOT:
-                       status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
+                       status.setEnabled(sel_row_start == sel_row_end
+                               && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTFoot(sel_row_start, dummyltt)
+                               && !tabular.ltCaption(sel_row_start));
+                       status.setOnOff(tabular.getRowOfLTLastFoot(sel_row_start, dummyltt));
                        break;
 
                case Tabular::UNSET_LTLASTFOOT:
-                       status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt));
+                       status.setOnOff(!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt));
                        break;
 
                case Tabular::SET_LTNEWPAGE:
                        status.setOnOff(tabular.getLTNewPage(sel_row_start));
                        break;
 
+               // only one row can be the caption
                case Tabular::TOGGLE_LTCAPTION:
-                       status.setEnabled(sel_row_start == sel_row_end);
+                       status.setEnabled(sel_row_start == sel_row_end
+                               && !tabular.getRowOfLTFirstHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTHead(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTFoot(sel_row_start, dummyltt)
+                               && !tabular.getRowOfLTLastFoot(sel_row_start, dummyltt)
+                               && (!tabular.haveLTCaption()
+                                       || tabular.ltCaption(sel_row_start)));
                        status.setOnOff(tabular.ltCaption(sel_row_start));
                        break;
 
@@ -3988,17 +4067,28 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                return true;
 
        case LFUN_PASTE:
-               if (cur.selIsMultiCell()) {
-                       status.setEnabled(false);
-                       status.message(_("You cannot paste into a multicell selection."));
-                       return true;
-               }
                if (tabularStackDirty() && theClipboard().isInternal()) {
-                       status.setEnabled(true);
+                       if (cur.selIsMultiCell()) {
+                               row_type rs, re;
+                               col_type cs, ce;
+                               getSelection(cur, rs, re, cs, ce);
+                               if (paste_tabular && paste_tabular->column_info.size() == ce - cs + 1
+                                         && paste_tabular->row_info.size() == re - rs + 1)
+                                       status.setEnabled(true);        
+                               else {
+                                       status.setEnabled(false);
+                                       status.message(_("Selection size should match clipboard content."));
+                               }
+                       } else
+                               status.setEnabled(true);
                        return true;
-               } 
+               }
                return cell(cur.idx())->getStatus(cur, cmd, status);
 
+       case LFUN_INSET_SETTINGS:
+               // relay this lfun to Inset, not to the cell.
+               return Inset::getStatus(cur, cmd, status);
+
        case LFUN_INSET_MODIFY:
                if (insetCode(cmd.getArg(0)) == TABULAR_CODE) {
                        status.setEnabled(true);
@@ -4696,12 +4786,18 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                tabular.setLTNewPage(row, !tabular.getLTNewPage(row));
                break;
 
-       case Tabular::TOGGLE_LTCAPTION:
-               cur.idx() = tabular.setLTCaption(row, !tabular.ltCaption(row));
+       case Tabular::TOGGLE_LTCAPTION: {
+               bool set = !tabular.ltCaption(row);
+               cur.idx() = tabular.setLTCaption(row, set);
                cur.pit() = 0;
                cur.pos() = 0;
                cur.setSelection(false);
+               // When a row is set as caption, then also insert a caption. Otherwise
+               // the LaTeX output is broken, when the user doesn't add a caption.
+               if (set)
+                       lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT));
                break;
+       }
 
        case Tabular::SET_BOOKTABS:
                tabular.use_booktabs = true;
@@ -4834,8 +4930,15 @@ bool InsetTabular::pasteClipboard(Cursor & cur)
 {
        if (!paste_tabular)
                return false;
-       col_type const actcol = tabular.cellColumn(cur.idx());
-       row_type const actrow = tabular.cellRow(cur.idx());
+       col_type actcol = tabular.cellColumn(cur.idx());
+       row_type actrow = tabular.cellRow(cur.idx());
+
+       if (cur.selIsMultiCell()) {
+               row_type re;
+               col_type ce;
+               getSelection(cur, actrow, re, actcol, ce);
+       }
+
        for (row_type r1 = 0, r2 = actrow;
             r1 < paste_tabular->row_info.size() && r2 < tabular.row_info.size();
             ++r1, ++r2) {
@@ -4843,7 +4946,7 @@ bool InsetTabular::pasteClipboard(Cursor & cur)
                    c1 < paste_tabular->column_info.size() && c2 < tabular.column_info.size();
                    ++c1, ++c2) {
                        if (paste_tabular->isPartOfMultiColumn(r1, c1) &&
-                           tabular.isPartOfMultiColumn(r2, c2))
+                             tabular.isPartOfMultiColumn(r2, c2))
                                continue;
                        if (paste_tabular->isPartOfMultiColumn(r1, c1)) {
                                --c2;