#include "DispatchResult.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
+#include "InsetIterator.h"
#include "InsetList.h"
#include "Language.h"
#include "LaTeXFeatures.h"
#include "Paragraph.h"
#include "ParagraphParameters.h"
#include "ParIterator.h"
+#include "TexRow.h"
+#include "texstream.h"
#include "TextClass.h"
#include "TextMetrics.h"
#include "support/gettext.h"
#include "support/lassert.h"
#include "support/lstrings.h"
-
-#include <boost/scoped_ptr.hpp>
+#include "support/unique_ptr.h"
#include <cstring>
+#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
///
-boost::scoped_ptr<Tabular> paste_tabular;
+unique_ptr<Tabular> paste_tabular;
struct TabularFeature {
{
// the SET/UNSET actions are used by the table dialog,
// the TOGGLE actions by the table toolbar buttons
+ // FIXME: these values have been hardcoded in InsetMathGrid and other
+ // math insets.
{ Tabular::APPEND_ROW, "append-row", false },
{ Tabular::APPEND_COLUMN, "append-column", false },
{ Tabular::DELETE_ROW, "delete-row", false },
{ Tabular::SET_MROFFSET, "set-mroffset", true },
{ Tabular::SET_ALL_LINES, "set-all-lines", false },
{ Tabular::UNSET_ALL_LINES, "unset-all-lines", false },
+ { Tabular::TOGGLE_LONGTABULAR, "toggle-longtabular", false },
{ Tabular::SET_LONGTABULAR, "set-longtabular", false },
{ Tabular::UNSET_LONGTABULAR, "unset-longtabular", false },
{ Tabular::SET_PWIDTH, "set-pwidth", true },
{ Tabular::UNSET_LTCAPTION, "unset-ltcaption", false },
{ Tabular::SET_SPECIAL_COLUMN, "set-special-column", true },
{ Tabular::SET_SPECIAL_MULTICOLUMN, "set-special-multicolumn", true },
+ { Tabular::TOGGLE_BOOKTABS, "toggle-booktabs", false },
{ Tabular::SET_BOOKTABS, "set-booktabs", false },
{ Tabular::UNSET_BOOKTABS, "unset-booktabs", false },
{ Tabular::SET_TOP_SPACE, "set-top-space", true },
// I would have liked a fromstr template a lot better. (Lgb)
-bool string2type(string const str, LyXAlignment & num)
+bool string2type(string const & str, LyXAlignment & num)
{
if (str == "none")
num = LYX_ALIGN_NONE;
}
-bool string2type(string const str, Tabular::HAlignment & num)
+bool string2type(string const & str, Tabular::HAlignment & num)
{
if (str == "left")
num = Tabular::LYX_LONGTABULAR_ALIGN_LEFT;
}
-bool string2type(string const str, Tabular::VAlignment & num)
+bool string2type(string const & str, Tabular::VAlignment & num)
{
if (str == "top")
num = Tabular::LYX_VALIGN_TOP;
}
-bool string2type(string const str, Tabular::BoxType & num)
+bool string2type(string const & str, Tabular::BoxType & num)
{
if (str == "none")
num = Tabular::BOX_NONE;
}
-bool string2type(string const str, bool & num)
+bool string2type(string const & str, bool & num)
{
if (str == "true")
num = true;
}
-DocIterator separatorPos(InsetTableCell * cell, docstring const & align_d)
+DocIterator separatorPos(InsetTableCell const * cell, docstring const & align_d)
{
DocIterator dit = doc_iterator_begin(&(cell->buffer()), cell);
for (; dit; dit.forwardChar())
}
-InsetTableCell splitCell(InsetTableCell & head, docstring const align_d, bool & hassep)
+InsetTableCell splitCell(InsetTableCell & head, docstring const & align_d, bool & hassep)
{
InsetTableCell tail = InsetTableCell(head);
DocIterator const dit = separatorPos(&head, align_d);
- hassep = dit;
+ hassep = (bool)dit;
if (hassep) {
pit_type const psize = head.paragraphs().front().size();
head.paragraphs().front().eraseChars(dit.pos(), psize, false);
- tail.paragraphs().front().eraseChars(0,
+ tail.paragraphs().front().eraseChars(0,
dit.pos() < psize ? dit.pos() + 1 : psize, false);
}
{
}
-Tabular::CellData & Tabular::CellData::operator=(CellData cs)
-{
- swap(cs);
+Tabular::CellData & Tabular::CellData::operator=(CellData const & cs)
+{
+ if (&cs == this)
+ return *this;
+ cellno = cs.cellno;
+ width = cs.width;
+ multicolumn = cs.multicolumn;
+ multirow = cs.multirow;
+ mroffset = cs.mroffset;
+ alignment = cs.alignment;
+ valignment = cs.valignment;
+ decimal_hoffset = cs.decimal_hoffset;
+ decimal_width = cs.decimal_width;
+ voffset = cs.voffset;
+ top_line = cs.top_line;
+ bottom_line = cs.bottom_line;
+ left_line = cs.left_line;
+ right_line = cs.right_line;
+ usebox = cs.usebox;
+ rotate = cs.rotate;
+ align_special = cs.align_special;
+ p_width = cs.p_width;
+ inset.reset(static_cast<InsetTableCell *>(cs.inset->clone()));
return *this;
}
-void Tabular::CellData::swap(CellData & rhs)
-{
- std::swap(cellno, rhs.cellno);
- std::swap(width, rhs.width);
- std::swap(multicolumn, rhs.multicolumn);
- std::swap(multirow, rhs.multirow);
- std::swap(mroffset, rhs.mroffset);
- std::swap(alignment, rhs.alignment);
- std::swap(valignment, rhs.valignment);
- std::swap(decimal_hoffset, rhs.decimal_hoffset);
- std::swap(decimal_width, rhs.decimal_width);
- std::swap(voffset, rhs.voffset);
- std::swap(top_line, rhs.top_line);
- std::swap(bottom_line, rhs.bottom_line);
- std::swap(left_line, rhs.left_line);
- std::swap(right_line, rhs.right_line);
- std::swap(usebox, rhs.usebox);
- std::swap(rotate, rhs.rotate);
- std::swap(align_special, rhs.align_special);
- p_width.swap(rhs.p_width);
- inset.swap(rhs.inset);
-}
-
-
Tabular::RowData::RowData()
: ascent(0),
descent(0),
Tabular::ltType::ltType()
- : topDL(false),
+ : set(false), topDL(false),
bottomDL(false),
empty(false)
{}
void Tabular::insertRow(row_type const row, bool copy)
{
row_info.insert(row_info.begin() + row + 1, RowData(row_info[row]));
- cell_info.insert(cell_info.begin() + row + 1,
+ 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_));
if (cell_info[row][c].multirow == CELL_BEGIN_OF_MULTIROW)
cell_info[row + 1][c].multirow = CELL_PART_OF_MULTIROW;
}
-
+
updateIndexes();
for (col_type c = 0; c < ncols(); ++c) {
if (isPartOfMultiRow(row, c))
void Tabular::appendColumn(col_type col)
-{
+{
insertColumn(col, false);
}
setBottomLine(i, bottomLine(j));
setTopLine(i, topLine(j));
setLeftLine(i, leftLine(j));
+ setRightLine(i, rightLine(j));
if (rightLine(i) && rightLine(j)) {
- setRightLine(i, true);
setRightLine(j, false);
}
if (buffer().params().track_changes)
idx_type const i = cellIndex(r, c);
if (columnSpan(i) == 1) {
if (getAlignment(i) == LYX_ALIGN_DECIMAL
- && cell_info[r][c].decimal_width!=0)
- new_width = max(new_width, cellInfo(i).width
+ && cell_info[r][c].decimal_width != 0)
+ new_width = max(new_width, cellInfo(i).width
+ max_dwidth[c] - cellInfo(i).decimal_width);
else
new_width = max(new_width, cellInfo(i).width);
if (align == LYX_ALIGN_DECIMAL && dpoint.empty())
dpoint = from_utf8(lyxrc.default_decimal_point);
} else {
- cellInfo(cell).alignment = align;
- cellInset(cell).get()->setContentAlignment(align);
+ cellInfo(cell).alignment = align;
+ cellInset(cell)->setContentAlignment(align);
}
}
*/
void toggleFixedWidth(Cursor & cur, InsetTableCell * inset, bool fixedWidth)
{
- inset->setAutoBreakRows(fixedWidth);
inset->toggleFixedWidth(fixedWidth);
if (fixedWidth)
return;
cur.pop();
}
-}
+} // namespace
void Tabular::setColumnPWidth(Cursor & cur, idx_type cell,
col_type const c = cellColumn(cell);
column_info[c].p_width = width;
- // reset the vertical alignment to top if the fixed with
+ // reset the vertical alignment to top if the fixed width
// is removed or zero because only fixed width columns can
// have a vertical alignment
if (column_info[c].p_width.zero())
// because of multicolumns
toggleFixedWidth(cur, cellInset(cell).get(),
!getPWidth(cell).zero());
+ if (isMultiRow(cell))
+ setAlignment(cell, LYX_ALIGN_LEFT, false);
}
// cur paragraph can become invalid after paragraphs were merged
if (cur.pit() > cur.lastpit())
idx_type i = cellIndex(r, c);
if (c == cellColumn(i) + columnSpan(i) - 1) {
++total;
- bool left = (c + 1 < ncols()
+ bool left = (c + 1 < ncols()
&& cellInfo(cellIndex(r, c + 1)).left_line)
|| c + 1 == ncols();
if (cellInfo(i).right_line && left)
{
if (!onlycolumn && (isMultiColumn(cell) || isMultiRow(cell)))
return cellInfo(cell).alignment;
-
+
return column_info[cellColumn(cell)].alignment;
}
}
+int Tabular::offsetVAlignment() const
+{
+ // for top-alignment the first horizontal table line must be exactly at
+ // the position of the base line of the surrounding text line
+ // for bottom alignment, the same is for the last table line
+ int offset_valign = 0;
+ switch (tabular_valignment) {
+ case Tabular::LYX_VALIGN_BOTTOM:
+ offset_valign = rowAscent(0) - height();
+ break;
+ case Tabular::LYX_VALIGN_MIDDLE:
+ offset_valign = (- height()) / 2 + rowAscent(0);
+ break;
+ case Tabular::LYX_VALIGN_TOP:
+ offset_valign = rowAscent(0);
+ break;
+ }
+ return offset_valign;
+}
+
+
Length const Tabular::getPWidth(idx_type cell) const
{
if (isMultiColumn(cell))
int voffset = cellInfo(cell).voffset;
if (isMultiRow(cell)) {
row_type const row = cellRow(cell);
- voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2;
+ voffset += (cellHeight(cell) - rowAscent(row) - rowDescent(row))/2;
}
return voffset;
}
<< ">\n";
// global longtable options
os << "<features"
- << write_attribute("rotate", convert<string>(rotate))
+ << write_attribute("rotate", rotate)
<< write_attribute("booktabs", use_booktabs)
<< write_attribute("islongtable", is_long_tabular)
<< write_attribute("firstHeadTopDL", endfirsthead.topDL)
<< write_attribute("lastFootEmpty", endlastfoot.empty);
// longtables cannot be aligned vertically
if (!is_long_tabular) {
- os << write_attribute("tabularvalignment", tabular_valignment);
- os << write_attribute("tabularwidth", tabular_width);
+ os << write_attribute("tabularvalignment", tabular_valignment);
+ os << write_attribute("tabularwidth", tabular_width);
}
if (is_long_tabular)
- os << write_attribute("longtabularalignment",
- longtabular_alignment);
+ os << write_attribute("longtabularalignment", longtabular_alignment);
os << ">\n";
for (col_type c = 0; c < ncols(); ++c) {
os << "<column"
cell_info[r][c].inset->write(os);
os << "\n\\end_inset\n"
<< "</cell>\n";
+ // FIXME This can be removed again once the mystery
+ // crash has been resolved.
+ os << flush;
}
os << "</row>\n";
}
bool Tabular::isMultiColumn(idx_type cell) const
{
- return (cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN
+ return (cellInfo(cell).multicolumn == CELL_BEGIN_OF_MULTICOLUMN
|| cellInfo(cell).multicolumn == CELL_PART_OF_MULTICOLUMN);
}
}
-Tabular::CellData & Tabular::cellInfo(idx_type cell) const
+Tabular::CellData const & Tabular::cellInfo(idx_type cell) const
+{
+ return cell_info[cellRow(cell)][cellColumn(cell)];
+}
+
+
+Tabular::CellData & Tabular::cellInfo(idx_type cell)
{
return cell_info[cellRow(cell)][cellColumn(cell)];
}
cs.alignment = column_info[col].alignment;
setRightLine(cell, right_border);
- for (idx_type i = 1; i < number; ++i) {
+ idx_type lastcell = cellIndex(row, col + number - 1);
+ for (idx_type i = 1; i < lastcell - cell + 1; ++i) {
CellData & cs1 = cellInfo(cell + i);
cs1.multicolumn = CELL_PART_OF_MULTICOLUMN;
cs.inset->appendParagraphs(cs1.inset->paragraphs());
}
Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number,
- bool const bottom_border)
+ bool const bottom_border,
+ LyXAlignment const halign)
{
idx_type const col = cellColumn(cell);
idx_type const row = cellRow(cell);
// be changed for the whole table row,
// support changing this only for the multirow cell can be done via
// \multirowsetup
- // this feature would be a fileformat change
- // until LyX supports this, use the deault alignment of multirow
- // cells: left
- cs.alignment = LYX_ALIGN_LEFT;
+ if (getPWidth(cell).zero())
+ cs.alignment = halign;
+ else
+ cs.alignment = LYX_ALIGN_LEFT;
// set the bottom line of the last selected cell
setBottomLine(cell, bottom_border);
col_type row = cellRow(cell) + 1;
while (row < nrows() && isPartOfMultiRow(row, column))
++row;
-
+
return row - cellRow(cell);
}
bool Tabular::needRotating() const
{
- if (rotate)
+ if (rotate && !is_long_tabular)
return true;
for (row_type r = 0; r < nrows(); ++r)
for (col_type c = 0; c < ncols(); ++c)
{
if (cellRow(cell) == 0)
return cell;
-
+
col_type const col = cellColumn(cell);
row_type r = cellRow(cell) - 1;
while (r > 0 && cell_info[r][col].multirow == CELL_PART_OF_MULTIROW)
}
-void Tabular::TeXTopHLine(otexstream & os, row_type row, string const lang) const
+void Tabular::TeXTopHLine(otexstream & os, row_type row, string const & lang) const
{
// we only output complete row lines and the 1st row here, the rest
// is done in Tabular::TeXBottomHLine(...)
for (col_type j = 0 ; j < c; ++j)
if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
++offset;
-
+
//babel makes the "-" character an active one, so we have to suppress this here
//see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289#
if (lang == "slovak" || lang == "czech")
- os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline")
+ os << "\\expandafter" << (use_booktabs ? "\\cmidrule" : "\\cline")
<< "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-";
else
os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-';
-
+
col_type cstart = c;
for ( ; c < ncols() && topline[c]; ++c) {}
-
+
for (col_type j = cstart ; j < c ; ++j)
if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
++offset;
-
+
os << c + offset << "} ";
}
}
}
-void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const lang) const
+void Tabular::TeXBottomHLine(otexstream & os, row_type row, string const & lang) const
{
// we output bottomlines of row r and the toplines of row r+1
// if the latter do not span the whole tabular
for (col_type j = 0 ; j < c; ++j)
if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
++offset;
-
+
//babel makes the "-" character an active one, so we have to suppress this here
//see http://groups.google.com/group/comp.text.tex/browse_thread/thread/af769424a4a0f289#
if (lang == "slovak" || lang == "czech")
<< "\\expandafter{\\expandafter" << c + 1 + offset << "\\string-";
else
os << (use_booktabs ? "\\cmidrule{" : "\\cline{") << c + 1 + offset << '-';
-
+
col_type cstart = c;
for ( ; c < ncols() && bottomline[c]; ++c) {}
-
+
for (col_type j = cstart ; j < c ; ++j)
if (column_info[j].alignment == LYX_ALIGN_DECIMAL)
++offset;
-
+
os << c + offset << "} ";
}
}
bool colright = columnRightLine(c);
bool colleft = columnLeftLine(c);
bool nextcolleft = nextcol < ncols() && columnLeftLine(nextcol);
- bool nextcellleft = nextcol < ncols()
+ bool nextcellleft = nextcol < ncols()
&& leftLine(cellIndex(r, nextcol));
bool coldouble = colright && nextcolleft;
bool celldouble = rightLine(cell) && nextcellleft;
// we center in multicol when no decimal point
if (column_info[c].alignment == LYX_ALIGN_DECIMAL) {
docstring const align_d = column_info[c].decimal_point;
- DocIterator const dit = separatorPos(cellInset(cell).get(), align_d);
+ DocIterator const dit = separatorPos(cellInset(cell), align_d);
ismulticol |= !dit;
}
OutputParams const & runparams) const
{
idx_type cell = cellIndex(row, 0);
- shared_ptr<InsetTableCell> inset = cellInset(cell);
+ InsetTableCell const * inset = cellInset(cell);
Paragraph const & par = inset->paragraphs().front();
string const lang = par.getParLanguage(buffer().params())->lang();
if (isPartOfMultiRow(row, c)
&& column_info[c].alignment != LYX_ALIGN_DECIMAL) {
if (cell != getLastCellInRow(row))
- os << " & ";
+ os << " & ";
continue;
}
TeXCellPreamble(os, cell, ismulticol, ismultirow);
- shared_ptr<InsetTableCell> inset = cellInset(cell);
+ InsetTableCell const * inset = cellInset(cell);
Paragraph const & par = inset->paragraphs().front();
+
+ os.texrow().forceStart(par.id(), 0);
+
bool rtl = par.isRTL(buffer().params())
&& !par.empty()
&& getPWidth(cell).zero()
if (getAlignment(cell) == LYX_ALIGN_DECIMAL) {
// copy cell and split in 2
- InsetTableCell head = InsetTableCell(*cellInset(cell).get());
- head.setBuffer(buffer());
+ InsetTableCell head = InsetTableCell(*cellInset(cell));
+ head.setBuffer(const_cast<Buffer &>(buffer()));
DocIterator dit = cellInset(cell)->getText(0)->macrocontextPosition();
dit.pop_back();
dit.push_back(CursorSlice(head));
tail.setMacrocontextPositionRecursive(dit);
tail.latex(os, newrp);
}
+ } else if (ltCaption(row)) {
+ // Inside longtable caption rows, we must only output the caption inset
+ // with its content and omit anything outside of that (see #10791)
+ InsetIterator it = inset_iterator_begin(*const_cast<InsetTableCell *>(inset));
+ InsetIterator i_end = inset_iterator_end(*const_cast<InsetTableCell *>(inset));
+ for (; it != i_end; ++it) {
+ if (it->lyxCode() != CAPTION_CODE)
+ continue;
+ it->latex(os, runparams);
+ break;
+ }
} else if (!isPartOfMultiRow(row, c)) {
if (!runparams.nice)
os.texrow().start(par.id(), 0);
void Tabular::latex(otexstream & os, OutputParams const & runparams) const
{
bool const is_tabular_star = !tabular_width.zero();
+ TexRow::RowEntry pos = TexRow::textEntry(runparams.lastid, runparams.lastpos);
//+---------------------------------------------------------------------
//+ first the opening preamble +
//+---------------------------------------------------------------------
os << safebreakln;
- if (runparams.lastid != -1)
- os.texrow().start(runparams.lastid, runparams.lastpos);
+ if (!TexRow::isNone(pos))
+ os.texrow().start(pos);
- if (rotate != 0)
+ if (rotate != 0 && !is_long_tabular)
os << "\\begin{turn}{" << convert<string>(rotate) << "}\n";
if (is_long_tabular) {
break;
}
}
-
+
os << "{";
if (is_tabular_star)
os << column_info[c].align_special;
} else {
if (!column_info[c].p_width.zero()) {
+ bool decimal = false;
switch (column_info[c].alignment) {
case LYX_ALIGN_LEFT:
os << ">{\\raggedright}";
case LYX_ALIGN_BLOCK:
case LYX_ALIGN_LAYOUT:
case LYX_ALIGN_SPECIAL:
+ break;
case LYX_ALIGN_DECIMAL:
+ os << ">{\\raggedleft}";
+ decimal = true;
break;
}
+ char valign = 'p';
switch (column_info[c].valignment) {
case LYX_VALIGN_TOP:
- os << 'p';
+ // this is the default
break;
case LYX_VALIGN_MIDDLE:
- os << 'm';
+ valign = 'm';
break;
case LYX_VALIGN_BOTTOM:
- os << 'b';
+ valign = 'b';
break;
- }
- os << '{'
- << from_ascii(column_info[c].p_width.asLatexString())
- << '}';
+ }
+ os << valign;
+
+ // Fixed-width cells with alignment at decimal separator
+ // are output as two cells of half the width with the decimal
+ // separator as column sep. This effectively puts the content
+ // centered, which differs from the normal decimal sep alignment
+ // and is not ideal, but we cannot do better ATM (see #9568).
+ // FIXME: Implement proper decimal sep alignment, e.g. via siunitx.
+ if (decimal) {
+ docstring const halffixedwith =
+ from_ascii(Length(column_info[c].p_width.value() / 2,
+ column_info[c].p_width.unit()).asLatexString());
+ os << '{'
+ << halffixedwith
+ << '}'
+ << "@{\\extracolsep{0pt}" << column_info[c].decimal_point << "}"
+ << valign
+ << '{'
+ << halffixedwith
+ << '}';
+ } else
+ os << '{'
+ << from_ascii(column_info[c].p_width.asLatexString())
+ << '}';
} else {
switch (column_info[c].alignment) {
case LYX_ALIGN_LEFT:
os << "\\end{tabular}";
}
- if (rotate != 0)
+ if (rotate != 0 && !is_long_tabular)
os << breakln << "\\end{turn}";
+
+ if (!TexRow::isNone(pos))
+ os.texrow().start(pos);
}
continue;
stringstream attr;
+
+ Length const cwidth = column_info[c].p_width;
+ if (!cwidth.zero()) {
+ string const hwidth = cwidth.asHTMLString();
+ attr << "style =\"width: " << hwidth << ";\" ";
+ }
+
attr << "align='";
switch (getAlignment(cell)) {
case LYX_ALIGN_LEFT:
else if (isMultiRow(cell))
attr << " rowspan='" << rowSpan(cell) << "'";
- xs << html::StartTag(celltag, attr.str()) << html::CR();
+ xs << html::StartTag(celltag, attr.str(), true) << html::CR();
ret += cellInset(cell)->xhtml(xs, runparams);
xs << html::EndTag(celltag) << html::CR();
++cell;
}
-shared_ptr<InsetTableCell> Tabular::cellInset(idx_type cell) const
+shared_ptr<InsetTableCell> Tabular::cellInset(idx_type cell)
{
return cell_info[cellRow(cell)][cellColumn(cell)].inset;
}
-shared_ptr<InsetTableCell> Tabular::cellInset(row_type row,
- col_type column) const
+shared_ptr<InsetTableCell> Tabular::cellInset(row_type row, col_type column)
{
return cell_info[row][column].inset;
}
+InsetTableCell const * Tabular::cellInset(idx_type cell) const
+{
+ return cell_info[cellRow(cell)][cellColumn(cell)].inset.get();
+}
+
+
void Tabular::setCellInset(row_type row, col_type column,
- shared_ptr<InsetTableCell> ins) const
+ shared_ptr<InsetTableCell> ins)
{
CellData & cd = cell_info[row][column];
cd.inset = ins;
if (getVAlignment(cell) != LYX_VALIGN_TOP
|| !getPWidth(cell).zero())
features.require("array");
+ // Tell footnote that we need a savenote
+ // environment in non-long tables or
+ // longtable headers/footers
+ else if (!is_long_tabular && !features.inFloat())
+ features.saveNoteEnv("tabular");
+ else if (!isValidRow(cellRow(cell)))
+ features.saveNoteEnv("longtable");
+
cellInset(cell)->validate(features);
+ features.saveNoteEnv(string());
}
}
}
+bool InsetTableCell::forceLocalFontSwitch() const
+{
+ return isFixedWidth;
+}
+
+
bool InsetTableCell::getStatus(Cursor & cur, FuncRequest const & cmd,
FuncStatus & status) const
{
bool enabled = true;
switch (cmd.action()) {
- case LFUN_LAYOUT:
- enabled = !forcePlainLayout();
- break;
- case LFUN_LAYOUT_PARAGRAPH:
- enabled = allowParagraphCustomization();
- break;
-
case LFUN_MATH_DISPLAY:
if (!hasFixedWidth()) {
enabled = false;
return true;
}
-docstring InsetTableCell::asString(bool intoInsets)
+docstring InsetTableCell::asString(bool intoInsets)
{
docstring retval;
if (paragraphs().empty())
}
-void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const
+void InsetTableCell::addToToc(DocIterator const & di, bool output_active,
+ UpdateType utype, TocBackend & backend) const
{
- InsetText::iterateForToc(di, output_active);
+ InsetText::iterateForToc(di, output_active, utype, backend);
}
InsetTabular::InsetTabular(Buffer * buf, row_type rows,
col_type columns)
- : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))), scx_(0),
- rowselect_(false), colselect_(false)
+ : Inset(buf), tabular(buf, max(rows, row_type(1)), max(columns, col_type(1))),
+ rowselect_(false), colselect_(false)
{
}
InsetTabular::InsetTabular(InsetTabular const & tab)
- : Inset(tab), tabular(tab.tabular), scx_(0)
+ : Inset(tab), tabular(tab.tabular),
+ rowselect_(false), colselect_(false)
{
}
bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const
{
return tabular.is_long_tabular &&
- (newtype == "Standard" || newtype == "LongTableNoNumber");
+ (newtype == "Standard" || newtype == "Unnumbered");
}
int InsetTabular::rowFromY(Cursor & cur, int y) const
{
// top y coordinate of tabular
- int h = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_;
+ int h = yo(cur.bv()) - tabular.rowAscent(0) + tabular.offsetVAlignment();
row_type r = 0;
for (; r < tabular.nrows() && y > h; ++r)
h += tabular.rowAscent(r) + tabular.rowDescent(r)
MetricsInfo m = mi;
Length const p_width = tabular.getPWidth(cell);
if (!p_width.zero())
- m.base.textwidth = p_width.inPixels(mi.base.textwidth);
+ m.base.textwidth = mi.base.inPixels(p_width);
tabular.cellInset(cell)->metrics(m, dim);
if (!p_width.zero())
dim.wid = m.base.textwidth;
- tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE
+ tabular.cellInfo(cell).width = dim.wid + 2 * WIDTH_OF_LINE
+ tabular.interColumnSpace(cell);
// FIXME(?): do we need a second metrics call?
- TextMetrics const & tm =
+ TextMetrics const & tm =
mi.base.bv->textMetrics(tabular.cellInset(cell)->getText(0));
// 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).get());
+ InsetTableCell tail = InsetTableCell(*tabular.cellInset(cell));
tail.setBuffer(tabular.buffer());
// we need to set macrocontext position everywhere
// otherwise we crash with nested insets (e.g. footnotes)
int const lastpardes = tm.last().second->descent()
+ TEXT_TO_INSET_OFFSET;
int offset = 0;
- switch (tabular.getVAlignment(cell)) {
+ switch (tabular.getVAlignment(cell)) {
case Tabular::LYX_VALIGN_TOP:
- break;
+ break;
case Tabular::LYX_VALIGN_MIDDLE:
- offset = -(dim.des - lastpardes)/2;
- break;
+ offset = -(dim.des - lastpardes)/2;
+ break;
case Tabular::LYX_VALIGN_BOTTOM:
- offset = -(dim.des - lastpardes);
+ offset = -(dim.des - lastpardes);
break;
}
tabular.cell_info[r][c].voffset = offset;
maxdes = max(maxdes, dim.des + offset);
}
int const top_space = tabular.row_info[r].top_space_default ?
- default_line_space :
- tabular.row_info[r].top_space.inPixels(mi.base.textwidth);
+ default_line_space :
+ mi.base.inPixels(tabular.row_info[r].top_space);
tabular.setRowAscent(r, maxasc + ADD_TO_HEIGHT + top_space);
int const bottom_space = tabular.row_info[r].bottom_space_default ?
- default_line_space :
- tabular.row_info[r].bottom_space.inPixels(mi.base.textwidth);
+ default_line_space :
+ mi.base.inPixels(tabular.row_info[r].bottom_space);
tabular.setRowDescent(r, maxdes + ADD_TO_HEIGHT + bottom_space);
}
- // for top-alignment the first horizontal table line must be exactly at
- // the position of the base line of the surrounding text line
- // for bottom alignment, the same is for the last table line
- switch (tabular.tabular_valignment) {
- case Tabular::LYX_VALIGN_BOTTOM:
- offset_valign_ = tabular.rowAscent(0) - tabular.height();
- break;
- case Tabular::LYX_VALIGN_MIDDLE:
- offset_valign_ = (- tabular.height()) / 2 + tabular.rowAscent(0);
- break;
- case Tabular::LYX_VALIGN_TOP:
- offset_valign_ = tabular.rowAscent(0);
- break;
- }
-
tabular.updateColumnWidths();
- dim.asc = tabular.rowAscent(0) - offset_valign_;
+ dim.asc = tabular.rowAscent(0) - tabular.offsetVAlignment();
dim.des = tabular.height() - dim.asc;
dim.wid = tabular.width() + 2 * ADD_TO_TABULAR_WIDTH;
}
-bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col)
+bool InsetTabular::isCellSelected(Cursor & cur, row_type row, col_type col)
const
{
if (&cur.inset() == this && cur.selection()) {
row_type rs, re;
col_type cs, ce;
getSelection(cur, rs, re, cs, ce);
-
+
idx_type const cell = tabular.cellIndex(row, col);
col_type const cspan = tabular.columnSpan(cell);
row_type const rspan = tabular.rowSpan(cell);
- if (col + cspan - 1 >= cs && col <= ce
+ if (col + cspan - 1 >= cs && col <= ce
&& row + rspan - 1 >= rs && row <= re)
return true;
- } else
- if (col == tabular.cellColumn(cur.idx())
+ } else
+ if (col == tabular.cellColumn(cur.idx())
&& row == tabular.cellRow(cur.idx())) {
CursorSlice const & beg = cur.selBegin();
CursorSlice const & end = cur.selEnd();
void InsetTabular::draw(PainterInfo & pi, int x, int y) const
{
- x += scx_ + ADD_TO_TABULAR_WIDTH;
+ x += ADD_TO_TABULAR_WIDTH;
BufferView * bv = pi.base.bv;
Cursor & cur = pi.base.bv->cursor();
- resetPos(cur);
// FIXME: As the full background is painted in drawBackground(),
// we have no choice but to do a full repaint for the Text cells.
bool const original_selection_state = pi.selected;
idx_type idx = 0;
- first_visible_cell = Tabular::npos;
- int yy = y + offset_valign_;
+ int yy = y + tabular.offsetVAlignment();
for (row_type r = 0; r < tabular.nrows(); ++r) {
int nx = x;
for (col_type c = 0; c < tabular.ncols(); ++c) {
if (tabular.isPartOfMultiColumn(r, c))
continue;
-
+
idx = tabular.cellIndex(r, c);
-
+
if (tabular.isPartOfMultiRow(r, c)) {
nx += tabular.cellWidth(idx);
continue;
}
- if (first_visible_cell == Tabular::npos)
- first_visible_cell = idx;
-
pi.selected |= isCellSelected(cur, r, c);
int const cx = nx + tabular.textHOffset(idx);
int const cy = yy + tabular.textVOffset(idx);
}
if (r + 1 < tabular.nrows())
- yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ yy += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ tabular.interRowSpace(r + 1);
}
}
void InsetTabular::drawBackground(PainterInfo & pi, int x, int y) const
{
- x += scx_ + ADD_TO_TABULAR_WIDTH;
- y += offset_valign_ - tabular.rowAscent(0);
+ x += ADD_TO_TABULAR_WIDTH;
+ y += tabular.offsetVAlignment() - tabular.rowAscent(0);
pi.pain.fillRectangle(x, y, tabular.width(), tabular.height(),
pi.backgroundColor(this));
}
void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
{
Cursor & cur = pi.base.bv->cursor();
- resetPos(cur);
- x += scx_ + ADD_TO_TABULAR_WIDTH;
+ x += ADD_TO_TABULAR_WIDTH;
if (!cur.selection())
return;
}
int const w = tabular.cellWidth(cell);
int const h = tabular.cellHeight(cell);
- int const yy = y - tabular.rowAscent(r) + offset_valign_;
+ int const yy = y - tabular.rowAscent(r) + tabular.offsetVAlignment();
if (isCellSelected(cur, r, c))
pi.pain.fillRectangle(xx, yy, w, h, Color_selection);
xx += w;
+ tabular.interRowSpace(r + 1);
}
- }
+ }
// FIXME: This code has no effect because InsetTableCell does not handle
// drawSelection other than the trivial implementation in Inset.
//else {
// Right
x -= tabular.interColumnSpace(cell);
col_type next_cell_col = col + 1;
- while (next_cell_col < tabular.ncols()
+ while (next_cell_col < tabular.ncols()
&& tabular.isMultiColumn(tabular.cellIndex(row, next_cell_col)))
next_cell_col++;
drawline = tabular.rightLine(cell)
{
//lyxerr << "InsetTabular::edit: " << this << endl;
cur.finishUndo();
- cur.setSelection(false);
cur.push(*this);
if (front) {
if (isRightToLeft(cur))
}
cur.setCurrentFont();
// FIXME: this accesses the position cache before it is initialized
- //resetPos(cur);
//cur.bv().fitCursor();
}
}
-void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const
+void InsetTabular::addToToc(DocIterator const & cpit, bool output_active,
+ UpdateType utype, TocBackend & backend) const
{
DocIterator dit = cpit;
dit.forwardPos();
size_t const end = dit.nargs();
for ( ; dit.idx() < end; dit.top().forwardIdx())
- cell(dit.idx())->addToToc(dit, output_active);
+ cell(dit.idx())->addToToc(dit, output_active, utype, backend);
+}
+
+
+bool InsetTabular::hitSelectRow(BufferView const & bv, int x) const
+{
+ int const x0 = xo(bv) + ADD_TO_TABULAR_WIDTH;
+ return x < x0 || x > x0 + tabular.width();
+}
+
+
+bool InsetTabular::hitSelectColumn(BufferView const & bv, int y) const
+{
+ int const y0 = yo(bv) - tabular.rowAscent(0) + tabular.offsetVAlignment();
+ // FIXME: using ADD_TO_TABULAR_WIDTH is not really correct since
+ // there is no margin added vertically to tabular insets.
+ // However, it works for now.
+ return y < y0 + ADD_TO_TABULAR_WIDTH || y > y0 + tabular.height() - ADD_TO_TABULAR_WIDTH;
+}
+
+
+bool InsetTabular::clickable(BufferView const & bv, int x, int y) const
+{
+ return hitSelectRow(bv, x) || hitSelectColumn(bv, y);
}
Cursor & bvcur = cur.bv().cursor();
FuncCode const act = cmd.action();
-
+
switch (act) {
case LFUN_MOUSE_PRESS: {
//lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl;
// select row
- if (cmd.x() < xo(cur.bv()) + ADD_TO_TABULAR_WIDTH
- || cmd.x() > xo(cur.bv()) + tabular.width()) {
+ if (hitSelectRow(cur.bv(), cmd.x())) {
row_type r = rowFromY(cur, cmd.y());
cur.idx() = tabular.getFirstCellInRow(r);
+ cur.pit() = 0;
cur.pos() = 0;
cur.resetAnchor();
cur.idx() = tabular.getLastCellInRow(r);
+ cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
- cur.setSelection(true);
- bvcur = cur;
+ cur.selection(true);
+ bvcur = cur;
rowselect_ = true;
break;
}
// select column
- int const y0 = yo(cur.bv()) - tabular.rowAscent(0) + offset_valign_;
- if (cmd.y() < y0 + ADD_TO_TABULAR_WIDTH
- || cmd.y() > y0 + tabular.height()) {
+ if (hitSelectColumn(cur.bv(), cmd.y())) {
col_type c = columnFromX(cur, cmd.x());
cur.idx() = tabular.cellIndex(0, c);
+ cur.pit() = 0;
cur.pos() = 0;
cur.resetAnchor();
cur.idx() = tabular.cellIndex(tabular.nrows() - 1, c);
+ cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
- cur.setSelection(true);
- bvcur = cur;
+ cur.selection(true);
+ bvcur = cur;
colselect_ = true;
break;
}
// do not reset cursor/selection if we have selected
// some cells (bug 2715).
if (cmd.button() == mouse_button::button3
- && &bvcur.selBegin().inset() == this
- && bvcur.selIsMultiCell())
+ && &bvcur.selBegin().inset() == this
+ && bvcur.selIsMultiCell())
;
else
// Let InsetTableCell do it
cur.pit() = 0;
cur.pos() = 0;
bvcur.setCursor(cur);
- bvcur.setSelection(true);
+ bvcur.selection(true);
break;
}
// select (additional) column
cur.pit() = 0;
cur.pos() = 0;
bvcur.setCursor(cur);
- bvcur.setSelection(true);
+ bvcur.selection(true);
break;
}
// only update if selection changes
cur.noScreenUpdate();
setCursorFromCoordinates(cur, cmd.x(), cmd.y());
bvcur.setCursor(cur);
- bvcur.setSelection(true);
+ bvcur.selection(true);
// if this is a multicell selection, we just set the cursor to
// the beginning of the cell's text.
if (bvcur.selIsMultiCell()) {
case LFUN_CELL_BACKWARD:
movePrevCell(cur);
- cur.setSelection(false);
+ cur.selection(false);
break;
case LFUN_CELL_FORWARD:
moveNextCell(cur);
- cur.setSelection(false);
+ cur.selection(false);
break;
case LFUN_CHAR_FORWARD_SELECT:
case LFUN_CHAR_RIGHT_SELECT:
case LFUN_CHAR_RIGHT:
case LFUN_CHAR_LEFT_SELECT:
- case LFUN_CHAR_LEFT:
+ case LFUN_CHAR_LEFT:
case LFUN_WORD_FORWARD:
case LFUN_WORD_FORWARD_SELECT:
case LFUN_WORD_BACKWARD:
case LFUN_WORD_RIGHT_SELECT:
case LFUN_WORD_LEFT:
case LFUN_WORD_LEFT_SELECT: {
- // determine whether we move to next or previous cell, where to enter
+ // determine whether we move to next or previous cell, where to enter
// the new cell from, and which command to "finish" (i.e., exit the
// inset) with:
bool next_cell;
EntryDirection entry_from = ENTRY_DIRECTION_IGNORE;
FuncCode finish_lfun;
- if (act == LFUN_CHAR_FORWARD
+ if (act == LFUN_CHAR_FORWARD
|| act == LFUN_CHAR_FORWARD_SELECT
|| act == LFUN_WORD_FORWARD
|| act == LFUN_WORD_FORWARD_SELECT) {
next_cell = false;
finish_lfun = LFUN_FINISHED_BACKWARD;
}
- // LEFT or RIGHT commands --- the interpretation will depend on the
+ // LEFT or RIGHT commands --- the interpretation will depend on the
// table's direction.
else {
bool const right = act == LFUN_CHAR_RIGHT
|| act == LFUN_WORD_RIGHT
|| act == LFUN_WORD_RIGHT_SELECT;
next_cell = isRightToLeft(cur) != right;
-
+
if (lyxrc.visual_cursor)
entry_from = right ? ENTRY_DIRECTION_LEFT:ENTRY_DIRECTION_RIGHT;
finish_lfun = right ? LFUN_FINISHED_RIGHT : LFUN_FINISHED_LEFT;
}
- bool const select = act == LFUN_CHAR_FORWARD_SELECT
+ bool const select = act == LFUN_CHAR_FORWARD_SELECT
|| act == LFUN_CHAR_BACKWARD_SELECT
|| act == LFUN_CHAR_RIGHT_SELECT
|| act == LFUN_CHAR_LEFT_SELECT
|| act == LFUN_WORD_BACKWARD_SELECT
|| act == LFUN_WORD_LEFT_SELECT;
- // If we have a multicell selection or we're
+ // If we have a multicell selection or we're
// not doing some LFUN_*_SELECT thing anyway...
if (!cur.selIsMultiCell() || !select) {
col_type const c = tabular.cellColumn(cur.idx());
row_type const r = tabular.cellRow(cur.idx());
- // Are we trying to select the whole cell and is the whole cell
+ // Are we trying to select the whole cell and is the whole cell
// not yet selected?
bool const select_whole = select && !isCellSelected(cur, r, c) &&
- ((next_cell && cur.pit() == cur.lastpit()
+ ((next_cell && cur.pit() == cur.lastpit()
&& cur.pos() == cur.lastpos())
|| (!next_cell && cur.pit() == 0 && cur.pos() == 0));
break;
}
- // FIXME: When we support the selection of an empty cell, remove
+ // FIXME: When we support the selection of an empty cell, remove
// the !empty_cell from this condition. For now we jump to the next
// cell if the current cell is empty.
if (cur.result().dispatched() && !empty_cell)
else
movePrevCell(cur, entry_from);
// if we're exiting the table, call the appropriate FINISHED lfun
- if (sl == cur.top())
+ if (sl == cur.top()) {
cmd = FuncRequest(finish_lfun);
- else
+ cur.undispatched();
+ } else
cur.dispatched();
cur.screenUpdateFlags(Update::Force | Update::FitCursor);
case LFUN_DOWN:
if (!(cur.selection() && cur.selIsMultiCell()))
cell(cur.idx())->dispatch(cur, cmd);
-
+
cur.dispatched(); // override the cell's decision
if (sl == cur.top()) {
// if our Text didn't do anything to the cursor
cur.screenUpdateFlags(Update::Force | Update::FitCursor);
break;
-// case LFUN_SCREEN_DOWN: {
-// //if (hasSelection())
-// // cur.selection() = false;
-// col_type const col = tabular.cellColumn(cur.idx());
-// int const t = cur.bv().top_y() + cur.bv().height();
-// if (t < yo() + tabular.getHeightOfTabular()) {
-// cur.bv().scrollDocView(t, true);
-// cur.idx() = tabular.cellBelow(first_visible_cell) + col;
-// } else {
-// cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1) + col;
-// }
-// cur.par() = 0;
-// cur.pos() = 0;
-// break;
-// }
-//
-// case LFUN_SCREEN_UP: {
-// //if (hasSelection())
-// // cur.selection() = false;
-// col_type const col = tabular.cellColumn(cur.idx());
-// int const t = cur.bv().top_y() + cur.bv().height();
-// if (yo() < 0) {
-// cur.bv().scrollDocView(t, true);
-// if (yo() > 0)
-// cur.idx() = col;
-// else
-// cur.idx() = tabular.cellBelow(first_visible_cell) + col;
-// } else {
-// cur.idx() = col;
-// }
-// cur.par() = cur.lastpar();
-// cur.pos() = cur.lastpos();
-// break;
-// }
-
case LFUN_LAYOUT_TABULAR:
cur.bv().showDialog("tabular");
break;
- case LFUN_INSET_MODIFY: {
- string arg;
- if (cmd.getArg(1) == "from-dialog")
- arg = cmd.getArg(0) + to_utf8(cmd.argument().substr(19));
+ case LFUN_INSET_MODIFY:
+ // we come from the dialog
+ if (cmd.getArg(0) == "tabular")
+ tabularFeatures(cur, cmd.getLongArg(1));
else
- arg = to_utf8(cmd.argument());
- if (!tabularFeatures(cur, arg))
cur.undispatched();
break;
- }
+
+ case LFUN_TABULAR_FEATURE:
+ tabularFeatures(cur, to_utf8(cmd.argument()));
+ break;
// insert file functions
case LFUN_FILE_INSERT_PLAINTEXT_PARA:
FileName(to_utf8(cmd.argument())));
if (tmpstr.empty())
break;
- cur.recordUndoInset(INSERT_UNDO);
+ cur.recordUndoInset();
if (insertPlaintextString(cur.bv(), tmpstr, false)) {
// content has been replaced,
// so cursor might be invalid
case LFUN_CUT:
if (cur.selIsMultiCell()) {
if (copySelection(cur)) {
- cur.recordUndoInset(DELETE_UNDO);
+ cur.recordUndoInset();
cutSelection(cur);
}
} else
case LFUN_SELF_INSERT:
if (cur.selIsMultiCell()) {
- cur.recordUndoInset(DELETE_UNDO);
+ cur.recordUndoInset();
cutSelection(cur);
BufferView * bv = &cur.bv();
docstring::const_iterator cit = cmd.argument().begin();
docstring::const_iterator const end = cmd.argument().end();
for (; cit != end; ++cit)
bv->translateAndInsert(*cit, getText(cur.idx()), cur);
-
+
cur.resetAnchor();
bv->bookmarkEditPosition();
} else
case LFUN_CHAR_DELETE_BACKWARD:
case LFUN_CHAR_DELETE_FORWARD:
if (cur.selIsMultiCell()) {
- cur.recordUndoInset(DELETE_UNDO);
+ cur.recordUndoInset();
cutSelection(cur);
} else
cell(cur.idx())->dispatch(cur, cmd);
// pass to InsertPlaintextString, but
// only if we have multi-cell content
if (clip.find_first_of(from_ascii("\t\n")) != docstring::npos) {
- cur.recordUndoInset(INSERT_UNDO);
+ cur.recordUndoInset();
if (insertPlaintextString(cur.bv(), clip, false)) {
// content has been replaced,
// so cursor might be invalid
break;
}
if (theClipboard().isInternal()) {
- cur.recordUndoInset(INSERT_UNDO);
+ cur.recordUndoInset();
pasteClipboard(cur);
}
break;
case LFUN_FONT_SIZE:
case LFUN_FONT_UNDERLINE:
case LFUN_FONT_STRIKEOUT:
+ case LFUN_FONT_CROSSOUT:
case LFUN_FONT_UNDERUNDERLINE:
case LFUN_FONT_UNDERWAVE:
case LFUN_LANGUAGE:
}
-// function sets an object as defined in func_status.h:
-// states OK, Unknown, Disabled, On, Off.
-bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
- FuncStatus & status) const
+bool InsetTabular::getFeatureStatus(Cursor & cur, string const & s,
+ string const & argument, FuncStatus & status) const
{
- switch (cmd.action()) {
- case LFUN_INSET_MODIFY: {
- if (&cur.inset() != this || cmd.getArg(0) != "tabular")
- break;
-
- // FIXME: We only check for the very first argument...
- string const s = cmd.getArg(1);
- // We always enable the lfun if it is coming from the dialog
- // because the dialog makes sure all the settings are valid,
- // even though the first argument might not be valid now.
- if (s == "from-dialog") {
- status.setEnabled(true);
- return true;
- }
int action = Tabular::LAST_ACTION;
int i = 0;
return true;
}
- string const argument = cmd.getLongArg(2);
-
row_type sel_row_start = 0;
row_type sel_row_end = 0;
col_type sel_col_start = 0;
case Tabular::SET_LINE_TOP:
case Tabular::SET_LINE_BOTTOM:
+ status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+ break;
+
case Tabular::SET_LINE_LEFT:
case Tabular::SET_LINE_RIGHT:
- status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+ status.setEnabled(!tabular.use_booktabs
+ && !tabular.ltCaption(tabular.cellRow(cur.idx())));
break;
case Tabular::TOGGLE_LINE_TOP:
break;
case Tabular::TOGGLE_LINE_LEFT:
- status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+ status.setEnabled(!tabular.use_booktabs
+ && !tabular.ltCaption(tabular.cellRow(cur.idx())));
status.setOnOff(tabular.leftLine(cur.idx()));
break;
case Tabular::TOGGLE_LINE_RIGHT:
- status.setEnabled(!tabular.ltCaption(tabular.cellRow(cur.idx())));
+ status.setEnabled(!tabular.use_booktabs
+ && !tabular.ltCaption(tabular.cellRow(cur.idx())));
status.setOnOff(tabular.rightLine(cur.idx()));
break;
// therefore allow always left but right and center only if there is no width
case Tabular::M_ALIGN_LEFT:
flag = false;
+ // fall through
case Tabular::ALIGN_LEFT:
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_LEFT);
break;
case Tabular::M_ALIGN_RIGHT:
flag = false;
+ // fall through
case Tabular::ALIGN_RIGHT:
- status.setEnabled(!(tabular.isMultiRow(cur.idx())
+ status.setEnabled(!(tabular.isMultiRow(cur.idx())
&& !tabular.getPWidth(cur.idx()).zero()));
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_RIGHT);
break;
case Tabular::M_ALIGN_CENTER:
flag = false;
+ // fall through
case Tabular::ALIGN_CENTER:
- status.setEnabled(!(tabular.isMultiRow(cur.idx())
+ status.setEnabled(!(tabular.isMultiRow(cur.idx())
&& !tabular.getPWidth(cur.idx()).zero()));
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_CENTER);
break;
break;
case Tabular::ALIGN_DECIMAL:
- status.setEnabled(!tabular.isMultiRow(cur.idx())
+ status.setEnabled(!tabular.isMultiRow(cur.idx())
&& !tabular.isMultiColumn(cur.idx()));
status.setOnOff(tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_DECIMAL);
break;
case Tabular::M_VALIGN_TOP:
flag = false;
+ // fall through
case Tabular::VALIGN_TOP:
status.setEnabled(!tabular.getPWidth(cur.idx()).zero()
&& !tabular.isMultiRow(cur.idx()));
case Tabular::M_VALIGN_BOTTOM:
flag = false;
+ // fall through
case Tabular::VALIGN_BOTTOM:
status.setEnabled(!tabular.getPWidth(cur.idx()).zero()
&& !tabular.isMultiRow(cur.idx()));
case Tabular::M_VALIGN_MIDDLE:
flag = false;
+ // fall through
case Tabular::VALIGN_MIDDLE:
status.setEnabled(!tabular.getPWidth(cur.idx()).zero()
&& !tabular.isMultiRow(cur.idx()));
break;
case Tabular::SET_LONGTABULAR:
+ case Tabular::TOGGLE_LONGTABULAR:
// setting as longtable is not allowed when table is inside a float
if (cur.innerInsetOfType(FLOAT_CODE) != 0
|| cur.innerInsetOfType(WRAP_CODE) != 0)
case Tabular::TABULAR_VALIGN_TOP:
status.setEnabled(tabular.tabular_width.zero());
- status.setOnOff(tabular.tabular_valignment
+ status.setOnOff(tabular.tabular_valignment
== Tabular::LYX_VALIGN_TOP);
break;
case Tabular::TABULAR_VALIGN_MIDDLE:
status.setEnabled(tabular.tabular_width.zero());
- status.setOnOff(tabular.tabular_valignment
+ status.setOnOff(tabular.tabular_valignment
== Tabular::LYX_VALIGN_MIDDLE);
break;
case Tabular::TABULAR_VALIGN_BOTTOM:
status.setEnabled(tabular.tabular_width.zero());
- status.setOnOff(tabular.tabular_valignment
+ status.setOnOff(tabular.tabular_valignment
== Tabular::LYX_VALIGN_BOTTOM);
break;
case Tabular::LONGTABULAR_ALIGN_LEFT:
- status.setOnOff(tabular.longtabular_alignment
+ status.setOnOff(tabular.longtabular_alignment
== Tabular::LYX_LONGTABULAR_ALIGN_LEFT);
break;
case Tabular::LONGTABULAR_ALIGN_CENTER:
- status.setOnOff(tabular.longtabular_alignment
+ status.setOnOff(tabular.longtabular_alignment
== Tabular::LYX_LONGTABULAR_ALIGN_CENTER);
break;
case Tabular::LONGTABULAR_ALIGN_RIGHT:
- status.setOnOff(tabular.longtabular_alignment
+ status.setOnOff(tabular.longtabular_alignment
== Tabular::LYX_LONGTABULAR_ALIGN_RIGHT);
break;
status.setOnOff(tabular.ltCaption(sel_row_start));
break;
+ case Tabular::TOGGLE_BOOKTABS:
case Tabular::SET_BOOKTABS:
status.setOnOff(tabular.use_booktabs);
break;
break;
}
return true;
+}
+
+
+// function sets an object as defined in FuncStatus.h:
+// states OK, Unknown, Disabled, On, Off.
+bool InsetTabular::getStatus(Cursor & cur, FuncRequest const & cmd,
+ FuncStatus & status) const
+{
+ switch (cmd.action()) {
+ case LFUN_INSET_MODIFY:
+ if (cmd.getArg(0) != "tabular")
+ break;
+ if (cmd.getArg(1) == "for-dialog") {
+ // The dialog is asking the status of a command
+ if (&cur.inset() != this)
+ break;
+ string action = cmd.getArg(2);
+ string arg = cmd.getLongArg(3);
+ return getFeatureStatus(cur, action, arg, status);
+ } else {
+ // We always enable the lfun if it is coming from the dialog
+ // because the dialog makes sure all the settings are valid,
+ // even though the first argument might not be valid now.
+ status.setEnabled(true);
+ return true;
+ }
+
+ case LFUN_TABULAR_FEATURE: {
+ if (&cur.inset() != this)
+ break;
+ string action = cmd.getArg(0);
+ string arg = cmd.getLongArg(1);
+ return getFeatureStatus(cur, action, arg, status);
}
case LFUN_CAPTION_INSERT: {
}
// check if there is already a caption
bool have_caption = false;
- InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get());
+ InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()));
ParagraphList::const_iterator pit = itc.paragraphs().begin();
ParagraphList::const_iterator pend = itc.paragraphs().end();
for (; pit != pend; ++pit) {
status.setEnabled(false);
return true;
}
+ // fall through
case LFUN_NEWLINE_INSERT: {
if (tabular.getPWidth(cur.idx()).zero()) {
status.setEnabled(false);
getSelection(cur, rs, re, cs, ce);
if (paste_tabular && paste_tabular->ncols() == ce - cs + 1
&& paste_tabular->nrows() == re - rs + 1)
- status.setEnabled(true);
+ status.setEnabled(true);
else {
status.setEnabled(false);
status.message(_("Selection size should match clipboard content."));
void InsetTabular::validate(LaTeXFeatures & features) const
{
tabular.validate(features);
- // FIXME XHTML
- // It'd be better to be able to get this from an InsetLayout, but at present
- // InsetLayouts do not seem really to work for things that aren't InsetTexts.
- if (features.runparams().flavor == OutputParams::HTML)
- features.addCSSSnippet(
- "table { border: 1px solid black; display: inline-block; }\n"
- "td { border: 1px solid black; padding: 0.5ex; }");
+ features.useInsetLayout(getLayout());
}
// y offset correction
y += cellYPos(sl.idx());
y += tabular.textVOffset(sl.idx());
- y += offset_valign_;
+ y += tabular.offsetVAlignment();
// x offset correction
x += cellXPos(sl.idx());
x += tabular.textHOffset(sl.idx());
x += ADD_TO_TABULAR_WIDTH;
- x += scx_;
}
Inset * InsetTabular::editXY(Cursor & cur, int x, int y)
{
//lyxerr << "InsetTabular::editXY: " << this << endl;
- cur.setSelection(false);
cur.push(*this);
cur.idx() = getNearestCell(cur.bv(), x, y);
- resetPos(cur);
return cur.bv().textMetrics(&cell(cur.idx())->text()).editXY(cur, x, y);
}
row_type row = tabular.cellRow(cell);
int ly = 0;
for (row_type r = 0; r < row; ++r)
- ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ ly += tabular.rowDescent(r) + tabular.rowAscent(r + 1)
+ tabular.interRowSpace(r + 1);
return ly;
}
}
-void InsetTabular::resetPos(Cursor & cur) const
-{
- BufferView & bv = cur.bv();
- int const maxwidth = bv.workWidth();
-
- int const scx_old = scx_;
- int const i = cur.find(this);
- if (i == -1) {
- scx_ = 0;
- } else {
- int const X1 = 0;
- int const X2 = maxwidth;
- int const offset = ADD_TO_TABULAR_WIDTH + 2;
- int const x1 = xo(cur.bv()) + cellXPos(cur[i].idx()) + offset;
- int const x2 = x1 + tabular.cellWidth(cur[i].idx());
-
- if (x1 < X1)
- scx_ = X1 + 20 - x1;
- else if (x2 > X2)
- scx_ = X2 - 20 - x2;
- else
- scx_ = 0;
- }
-
- // only update if offset changed
- if (scx_ != scx_old)
- cur.screenUpdateFlags(Update::Force | Update::FitCursor);
-}
-
-
void InsetTabular::moveNextCell(Cursor & cur, EntryDirection entry_from)
{
row_type const row = tabular.cellRow(cur.idx());
if (cur.selIsMultiCell()) {
cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
- resetPos(cur);
return;
}
cur.pos() = 0;
// in visual mode, place cursor at extreme left or right
-
+
switch(entry_from) {
case ENTRY_DIRECTION_RIGHT:
}
cur.setCurrentFont();
- resetPos(cur);
}
if (cur.selIsMultiCell()) {
cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
- resetPos(cur);
return;
}
cur.pos() = cur.lastpos();
// in visual mode, place cursor at extreme left or right
-
+
switch(entry_from) {
case ENTRY_DIRECTION_RIGHT:
}
cur.setCurrentFont();
- resetPos(cur);
}
-bool InsetTabular::tabularFeatures(Cursor & cur, string const & argument)
+void InsetTabular::tabularFeatures(Cursor & cur, string const & argument)
{
+ cur.recordUndoInset(this);
+
istringstream is(argument);
+ // limit the size of strings we read to avoid memory problems
+ is >> setw(65636);
string s;
- is >> s;
- if (insetCode(s) != TABULAR_CODE)
- return false;
-
// Safe guard.
size_t safe_guard = 0;
for (;;) {
if (is.eof())
- break;
+ return;
safe_guard++;
if (safe_guard > 1000) {
LYXERR0("parameter max count reached!");
- break;
+ return;
}
is >> s;
Tabular::Feature action = Tabular::LAST_ACTION;
LYXERR(Debug::DEBUG, "Feature: " << s << "\t\tvalue: " << val);
tabularFeatures(cur, action, val);
}
- return true;
}
bool InsetTabular::oneCellHasRotationState(bool rotated,
row_type row_start, row_type row_end,
- col_type col_start, col_type col_end) const
+ col_type col_start, col_type col_end) const
{
for (row_type r = row_start; r <= row_end; ++r)
for (col_type c = col_start; c <= col_end; ++c)
break;
case Tabular::ALIGN_DECIMAL:
- if (tabular.column_info[tabular.cellColumn(cur.idx())].alignment == LYX_ALIGN_DECIMAL)
- setAlign = LYX_ALIGN_CENTER;
- else
- setAlign = LYX_ALIGN_DECIMAL;
+ setAlign = LYX_ALIGN_DECIMAL;
break;
case Tabular::M_VALIGN_TOP:
break;
}
- cur.recordUndoInset(ATOMIC_UNDO, this);
-
getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end);
row_type const row = tabular.cellRow(cur.idx());
col_type const column = tabular.cellColumn(cur.idx());
cur.idx() = tabular.cellIndex(sel_row_start, column);
cur.pit() = 0;
cur.pos() = 0;
- cur.setSelection(false);
+ cur.selection(false);
break;
case Tabular::DELETE_COLUMN:
cur.idx() = tabular.cellIndex(row, sel_col_start);
cur.pit() = 0;
cur.pos() = 0;
- cur.setSelection(false);
+ cur.selection(false);
break;
case Tabular::COPY_ROW:
case Tabular::M_VALIGN_BOTTOM:
case Tabular::M_VALIGN_MIDDLE:
flag = false;
+ // fall through
case Tabular::VALIGN_TOP:
case Tabular::VALIGN_BOTTOM:
case Tabular::VALIGN_MIDDLE:
tabular.rightLine(cur.selEnd().idx()));
cur.pit() = 0;
cur.pos() = 0;
- cur.setSelection(false);
+ cur.selection(false);
break;
}
// check whether we are completely in a multirow
if (!tabular.isMultiRow(cur.idx()))
tabular.setMultiRow(cur.idx(), 1,
- tabular.bottomLine(cur.idx()));
+ tabular.bottomLine(cur.idx()),
+ tabular.getAlignment(cur.idx()));
break;
}
// we have a selection so this means we just add all this
row_type const row_start = tabular.cellRow(s_start);
row_type const row_end = tabular.cellRow(cur.selEnd().idx());
cur.idx() = tabular.setMultiRow(s_start, row_end - row_start + 1,
- tabular.bottomLine(cur.selEnd().idx()));
+ tabular.bottomLine(cur.selEnd().idx()),
+ tabular.getAlignment(cur.selEnd().idx()));
cur.pit() = 0;
cur.pos() = 0;
- cur.setSelection(false);
+ cur.selection(false);
break;
}
case Tabular::SET_ALL_LINES:
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) {
}
break;
+ case Tabular::TOGGLE_LONGTABULAR:
+ if (tabular.is_long_tabular)
+ tabularFeatures(cur, Tabular::UNSET_LONGTABULAR);
+ else
+ tabular.is_long_tabular = true;
+ break;
+
case Tabular::SET_LONGTABULAR:
tabular.is_long_tabular = true;
break;
tabular.longtabular_alignment = Tabular::LYX_LONGTABULAR_ALIGN_RIGHT;
break;
-
+
case Tabular::SET_ROTATE_CELL:
for (row_type r = sel_row_start; r <= sel_row_end; ++r)
case Tabular::UNSET_LTFIRSTHEAD:
flag = false;
+ // fall through
case Tabular::SET_LTFIRSTHEAD:
tabular.getRowOfLTFirstHead(row, ltt);
checkLongtableSpecial(ltt, value, flag);
case Tabular::UNSET_LTHEAD:
flag = false;
+ // fall through
case Tabular::SET_LTHEAD:
tabular.getRowOfLTHead(row, ltt);
checkLongtableSpecial(ltt, value, flag);
case Tabular::UNSET_LTFOOT:
flag = false;
+ // fall through
case Tabular::SET_LTFOOT:
tabular.getRowOfLTFoot(row, ltt);
checkLongtableSpecial(ltt, value, flag);
case Tabular::UNSET_LTLASTFOOT:
flag = false;
+ // fall through
case Tabular::SET_LTLASTFOOT:
tabular.getRowOfLTLastFoot(row, ltt);
checkLongtableSpecial(ltt, value, flag);
case Tabular::UNSET_LTNEWPAGE:
flag = false;
+ // fall through
case Tabular::SET_LTNEWPAGE:
tabular.setLTNewPage(row, flag);
break;
cur.idx() = tabular.setLTCaption(row, true);
cur.pit() = 0;
cur.pos() = 0;
- cur.setSelection(false);
+ cur.selection(false);
// If a row is set as caption, then also insert
// a caption. Otherwise the LaTeX output is broken.
- lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL));
+ // Select cell if it is non-empty
+ if (cur.lastpos() > 0 || cur.lastpit() > 0)
+ lyx::dispatch(FuncRequest(LFUN_INSET_SELECT_ALL));
lyx::dispatch(FuncRequest(LFUN_CAPTION_INSERT));
break;
}
-
+
case Tabular::UNSET_LTCAPTION: {
if (!tabular.ltCaption(row))
break;
cur.idx() = tabular.setLTCaption(row, false);
cur.pit() = 0;
cur.pos() = 0;
- cur.setSelection(false);
+ cur.selection(false);
FuncRequest fr(LFUN_INSET_DISSOLVE, "caption");
if (lyx::getStatus(fr).enabled())
lyx::dispatch(fr);
break;
}
+ case Tabular::TOGGLE_BOOKTABS:
+ tabular.use_booktabs = !tabular.use_booktabs;
+ break;
+
case Tabular::SET_BOOKTABS:
tabular.use_booktabs = true;
break;
}
-docstring InsetTabular::asString(idx_type stidx, idx_type enidx,
+docstring InsetTabular::asString(idx_type stidx, idx_type enidx,
bool intoInsets)
{
LASSERT(stidx <= enidx, return docstring());
if (usePaste) {
paste_tabular.reset(new Tabular(buffer_, rows, maxCols));
loctab = paste_tabular.get();
- cols = 0;
dirtyTabularStack(true);
} else {
loctab = &tabular;
}
-void InsetTabular::completionPosAndDim(Cursor const & cur, int & x, int & y,
+void InsetTabular::completionPosAndDim(Cursor const & cur, int & x, int & y,
Dimension & dim) const
{
TextMetrics const & tm = cur.bv().textMetrics(cur.text());
}
+void InsetTabular::setLayoutForHiddenCells(DocumentClass const & dc)
+{
+ for (Tabular::col_type c = 0; c < tabular.ncols(); ++c) {
+ for (Tabular::row_type r = 0; r < tabular.nrows(); ++r) {
+ if (!tabular.isPartOfMultiColumn(r,c) &&
+ !tabular.isPartOfMultiRow(r,c))
+ continue;
+
+ ParagraphList & parlist = tabular.cellInset(r,c)->paragraphs();
+ ParagraphList::iterator it = parlist.begin();
+ ParagraphList::iterator const en = parlist.end();
+ for (; it != en; ++it)
+ it->setLayout(dc.plainLayout());
+ }
+ }
+}
+
+
} // namespace lyx