#include "frontends/Painter.h"
#include "frontends/Selection.h"
+#include "support/Changer.h"
#include "support/convert.h"
#include "support/debug.h"
#include "support/docstream.h"
{ 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 },
{ 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},
{ 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 }
};
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) {
if (row + 1 < nrows() &&
cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW &&
cell_info[row + 1][c].multirow == CELL_PART_OF_MULTIROW) {
- cell_info[row + 1][c].multirow = CELL_BEGIN_OF_MULTIROW;
+ cell_info[row + 1][c] = cell_info[row][c];
}
}
if (ct)
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;
}
if (col + 1 < ncols() &&
cell_info[r][col].multicolumn == CELL_BEGIN_OF_MULTICOLUMN &&
cell_info[r][col + 1].multicolumn == CELL_PART_OF_MULTICOLUMN) {
- cell_info[r][col + 1].multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
+ cell_info[r][col + 1] = cell_info[r][col];
}
if (!ct)
cell_info[r].erase(cell_info[r].begin() + 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;
}
}
+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)
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;
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;
os << "\\multirow{" << rowSpan(cell) << "}{";
if (!getPWidth(cell).zero())
os << from_ascii(getPWidth(cell).asLatexString());
- else
- // we need to set a default value
- os << "*";
+ else {
+ if (column_info[c].varwidth)
+ // this inherits varwidth size
+ os << "=";
+ else
+ // we need to set a default value
+ os << "*";
+ }
os << "}";
if (!getMROffset(cell).zero())
os << "[" << from_ascii(getMROffset(cell).asLatexString()) << "]";
} else if (!isPartOfMultiRow(row, c)) {
if (!runparams.nice)
os.texrow().start(par.id(), 0);
- if (isMultiRow(cell))
+ if (isMultiRow(cell) && !LaTeXFeatures::isAvailable("multirow-2021/01/29"))
newrp.isNonLong = true;
inset->latex(os, newrp);
}
}
+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
{
Length const cwidth = column_info[c].p_width;
if (!cwidth.zero()) {
string const hwidth = cwidth.asHTMLString();
- attr << "style =\"width: " << hwidth << ";\" ";
+ attr << "style=\"width: " << hwidth << ";\" ";
}
attr << "align='";
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) << "'";
else if (isMultiRow(cell))
attr << " rowspan='" << rowSpan(cell) << "'";
+ OutputParams rp = runparams;
+ rp.docbook_in_par = false;
+ rp.docbook_force_pars = true;
xs << xml::StartTag(celltag, attr.str(), true);
- cellInset(cell)->docbook(xs, runparams);
+ cellInset(cell)->docbook(xs, rp);
xs << xml::EndTag(celltag);
xs << xml::CR();
++cell;
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) << "'";
if (((havefirsthead && row_info[r].endfirsthead) ||
(havehead && row_info[r].endhead)) &&
!row_info[r].caption) {
- docbookRow(xs, r, runparams, true); // TODO: HTML vs CALS
+ docbookRow(xs, r, runparams, true);
}
}
xs << xml::EndTag("thead");
Length const cwidth = column_info[c].p_width;
if (!cwidth.zero()) {
string const hwidth = cwidth.asHTMLString();
- attr << "style =\"width: " << hwidth << ";\" ";
+ attr << "style=\"width: " << hwidth << ";\" ";
}
attr << "align='";
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) << "'";
// 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);
// 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)
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)
}
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)) {
if (insertPlaintextString(cur.bv(), clip, false)) {
// content has been replaced,
// so cursor might be invalid
- cur.pos() = cur.lastpos();
- cur.pit() = cur.lastpit();
+ cur.fixIfBroken();
bvcur.setCursor(cur);
break;
}
break;
}
}
- else if (theClipboard().hasTextContents(Clipboard::LyXTextType)) {
+ else if (!theClipboard().isInternal()
+ && theClipboard().hasTextContents(Clipboard::LyXTextType)) {
// This might be tabular data from another LyX instance. Check!
docstring const clip =
theClipboard().getAsText(Clipboard::PlainTextType);
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:
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);
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;
}
// 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) {
}
-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;
}
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;
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:
}
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)
// 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;
}
bool InsetTabular::showCompletionCursor() const
{
- return lyxrc.completion_cursor_text;
+ return lyxrc.completion_cursor_text &&
+ (lyxrc.completion_inline_text || lyxrc.completion_popup_text);
}