Support varwidth's V tabular column type

This effectively enables linebreaks, multipars and layout changes in
non-fixed width (i.e., standard) table columns.

Fixes: #6577

TODO: metrics are wrong (too wide) on screen with linebreaks.
This commit is contained in:
Juergen Spitzmueller 2018-07-01 19:18:38 +02:00
parent 620efb3540
commit 9dcb24d578
9 changed files with 307 additions and 74 deletions

View File

@ -7,6 +7,11 @@ changes happened in particular if possible. A good example would be
----------------------- -----------------------
2018-07-01 Jürgen Spitzmüller <spitz@lyx.org>
* format incremented to 555: Support varwidth's V tabular column type.
This effectively enables linebreaks, multipars and layout changes in
non-fixed width (i.e., standard) table columns.
2018-06-23 Jürgen Spitzmüller <spitz@lyx.org> 2018-06-23 Jürgen Spitzmüller <spitz@lyx.org>
* format incremented to 554: Support tabularx and xltabular: * format incremented to 554: Support tabularx and xltabular:
- add column flag "varwidth=true", which will output column type 'X' - add column flag "varwidth=true", which will output column type 'X'

View File

@ -5431,6 +5431,35 @@ varioref
the page of the referred label. the page of the referred label.
\end_layout \end_layout
\begin_layout Subsubsection
varwidth
\end_layout
\begin_layout Description
Found:
\begin_inset Info
type "package"
arg "varwidth"
\end_inset
\end_layout
\begin_layout Description
CTAN:
\family typewriter
macros/latex/contrib/varwidth/
\end_layout
\begin_layout Description
Notes: The package
\family sans
varwidth
\family default
\color none
is needed to allow for line and paragraph breaks in standard tabular columns.
\end_layout
\begin_layout Subsection \begin_layout Subsection
xltabular xltabular
\end_layout \end_layout
@ -6750,7 +6779,7 @@ Notes: The package
varwidth varwidth
\family default \family default
\color none \color none
is used to produce minipages variable (i. is used to produce minipages of variable (i.
\begin_inset space \thinspace{} \begin_inset space \thinspace{}
\end_inset \end_inset

View File

@ -24,14 +24,14 @@ import sys, os
# Uncomment only what you need to import, please. # Uncomment only what you need to import, please.
from parser_tools import (find_end_of_inset, find_end_of_layout, find_token, from parser_tools import (count_pars_in_inset, find_end_of_inset, find_end_of_layout,
get_bool_value, get_value, get_quoted_value) find_token, get_bool_value, get_option_value, get_value, get_quoted_value)
# del_token, del_value, del_complete_lines, # del_token, del_value, del_complete_lines,
# find_complete_lines, find_end_of, # find_complete_lines, find_end_of,
# find_re, find_substring, find_token_backwards, # find_re, find_substring, find_token_backwards,
# get_containing_inset, get_containing_layout, # get_containing_inset, get_containing_layout,
# is_in_inset, set_bool_value # is_in_inset, set_bool_value
# find_tokens, find_token_exact, check_token, get_option_value # find_tokens, find_token_exact, check_token
from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble) from lyx2lyx_tools import (put_cmd_in_ert, add_to_preamble)
# revert_font_attrs, insert_to_preamble, latex_length # revert_font_attrs, insert_to_preamble, latex_length
@ -118,15 +118,15 @@ def revert_paratype(document):
document.header[i1] = document.header[i1].replace("PTSerif-TLF", "default") document.header[i1] = document.header[i1].replace("PTSerif-TLF", "default")
if j!= -1: if j!= -1:
if sfoption != "": if sfoption != "":
add_to_preamble(document, ["\\usepackage[" + sfoption + "]{PTSans}"]) add_to_preamble(document, ["\\usepackage[" + sfoption + "]{PTSans}"])
else: else:
add_to_preamble(document, ["\\usepackage{PTSans}"]) add_to_preamble(document, ["\\usepackage{PTSans}"])
document.header[j] = document.header[j].replace("PTSans-TLF", "default") document.header[j] = document.header[j].replace("PTSans-TLF", "default")
if k!= -1: if k!= -1:
if ttoption != "": if ttoption != "":
add_to_preamble(document, ["\\usepackage[" + ttoption + "]{PTMono}"]) add_to_preamble(document, ["\\usepackage[" + ttoption + "]{PTMono}"])
else: else:
add_to_preamble(document, ["\\usepackage{PTMono}"]) add_to_preamble(document, ["\\usepackage{PTMono}"])
document.header[k] = document.header[k].replace("PTMono-TLF", "default") document.header[k] = document.header[k].replace("PTMono-TLF", "default")
@ -345,6 +345,100 @@ def revert_stretchcolumn(document):
i = i + 1 i = i + 1
def revert_vcolumns(document):
" Revert standard columns with line breaks etc. "
i = 0
needvarwidth = False
needarray = False
try:
while True:
i = find_token(document.body, "\\begin_inset Tabular", i)
if i == -1:
return
j = find_end_of_inset(document.body, i)
if j == -1:
document.warning("Malformed LyX document: Could not find end of tabular.")
i += 1
continue
# Collect necessary column information
m = i + 1
nrows = int(document.body[i+1].split('"')[3])
ncols = int(document.body[i+1].split('"')[5])
col_info = []
for k in range(ncols):
m = find_token(document.body, "<column", m)
width = get_option_value(document.body[m], 'width')
varwidth = get_option_value(document.body[m], 'varwidth')
alignment = get_option_value(document.body[m], 'alignment')
special = get_option_value(document.body[m], 'special')
col_info.append([width, varwidth, alignment, special, m])
# Now parse cells
m = i + 1
lines = []
for row in range(nrows):
for col in range(ncols):
m = find_token(document.body, "<cell", m)
multicolumn = get_option_value(document.body[m], 'multicolumn')
multirow = get_option_value(document.body[m], 'multirow')
width = get_option_value(document.body[m], 'width')
rotate = get_option_value(document.body[m], 'rotate')
# Check for: linebreaks, multipars, non-standard environments
begcell = m
endcell = find_token(document.body, "</cell>", begcell)
vcand = False
if find_token(document.body, "\\begin_inset Newline", begcell, endcell) != -1:
vcand = True
elif count_pars_in_inset(document.body, begcell + 2) > 1:
vcand = True
elif get_value(document.body, "\\begin_layout", begcell) != "Plain Layout":
vcand = True
if vcand and rotate == "" and ((multicolumn == "" and multirow == "") or width == ""):
if col_info[col][0] == "" and col_info[col][1] == "" and col_info[col][3] == "":
needvarwidth = True
alignment = col_info[col][2]
col_line = col_info[col][4]
vval = ""
if alignment == "center":
vval = ">{\\centering}"
elif alignment == "left":
vval = ">{\\raggedright}"
elif alignment == "right":
vval = ">{\\raggedleft}"
if vval != "":
needarray = True
vval += "V{\\linewidth}"
document.body[col_line] = document.body[col_line][:-1] + " special=\"" + vval + "\">"
# ERT newlines and linebreaks (since LyX < 2.4 automatically inserts parboxes
# with newlines, and we do not want that)
while True:
endcell = find_token(document.body, "</cell>", begcell)
linebreak = False
nl = find_token(document.body, "\\begin_inset Newline newline", begcell, endcell)
if nl == -1:
nl = find_token(document.body, "\\begin_inset Newline linebreak", begcell, endcell)
if nl == -1:
break
linebreak = True
nle = find_end_of_inset(document.body, nl)
del(document.body[nle:nle+1])
if linebreak:
document.body[nl:nl+1] = put_cmd_in_ert("\\linebreak{}")
else:
document.body[nl:nl+1] = put_cmd_in_ert("\\\\")
m += 1
i = j + 1
finally:
if needarray == True:
add_to_preamble(document, ["\\usepackage{array}"])
if needvarwidth == True:
add_to_preamble(document, ["\\usepackage{varwidth}"])
## ##
# Conversion hub # Conversion hub
# #
@ -360,10 +454,12 @@ convert = [
[551, []], [551, []],
[552, []], [552, []],
[553, []], [553, []],
[554, []] [554, []],
[555, []]
] ]
revert = [ revert = [
[554, [revert_vcolumns]],
[553, [revert_stretchcolumn]], [553, [revert_stretchcolumn]],
[552, [revert_tuftecite]], [552, [revert_tuftecite]],
[551, [revert_floatpclass, revert_floatalignment]], [551, [revert_floatpclass, revert_floatalignment]],

View File

@ -160,7 +160,8 @@ ParagraphMetrics & TextMetrics::parMetrics(pit_type pit, bool redo)
} }
bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width) bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width,
bool const expand_on_multipars)
{ {
LBUFERR(mi.base.textwidth > 0); LBUFERR(mi.base.textwidth > 0);
max_width_ = mi.base.textwidth; max_width_ = mi.base.textwidth;
@ -170,7 +171,7 @@ bool TextMetrics::metrics(MetricsInfo & mi, Dimension & dim, int min_width)
dim_ = Dimension(); dim_ = Dimension();
dim_.wid = min_width; dim_.wid = min_width;
pit_type const npar = text_->paragraphs().size(); pit_type const npar = text_->paragraphs().size();
if (npar > 1) if (npar > 1 && expand_on_multipars)
// If there is more than one row, expand the text to // If there is more than one row, expand the text to
// the full allowable width. // the full allowable width.
dim_.wid = max_width_; dim_.wid = max_width_;

View File

@ -55,7 +55,8 @@ public:
/// compute text metrics. /// compute text metrics.
bool metrics(MetricsInfo & mi, Dimension & dim, int min_width = 0); bool metrics(MetricsInfo & mi, Dimension & dim, int min_width = 0,
bool const expand_on_multipars = true);
/// ///
void newParMetricsDown(); void newParMetricsDown();

View File

@ -917,8 +917,11 @@ void Tabular::updateIndexes()
// reset column and row of cells and update their width and alignment // reset column and row of cells and update their width and alignment
for (row_type row = 0; row < nrows(); ++row) for (row_type row = 0; row < nrows(); ++row)
for (col_type column = 0; column < ncols(); ++column) { for (col_type column = 0; column < ncols(); ++column) {
if (isPartOfMultiColumn(row, column)) if (isPartOfMultiColumn(row, column)) {
cell_info[row][column].inset->toggleMultiCol(true);
continue; continue;
}
cell_info[row][column].inset->toggleMultiCol(false);
// columnofcell needs to be called before setting width and aligment // columnofcell needs to be called before setting width and aligment
// multirow cells inherit the width from the column width // multirow cells inherit the width from the column width
if (!isPartOfMultiRow(row, column)) { if (!isPartOfMultiRow(row, column)) {
@ -926,8 +929,11 @@ void Tabular::updateIndexes()
rowofcell[i] = row; rowofcell[i] = row;
} }
setFixedWidth(row, column); setFixedWidth(row, column);
if (isPartOfMultiRow(row, column)) if (isPartOfMultiRow(row, column)) {
cell_info[row][column].inset->toggleMultiRow(true);
continue; continue;
}
cell_info[row][column].inset->toggleMultiRow(false);
cell_info[row][column].inset->setContentAlignment( cell_info[row][column].inset->setContentAlignment(
getAlignment(cellIndex(row, column))); getAlignment(cellIndex(row, column)));
++i; ++i;
@ -1130,14 +1136,16 @@ void Tabular::setVAlignment(idx_type cell, VAlignment align,
namespace { namespace {
/** /**
* Allow line and paragraph breaks for fixed width cells or disallow them, * Allow line and paragraph breaks for fixed width multicol/multirow cells
* merge cell paragraphs and reset layout to standard for variable width * or disallow them, merge cell paragraphs and reset layout to standard
* cells. * for variable width multicol cells.
*/ */
void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth) void toggleFixedWidth(Cursor & cur, InsetTableCell * inset,
bool const fixedWidth, bool const multicol,
bool const multirow)
{ {
inset->toggleFixedWidth(fixedWidth); inset->toggleFixedWidth(fixedWidth);
if (fixedWidth) if (!multirow && (fixedWidth || !multicol))
return; return;
// merge all paragraphs to one // merge all paragraphs to one
@ -1145,6 +1153,19 @@ void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth)
while (inset->paragraphs().size() > 1) while (inset->paragraphs().size() > 1)
mergeParagraph(bp, inset->paragraphs(), 0); mergeParagraph(bp, inset->paragraphs(), 0);
// This is relevant for multirows
if (fixedWidth)
return;
// remove newlines
ParagraphList::iterator pit = inset->paragraphs().begin();
for (; pit != inset->paragraphs().end(); ++pit) {
for (pos_type j = 0; j != pit->size(); ++j) {
if (pit->isNewline(j))
pit->eraseChar(j, bp.track_changes);
}
}
// reset layout // reset layout
cur.push(*inset); cur.push(*inset);
// undo information has already been recorded // undo information has already been recorded
@ -1171,16 +1192,13 @@ void Tabular::setColumnPWidth(Cursor & cur, idx_type cell,
idx_type const cidx = cellIndex(r, c); idx_type const cidx = cellIndex(r, c);
// because of multicolumns // because of multicolumns
toggleFixedWidth(cur, cellInset(cidx).get(), toggleFixedWidth(cur, cellInset(cidx).get(),
!getPWidth(cidx).zero()); !getPWidth(cidx).zero(), isMultiColumn(cidx),
isMultiRow(cidx));
if (isMultiRow(cidx)) if (isMultiRow(cidx))
setAlignment(cidx, LYX_ALIGN_LEFT, false); setAlignment(cidx, LYX_ALIGN_LEFT, false);
} }
// cur paragraph can become invalid after paragraphs were merged // cur can become invalid after paragraphs were merged
if (cur.pit() > cur.lastpit()) cur.fixIfBroken();
cur.pit() = cur.lastpit();
// cur position can become invalid after newlines were removed
if (cur.pos() > cur.lastpos())
cur.pos() = cur.lastpos();
} }
@ -1201,13 +1219,10 @@ bool Tabular::setMColumnPWidth(Cursor & cur, idx_type cell,
return false; return false;
cellInfo(cell).p_width = width; cellInfo(cell).p_width = width;
toggleFixedWidth(cur, cellInset(cell).get(), !width.zero()); toggleFixedWidth(cur, cellInset(cell).get(), !width.zero(),
// cur paragraph can become invalid after paragraphs were merged isMultiColumn(cell), isMultiRow(cell));
if (cur.pit() > cur.lastpit()) // cur can become invalid after paragraphs were merged
cur.pit() = cur.lastpit(); cur.fixIfBroken();
// cur position can become invalid after newlines were removed
if (cur.pos() > cur.lastpos())
cur.pos() = cur.lastpos();
return true; return true;
} }
@ -1717,6 +1732,16 @@ bool Tabular::hasVarwidthColumn() const
} }
bool Tabular::isVTypeColumn(col_type c) const
{
for (row_type r = 0; r < nrows(); ++r) {
idx_type idx = cellIndex(r, c);
if (getRotateCell(idx) == 0 && useBox(idx) == BOX_VARWIDTH)
return true;
}
return false;
}
Tabular::CellData const & Tabular::cellInfo(idx_type cell) const Tabular::CellData const & Tabular::cellInfo(idx_type cell) const
{ {
@ -1730,7 +1755,7 @@ Tabular::CellData & Tabular::cellInfo(idx_type cell)
} }
Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number, Tabular::idx_type Tabular::setMultiColumn(Cursor & cur, idx_type cell, idx_type number,
bool const right_border) bool const right_border)
{ {
idx_type const col = cellColumn(cell); idx_type const col = cellColumn(cell);
@ -1745,6 +1770,14 @@ Tabular::idx_type Tabular::setMultiColumn(idx_type cell, idx_type number,
if (column_info[col].alignment != LYX_ALIGN_DECIMAL) if (column_info[col].alignment != LYX_ALIGN_DECIMAL)
cs.alignment = column_info[col].alignment; cs.alignment = column_info[col].alignment;
setRightLine(cell, right_border); setRightLine(cell, right_border);
// non-fixed width multicolumns cannot have multiple paragraphs
if (getPWidth(cell).zero()) {
toggleFixedWidth(cur, cellInset(cell).get(),
!getPWidth(cell).zero(), isMultiColumn(cell),
isMultiRow(cell));
// cur can become invalid after paragraphs were merged
cur.fixIfBroken();
}
idx_type lastcell = cellIndex(row, col + number - 1); idx_type lastcell = cellIndex(row, col + number - 1);
for (idx_type i = 1; i < lastcell - cell + 1; ++i) { for (idx_type i = 1; i < lastcell - cell + 1; ++i) {
@ -1773,7 +1806,7 @@ bool Tabular::hasMultiRow(row_type r) const
return false; return false;
} }
Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number, Tabular::idx_type Tabular::setMultiRow(Cursor & cur, idx_type cell, idx_type number,
bool const bottom_border, bool const bottom_border,
LyXAlignment const halign) LyXAlignment const halign)
{ {
@ -1796,6 +1829,15 @@ Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number,
else else
cs.alignment = LYX_ALIGN_LEFT; cs.alignment = LYX_ALIGN_LEFT;
// Multirows cannot have multiple paragraphs
if (getPWidth(cell).zero()) {
toggleFixedWidth(cur, cellInset(cell).get(),
!getPWidth(cell).zero(),
isMultiColumn(cell), isMultiRow(cell));
// cur can become invalid after paragraphs were merged
cur.fixIfBroken();
}
// set the bottom line of the last selected cell // set the bottom line of the last selected cell
setBottomLine(cell, bottom_border); setBottomLine(cell, bottom_border);
@ -1949,7 +1991,7 @@ Tabular::BoxType Tabular::getUsebox(idx_type cell) const
return BOX_NONE; return BOX_NONE;
if (cellInfo(cell).usebox > 1) if (cellInfo(cell).usebox > 1)
return cellInfo(cell).usebox; return cellInfo(cell).usebox;
return useParbox(cell); return useBox(cell);
} }
@ -2078,11 +2120,11 @@ bool Tabular::haveLTLastFoot(bool withcaptions) const
} }
Tabular::idx_type Tabular::setLTCaption(row_type row, bool what) Tabular::idx_type Tabular::setLTCaption(Cursor & cur, row_type row, bool what)
{ {
idx_type i = getFirstCellInRow(row); idx_type i = getFirstCellInRow(row);
if (what) { if (what) {
setMultiColumn(i, numberOfCellsInRow(row), false); setMultiColumn(cur, i, numberOfCellsInRow(row), false);
setTopLine(i, false); setTopLine(i, false);
setBottomLine(i, false); setBottomLine(i, false);
setLeftLine(i, false); setLeftLine(i, false);
@ -2490,7 +2532,7 @@ void Tabular::TeXCellPreamble(otexstream & os, idx_type cell,
} }
os << "]{" << from_ascii(getPWidth(cell).asLatexString()) os << "]{" << from_ascii(getPWidth(cell).asLatexString())
<< "}\n"; << "}\n";
} else if (getUsebox(cell) == BOX_VARWIDTH) { } else if (getRotateCell(cell) != 0 && getUsebox(cell) == BOX_VARWIDTH) {
os << "\\begin{varwidth}["; os << "\\begin{varwidth}[";
switch (valign) { switch (valign) {
case LYX_VALIGN_TOP: case LYX_VALIGN_TOP:
@ -2520,7 +2562,7 @@ void Tabular::TeXCellPostamble(otexstream & os, idx_type cell,
os << '}'; os << '}';
else if (getUsebox(cell) == BOX_MINIPAGE) else if (getUsebox(cell) == BOX_MINIPAGE)
os << breakln << "\\end{minipage}"; os << breakln << "\\end{minipage}";
else if (getUsebox(cell) == BOX_VARWIDTH) else if (getRotateCell(cell) != 0 && getUsebox(cell) == BOX_VARWIDTH)
os << breakln << "\\end{varwidth}"; os << breakln << "\\end{varwidth}";
if (getRotateCell(cell) != 0) if (getRotateCell(cell) != 0)
os << breakln << "\\end{turn}"; os << breakln << "\\end{turn}";
@ -2964,6 +3006,25 @@ void Tabular::latex(otexstream & os, OutputParams const & runparams) const
break; break;
} }
os << 'X'; os << 'X';
} else if (isVTypeColumn(c)) {
switch (column_info[c].alignment) {
case LYX_ALIGN_LEFT:
os << ">{\\raggedright}";
break;
case LYX_ALIGN_RIGHT:
os << ">{\\raggedleft}";
break;
case LYX_ALIGN_CENTER:
os << ">{\\centering}";
break;
case LYX_ALIGN_NONE:
case LYX_ALIGN_BLOCK:
case LYX_ALIGN_LAYOUT:
case LYX_ALIGN_SPECIAL:
case LYX_ALIGN_DECIMAL:
break;
}
os << "V{\\linewidth}";
} else { } else {
switch (column_info[c].alignment) { switch (column_info[c].alignment) {
case LYX_ALIGN_LEFT: case LYX_ALIGN_LEFT:
@ -3588,7 +3649,8 @@ void Tabular::validate(LaTeXFeatures & features) const
if (getUsebox(cell) == BOX_VARWIDTH) if (getUsebox(cell) == BOX_VARWIDTH)
features.require("varwidth"); features.require("varwidth");
if (getVAlignment(cell) != LYX_VALIGN_TOP if (getVAlignment(cell) != LYX_VALIGN_TOP
|| !getPWidth(cell).zero()) || !getPWidth(cell).zero()
|| isVTypeColumn(cellColumn(cell)))
features.require("array"); features.require("array");
// Tell footnote that we need a savenote // Tell footnote that we need a savenote
// environment in non-long tables or // environment in non-long tables or
@ -3604,17 +3666,19 @@ void Tabular::validate(LaTeXFeatures & features) const
} }
Tabular::BoxType Tabular::useParbox(idx_type cell) const Tabular::BoxType Tabular::useBox(idx_type cell) const
{ {
ParagraphList const & parlist = cellInset(cell)->paragraphs(); ParagraphList const & parlist = cellInset(cell)->paragraphs();
if (parlist.size() > 1)
return BOX_VARWIDTH;
ParagraphList::const_iterator cit = parlist.begin(); ParagraphList::const_iterator cit = parlist.begin();
ParagraphList::const_iterator end = parlist.end(); ParagraphList::const_iterator end = parlist.end();
bool const turned = getRotateCell(cell) != 0;
for (; cit != end; ++cit) for (; cit != end; ++cit)
for (int i = 0; i < cit->size(); ++i) for (int i = 0; i < cit->size(); ++i)
if (cit->isNewline(i)) if (cit->isNewline(i) || cit->layout().isEnvironment())
return turned ? BOX_VARWIDTH : BOX_PARBOX; return BOX_VARWIDTH;
return BOX_NONE; return BOX_NONE;
} }
@ -3628,13 +3692,13 @@ Tabular::BoxType Tabular::useParbox(idx_type cell) const
InsetTableCell::InsetTableCell(Buffer * buf) InsetTableCell::InsetTableCell(Buffer * buf)
: InsetText(buf, InsetText::PlainLayout), isFixedWidth(false), : InsetText(buf, InsetText::PlainLayout), isFixedWidth(false),
contentAlign(LYX_ALIGN_CENTER) isMultiColumn(false), isMultiRow(false), contentAlign(LYX_ALIGN_CENTER)
{} {}
bool InsetTableCell::forcePlainLayout(idx_type) const bool InsetTableCell::forcePlainLayout(idx_type) const
{ {
return !isFixedWidth; return isMultiRow || (isMultiColumn && !isFixedWidth);
} }
@ -3701,6 +3765,34 @@ docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const
} }
void InsetTableCell::metrics(MetricsInfo & mi, Dimension & dim) const
{
TextMetrics & tm = mi.base.bv->textMetrics(&text());
// Hand font through to contained lyxtext:
tm.font_.fontInfo() = mi.base.font;
mi.base.textwidth -= 2 * TEXT_TO_INSET_OFFSET;
// This can happen when a layout has a left and right margin,
// and the view is made very narrow. We can't do better than
// to draw it partly out of view (bug 5890).
if (mi.base.textwidth < 1)
mi.base.textwidth = 1;
// We tell metrics here not to expand on multiple pars
// This is the difference to InsetText::Metrics
// FIXME: pars with newlines are still too wide!
if (hasFixedWidth())
tm.metrics(mi, dim, mi.base.textwidth, false);
else
tm.metrics(mi, dim, 0, false);
mi.base.textwidth += 2 * TEXT_TO_INSET_OFFSET;
dim.asc += TEXT_TO_INSET_OFFSET;
dim.des += TEXT_TO_INSET_OFFSET;
dim.wid += 2 * TEXT_TO_INSET_OFFSET;
}
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// //
@ -3921,8 +4013,7 @@ void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
} }
bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col) const
const
{ {
if (&cur.inset() == this && cur.selection()) { if (&cur.inset() == this && cur.selection()) {
if (cur.selIsMultiCell()) { if (cur.selIsMultiCell()) {
@ -5190,13 +5281,13 @@ bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
return true; return true;
} }
// fall through // fall through
case LFUN_NEWLINE_INSERT: { case LFUN_NEWLINE_INSERT:
if (tabular.getPWidth(cur.idx()).zero()) { if ((tabular.isMultiColumn(cur.idx()) || tabular.isMultiRow(cur.idx()))
&& tabular.getPWidth(cur.idx()).zero()) {
status.setEnabled(false); status.setEnabled(false);
return true; return true;
} else }
return cell(cur.idx())->getStatus(cur, cmd, status); return cell(cur.idx())->getStatus(cur, cmd, status);
}
case LFUN_NEWPAGE_INSERT: case LFUN_NEWPAGE_INSERT:
status.setEnabled(false); status.setEnabled(false);
@ -5863,7 +5954,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
// just multicol for one single cell // just multicol for one single cell
// check whether we are completely in a multicol // check whether we are completely in a multicol
if (!tabular.isMultiColumn(cur.idx())) if (!tabular.isMultiColumn(cur.idx()))
tabular.setMultiColumn(cur.idx(), 1, tabular.setMultiColumn(cur, cur.idx(), 1,
tabular.rightLine(cur.idx())); tabular.rightLine(cur.idx()));
break; break;
} }
@ -5872,7 +5963,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
idx_type const s_start = cur.selBegin().idx(); idx_type const s_start = cur.selBegin().idx();
row_type const col_start = tabular.cellColumn(s_start); row_type const col_start = tabular.cellColumn(s_start);
row_type const col_end = tabular.cellColumn(cur.selEnd().idx()); 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(cur, s_start, col_end - col_start + 1,
tabular.rightLine(cur.selEnd().idx())); tabular.rightLine(cur.selEnd().idx()));
cur.pit() = 0; cur.pit() = 0;
cur.pos() = 0; cur.pos() = 0;
@ -5918,7 +6009,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
// just multirow for one single cell // just multirow for one single cell
// check whether we are completely in a multirow // check whether we are completely in a multirow
if (!tabular.isMultiRow(cur.idx())) if (!tabular.isMultiRow(cur.idx()))
tabular.setMultiRow(cur.idx(), 1, tabular.setMultiRow(cur, cur.idx(), 1,
tabular.bottomLine(cur.idx()), tabular.bottomLine(cur.idx()),
tabular.getAlignment(cur.idx())); tabular.getAlignment(cur.idx()));
break; break;
@ -5928,7 +6019,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
idx_type const s_start = cur.selBegin().idx(); idx_type const s_start = cur.selBegin().idx();
row_type const row_start = tabular.cellRow(s_start); row_type const row_start = tabular.cellRow(s_start);
row_type const row_end = tabular.cellRow(cur.selEnd().idx()); 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(cur, s_start, row_end - row_start + 1,
tabular.bottomLine(cur.selEnd().idx()), tabular.bottomLine(cur.selEnd().idx()),
tabular.getAlignment(cur.selEnd().idx())); tabular.getAlignment(cur.selEnd().idx()));
cur.pit() = 0; cur.pit() = 0;
@ -6141,7 +6232,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
case Tabular::SET_LTCAPTION: { case Tabular::SET_LTCAPTION: {
if (tabular.ltCaption(row)) if (tabular.ltCaption(row))
break; break;
cur.idx() = tabular.setLTCaption(row, true); cur.idx() = tabular.setLTCaption(cur, row, true);
cur.pit() = 0; cur.pit() = 0;
cur.pos() = 0; cur.pos() = 0;
cur.selection(false); cur.selection(false);
@ -6157,7 +6248,7 @@ void InsetTabular::tabularFeatures(Cursor & cur,
case Tabular::UNSET_LTCAPTION: { case Tabular::UNSET_LTCAPTION: {
if (!tabular.ltCaption(row)) if (!tabular.ltCaption(row))
break; break;
cur.idx() = tabular.setLTCaption(row, false); cur.idx() = tabular.setLTCaption(cur, row, false);
cur.pit() = 0; cur.pit() = 0;
cur.pos() = 0; cur.pos() = 0;
cur.selection(false); cur.selection(false);
@ -6457,7 +6548,7 @@ bool InsetTabular::allowParagraphCustomization(idx_type cell) const
bool InsetTabular::forcePlainLayout(idx_type cell) const bool InsetTabular::forcePlainLayout(idx_type cell) const
{ {
return !tabular.getPWidth(cell).zero(); return tabular.isMultiColumn(cell) && !tabular.getPWidth(cell).zero();
} }

View File

@ -63,6 +63,10 @@ public:
/// ///
void toggleFixedWidth(bool fw) { isFixedWidth = fw; } void toggleFixedWidth(bool fw) { isFixedWidth = fw; }
/// ///
void toggleMultiCol(bool m) { isMultiColumn = m; }
///
void toggleMultiRow(bool m) { isMultiRow = m; }
///
void setContentAlignment(LyXAlignment al) {contentAlign = al; } void setContentAlignment(LyXAlignment al) {contentAlign = al; }
/// writes the contents of the cell as a string, optionally /// writes the contents of the cell as a string, optionally
/// descending into insets /// descending into insets
@ -72,14 +76,17 @@ public:
/// ///
void addToToc(DocIterator const & di, bool output_active, void addToToc(DocIterator const & di, bool output_active,
UpdateType utype, TocBackend & backend) const; UpdateType utype, TocBackend & backend) const;
///
void metrics(MetricsInfo &, Dimension &) const;
private: private:
/// unimplemented /// unimplemented
InsetTableCell(); InsetTableCell();
/// unimplemented /// unimplemented
void operator=(InsetTableCell const &); void operator=(InsetTableCell const &);
// FIXME // FIXME
// This boolean is supposed to track whether the cell has had its // These booleans are supposed to track whether the cell has had its
// width explicitly set. We need to know this to determine whether // width explicitly set and whether it is part of a multicolumn, respectively.
// We need to know this to determine whether
// layout changes and paragraph customization are allowed---that is, // layout changes and paragraph customization are allowed---that is,
// we need it in forcePlainLayout() and allowParagraphCustomization(). // we need it in forcePlainLayout() and allowParagraphCustomization().
// Unfortunately, that information is not readily available in // Unfortunately, that information is not readily available in
@ -102,6 +109,10 @@ private:
// --rgh // --rgh
/// ///
bool isFixedWidth; bool isFixedWidth;
///
bool isMultiColumn;
///
bool isMultiRow;
// FIXME: Here the thoughts from the comment above also apply. // FIXME: Here the thoughts from the comment above also apply.
/// ///
LyXAlignment contentAlign; LyXAlignment contentAlign;
@ -120,11 +131,7 @@ private:
/// Is the width forced to some value? /// Is the width forced to some value?
bool hasFixedWidth() const { return isFixedWidth; } bool hasFixedWidth() const { return isFixedWidth; }
/// Can the cell contain several paragraphs? /// Can the cell contain several paragraphs?
/** FIXME this is wrong for multirows, that are limited to one bool allowMultiPar() const { return !isMultiRow && (!isMultiColumn || isFixedWidth); }
* paragraph. However, we cannot test for this (see the big
* comment above).
*/
bool allowMultiPar() const { return isFixedWidth; }
}; };
@ -534,7 +541,9 @@ public:
/// ///
bool hasVarwidthColumn() const; bool hasVarwidthColumn() const;
/// ///
idx_type setMultiColumn(idx_type cell, idx_type number, bool isVTypeColumn(col_type cell) const;
///
idx_type setMultiColumn(Cursor & cur, idx_type cell, idx_type number,
bool const right_border); bool const right_border);
/// ///
void unsetMultiColumn(idx_type cell); void unsetMultiColumn(idx_type cell);
@ -547,7 +556,7 @@ public:
/// ///
bool hasMultiRow(row_type r) const; bool hasMultiRow(row_type r) const;
/// ///
idx_type setMultiRow(idx_type cell, idx_type number, idx_type setMultiRow(Cursor & cur, idx_type cell, idx_type number,
bool const bottom_border, bool const bottom_border,
LyXAlignment const halign); LyXAlignment const halign);
/// ///
@ -595,7 +604,7 @@ public:
/// ///
bool getLTNewPage(row_type row) const; bool getLTNewPage(row_type row) const;
/// ///
idx_type setLTCaption(row_type row, bool what); idx_type setLTCaption(Cursor & cur, row_type row, bool what);
/// ///
bool ltCaption(row_type row) const; bool ltCaption(row_type row) const;
/// ///
@ -804,7 +813,7 @@ public:
/// ///
idx_type rowSpan(idx_type cell) const; idx_type rowSpan(idx_type cell) const;
/// ///
BoxType useParbox(idx_type cell) const; BoxType useBox(idx_type cell) const;
/// ///
// helper function for Latex // helper function for Latex
/// ///

View File

@ -59,6 +59,7 @@ Format LaTeX feature LyX feature
546 Landscape support 546 Landscape support
\begin{landscape}...\end{landscape} \begin_inset Flex Landscape \begin{landscape}...\end{landscape} \begin_inset Flex Landscape
with longtable content: <features rotate ="90"...> with longtable content: <features rotate ="90"...>
555 V column type (varwidth package) Automatically detected with newlines, paragraph breaks and environment content in cells of rows

View File

@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in // Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own. // independent branches. Instead add your own.
#define LYX_FORMAT_LYX 554 // spitz: tabularx/xltabular #define LYX_FORMAT_LYX 555 // spitz: varwidth V columns
#define LYX_FORMAT_TEX2LYX 554 #define LYX_FORMAT_TEX2LYX 555
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX #if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER #ifndef _MSC_VER