* \author Jürgen Vigna
* \author Uwe Stöhr
* \author Edwin Leuven
+ * \author Scott Kostyshak
*
* Full author contact details are available in file CREDITS.
*/
#include "DispatchResult.h"
#include "FuncRequest.h"
#include "FuncStatus.h"
+#include "InsetList.h"
#include "Language.h"
#include "LaTeXFeatures.h"
#include "Lexer.h"
#include <boost/scoped_ptr.hpp>
-#include <sstream>
+#include <cstring>
#include <iostream>
#include <limits>
-#include <cstring>
+#include <sstream>
using namespace std;
using namespace lyx::support;
{ Tabular::DELETE_COLUMN, "delete-column", false },
{ Tabular::COPY_ROW, "copy-row", false },
{ Tabular::COPY_COLUMN, "copy-column", false },
+ { Tabular::MOVE_COLUMN_RIGHT, "move-column-right", false },
+ { Tabular::MOVE_COLUMN_LEFT, "move-column-left", false },
+ { Tabular::MOVE_ROW_DOWN, "move-row-down", false },
+ { Tabular::MOVE_ROW_UP, "move-row-up", false },
{ Tabular::SET_LINE_TOP, "set-line-top", true },
{ Tabular::SET_LINE_BOTTOM, "set-line-bottom", true },
{ Tabular::SET_LINE_LEFT, "set-line-left", true },
}
+void Tabular::moveColumn(col_type col, ColDirection direction)
+{
+ if (direction == Tabular::LEFT)
+ col = col - 1;
+
+ std::swap(column_info[col], column_info[col + 1]);
+
+ for (row_type r = 0; r < nrows(); ++r) {
+ std::swap(cell_info[r][col], cell_info[r][col + 1]);
+ std::swap(cell_info[r][col].left_line, cell_info[r][col + 1].left_line);
+ std::swap(cell_info[r][col].right_line, cell_info[r][col + 1].right_line);
+
+ // FIXME track changes is broken for tabular features (#8469)
+ idx_type const i = cellIndex(r, col);
+ idx_type const j = cellIndex(r, col + 1);
+ if (buffer().params().trackChanges) {
+ cellInfo(i).inset->setChange(Change(Change::INSERTED));
+ cellInfo(j).inset->setChange(Change(Change::INSERTED));
+ }
+ }
+ updateIndexes();
+}
+
+
+void Tabular::moveRow(row_type row, RowDirection direction)
+{
+ if (direction == Tabular::UP)
+ row = row - 1;
+
+ std::swap(row_info[row], row_info[row + 1]);
+
+ for (col_type c = 0; c < ncols(); ++c) {
+ std::swap(cell_info[row][c], cell_info[row + 1][c]);
+ std::swap(cell_info[row][c].top_line, cell_info[row + 1][c].top_line);
+ std::swap(cell_info[row][c].bottom_line, cell_info[row + 1][c].bottom_line);
+
+ // FIXME track changes is broken for tabular features (#8469)
+ idx_type const i = cellIndex(row, c);
+ idx_type const j = cellIndex(row + 1, c);
+ if (buffer().params().trackChanges) {
+ cellInfo(i).inset->setChange(Change(Change::INSERTED));
+ cellInfo(j).inset->setChange(Change(Change::INSERTED));
+ }
+ }
+ updateIndexes();
+}
+
+
void Tabular::deleteColumn(col_type const col)
{
// Not allowed to delete last column
l_getline(is, line);
if (!prefixIs(line, "<lyxtabular ") && !prefixIs(line, "<Tabular ")) {
- LASSERT(false, /**/);
- return;
+ LASSERT(false, return);
}
int version;
if (!getTokenValue(line, "version", version))
return;
- LASSERT(version >= 2, /**/);
+ LATTEST(version >= 2);
int rows_arg;
if (!getTokenValue(line, "rows", rows_arg))
}
+bool Tabular::hasMultiColumn(col_type c) const
+{
+ for (row_type r = 0; r < nrows(); ++r) {
+ if (isMultiColumn(cellIndex(r, c)))
+ return true;
+ }
+ return false;
+}
+
+
Tabular::CellData & Tabular::cellInfo(idx_type cell) const
{
return cell_info[cellRow(cell)][cellColumn(cell)];
cs.multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
if (column_info[col].alignment != LYX_ALIGN_DECIMAL)
cs.alignment = column_info[col].alignment;
- if (col > 0)
- setRightLine(cell, right_border);
+ setRightLine(cell, right_border);
for (idx_type i = 1; i < number; ++i) {
CellData & cs1 = cellInfo(cell + i);
|| cellInfo(cell).multirow == CELL_PART_OF_MULTIROW);
}
+bool Tabular::hasMultiRow(row_type r) const
+{
+ for (col_type c = 0; c < ncols(); ++c) {
+ if (isMultiRow(cellIndex(r, c)))
+ return true;
+ }
+ return false;
+}
Tabular::idx_type Tabular::setMultiRow(idx_type cell, idx_type number,
bool const bottom_border)
Tabular::idx_type Tabular::cellIndex(row_type row, col_type column) const
{
- LASSERT(column != npos && column < ncols()
- && row != npos && row < nrows(), /**/);
+ LASSERT(column != npos && column < ncols(), column = 0);
+ LASSERT(row != npos && row < nrows(), row = 0);
return cell_info[row][column].cellno;
}
int Tabular::rowAscent(row_type row) const
{
- LASSERT(row < nrows(), /**/);
+ LASSERT(row < nrows(), row = 0);
return row_info[row].ascent;
}
int Tabular::rowDescent(row_type row) const
{
- LASSERT(row < nrows(), /**/);
+ LASSERT(row < nrows(), row = 0);
return row_info[row].descent;
}
bool Tabular::isPartOfMultiColumn(row_type row, col_type column) const
{
- LASSERT(row < nrows(), /**/);
- LASSERT(column < ncols(), /**/);
+ LASSERT(row < nrows(), return false);
+ LASSERT(column < ncols(), return false);
return cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN;
}
bool Tabular::isPartOfMultiRow(row_type row, col_type column) const
{
- LASSERT(row < nrows(), /**/);
- LASSERT(column < ncols(), /**/);
+ LASSERT(row < nrows(), return false);
+ LASSERT(column < ncols(), return false);
return cell_info[row][column].multirow == CELL_PART_OF_MULTIROW;
}
if (!is_long_tabular)
return;
+ // caption handling
+ // output caption which is in no header or footer
+ if (haveLTCaption()) {
+ for (row_type r = 0; r < nrows(); ++r) {
+ if (row_info[r].caption &&
+ !row_info[r].endfirsthead && !row_info[r].endhead &&
+ !row_info[r].endfoot && !row_info[r].endlastfoot)
+ TeXRow(os, r, runparams);
+ }
+ }
// output first header info
if (haveLTFirstHead()) {
if (endfirsthead.topDL)
}
-bool Tabular::plaintextTopHLine(odocstream & os, row_type row,
+bool Tabular::plaintextTopHLine(odocstringstream & os, row_type row,
vector<unsigned int> const & clen) const
{
idx_type const fcell = getFirstCellInRow(row);
}
-bool Tabular::plaintextBottomHLine(odocstream & os, row_type row,
+bool Tabular::plaintextBottomHLine(odocstringstream & os, row_type row,
vector<unsigned int> const & clen) const
{
idx_type const fcell = getFirstCellInRow(row);
}
-void Tabular::plaintextPrintCell(odocstream & os,
+void Tabular::plaintextPrintCell(odocstringstream & os,
OutputParams const & runparams,
idx_type cell, row_type row, col_type column,
vector<unsigned int> const & clen,
- bool onlydata) const
+ bool onlydata, size_t max_length) const
{
odocstringstream sstr;
- cellInset(cell)->plaintext(sstr, runparams);
+ cellInset(cell)->plaintext(sstr, runparams, max_length);
if (onlydata) {
os << sstr.str();
}
-void Tabular::plaintext(odocstream & os,
+void Tabular::plaintext(odocstringstream & os,
OutputParams const & runparams, int const depth,
- bool onlydata, char_type delim) const
+ bool onlydata, char_type delim, size_t max_length) const
{
// first calculate the width of the single columns
vector<unsigned int> clen(ncols());
if (isMultiColumn(cell))
continue;
odocstringstream sstr;
- cellInset(cell)->plaintext(sstr, runparams);
+ cellInset(cell)->plaintext(sstr, runparams, max_length);
if (clen[c] < sstr.str().length())
clen[c] = sstr.str().length();
}
if (cell_info[r][c].multicolumn != CELL_BEGIN_OF_MULTICOLUMN)
continue;
odocstringstream sstr;
- cellInset(cell)->plaintext(sstr, runparams);
+ cellInset(cell)->plaintext(sstr, runparams, max_length);
int len = int(sstr.str().length());
idx_type const n = columnSpan(cell);
for (col_type k = c; len > 0 && k < c + n - 1; ++k)
// we don't use operator<< for single UCS4 character.
// see explanation in docstream.h
os.put(delim);
- plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata);
+ plaintextPrintCell(os, runparams, cell, r, c, clen, onlydata, max_length);
++cell;
+ if (os.str().size() > max_length)
+ break;
}
os << endl;
if (!onlydata) {
if (plaintextBottomHLine(os, r, clen))
os << docstring(depth * 2, ' ');
}
+ if (os.str().size() > max_length)
+ break;
}
}
}
+void InsetTableCell::addToToc(DocIterator const & di, bool output_active) const
+{
+ InsetText::iterateForToc(di, output_active);
+}
+
+
docstring InsetTableCell::xhtml(XHTMLStream & xs, OutputParams const & rp) const
{
if (!isFixedWidth)
}
+bool InsetTabular::allowsCaptionVariation(std::string const & newtype) const
+{
+ return tabular.is_long_tabular &&
+ (newtype == "Standard" || newtype == "LongTableNoNumber");
+}
+
+
void InsetTabular::write(ostream & os) const
{
os << "Tabular" << endl;
{
//lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
// mi.base.textwidth << "\n";
- if (!mi.base.bv) {
- LYXERR0("need bv");
- LASSERT(false, /**/);
- }
+ LBUFERR(mi.base.bv);
for (row_type r = 0; r < tabular.nrows(); ++r) {
int maxasc = 0;
// Right
x -= tabular.interColumnSpace(cell);
+ col_type next_cell_col = col + 1;
+ while (next_cell_col < tabular.ncols()
+ && tabular.isMultiColumn(tabular.cellIndex(row, next_cell_col)))
+ next_cell_col++;
drawline = tabular.rightLine(cell)
- || (col + 1 < tabular.ncols()
- && tabular.leftLine(tabular.cellIndex(row, col + 1)));
+ || (next_cell_col < tabular.ncols()
+ && tabular.leftLine(tabular.cellIndex(row, next_cell_col)));
pi.pain.line(x + w, y, x + w, y + h,
drawline ? linecolor : gridcolor,
drawline ? Painter::line_solid : Painter::line_onoffdash);
// In a longtable, tell captions what the current float is
Counters & cnts = buffer().masterBuffer()->params().documentClass().counters();
string const saveflt = cnts.current_float();
- if (tabular.is_long_tabular)
+ if (tabular.is_long_tabular) {
cnts.current_float("table");
+ // in longtables, we only step the counter once
+ cnts.step(from_ascii("table"), utype);
+ cnts.isLongtable(true);
+ }
ParIterator it2 = it;
it2.forwardPos();
buffer().updateBuffer(it2, utype);
//reset afterwards
- if (tabular.is_long_tabular)
+ if (tabular.is_long_tabular) {
cnts.current_float(saveflt);
+ cnts.isLongtable(false);
+ }
}
-void InsetTabular::addToToc(DocIterator const & cpit) const
+void InsetTabular::addToToc(DocIterator const & cpit, bool output_active) const
{
DocIterator dit = cpit;
dit.forwardPos();
size_t const end = dit.nargs();
for ( ; dit.idx() < end; dit.top().forwardIdx())
- cell(dit.idx())->addToToc(dit);
+ cell(dit.idx())->addToToc(dit, output_active);
}
if (select_whole && !empty_cell){
getText(cur.idx())->selectAll(cur);
cur.dispatched();
+ cur.screenUpdateFlags(Update::Force | Update::FitCursor);
break;
}
cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
cur.setCurrentFont();
+ cur.screenUpdateFlags(Update::Force | Update::FitCursor);
return;
}
- cur.screenUpdateFlags(Update::FitCursor);
+ cur.screenUpdateFlags(Update::Force | Update::FitCursor);
break;
case LFUN_UP_SELECT:
cur.pit() = 0;
cur.pos() = cur.lastpos();
cur.setCurrentFont();
+ cur.screenUpdateFlags(Update::Force | Update::FitCursor);
return;
}
- cur.screenUpdateFlags(Update::FitCursor);
+ cur.screenUpdateFlags(Update::Force | Update::FitCursor);
break;
// case LFUN_SCREEN_DOWN: {
if (cur.selIsMultiCell()) {
cur.recordUndoInset(DELETE_UNDO);
cutSelection(cur);
- }
- cell(cur.idx())->dispatch(cur, cmd);
+ 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
+ cell(cur.idx())->dispatch(cur, cmd);
break;
case LFUN_CHAR_DELETE_BACKWARD:
case LFUN_CLIPBOARD_PASTE:
case LFUN_PRIMARY_SELECTION_PASTE: {
docstring const clip = (act == LFUN_CLIPBOARD_PASTE) ?
- theClipboard().getAsText() :
+ theClipboard().getAsText(Clipboard::PlainTextType) :
theSelection().get();
if (clip.empty())
break;
case LFUN_FONT_SIZE:
case LFUN_FONT_UNDERLINE:
case LFUN_FONT_STRIKEOUT:
- case LFUN_FONT_UULINE:
- case LFUN_FONT_UWAVE:
+ case LFUN_FONT_UNDERUNDERLINE:
+ case LFUN_FONT_UNDERWAVE:
case LFUN_LANGUAGE:
+ case LFUN_PARAGRAPH_PARAMS_APPLY:
+ case LFUN_PARAGRAPH_PARAMS:
case LFUN_WORD_CAPITALIZE:
case LFUN_WORD_UPCASE:
case LFUN_WORD_LOWCASE:
&& tabular.tabular_valignment == Tabular::LYX_VALIGN_MIDDLE);
break;
+ case Tabular::MOVE_COLUMN_RIGHT:
+ case Tabular::MOVE_COLUMN_LEFT:
+ case Tabular::MOVE_ROW_DOWN:
+ case Tabular::MOVE_ROW_UP: {
+ if (cur.selection()) {
+ status.message(_("Selections not supported."));
+ status.setEnabled(false);
+ break;
+ }
+
+ if ((action == Tabular::MOVE_COLUMN_RIGHT &&
+ tabular.ncols() == tabular.cellColumn(cur.idx()) + 1) ||
+ (action == Tabular::MOVE_COLUMN_LEFT &&
+ tabular.cellColumn(cur.idx()) == 0) ||
+ (action == Tabular::MOVE_ROW_DOWN &&
+ tabular.nrows() == tabular.cellRow(cur.idx()) + 1) ||
+ (action == Tabular::MOVE_ROW_UP &&
+ tabular.cellRow(cur.idx()) == 0)) {
+ status.setEnabled(false);
+ break;
+ }
+
+ if (action == Tabular::MOVE_COLUMN_RIGHT ||
+ action == Tabular::MOVE_COLUMN_LEFT) {
+ if (tabular.hasMultiColumn(tabular.cellColumn(cur.idx())) ||
+ tabular.hasMultiColumn(tabular.cellColumn(cur.idx()) +
+ (action == Tabular::MOVE_COLUMN_RIGHT ? 1 : -1))) {
+ status.message(_("Multi-column in current or"
+ " destination column."));
+ status.setEnabled(false);
+ break;
+ }
+ }
+
+ if (action == Tabular::MOVE_ROW_DOWN ||
+ action == Tabular::MOVE_ROW_UP) {
+ if (tabular.hasMultiRow(tabular.cellRow(cur.idx())) ||
+ tabular.hasMultiRow(tabular.cellRow(cur.idx()) +
+ (action == Tabular::MOVE_ROW_DOWN ? 1 : -1))) {
+ status.message(_("Multi-row in current or"
+ " destination row."));
+ status.setEnabled(false);
+ break;
+ }
+ }
+
+ status.setEnabled(true);
+ break;
+ }
+
case Tabular::SET_DECIMAL_POINT:
status.setEnabled(
tabular.getAlignment(cur.idx()) == LYX_ALIGN_DECIMAL);
break;
case Tabular::UNSET_LTFIRSTHEAD:
- status.setEnabled(sel_row_start == sel_row_end && !tabular.ltCaption(sel_row_start));
+ status.setEnabled(sel_row_start == sel_row_end);
status.setOnOff(!tabular.getRowOfLTFirstHead(sel_row_start, dummyltt));
break;
break;
case Tabular::UNSET_LTHEAD:
- status.setEnabled(sel_row_start == sel_row_end && !tabular.ltCaption(sel_row_start));
+ status.setEnabled(sel_row_start == sel_row_end);
status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt));
break;
break;
case Tabular::UNSET_LTFOOT:
- status.setEnabled(sel_row_start == sel_row_end && !tabular.ltCaption(sel_row_start));
+ status.setEnabled(sel_row_start == sel_row_end);
status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt));
break;
break;
case Tabular::UNSET_LTLASTFOOT:
- status.setEnabled(sel_row_start == sel_row_end && !tabular.ltCaption(sel_row_start));
+ status.setEnabled(sel_row_start == sel_row_end);
status.setOnOff(!tabular.getRowOfLTLastFoot(sel_row_start, dummyltt));
break;
return true;
}
+ case LFUN_CAPTION_INSERT: {
+ // caption is only allowed in caption cell of longtable
+ if (!tabular.ltCaption(tabular.cellRow(cur.idx()))) {
+ status.setEnabled(false);
+ return true;
+ }
+ // only standard caption is allowed
+ string arg = cmd.getArg(0);
+ if (!arg.empty() && arg != "Standard") {
+ status.setEnabled(false);
+ return true;
+ }
+ // check if there is already a caption
+ bool have_caption = false;
+ InsetTableCell itc = InsetTableCell(*tabular.cellInset(cur.idx()).get());
+ ParagraphList::const_iterator pit = itc.paragraphs().begin();
+ ParagraphList::const_iterator pend = itc.paragraphs().end();
+ for (; pit != pend; ++pit) {
+ InsetList::const_iterator it = pit->insetList().begin();
+ InsetList::const_iterator end = pit->insetList().end();
+ for (; it != end; ++it) {
+ if (it->inset->lyxCode() == CAPTION_CODE) {
+ have_caption = true;
+ break;
+ }
+ }
+ }
+ status.setEnabled(!have_caption);
+ return true;
+ }
+
// These are only enabled inside tabular
case LFUN_CELL_BACKWARD:
case LFUN_CELL_FORWARD:
}
// disable in non-fixed-width cells
- case LFUN_BREAK_PARAGRAPH:
+ case LFUN_PARAGRAPH_BREAK:
// multirow does not allow paragraph breaks
if (tabular.isMultiRow(cur.idx())) {
status.setEnabled(false);
}
-int InsetTabular::plaintext(odocstream & os, OutputParams const & runparams) const
+int InsetTabular::plaintext(odocstringstream & os,
+ OutputParams const & runparams, size_t max_length) const
{
os << '\n'; // output table on a new line
int const dp = runparams.linelen > 0 ? runparams.depth : 0;
- tabular.plaintext(os, runparams, dp, false, 0);
+ tabular.plaintext(os, runparams, dp, false, 0, max_length);
return PLAINTEXT_NEWLINE;
}
break;
case Tabular::DELETE_ROW:
+ if (sel_row_end == tabular.nrows() - 1 && sel_row_start != 0) {
+ for (col_type c = 0; c < tabular.ncols(); c++)
+ tabular.setBottomLine(tabular.cellIndex(sel_row_start - 1, c),
+ tabular.bottomLine(tabular.cellIndex(sel_row_end, c)));
+ }
+
for (row_type r = sel_row_start; r <= sel_row_end; ++r)
tabular.deleteRow(sel_row_start);
if (sel_row_start >= tabular.nrows())
break;
case Tabular::DELETE_COLUMN:
+ if (sel_col_end == tabular.ncols() - 1 && sel_col_start != 0) {
+ for (row_type r = 0; r < tabular.nrows(); r++)
+ tabular.setRightLine(tabular.cellIndex(r, sel_col_start - 1),
+ tabular.rightLine(tabular.cellIndex(r, sel_col_end)));
+ }
+
+ if (sel_col_start == 0 && sel_col_end != tabular.ncols() - 1) {
+ for (row_type r = 0; r < tabular.nrows(); r++)
+ tabular.setLeftLine(tabular.cellIndex(r, sel_col_end + 1),
+ tabular.leftLine(tabular.cellIndex(r, 0)));
+ }
+
for (col_type c = sel_col_start; c <= sel_col_end; ++c)
tabular.deleteColumn(sel_col_start);
if (sel_col_start >= tabular.ncols())
cur.idx() = tabular.cellIndex(row, column);
break;
+ case Tabular::MOVE_COLUMN_RIGHT:
+ tabular.moveColumn(column, Tabular::RIGHT);
+ cur.idx() = tabular.cellIndex(row, column + 1);
+ break;
+
+ case Tabular::MOVE_COLUMN_LEFT:
+ tabular.moveColumn(column, Tabular::LEFT);
+ cur.idx() = tabular.cellIndex(row, column - 1);
+ break;
+
+ case Tabular::MOVE_ROW_DOWN:
+ tabular.moveRow(row, Tabular::DOWN);
+ cur.idx() = tabular.cellIndex(row + 1, column);
+ break;
+
+ case Tabular::MOVE_ROW_UP:
+ tabular.moveRow(row, Tabular::UP);
+ cur.idx() = tabular.cellIndex(row - 1, column);
+ break;
+
case Tabular::SET_LINE_TOP:
case Tabular::TOGGLE_LINE_TOP: {
bool lineSet = (feature == Tabular::SET_LINE_TOP)
tabular.rightLine(cur.idx()));
break;
}
- // we have a selection so this means we just add all this
+ // we have a selection so this means we just add all these
// cells to form a multicolumn cell
idx_type const s_start = cur.selBegin().idx();
row_type const col_start = tabular.cellColumn(s_start);
odocstringstream os;
OutputParams const runparams(0);
- paste_tabular->plaintext(os, runparams, 0, true, '\t');
+ paste_tabular->plaintext(os, runparams, 0, true, '\t', INT_MAX);
// Needed for the "Edit->Paste recent" menu and the system clipboard.
cap::copySelection(cur, os.str());
bool InsetTabular::isRightToLeft(Cursor & cur) const
{
- LASSERT(cur.depth() > 1, /**/);
+ // LASSERT: It might be better to abandon this Buffer.
+ LASSERT(cur.depth() > 1, return false);
Paragraph const & parentpar = cur[cur.depth() - 2].paragraph();
pos_type const parentpos = cur[cur.depth() - 2].pos();
return parentpar.getFontSettings(buffer().params(),