]> git.lyx.org Git - features.git/blobdiff - src/insets/InsetTabular.cpp
XHTML/DocBook: merge code duplicates for vertical alignment.
[features.git] / src / insets / InsetTabular.cpp
index ec2a7a303abb435a5e20d90191910d5014b724e6..092c868a0005a9ffcc96fde80675338b62a9875f 100644 (file)
@@ -57,6 +57,7 @@
 #include "frontends/Painter.h"
 #include "frontends/Selection.h"
 
+#include "support/Changer.h"
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/docstream.h"
@@ -163,6 +164,7 @@ TabularFeature tabularFeature[] =
        { Tabular::UNSET_MULTIROW, "unset-multirow", false },
        { Tabular::SET_MROFFSET, "set-mroffset", true },
        { Tabular::SET_ALL_LINES, "set-all-lines", false },
+       { Tabular::TOGGLE_ALL_LINES, "toggle-all-lines", false },
        { Tabular::RESET_FORMAL_DEFAULT, "reset-formal-default", false },
        { Tabular::UNSET_ALL_LINES, "unset-all-lines", false },
        { Tabular::TOGGLE_LONGTABULAR, "toggle-longtabular", false },
@@ -200,6 +202,7 @@ TabularFeature tabularFeature[] =
        { Tabular::SET_BOTTOM_SPACE, "set-bottom-space", true },
        { Tabular::SET_INTERLINE_SPACE, "set-interline-space", true },
        { Tabular::SET_BORDER_LINES, "set-border-lines", false },
+       { Tabular::TOGGLE_BORDER_LINES, "toggle-border-lines", false },
        { Tabular::TABULAR_VALIGN_TOP, "tabular-valign-top", false},
        { Tabular::TABULAR_VALIGN_MIDDLE, "tabular-valign-middle", false},
        { Tabular::TABULAR_VALIGN_BOTTOM, "tabular-valign-bottom", false},
@@ -209,6 +212,7 @@ TabularFeature tabularFeature[] =
        { Tabular::SET_DECIMAL_POINT, "set-decimal-point", true },
        { Tabular::SET_TABULAR_WIDTH, "set-tabular-width", true },
        { Tabular::SET_INNER_LINES, "set-inner-lines", false },
+       { Tabular::TOGGLE_INNER_LINES, "toggle-inner-lines", false },
        { Tabular::LAST_ACTION, "", false }
 };
 
@@ -616,7 +620,7 @@ DocIterator separatorPos(InsetTableCell const * cell, docstring const & align_d)
 
 InsetTableCell splitCell(InsetTableCell & head, docstring const & align_d, bool & hassep)
 {
-       InsetTableCell tail = InsetTableCell(head);
+       InsetTableCell tail = head;
        DocIterator const dit = separatorPos(&head, align_d);
        hassep = static_cast<bool>(dit);
        if (hassep) {
@@ -838,13 +842,13 @@ void Tabular::appendRow(row_type row)
 
 void Tabular::insertRow(row_type const row, bool copy)
 {
-       row_info.insert(row_info.begin() + row + 1, RowData(row_info[row]));
+       row_info.insert(row_info.begin() + row + 1, row_info[row]);
        cell_info.insert(cell_info.begin() + row + 1,
                cell_vector(0, CellData(buffer_)));
 
        for (col_type c = 0; c < ncols(); ++c) {
                cell_info[row + 1].insert(cell_info[row + 1].begin() + c,
-                       copy ? CellData(cell_info[row][c]) : CellData(buffer_));
+                       copy ? cell_info[row][c] : CellData(buffer_));
                if (cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW)
                        cell_info[row + 1][c].multirow = CELL_PART_OF_MULTIROW;
        }
@@ -1001,11 +1005,11 @@ void Tabular::appendColumn(col_type col)
 void Tabular::insertColumn(col_type const col, bool copy)
 {
        bool const ct = buffer().params().track_changes;
-       column_info.insert(column_info.begin() + col + 1, ColumnData(column_info[col]));
+       column_info.insert(column_info.begin() + col + 1, column_info[col]);
 
        for (row_type r = 0; r < nrows(); ++r) {
                cell_info[r].insert(cell_info[r].begin() + col + 1,
-                       copy ? CellData(cell_info[r][col]) : CellData(buffer_));
+                       copy ? cell_info[r][col] : CellData(buffer_));
                if (cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN)
                        cell_info[r][col + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
        }
@@ -1120,6 +1124,76 @@ bool Tabular::rightLine(idx_type cell, bool const ignore_bt) const
 }
 
 
+bool Tabular::outsideBorders(
+       row_type const sel_row_start, row_type const sel_row_end,
+       col_type const sel_col_start, col_type const sel_col_end) const
+{
+       if (!use_booktabs)
+               for (row_type r = sel_row_start; r <= sel_row_end; ++r) {
+                       if (!leftLine(cellIndex(r, sel_col_start))
+                               || !rightLine(cellIndex(r, sel_col_end)))
+                               return false;
+               }
+       for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+               if (!topLine(cellIndex(sel_row_start, c))
+                       || !bottomLine(cellIndex(sel_row_end, c)))
+                       return false;
+       }
+       return true;
+}
+
+
+bool Tabular::innerBorders(
+       row_type const sel_row_start, row_type const sel_row_end,
+       col_type const sel_col_start, col_type const sel_col_end) const
+{
+       // Single cell has no inner borders
+       if (sel_row_start == sel_row_end && sel_col_start == sel_col_end)
+               return false;
+       for (row_type r = sel_row_start; r <= sel_row_end; ++r)
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                       idx_type const cell = cellIndex(r, c);
+                       if ((r != sel_row_start && !topLine(cell)
+                                       && cell_info[r][c].multirow != CELL_PART_OF_MULTIROW)
+                               || (!use_booktabs
+                                       && c != sel_col_start && !leftLine(cell)
+                                       && cell_info[r][c].multicolumn != CELL_PART_OF_MULTICOLUMN))
+                               return false;
+               }
+       return true;
+}
+
+
+void Tabular::setLines(
+       row_type const sel_row_start, row_type const sel_row_end,
+       col_type const sel_col_start, col_type const sel_col_end,
+       bool setLinesInnerOnly, bool setLines)
+{
+       for (row_type r = sel_row_start; r <= sel_row_end; ++r)
+               for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
+                       idx_type const cell = cellIndex(r, c);
+                       if (!(setLinesInnerOnly && r == sel_row_start)
+                               // for multirows, cell is taken care of at beginning
+                               && cell_info[r][c].multirow != CELL_PART_OF_MULTIROW)
+                               setTopLine(cell, setLines);
+                       if (!(setLinesInnerOnly && r == sel_row_end)
+                               &&  (r == sel_row_end || (!setLines
+                                       // for multirows, cell is taken care of at the last part
+                                       && cell_info[r + 1][c].multirow != CELL_PART_OF_MULTIROW)))
+                               setBottomLine(cell, setLines);
+                       if (!(setLinesInnerOnly && c == sel_col_start)
+                               // for multicolumns, cell is taken care of at beginning
+                               && cell_info[r][c].multicolumn != CELL_PART_OF_MULTICOLUMN)
+                               setLeftLine(cell, setLines);
+                       if (!(setLinesInnerOnly && c == sel_col_end)
+                               && (c == sel_col_end || (!setLines
+                                       // for multicolumns, cell is taken care of at the last part
+                                       && cell_info[r][c + 1].multicolumn != CELL_PART_OF_MULTICOLUMN)))
+                               setRightLine(cell, setLines);
+               }
+}
+
+
 pair<bool, bool> Tabular::topLineTrim(idx_type const cell) const
 {
        if (!use_booktabs)
@@ -2604,7 +2678,7 @@ void Tabular::TeXTopHLine(otexstream & os, row_type row, list<col_type> columns,
                                                break;
                                }
 
-                               for (col_type j = cstart ; j < c ; ++j)
+                               for (col_type j = cstart ; j <= c ; ++j)
                                        if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
                                                ++offset;
                                col_type lastcol = (*it1 == *it2) ? c + 1 + offset : columns.size() - c + offset;
@@ -2740,7 +2814,7 @@ void Tabular::TeXBottomHLine(otexstream & os, row_type row, list<col_type> colum
                                                break;
                                }
 
-                               for (col_type j = cstart ; j < c ; ++j)
+                               for (col_type j = cstart ; j <= c ; ++j)
                                        if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
                                                ++offset;
                                col_type lastcol = (*it1 == *it2) ? c + 1 + offset : columns.size() - c + offset;
@@ -3552,6 +3626,19 @@ void Tabular::docbookRow(XMLStream & xs, row_type row,
 }
 
 
+std::string Tabular::getVAlignAsXmlAttribute(idx_type cell) const
+{
+       switch (getVAlignment(cell)) {
+       case LYX_VALIGN_TOP:
+               return "valign='top'";
+       case LYX_VALIGN_BOTTOM:
+               return "valign='bottom'";
+       case LYX_VALIGN_MIDDLE:
+               return "valign='middle'";
+       }
+}
+
+
 void Tabular::docbookRowAsHTML(XMLStream & xs, row_type row,
                   OutputParams const & runparams, bool header) const
 {
@@ -3592,19 +3679,7 @@ void Tabular::docbookRowAsHTML(XMLStream & xs, row_type row,
                        attr << "center";
                        break;
                }
-               attr << "'";
-               attr << " valign='";
-               switch (getVAlignment(cell)) {
-               case LYX_VALIGN_TOP:
-                       attr << "top";
-                       break;
-               case LYX_VALIGN_BOTTOM:
-                       attr << "bottom";
-                       break;
-               case LYX_VALIGN_MIDDLE:
-                       attr << "middle";
-               }
-               attr << "'";
+               attr << "' " << getVAlignAsXmlAttribute(cell);
 
                if (isMultiColumn(cell))
                        attr << " colspan='" << columnSpan(cell) << "'";
@@ -3659,19 +3734,7 @@ void Tabular::docbookRowAsCALS(XMLStream & xs, row_type row,
                        attr << "center";
                        break;
                }
-               attr << "'";
-               attr << " valign='";
-               switch (getVAlignment(cell)) {
-               case LYX_VALIGN_TOP:
-                       attr << "top";
-                       break;
-               case LYX_VALIGN_BOTTOM:
-                       attr << "bottom";
-                       break;
-               case LYX_VALIGN_MIDDLE:
-                       attr << "middle";
-               }
-               attr << "'";
+               attr << "' " << getVAlignAsXmlAttribute(cell);
 
                if (isMultiColumn(cell))
                        attr << " colspan='" << columnSpan(cell) << "'";
@@ -3823,19 +3886,7 @@ docstring Tabular::xhtmlRow(XMLStream & xs, row_type row,
                        attr << "center";
                        break;
                }
-               attr << "'";
-               attr << " valign='";
-               switch (getVAlignment(cell)) {
-               case LYX_VALIGN_TOP:
-                       attr << "top";
-                       break;
-               case LYX_VALIGN_BOTTOM:
-                       attr << "bottom";
-                       break;
-               case LYX_VALIGN_MIDDLE:
-                       attr << "middle";
-               }
-               attr << "'";
+               attr << "' " << getVAlignAsXmlAttribute(cell);
 
                if (isMultiColumn(cell))
                        attr << " colspan='" << columnSpan(cell) << "'";
@@ -4341,10 +4392,11 @@ void InsetTableCell::metrics(MetricsInfo & mi, Dimension & dim) const
 
        // We tell metrics here not to expand on multiple pars
        // This is the difference to InsetText::Metrics
-       if (hasFixedWidth() || isVarwidth)
-               tm.metrics(mi, dim, mi.base.textwidth, false);
+       Changer changetight = changeVar(mi.tight_insets, true);
+       if (hasFixedWidth())
+               tm.metrics(mi, dim, mi.base.textwidth);
        else
-               tm.metrics(mi, dim, 0, false);
+               tm.metrics(mi, dim, 0);
        mi.base.textwidth += horiz_offset;
        dim.asc += topOffset(mi.base.bv);
        dim.des += bottomOffset(mi.base.bv);
@@ -4523,7 +4575,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
                        // determine horizontal offset because of decimal align (if necessary)
                        int decimal_width = 0;
                        if (tabular.getAlignment(cell) == LYX_ALIGN_DECIMAL) {
-                               InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell));
+                               InsetTableCell tail = *tabular.cellInset(cell);
                                tail.setBuffer(tabular.buffer());
                                // we need to set macrocontext position everywhere
                                // otherwise we crash with nested insets (e.g. footnotes)
@@ -4776,7 +4828,7 @@ void InsetTabular::drawCellLines(PainterInfo & pi, int x, int y,
        Color colour = Color_tabularline;
        if (tabular.column_info[col].change.changed()
            || tabular.row_info[row].change.changed())
-               colour = InsetTableCell(*tabular.cellInset(cell)).paragraphs().front().lookupChange(0).color();
+               colour = tabular.cellInset(cell)->paragraphs().front().lookupChange(0).color();
 
        // Top
        bool drawline = tabular.topLine(cell)
@@ -5262,6 +5314,13 @@ void InsetTabular::doDispatch(Cursor & cur, FuncRequest & cmd)
                }
                break;
 
+       case LFUN_COPY:
+               if (cur.selIsMultiCell())
+                       copySelection(cur);
+               else
+                       cell(cur.idx())->dispatch(cur, cmd);
+               break;
+
        case LFUN_CUT:
                if (cur.selIsMultiCell()) {
                        if (copySelection(cur)) {
@@ -5539,8 +5598,6 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
                case Tabular::SET_SPECIAL_MULTICOLUMN:
                case Tabular::APPEND_ROW:
                case Tabular::APPEND_COLUMN:
-               case Tabular::DELETE_ROW:
-               case Tabular::DELETE_COLUMN:
                case Tabular::COPY_ROW:
                case Tabular::COPY_COLUMN:
                case Tabular::SET_TOP_SPACE:
@@ -5549,6 +5606,13 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
                        status.clear();
                        return true;
 
+               case Tabular::DELETE_ROW:
+                       status.setEnabled(tabular.nrows() > 1);
+                       break;
+               case Tabular::DELETE_COLUMN:
+                       status.setEnabled(tabular.ncols() > 1);
+                       break;
+
                case Tabular::SET_TABULAR_WIDTH:
                        status.setEnabled(!tabular.rotate
                                && tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE);
@@ -5643,9 +5707,28 @@ bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
                        status.setOnOff(tabular.isMultiRow(cur.idx()));
                        break;
 
+               case Tabular::TOGGLE_INNER_LINES:
+                       status.setOnOff(tabular.innerBorders(sel_row_start, sel_row_end,
+                                                                                                sel_col_start, sel_col_end));
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       break;
+               case Tabular::TOGGLE_ALL_LINES:
+                       status.setOnOff(tabular.innerBorders(sel_row_start, sel_row_end,
+                                                                                                sel_col_start, sel_col_end)
+                                               && tabular.outsideBorders(sel_row_start, sel_row_end,
+                                                                                                 sel_col_start, sel_col_end));
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       break;
                case Tabular::SET_ALL_LINES:
                case Tabular::UNSET_ALL_LINES:
                case Tabular::SET_INNER_LINES:
+                       status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+                       break;
+
+               case Tabular::TOGGLE_BORDER_LINES:
+                       status.setOnOff(tabular.outsideBorders(sel_row_start, sel_row_end,
+                                                                                                  sel_col_start, sel_col_end));
+                       // fall through
                case Tabular::SET_BORDER_LINES:
                        status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
                        break;
@@ -6009,7 +6092,7 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
                }
                // check if there is already a caption
                bool have_caption = false;
-               InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()));
+               InsetTableCell itc = *tabular.cellInset(cur.idx());
                ParagraphList::const_iterator pit = itc.paragraphs().begin();
                ParagraphList::const_iterator pend = itc.paragraphs().end();
                for (; pit != pend; ++pit) {
@@ -6130,21 +6213,21 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
 }
 
 
-Inset::RowFlags InsetTabular::rowFlags() const
+int InsetTabular::rowFlags() const
 {
-               if (tabular.is_long_tabular) {
-                       switch (tabular.longtabular_alignment) {
-                       case Tabular::LYX_LONGTABULAR_ALIGN_LEFT:
-                               return Display | AlignLeft;
-                       case Tabular::LYX_LONGTABULAR_ALIGN_CENTER:
-                               return Display;
-                       case Tabular::LYX_LONGTABULAR_ALIGN_RIGHT:
-                               return Display | AlignRight;
-                       default:
-                               return Display;
-                       }
-               } else
-                       return Inline;
+       if (tabular.is_long_tabular) {
+               switch (tabular.longtabular_alignment) {
+               case Tabular::LYX_LONGTABULAR_ALIGN_LEFT:
+                       return Display | AlignLeft;
+               case Tabular::LYX_LONGTABULAR_ALIGN_CENTER:
+                       return Display;
+               case Tabular::LYX_LONGTABULAR_ALIGN_RIGHT:
+                       return Display | AlignRight;
+               default:
+                       return Display;
+               }
+       } else
+               return Inline;
 }
 
 
@@ -6497,7 +6580,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
        row_type sel_row_start;
        row_type sel_row_end;
        bool setLines = false;
-       bool setLinesInnerOnly = false;
+       bool toggle = false;
        LyXAlignment setAlign = LYX_ALIGN_LEFT;
        Tabular::VAlignment setVAlign = Tabular::LYX_VALIGN_TOP;
 
@@ -6921,27 +7004,36 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                break;
        }
 
+       case Tabular::TOGGLE_INNER_LINES:
+               toggle = true;
+               // fall through
        case Tabular::SET_INNER_LINES:
-               setLinesInnerOnly = true;
+               if (toggle)
+                       setLines = !tabular.innerBorders(sel_row_start, sel_row_end,
+                                                                                    sel_col_start, sel_col_end);
+               else
+                       setLines = true;
+               tabular.setLines(sel_row_start, sel_row_end,
+                                                sel_col_start, sel_col_end,
+                                                true, setLines);
+               break;
+
+       case Tabular::TOGGLE_ALL_LINES:
+               toggle = true;
                // fall through
        case Tabular::SET_ALL_LINES:
-               setLines = true;
+               if (toggle)
+                       setLines = !tabular.innerBorders(sel_row_start, sel_row_end,
+                                                                                    sel_col_start, sel_col_end)
+                                       || !tabular.outsideBorders(sel_row_start, sel_row_end,
+                                                                                      sel_col_start, sel_col_end);
+               else
+                       setLines = true;
                // fall through
        case Tabular::UNSET_ALL_LINES:
-               for (row_type r = sel_row_start; r <= sel_row_end; ++r)
-                       for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
-                               idx_type const cell = tabular.cellIndex(r, c);
-                               if (!setLinesInnerOnly || r != sel_row_start)
-                                       tabular.setTopLine(cell, setLines);
-                               if ((!setLinesInnerOnly || r != sel_row_end)
-                                   && (!setLines || r == sel_row_end))
-                                       tabular.setBottomLine(cell, setLines);
-                               if ((!setLinesInnerOnly || c != sel_col_end)
-                                   && (!setLines || c == sel_col_end))
-                                       tabular.setRightLine(cell, setLines);
-                               if ((!setLinesInnerOnly || c != sel_col_start))
-                                       tabular.setLeftLine(cell, setLines);
-                       }
+               tabular.setLines(sel_row_start, sel_row_end,
+                                                sel_col_start, sel_col_end,
+                                                false, setLines);
                break;
 
        case Tabular::RESET_FORMAL_DEFAULT:
@@ -6955,16 +7047,24 @@ void InsetTabular::tabularFeatures(Cursor & cur,
                }
                break;
 
-       case Tabular::SET_BORDER_LINES:
+       case Tabular::TOGGLE_BORDER_LINES:
+               toggle = true;
+               // fall through
+       case Tabular::SET_BORDER_LINES: {
+               bool const border = toggle &&
+                               tabular.outsideBorders(sel_row_start, sel_row_end,
+                                                                          sel_col_start, sel_col_end)
+                               ? false : true;
                for (row_type r = sel_row_start; r <= sel_row_end; ++r) {
-                       tabular.setLeftLine(tabular.cellIndex(r, sel_col_start), true);
-                       tabular.setRightLine(tabular.cellIndex(r, sel_col_end), true);
+                       tabular.setLeftLine(tabular.cellIndex(r, sel_col_start), border);
+                       tabular.setRightLine(tabular.cellIndex(r, sel_col_end), border);
                }
                for (col_type c = sel_col_start; c <= sel_col_end; ++c) {
-                       tabular.setTopLine(tabular.cellIndex(sel_row_start, c), true);
-                       tabular.setBottomLine(tabular.cellIndex(sel_row_end, c), true);
+                       tabular.setTopLine(tabular.cellIndex(sel_row_start, c), border);
+                       tabular.setBottomLine(tabular.cellIndex(sel_row_end, c), border);
                }
                break;
+       }
 
        case Tabular::TOGGLE_LONGTABULAR:
                if (tabular.is_long_tabular)
@@ -7304,12 +7404,15 @@ bool InsetTabular::pasteClipboard(Cursor & cur)
                        // FIXME?: why do we need to do this explicitly? (EL)
                        tabular.cellInset(r2, c2)->setBuffer(tabular.buffer());
 
-                       if (!lyxrc.ct_markup_copied) {
-                               // do not paste deleted text
-                               inset->acceptChanges();
+                       if (lyxrc.ct_markup_copied) {
+                               // Only change to inserted if ct is active,
+                               // otherwise leave markup as is
+                               if (buffer().params().track_changes)
+                                       inset->setChange(Change(Change::INSERTED));
+                       } else
+                               // Resolve all markup to inserted or unchanged
                                inset->setChange(Change(buffer().params().track_changes ?
-                                               Change::INSERTED : Change::UNCHANGED));
-                       }
+                                                        Change::INSERTED : Change::UNCHANGED));
                        cur.pos() = 0;
                        cur.pit() = 0;
                }