lyx_mirror/src/insets/insettabular.C

2110 lines
53 KiB
C++
Raw Normal View History

/**
* \file insettabular.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author J<EFBFBD>rgen Vigna
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "insettabular.h"
#include "buffer.h"
#include "bufferparams.h"
#include "BufferView.h"
#include "cursor.h"
#include "CutAndPaste.h"
#include "coordcache.h"
#include "debug.h"
#include "dispatchresult.h"
#include "funcrequest.h"
#include "FuncStatus.h"
#include "gettext.h"
#include "language.h"
#include "LColor.h"
#include "lyx_cb.h"
#include "lyxlex.h"
#include "metricsinfo.h"
#include "outputparams.h"
#include "paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
#include "undo.h"
#include "support/convert.h"
#include "frontends/Alert.h"
#include "frontends/Clipboard.h"
#include "frontends/Painter.h"
Split clipboard and X selection * src/LyXAction.C (LyXAction::init): handle new LFUN_CLIPBOARD_PASTE * src/insets/insettabular.C (InsetTabular::doDispatch): ditto * src/insets/insetbox.C (InsetBox::doDispatch): ditto * src/insets/insetert.C (InsetERT::doDispatch): ditto (InsetERT::getStatus): ditto * src/insets/insetcharstyle.C (InsetCharStyle::doDispatch): ditto * src/BufferView_pimpl.C (BufferView::Pimpl::selectionRequest): stuff selection, not clipboard * src/mathed/math_nestinset.C (MathNestInset::lfunMousePress): get stuff selection, not clipboard (MathNestInset::lfunMouseRelease): clipboard -> selection in commented code * src/CutAndPaste.C (cutSelection): ditto * src/frontends/{qt3,gtk}/GuiImplementation.C (GuiImplementation::newWorkArea): create new selection, not clipboard, since the clipboard is now an object (GuiImplementation::destroyWorkArea): destroy selection, not clipboard * src/frontends/{qt4,qt3,gtk}/GuiSelection.h: new, copied from GuiClipboard.h * src/frontends/{qt4,qt3,gtk}/GuiSelection.C: new, copied from GuiClipboard.C * src/frontends/{qt3,gtk}/GuiImplementation.h (selection): new accessor for selection_ (selection_): new, the global selection object * src/frontends/{qt4,qt3,gtk}/Makefile.am: add GuiSelection.C and GuiSelection.h * src/frontends/{qt4,qt3,gtk}/GuiClipboard.C (GuiClipboard::get): return clipboard, not selection (GuiClipboard::put): stuff clipboard, not selection * src/frontends/{qt4,qt3,gtk}/GuiClipboard.h (haveSelection): remove (this is now in GuiSelection) * src/frontends/{qt3,gtk}/GuiClipboard.h (old_work_area_): remove, since it is not needed anymore * src/frontends/gtk/ghelpers.C (getGTKStockIcon): handle LFUN_CLIPBOARD_PASTE * src/frontends/Clipboard.h (haveSelection): remove (this is now in Selection) * src/frontends/qt4/GuiImplementation.[Ch] (GuiImplementation::selection): new accessor for selection_ * src/frontends/Gui.h (selection): New accessor for the global selection object * src/frontends/Selection.h; new, copied from Clipboard.h * src/frontends/Makefile.am: add Selection.h * src/text3.C (various): s/clipboard().haveSelection/selection().haveSelection/ (LyXText::dispatch): handle LFUN_CLIPBOARD_PASTE (LyXText::getStatus): ditto * src/lfuns.h: new lfun LFUN_CLIPBOARD_PASTE * lib/ui/stdmenus.ui: add new lfun LFUN_CLIPBOARD_PASTE git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@14408 a592a061-630c-0410-9148-cb99ea01b6c8
2006-07-10 11:32:25 +00:00
#include "frontends/Selection.h"
#include "frontends/nullpainter.h"
#include <sstream>
#include <iostream>
#include <limits>
namespace lyx {
using cap::dirtyTabularStack;
using cap::tabularStackDirty;
using graphics::PreviewLoader;
using support::ltrim;
using frontend::Painter;
using frontend::Clipboard;
using boost::shared_ptr;
using std::auto_ptr;
using std::endl;
using std::max;
using std::string;
using std::istringstream;
using std::ostream;
using std::ostringstream;
using std::swap;
using std::vector;
namespace Alert = frontend::Alert;
namespace {
int const ADD_TO_HEIGHT = 2;
int const ADD_TO_TABULAR_WIDTH = 2;
int const default_line_space = 10;
///
boost::scoped_ptr<LyXTabular> paste_tabular;
struct TabularFeature {
LyXTabular::Feature action;
string feature;
};
TabularFeature tabularFeature[] =
{
{ LyXTabular::APPEND_ROW, "append-row" },
{ LyXTabular::APPEND_COLUMN, "append-column" },
{ LyXTabular::DELETE_ROW, "delete-row" },
{ LyXTabular::DELETE_COLUMN, "delete-column" },
{ LyXTabular::COPY_ROW, "copy-row" },
{ LyXTabular::COPY_COLUMN, "copy-column" },
{ LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
{ LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
{ LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
{ LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
{ LyXTabular::ALIGN_LEFT, "align-left" },
{ LyXTabular::ALIGN_RIGHT, "align-right" },
{ LyXTabular::ALIGN_CENTER, "align-center" },
{ LyXTabular::ALIGN_BLOCK, "align-block" },
{ LyXTabular::VALIGN_TOP, "valign-top" },
{ LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
{ LyXTabular::VALIGN_MIDDLE, "valign-middle" },
{ LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
{ LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
{ LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
{ LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
{ LyXTabular::M_ALIGN_LEFT, "m-align-left" },
{ LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
{ LyXTabular::M_ALIGN_CENTER, "m-align-center" },
{ LyXTabular::M_VALIGN_TOP, "m-valign-top" },
{ LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
{ LyXTabular::M_VALIGN_MIDDLE, "m-valign-middle" },
{ LyXTabular::MULTICOLUMN, "multicolumn" },
{ LyXTabular::SET_ALL_LINES, "set-all-lines" },
{ LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
{ LyXTabular::SET_LONGTABULAR, "set-longtabular" },
{ LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
{ LyXTabular::SET_PWIDTH, "set-pwidth" },
{ LyXTabular::SET_MPWIDTH, "set-mpwidth" },
{ LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
{ LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
{ LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
{ LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
{ LyXTabular::SET_USEBOX, "set-usebox" },
{ LyXTabular::SET_LTHEAD, "set-lthead" },
{ LyXTabular::UNSET_LTHEAD, "unset-lthead" },
{ LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
{ LyXTabular::UNSET_LTFIRSTHEAD, "unset-ltfirsthead" },
{ LyXTabular::SET_LTFOOT, "set-ltfoot" },
{ LyXTabular::UNSET_LTFOOT, "unset-ltfoot" },
{ LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
{ LyXTabular::UNSET_LTLASTFOOT, "unset-ltlastfoot" },
{ LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
{ LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
{ LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
{ LyXTabular::SET_BOOKTABS, "set-booktabs" },
{ LyXTabular::UNSET_BOOKTABS, "unset-booktabs" },
{ LyXTabular::SET_TOP_SPACE, "set-top-space" },
{ LyXTabular::SET_BOTTOM_SPACE, "set-bottom-space" },
{ LyXTabular::SET_INTERLINE_SPACE, "set-interline-space" },
{ LyXTabular::LAST_ACTION, "" }
};
class FeatureEqual : public std::unary_function<TabularFeature, bool> {
public:
FeatureEqual(LyXTabular::Feature feature)
: feature_(feature) {}
bool operator()(TabularFeature const & tf) const {
return tf.action == feature_;
}
private:
LyXTabular::Feature feature_;
};
} // namespace anon
string const featureAsString(LyXTabular::Feature feature)
{
TabularFeature * end = tabularFeature +
sizeof(tabularFeature) / sizeof(TabularFeature);
TabularFeature * it = std::find_if(tabularFeature, end,
FeatureEqual(feature));
return (it == end) ? string() : it->feature;
}
bool InsetTabular::hasPasteBuffer() const
{
return (paste_tabular.get() != 0);
}
InsetTabular::InsetTabular(Buffer const & buf, row_type rows,
col_type columns)
: tabular(buf.params(), max(rows, row_type(1)),
max(columns, col_type(1))), buffer_(&buf), scx_(0)
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
{}
InsetTabular::InsetTabular(InsetTabular const & tab)
: InsetOld(tab), tabular(tab.tabular),
buffer_(tab.buffer_), scx_(0)
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
{}
InsetTabular::~InsetTabular()
{
InsetTabularMailer(*this).hideDialog();
}
auto_ptr<InsetBase> InsetTabular::doClone() const
{
return auto_ptr<InsetBase>(new InsetTabular(*this));
}
Buffer const & InsetTabular::buffer() const
{
return *buffer_;
}
void InsetTabular::buffer(Buffer const * b)
{
buffer_ = b;
}
void InsetTabular::write(Buffer const & buf, ostream & os) const
{
os << "Tabular" << endl;
tabular.write(buf, os);
}
void InsetTabular::read(Buffer const & buf, LyXLex & lex)
{
bool const old_format = (lex.getString() == "\\LyXTable");
tabular.read(buf, lex);
if (old_format)
return;
lex.next();
string token = lex.getString();
while (lex.isOK() && (token != "\\end_inset")) {
lex.next();
token = lex.getString();
}
if (token != "\\end_inset") {
lex.printError("Missing \\end_inset at this point. "
"Read: `$$Token'");
}
}
void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
{
//lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
// mi.base.textwidth << "\n";
if (!mi.base.bv) {
lyxerr << "InsetTabular::metrics: need bv" << endl;
BOOST_ASSERT(false);
}
row_type i = 0;
for (idx_type cell = 0; i < tabular.rows(); ++i) {
int maxAsc = 0;
int maxDesc = 0;
for (col_type j = 0; j < tabular.columns(); ++j) {
if (tabular.isPartOfMultiColumn(i, j))
// Multicolumn cell, but not first one
continue;
Dimension dim;
MetricsInfo m = mi;
LyXLength p_width;
if (tabular.cell_info[i][j].multicolumn ==
LyXTabular::CELL_BEGIN_OF_MULTICOLUMN)
p_width = tabular.cellinfo_of_cell(cell).p_width;
else
p_width = tabular.column_info[j].p_width;
if (!p_width.zero())
m.base.textwidth = p_width.inPixels(mi.base.textwidth);
tabular.getCellInset(cell)->metrics(m, dim);
if (!p_width.zero())
dim.wid = m.base.textwidth;
tabular.setWidthOfCell(cell, dim.wid);
if (p_width.zero()) {
m.base.textwidth = dim.wid + 2 * ADD_TO_TABULAR_WIDTH;
// FIXME there must be a way to get rid of
// the second metrics call
tabular.getCellInset(cell)->metrics(m, dim);
}
maxAsc = max(maxAsc, dim.asc);
maxDesc = max(maxDesc, dim.des);
++cell;
}
int const top_space = tabular.row_info[i].top_space_default ?
default_line_space :
tabular.row_info[i].top_space.inPixels(mi.base.textwidth);
tabular.setAscentOfRow(i, maxAsc + ADD_TO_HEIGHT + top_space);
int const bottom_space = tabular.row_info[i].bottom_space_default ?
default_line_space :
tabular.row_info[i].bottom_space.inPixels(mi.base.textwidth);
tabular.setDescentOfRow(i, maxDesc + ADD_TO_HEIGHT + bottom_space);
}
dim.asc = tabular.getAscentOfRow(0);
dim.des = tabular.getHeightOfTabular() - dim.asc;
dim.wid = tabular.getWidthOfTabular() + 2 * ADD_TO_TABULAR_WIDTH;
dim_ = dim;
}
void InsetTabular::draw(PainterInfo & pi, int x, int y) const
{
setPosCache(pi, x, y);
//lyxerr << "InsetTabular::draw: " << x << " " << y << endl;
BufferView * bv = pi.base.bv;
resetPos(bv->cursor());
x += scx_;
x += ADD_TO_TABULAR_WIDTH;
idx_type idx = 0;
first_visible_cell = LyXTabular::npos;
for (row_type i = 0; i < tabular.rows(); ++i) {
int nx = x;
int const a = tabular.getAscentOfRow(i);
int const d = tabular.getDescentOfRow(i);
idx = tabular.getCellNumber(i, 0);
for (col_type j = 0; j < tabular.columns(); ++j) {
if (tabular.isPartOfMultiColumn(i, j))
continue;
if (first_visible_cell == LyXTabular::npos)
first_visible_cell = idx;
int const cx = nx + tabular.getBeginningOfTextInCell(idx);
if (nx + tabular.getWidthOfColumn(idx) < 0
|| nx > bv->workWidth()
|| y + d < 0
|| y - a > bv->workHeight()) {
pi.pain.setDrawingEnabled(false);
cell(idx)->draw(pi, cx, y);
drawCellLines(pi.pain, nx, y, i, idx, pi.erased_);
pi.pain.setDrawingEnabled(true);
} else {
cell(idx)->draw(pi, cx, y);
drawCellLines(pi.pain, nx, y, i, idx, pi.erased_);
}
nx += tabular.getWidthOfColumn(idx);
++idx;
}
if (i + 1 < tabular.rows())
y += d + tabular.getAscentOfRow(i + 1) +
tabular.getAdditionalHeight(i + 1);
}
}
void InsetTabular::drawSelection(PainterInfo & pi, int x, int y) const
{
setPosCache(pi, x, y);
LCursor & cur = pi.base.bv->cursor();
x += scx_ + ADD_TO_TABULAR_WIDTH;
// Paint background of current tabular
int const w = tabular.getWidthOfTabular();
int const h = tabular.getHeightOfTabular();
int yy = y - tabular.getAscentOfRow(0);
pi.pain.fillRectangle(x, yy, w, h, backgroundColor());
if (!cur.selection())
return;
if (!ptr_cmp(&cur.inset(), this))
return;
//resetPos(cur);
if (tablemode(cur)) {
row_type rs, re;
col_type cs, ce;
getSelection(cur, rs, re, cs, ce);
y -= tabular.getAscentOfRow(0);
for (row_type j = 0; j < tabular.rows(); ++j) {
int const a = tabular.getAscentOfRow(j);
int const h = a + tabular.getDescentOfRow(j);
int xx = x;
y += tabular.getAdditionalHeight(j);
for (col_type i = 0; i < tabular.columns(); ++i) {
if (tabular.isPartOfMultiColumn(j, i))
continue;
idx_type const cell =
tabular.getCellNumber(j, i);
int const w = tabular.getWidthOfColumn(cell);
if (i >= cs && i <= ce && j >= rs && j <= re)
pi.pain.fillRectangle(xx, y, w, h,
LColor::selection);
xx += w;
}
y += h;
}
} else {
cur.text()->drawSelection(pi, x + getCellXPos(cur.idx()) + tabular.getBeginningOfTextInCell(cur.idx()), 0 /*this value is ignored */);
}
}
void InsetTabular::drawCellLines(Painter & pain, int x, int y,
row_type row, idx_type cell, bool erased) const
{
int x2 = x + tabular.getWidthOfColumn(cell);
bool on_off = false;
LColor::color col = LColor::tabularline;
LColor::color onoffcol = LColor::tabularonoffline;
if (erased) {
col = LColor::strikeout;
onoffcol = LColor::strikeout;
}
if (!tabular.topAlreadyDrawn(cell)) {
on_off = !tabular.topLine(cell);
pain.line(x, y - tabular.getAscentOfRow(row),
x2, y - tabular.getAscentOfRow(row),
on_off ? onoffcol : col,
on_off ? Painter::line_onoffdash : Painter::line_solid);
}
on_off = !tabular.bottomLine(cell);
pain.line(x, y + tabular.getDescentOfRow(row),
x2, y + tabular.getDescentOfRow(row),
on_off ? onoffcol : col,
on_off ? Painter::line_onoffdash : Painter::line_solid);
if (!tabular.leftAlreadyDrawn(cell)) {
on_off = !tabular.leftLine(cell);
pain.line(x, y - tabular.getAscentOfRow(row),
x, y + tabular.getDescentOfRow(row),
on_off ? onoffcol : col,
on_off ? Painter::line_onoffdash : Painter::line_solid);
}
on_off = !tabular.rightLine(cell);
pain.line(x2 - tabular.getAdditionalWidth(cell),
y - tabular.getAscentOfRow(row),
x2 - tabular.getAdditionalWidth(cell),
y + tabular.getDescentOfRow(row),
on_off ? onoffcol : col,
on_off ? Painter::line_onoffdash : Painter::line_solid);
}
docstring const InsetTabular::editMessage() const
{
return _("Opened table");
}
void InsetTabular::edit(LCursor & cur, bool left)
{
//lyxerr << "InsetTabular::edit: " << this << endl;
finishUndo();
cur.selection() = false;
cur.push(*this);
if (left) {
if (isRightToLeft(cur))
cur.idx() = tabular.getLastCellInRow(0);
else
cur.idx() = 0;
cur.pit() = 0;
cur.pos() = 0;
} else {
if (isRightToLeft(cur))
cur.idx() = tabular.getFirstCellInRow(tabular.rows() - 1);
else
cur.idx() = tabular.getNumberOfCells() - 1;
cur.pit() = 0;
cur.pos() = cur.lastpos(); // FIXME crude guess
}
// FIXME: this accesses the position cache before it is initialized
//resetPos(cur);
//cur.bv().fitCursor();
}
void InsetTabular::doDispatch(LCursor & cur, FuncRequest & cmd)
{
lyxerr[Debug::DEBUG] << "# InsetTabular::doDispatch: cmd: " << cmd
<< "\n cur:" << cur << endl;
CursorSlice sl = cur.top();
LCursor & bvcur = cur.bv().cursor();
switch (cmd.action) {
case LFUN_MOUSE_PRESS:
//lyxerr << "# InsetTabular::MousePress\n" << cur.bv().cursor() << endl;
if (cmd.button() == mouse_button::button1
|| cmd.button() == mouse_button::button3) {
cur.selection() = false;
setCursorFromCoordinates(cur, cmd.x, cmd.y);
cur.resetAnchor();
bvcur = cur;
break;
}
if (cmd.button() == mouse_button::button2) {
cmd = FuncRequest(LFUN_PRIMARY_SELECTION_PASTE, "paragraph");
doDispatch(cur, cmd);
}
break;
case LFUN_MOUSE_MOTION:
//lyxerr << "# InsetTabular::MouseMotion\n" << bvcur << endl;
if (cmd.button() == mouse_button::button1) {
// only accept motions to places not deeper nested than the real anchor
if (bvcur.anchor_.hasPart(cur)) {
setCursorFromCoordinates(cur, cmd.x, cmd.y);
bvcur.setCursor(cur);
bvcur.selection() = true;
} else
cur.undispatched();
}
break;
case LFUN_MOUSE_RELEASE:
//lyxerr << "# InsetTabular::MouseRelease\n" << bvcur << endl;
if (cmd.button() == mouse_button::button3)
InsetTabularMailer(*this).showDialog(&cur.bv());
break;
case LFUN_CELL_BACKWARD:
movePrevCell(cur);
cur.selection() = false;
break;
case LFUN_CELL_FORWARD:
moveNextCell(cur);
cur.selection() = false;
break;
case LFUN_CHAR_FORWARD_SELECT:
case LFUN_CHAR_FORWARD:
cell(cur.idx())->dispatch(cur, cmd);
if (!cur.result().dispatched()) {
isRightToLeft(cur) ? movePrevCell(cur) : moveNextCell(cur);
if (sl == cur.top())
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
else
cur.dispatched();
}
break;
case LFUN_CHAR_BACKWARD_SELECT:
case LFUN_CHAR_BACKWARD:
cell(cur.idx())->dispatch(cur, cmd);
if (!cur.result().dispatched()) {
isRightToLeft(cur) ? moveNextCell(cur) : movePrevCell(cur);
if (sl == cur.top())
cmd = FuncRequest(LFUN_FINISHED_LEFT);
else
cur.dispatched();
}
break;
case LFUN_DOWN_SELECT:
case LFUN_DOWN:
cell(cur.idx())->dispatch(cur, cmd);
cur.dispatched(); // override the cell's decision
if (sl == cur.top())
// if our LyXText didn't do anything to the cursor
// then we try to put the cursor into the cell below
// setting also the right targetX.
if (tabular.row_of_cell(cur.idx()) != tabular.rows() - 1) {
cur.idx() = tabular.getCellBelow(cur.idx());
cur.pit() = 0;
cur.pos() = cell(cur.idx())->getText(0)->x2pos(
cur.pit(), 0, cur.targetX());
}
if (sl == cur.top()) {
// we trick it to go to the RIGHT after leaving the
// tabular.
cmd = FuncRequest(LFUN_FINISHED_RIGHT);
cur.undispatched();
}
break;
case LFUN_UP_SELECT:
case LFUN_UP:
cell(cur.idx())->dispatch(cur, cmd);
cur.dispatched(); // override the cell's decision
if (sl == cur.top())
// if our LyXText didn't do anything to the cursor
// then we try to put the cursor into the cell above
// setting also the right targetX.
if (tabular.row_of_cell(cur.idx()) != 0) {
cur.idx() = tabular.getCellAbove(cur.idx());
cur.pit() = cur.lastpit();
LyXText const * text = cell(cur.idx())->getText(0);
cur.pos() = text->x2pos(
cur.pit(),
text->paragraphs().back().rows().size()-1,
cur.targetX());
}
if (sl == cur.top()) {
cmd = FuncRequest(LFUN_FINISHED_UP);
cur.undispatched();
}
break;
// case LFUN_SCREEN_DOWN: {
// //if (hasSelection())
// // cur.selection() = false;
// col_type const col = tabular.column_of_cell(cur.idx());
// int const t = cur.bv().top_y() + cur.bv().height();
// if (t < yo() + tabular.getHeightOfTabular()) {
// cur.bv().scrollDocView(t);
// cur.idx() = tabular.getCellBelow(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.column_of_cell(cur.idx());
// int const t = cur.bv().top_y() + cur.bv().height();
// if (yo() < 0) {
// cur.bv().scrollDocView(t);
// if (yo() > 0)
// cur.idx() = col;
// else
// cur.idx() = tabular.getCellBelow(first_visible_cell) + col;
// } else {
// cur.idx() = col;
// }
// cur.par() = cur.lastpar();
// cur.pos() = cur.lastpos();
// break;
// }
case LFUN_LAYOUT_TABULAR:
InsetTabularMailer(*this).showDialog(&cur.bv());
break;
case LFUN_INSET_DIALOG_UPDATE:
InsetTabularMailer(*this).updateDialog(&cur.bv());
break;
case LFUN_TABULAR_FEATURE:
if (!tabularFeatures(cur, to_utf8(cmd.argument())))
cur.undispatched();
break;
// insert file functions
case LFUN_FILE_INSERT_ASCII_PARA:
case LFUN_FILE_INSERT_ASCII: {
// FIXME: We don't know the encoding of filenames
string const tmpstr = getContentsOfAsciiFile(&cur.bv(), to_utf8(cmd.argument()), false);
// FIXME: We don't know the encoding of the file
if (!tmpstr.empty() && !insertAsciiString(cur.bv(), from_utf8(tmpstr), false))
cur.undispatched();
break;
}
case LFUN_CUT:
if (tablemode(cur)) {
if (copySelection(cur)) {
recordUndoInset(cur, Undo::DELETE);
cutSelection(cur);
}
}
else
cell(cur.idx())->dispatch(cur, cmd);
break;
case LFUN_CHAR_DELETE_BACKWARD:
case LFUN_CHAR_DELETE_FORWARD:
if (tablemode(cur)) {
recordUndoInset(cur, Undo::DELETE);
cutSelection(cur);
}
else
cell(cur.idx())->dispatch(cur, cmd);
break;
case LFUN_COPY:
if (!cur.selection())
break;
if (tablemode(cur)) {
finishUndo();
copySelection(cur);
} else
cell(cur.idx())->dispatch(cur, cmd);
break;
Split clipboard and X selection * src/LyXAction.C (LyXAction::init): handle new LFUN_CLIPBOARD_PASTE * src/insets/insettabular.C (InsetTabular::doDispatch): ditto * src/insets/insetbox.C (InsetBox::doDispatch): ditto * src/insets/insetert.C (InsetERT::doDispatch): ditto (InsetERT::getStatus): ditto * src/insets/insetcharstyle.C (InsetCharStyle::doDispatch): ditto * src/BufferView_pimpl.C (BufferView::Pimpl::selectionRequest): stuff selection, not clipboard * src/mathed/math_nestinset.C (MathNestInset::lfunMousePress): get stuff selection, not clipboard (MathNestInset::lfunMouseRelease): clipboard -> selection in commented code * src/CutAndPaste.C (cutSelection): ditto * src/frontends/{qt3,gtk}/GuiImplementation.C (GuiImplementation::newWorkArea): create new selection, not clipboard, since the clipboard is now an object (GuiImplementation::destroyWorkArea): destroy selection, not clipboard * src/frontends/{qt4,qt3,gtk}/GuiSelection.h: new, copied from GuiClipboard.h * src/frontends/{qt4,qt3,gtk}/GuiSelection.C: new, copied from GuiClipboard.C * src/frontends/{qt3,gtk}/GuiImplementation.h (selection): new accessor for selection_ (selection_): new, the global selection object * src/frontends/{qt4,qt3,gtk}/Makefile.am: add GuiSelection.C and GuiSelection.h * src/frontends/{qt4,qt3,gtk}/GuiClipboard.C (GuiClipboard::get): return clipboard, not selection (GuiClipboard::put): stuff clipboard, not selection * src/frontends/{qt4,qt3,gtk}/GuiClipboard.h (haveSelection): remove (this is now in GuiSelection) * src/frontends/{qt3,gtk}/GuiClipboard.h (old_work_area_): remove, since it is not needed anymore * src/frontends/gtk/ghelpers.C (getGTKStockIcon): handle LFUN_CLIPBOARD_PASTE * src/frontends/Clipboard.h (haveSelection): remove (this is now in Selection) * src/frontends/qt4/GuiImplementation.[Ch] (GuiImplementation::selection): new accessor for selection_ * src/frontends/Gui.h (selection): New accessor for the global selection object * src/frontends/Selection.h; new, copied from Clipboard.h * src/frontends/Makefile.am: add Selection.h * src/text3.C (various): s/clipboard().haveSelection/selection().haveSelection/ (LyXText::dispatch): handle LFUN_CLIPBOARD_PASTE (LyXText::getStatus): ditto * src/lfuns.h: new lfun LFUN_CLIPBOARD_PASTE * lib/ui/stdmenus.ui: add new lfun LFUN_CLIPBOARD_PASTE git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@14408 a592a061-630c-0410-9148-cb99ea01b6c8
2006-07-10 11:32:25 +00:00
case LFUN_CLIPBOARD_PASTE:
case LFUN_PRIMARY_SELECTION_PASTE: {
docstring const clip = (cmd.action == LFUN_CLIPBOARD_PASTE) ?
theClipboard().get() :
theSelection().get();
if (clip.empty())
break;
// pass to InsertAsciiString, but
// only if we have multi-cell content
if (clip.find_first_of(from_ascii("\t\n")) != docstring::npos) {
if (insertAsciiString(cur.bv(), clip, false)) {
// content has been replaced,
// so cursor might be invalid
cur.pos() = cur.lastpos();
bvcur.setCursor(cur);
break;
}
} else {
// so that the clipboard is used and it goes on
// to default
// and executes LFUN_PRIMARY_SELECTION_PASTE in insettext!
paste_tabular.reset();
dirtyTabularStack(false);
}
// fall through
}
case LFUN_PASTE:
if (hasPasteBuffer() && tabularStackDirty()) {
recordUndoInset(cur, Undo::INSERT);
pasteSelection(cur);
break;
}
cell(cur.idx())->dispatch(cur, cmd);
break;
case LFUN_FONT_EMPH:
case LFUN_FONT_BOLD:
case LFUN_FONT_ROMAN:
case LFUN_FONT_NOUN:
case LFUN_FONT_ITAL:
case LFUN_FONT_FRAK:
case LFUN_FONT_CODE:
case LFUN_FONT_SANS:
case LFUN_FONT_FREE_APPLY:
case LFUN_FONT_FREE_UPDATE:
case LFUN_FONT_SIZE:
case LFUN_FONT_UNDERLINE:
case LFUN_LANGUAGE:
case LFUN_WORD_CAPITALIZE:
case LFUN_WORD_UPCASE:
case LFUN_WORD_LOWCASE:
case LFUN_CHARS_TRANSPOSE:
if (tablemode(cur)) {
row_type rs, re;
col_type cs, ce;
getSelection(cur, rs, re, cs, ce);
LCursor tmpcur = cur;
for (row_type i = rs; i <= re; ++i) {
for (col_type j = cs; j <= ce; ++j) {
// cursor follows cell:
tmpcur.idx() = tabular.getCellNumber(i, j);
// select this cell only:
tmpcur.pit() = 0;
tmpcur.pos() = 0;
tmpcur.resetAnchor();
tmpcur.pit() = tmpcur.lastpit();
tmpcur.pos() = tmpcur.top().lastpos();
tmpcur.setCursor(tmpcur);
tmpcur.setSelection();
cell(tmpcur.idx())->dispatch(tmpcur, cmd);
}
}
break;
} else {
cell(cur.idx())->dispatch(cur, cmd);
break;
}
default:
// we try to handle this event in the insets dispatch function.
cell(cur.idx())->dispatch(cur, cmd);
break;
}
// FIXME: this accesses the position cache before it is initialized
//resetPos(cur);
InsetTabularMailer(*this).updateDialog(&cur.bv());
}
// function sets an object as defined in func_status.h:
// states OK, Unknown, Disabled, On, Off.
bool InsetTabular::getStatus(LCursor & cur, FuncRequest const & cmd,
FuncStatus & status) const
{
switch (cmd.action) {
case LFUN_TABULAR_FEATURE: {
int action = LyXTabular::LAST_ACTION;
int i = 0;
for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
string const tmp = tabularFeature[i].feature;
if (tmp == to_utf8(cmd.argument()).substr(0, tmp.length())) {
action = tabularFeature[i].action;
break;
}
}
if (action == LyXTabular::LAST_ACTION) {
status.clear();
status.unknown(true);
return true;
}
string const argument
= ltrim(to_utf8(cmd.argument()).substr(tabularFeature[i].feature.length()));
row_type sel_row_start = 0;
row_type sel_row_end = 0;
col_type dummy;
LyXTabular::ltType dummyltt;
bool flag = true;
getSelection(cur, sel_row_start, sel_row_end, dummy, dummy);
switch (action) {
case LyXTabular::SET_PWIDTH:
case LyXTabular::SET_MPWIDTH:
case LyXTabular::SET_SPECIAL_COLUMN:
case LyXTabular::SET_SPECIAL_MULTI:
case LyXTabular::APPEND_ROW:
case LyXTabular::APPEND_COLUMN:
case LyXTabular::DELETE_ROW:
case LyXTabular::DELETE_COLUMN:
case LyXTabular::COPY_ROW:
case LyXTabular::COPY_COLUMN:
case LyXTabular::SET_ALL_LINES:
case LyXTabular::UNSET_ALL_LINES:
case LyXTabular::SET_TOP_SPACE:
case LyXTabular::SET_BOTTOM_SPACE:
case LyXTabular::SET_INTERLINE_SPACE:
status.clear();
return true;
case LyXTabular::MULTICOLUMN:
status.setOnOff(tabular.isMultiColumn(cur.idx()));
break;
case LyXTabular::M_TOGGLE_LINE_TOP:
flag = false;
case LyXTabular::TOGGLE_LINE_TOP:
status.setOnOff(tabular.topLine(cur.idx(), flag));
break;
case LyXTabular::M_TOGGLE_LINE_BOTTOM:
flag = false;
case LyXTabular::TOGGLE_LINE_BOTTOM:
status.setOnOff(tabular.bottomLine(cur.idx(), flag));
break;
case LyXTabular::M_TOGGLE_LINE_LEFT:
flag = false;
case LyXTabular::TOGGLE_LINE_LEFT:
status.setOnOff(tabular.leftLine(cur.idx(), flag));
break;
case LyXTabular::M_TOGGLE_LINE_RIGHT:
flag = false;
case LyXTabular::TOGGLE_LINE_RIGHT:
status.setOnOff(tabular.rightLine(cur.idx(), flag));
break;
case LyXTabular::M_ALIGN_LEFT:
flag = false;
case LyXTabular::ALIGN_LEFT:
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_LEFT);
break;
case LyXTabular::M_ALIGN_RIGHT:
flag = false;
case LyXTabular::ALIGN_RIGHT:
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_RIGHT);
break;
case LyXTabular::M_ALIGN_CENTER:
flag = false;
case LyXTabular::ALIGN_CENTER:
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_CENTER);
break;
case LyXTabular::ALIGN_BLOCK:
status.enabled(!tabular.getPWidth(cur.idx()).zero());
status.setOnOff(tabular.getAlignment(cur.idx(), flag) == LYX_ALIGN_BLOCK);
break;
case LyXTabular::M_VALIGN_TOP:
flag = false;
case LyXTabular::VALIGN_TOP:
status.setOnOff(
tabular.getVAlignment(cur.idx(), flag) == LyXTabular::LYX_VALIGN_TOP);
break;
case LyXTabular::M_VALIGN_BOTTOM:
flag = false;
case LyXTabular::VALIGN_BOTTOM:
status.setOnOff(
tabular.getVAlignment(cur.idx(), flag) == LyXTabular::LYX_VALIGN_BOTTOM);
break;
case LyXTabular::M_VALIGN_MIDDLE:
flag = false;
case LyXTabular::VALIGN_MIDDLE:
status.setOnOff(
tabular.getVAlignment(cur.idx(), flag) == LyXTabular::LYX_VALIGN_MIDDLE);
break;
case LyXTabular::SET_LONGTABULAR:
status.setOnOff(tabular.isLongTabular());
break;
case LyXTabular::UNSET_LONGTABULAR:
status.setOnOff(!tabular.isLongTabular());
break;
case LyXTabular::SET_ROTATE_TABULAR:
status.setOnOff(tabular.getRotateTabular());
break;
case LyXTabular::UNSET_ROTATE_TABULAR:
status.setOnOff(!tabular.getRotateTabular());
break;
case LyXTabular::SET_ROTATE_CELL:
status.setOnOff(tabular.getRotateCell(cur.idx()));
break;
case LyXTabular::UNSET_ROTATE_CELL:
status.setOnOff(!tabular.getRotateCell(cur.idx()));
break;
case LyXTabular::SET_USEBOX:
status.setOnOff(convert<int>(argument) == tabular.getUsebox(cur.idx()));
break;
case LyXTabular::SET_LTFIRSTHEAD:
status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
break;
case LyXTabular::UNSET_LTFIRSTHEAD:
status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt));
break;
case LyXTabular::SET_LTHEAD:
status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
break;
case LyXTabular::UNSET_LTHEAD:
status.setOnOff(!tabular.getRowOfLTHead(sel_row_start, dummyltt));
break;
case LyXTabular::SET_LTFOOT:
status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
break;
case LyXTabular::UNSET_LTFOOT:
status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt));
break;
case LyXTabular::SET_LTLASTFOOT:
status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
break;
case LyXTabular::UNSET_LTLASTFOOT:
status.setOnOff(!tabular.getRowOfLTFoot(sel_row_start, dummyltt));
break;
case LyXTabular::SET_LTNEWPAGE:
status.setOnOff(tabular.getLTNewPage(sel_row_start));
break;
case LyXTabular::SET_BOOKTABS:
status.setOnOff(tabular.useBookTabs());
break;
case LyXTabular::UNSET_BOOKTABS:
status.setOnOff(!tabular.useBookTabs());
break;
default:
status.clear();
status.enabled(false);
break;
}
return true;
}
// These are only enabled inside tabular
case LFUN_CELL_BACKWARD:
case LFUN_CELL_FORWARD:
status.enabled(true);
return true;
// disable these with multiple cells selected
case LFUN_INSET_INSERT:
case LFUN_TABULAR_INSERT:
case LFUN_CHARSTYLE_INSERT:
case LFUN_FLOAT_INSERT:
case LFUN_FLOAT_WIDE_INSERT:
case LFUN_FOOTNOTE_INSERT:
case LFUN_MARGINALNOTE_INSERT:
case LFUN_MATH_INSERT:
case LFUN_MATH_MODE:
case LFUN_MATH_MUTATE:
case LFUN_MATH_DISPLAY:
case LFUN_NOTE_INSERT:
case LFUN_OPTIONAL_INSERT:
case LFUN_BOX_INSERT:
case LFUN_BRANCH_INSERT:
case LFUN_WRAP_INSERT:
case LFUN_ERT_INSERT: {
if (tablemode(cur)) {
status.enabled(false);
return true;
} else
return cell(cur.idx())->getStatus(cur, cmd, status);
}
// disable in non-fixed-width cells
case LFUN_BREAK_LINE:
case LFUN_BREAK_PARAGRAPH:
case LFUN_BREAK_PARAGRAPH_KEEP_LAYOUT:
case LFUN_BREAK_PARAGRAPH_SKIP: {
if (tabular.getPWidth(cur.idx()).zero()) {
status.enabled(false);
return true;
} else
return cell(cur.idx())->getStatus(cur, cmd, status);
}
case LFUN_PASTE:
if (tabularStackDirty()) {
status.enabled(true);
return true;
}
case LFUN_INSET_MODIFY:
if (translate(cmd.getArg(0)) == TABULAR_CODE) {
status.enabled(true);
return true;
}
// Fall through
default:
// we try to handle this event in the insets dispatch function.
return cell(cur.idx())->getStatus(cur, cmd, status);
}
}
int InsetTabular::latex(Buffer const & buf, odocstream & os,
OutputParams const & runparams) const
{
return tabular.latex(buf, os, runparams);
}
int InsetTabular::plaintext(Buffer const & buf, odocstream & os,
OutputParams const & runparams) const
{
int const dp = runparams.linelen ? runparams.depth : 0;
return tabular.plaintext(buf, os, runparams, dp, false, 0);
}
int InsetTabular::docbook(Buffer const & buf, odocstream & os,
OutputParams const & runparams) const
{
int ret = 0;
InsetBase * master = 0;
#ifdef WITH_WARNINGS
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
#warning Why not pass a proper DocIterator here?
#endif
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
#if 0
// if the table is inside a float it doesn't need the informaltable
// wrapper. Search for it.
for (master = owner(); master; master = master->owner())
if (master->lyxCode() == InsetBase::FLOAT_CODE)
break;
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
#endif
if (!master) {
os << "<informaltable>";
++ret;
}
ret += tabular.docbook(buf, os, runparams);
if (!master) {
os << "</informaltable>";
++ret;
}
return ret;
}
void InsetTabular::validate(LaTeXFeatures & features) const
{
tabular.validate(features);
}
shared_ptr<InsetText const> InsetTabular::cell(idx_type idx) const
{
return tabular.getCellInset(idx);
}
shared_ptr<InsetText> InsetTabular::cell(idx_type idx)
{
return tabular.getCellInset(idx);
}
void InsetTabular::cursorPos(BufferView const & bv,
CursorSlice const & sl, bool boundary, int & x, int & y) const
{
cell(sl.idx())->cursorPos(bv, sl, boundary, x, y);
// y offset correction
int const row = tabular.row_of_cell(sl.idx());
for (int i = 0; i <= row; ++i) {
if (i != 0) {
y += tabular.getAscentOfRow(i);
y += tabular.getAdditionalHeight(i);
}
if (i != row)
y += tabular.getDescentOfRow(i);
}
// x offset correction
int const col = tabular.column_of_cell(sl.idx());
int idx = tabular.getCellNumber(row, 0);
for (int j = 0; j < col; ++j) {
if (tabular.isPartOfMultiColumn(row, j))
continue;
x += tabular.getWidthOfColumn(idx);
++idx;
}
x += tabular.getBeginningOfTextInCell(idx);
x += ADD_TO_TABULAR_WIDTH;
x += scx_;
}
int InsetTabular::dist(BufferView & bv, idx_type const cell, int x, int y) const
{
int xx = 0;
int yy = 0;
InsetBase const & inset = *tabular.getCellInset(cell);
Point o = bv.coordCache().getInsets().xy(&inset);
int const xbeg = o.x_ - tabular.getBeginningOfTextInCell(cell);
int const xend = xbeg + tabular.getWidthOfColumn(cell);
row_type const row = tabular.row_of_cell(cell);
int const ybeg = o.y_ - tabular.getAscentOfRow(row) -
tabular.getAdditionalHeight(row);
int const yend = o.y_ + tabular.getDescentOfRow(row);
if (x < xbeg)
xx = xbeg - x;
else if (x > xend)
xx = x - xend;
if (y < ybeg)
yy = ybeg - y;
else if (y > yend)
yy = y - yend;
//lyxerr << " xbeg=" << xbeg << " xend=" << xend
// << " ybeg=" << ybeg << " yend=" << yend
// << " xx=" << xx << " yy=" << yy
// << " dist=" << xx + yy << endl;
return xx + yy;
}
InsetBase * InsetTabular::editXY(LCursor & cur, int x, int y)
{
//lyxerr << "InsetTabular::editXY: " << this << endl;
cur.selection() = false;
cur.push(*this);
cur.idx() = getNearestCell(cur.bv(), x, y);
resetPos(cur);
return cell(cur.idx())->text_.editXY(cur, x, y);
}
void InsetTabular::setCursorFromCoordinates(LCursor & cur, int x, int y) const
{
cur.idx() = getNearestCell(cur.bv(), x, y);
cell(cur.idx())->text_.setCursorFromCoordinates(cur, x, y);
}
InsetTabular::idx_type InsetTabular::getNearestCell(BufferView & bv, int x, int y) const
{
idx_type idx_min = 0;
int dist_min = std::numeric_limits<int>::max();
for (idx_type i = 0, n = nargs(); i != n; ++i) {
if (bv.coordCache().getInsets().has(tabular.getCellInset(i).get())) {
int const d = dist(bv, i, x, y);
if (d < dist_min) {
dist_min = d;
idx_min = i;
}
}
}
return idx_min;
}
int InsetTabular::getCellXPos(idx_type const cell) const
{
idx_type c = cell;
for (; !tabular.isFirstCellInRow(c); --c)
;
int lx = tabular.getWidthOfColumn(cell);
for (; c < cell; ++c)
lx += tabular.getWidthOfColumn(c);
return lx - tabular.getWidthOfColumn(cell);
}
void InsetTabular::resetPos(LCursor & cur) const
{
BufferView & bv = cur.bv();
int const maxwidth = bv.workWidth();
if (&cur.inset() != this) {
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()) + getCellXPos(cur.idx()) + offset;
int const x2 = x1 + tabular.getWidthOfColumn(cur.idx());
if (x1 < X1)
scx_ = X1 + 20 - x1;
else if (x2 > X2)
scx_ = X2 - 20 - x2;
else
scx_ = 0;
}
cur.updateFlags(Update::Force | Update::FitCursor);
InsetTabularMailer(*this).updateDialog(&bv);
}
void InsetTabular::moveNextCell(LCursor & cur)
{
if (isRightToLeft(cur)) {
if (tabular.isFirstCellInRow(cur.idx())) {
row_type const row = tabular.row_of_cell(cur.idx());
if (row == tabular.rows() - 1)
return;
cur.idx() = tabular.getCellBelow(tabular.getLastCellInRow(row));
} else {
if (cur.idx() == 0)
return;
--cur.idx();
}
} else {
if (tabular.isLastCell(cur.idx()))
return;
++cur.idx();
}
cur.pit() = 0;
cur.pos() = 0;
resetPos(cur);
}
void InsetTabular::movePrevCell(LCursor & cur)
{
if (isRightToLeft(cur)) {
if (tabular.isLastCellInRow(cur.idx())) {
row_type const row = tabular.row_of_cell(cur.idx());
if (row == 0)
return;
cur.idx() = tabular.getFirstCellInRow(row);
cur.idx() = tabular.getCellAbove(cur.idx());
} else {
if (tabular.isLastCell(cur.idx()))
return;
++cur.idx();
}
} else {
if (cur.idx() == 0) // first cell
return;
--cur.idx();
}
cur.pit() = cur.lastpit();
cur.pos() = cur.lastpos();
// FIXME: this accesses the position cache before it is initialized
//resetPos(cur);
}
bool InsetTabular::tabularFeatures(LCursor & cur, string const & what)
{
LyXTabular::Feature action = LyXTabular::LAST_ACTION;
int i = 0;
for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
string const tmp = tabularFeature[i].feature;
if (tmp == what.substr(0, tmp.length())) {
//if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
//tabularFeatures[i].feature.length())) {
action = tabularFeature[i].action;
break;
}
}
if (action == LyXTabular::LAST_ACTION)
return false;
string const val =
ltrim(what.substr(tabularFeature[i].feature.length()));
tabularFeatures(cur, action, val);
return true;
}
namespace {
void checkLongtableSpecial(LyXTabular::ltType & ltt,
string const & special, bool & flag)
{
if (special == "dl_above") {
ltt.topDL = flag;
ltt.set = false;
} else if (special == "dl_below") {
ltt.bottomDL = flag;
ltt.set = false;
} else if (special == "empty") {
ltt.empty = flag;
ltt.set = false;
} else if (flag) {
ltt.empty = false;
ltt.set = true;
}
}
} // anon namespace
void InsetTabular::tabularFeatures(LCursor & cur,
LyXTabular::Feature feature, string const & value)
{
BufferView & bv = cur.bv();
col_type sel_col_start;
col_type sel_col_end;
row_type sel_row_start;
row_type sel_row_end;
bool setLines = false;
LyXAlignment setAlign = LYX_ALIGN_LEFT;
LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
switch (feature) {
case LyXTabular::M_ALIGN_LEFT:
case LyXTabular::ALIGN_LEFT:
setAlign = LYX_ALIGN_LEFT;
break;
case LyXTabular::M_ALIGN_RIGHT:
case LyXTabular::ALIGN_RIGHT:
setAlign = LYX_ALIGN_RIGHT;
break;
case LyXTabular::M_ALIGN_CENTER:
case LyXTabular::ALIGN_CENTER:
setAlign = LYX_ALIGN_CENTER;
break;
case LyXTabular::ALIGN_BLOCK:
setAlign = LYX_ALIGN_BLOCK;
break;
case LyXTabular::M_VALIGN_TOP:
case LyXTabular::VALIGN_TOP:
setVAlign = LyXTabular::LYX_VALIGN_TOP;
break;
case LyXTabular::M_VALIGN_BOTTOM:
case LyXTabular::VALIGN_BOTTOM:
setVAlign = LyXTabular::LYX_VALIGN_BOTTOM;
break;
case LyXTabular::M_VALIGN_MIDDLE:
case LyXTabular::VALIGN_MIDDLE:
setVAlign = LyXTabular::LYX_VALIGN_MIDDLE;
break;
default:
break;
}
recordUndoInset(cur, Undo::ATOMIC);
getSelection(cur, sel_row_start, sel_row_end, sel_col_start, sel_col_end);
row_type const row = tabular.row_of_cell(cur.idx());
col_type const column = tabular.column_of_cell(cur.idx());
bool flag = true;
LyXTabular::ltType ltt;
switch (feature) {
case LyXTabular::SET_PWIDTH: {
LyXLength const len(value);
tabular.setColumnPWidth(cur, cur.idx(), len);
if (len.zero()
&& tabular.getAlignment(cur.idx(), true) == LYX_ALIGN_BLOCK)
tabularFeatures(cur, LyXTabular::ALIGN_CENTER, string());
break;
}
case LyXTabular::SET_MPWIDTH:
tabular.setMColumnPWidth(cur, cur.idx(), LyXLength(value));
break;
case LyXTabular::SET_SPECIAL_COLUMN:
case LyXTabular::SET_SPECIAL_MULTI:
tabular.setAlignSpecial(cur.idx(),value,feature);
break;
case LyXTabular::APPEND_ROW:
// append the row into the tabular
tabular.appendRow(bv.buffer()->params(), cur.idx());
break;
case LyXTabular::APPEND_COLUMN:
// append the column into the tabular
tabular.appendColumn(bv.buffer()->params(), cur.idx());
cur.idx() = tabular.getCellNumber(row, column);
break;
case LyXTabular::DELETE_ROW:
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
tabular.deleteRow(sel_row_start);
if (sel_row_start >= tabular.rows())
--sel_row_start;
cur.idx() = tabular.getCellNumber(sel_row_start, column);
cur.pit() = 0;
cur.pos() = 0;
cur.selection() = false;
break;
case LyXTabular::DELETE_COLUMN:
for (col_type i = sel_col_start; i <= sel_col_end; ++i)
tabular.deleteColumn(sel_col_start);
if (sel_col_start >= tabular.columns())
--sel_col_start;
cur.idx() = tabular.getCellNumber(row, sel_col_start);
cur.pit() = 0;
cur.pos() = 0;
cur.selection() = false;
break;
case LyXTabular::COPY_ROW:
tabular.copyRow(bv.buffer()->params(), row);
break;
case LyXTabular::COPY_COLUMN:
tabular.copyColumn(bv.buffer()->params(), column);
cur.idx() = tabular.getCellNumber(row, column);
break;
case LyXTabular::M_TOGGLE_LINE_TOP:
flag = false;
case LyXTabular::TOGGLE_LINE_TOP: {
bool lineSet = !tabular.topLine(cur.idx(), flag);
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setTopLine(
tabular.getCellNumber(i, j),
lineSet, flag);
break;
}
case LyXTabular::M_TOGGLE_LINE_BOTTOM:
flag = false;
case LyXTabular::TOGGLE_LINE_BOTTOM: {
bool lineSet = !tabular.bottomLine(cur.idx(), flag);
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setBottomLine(
tabular.getCellNumber(i, j),
lineSet,
flag);
break;
}
case LyXTabular::M_TOGGLE_LINE_LEFT:
flag = false;
case LyXTabular::TOGGLE_LINE_LEFT: {
bool lineSet = !tabular.leftLine(cur.idx(), flag);
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setLeftLine(
tabular.getCellNumber(i,j),
lineSet,
flag);
break;
}
case LyXTabular::M_TOGGLE_LINE_RIGHT:
flag = false;
case LyXTabular::TOGGLE_LINE_RIGHT: {
bool lineSet = !tabular.rightLine(cur.idx(), flag);
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setRightLine(
tabular.getCellNumber(i,j),
lineSet,
flag);
break;
}
case LyXTabular::M_ALIGN_LEFT:
case LyXTabular::M_ALIGN_RIGHT:
case LyXTabular::M_ALIGN_CENTER:
flag = false;
case LyXTabular::ALIGN_LEFT:
case LyXTabular::ALIGN_RIGHT:
case LyXTabular::ALIGN_CENTER:
case LyXTabular::ALIGN_BLOCK:
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setAlignment(
tabular.getCellNumber(i, j),
setAlign,
flag);
break;
case LyXTabular::M_VALIGN_TOP:
case LyXTabular::M_VALIGN_BOTTOM:
case LyXTabular::M_VALIGN_MIDDLE:
flag = false;
case LyXTabular::VALIGN_TOP:
case LyXTabular::VALIGN_BOTTOM:
case LyXTabular::VALIGN_MIDDLE:
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setVAlignment(
tabular.getCellNumber(i, j),
setVAlign, flag);
break;
case LyXTabular::MULTICOLUMN: {
if (sel_row_start != sel_row_end) {
#ifdef WITH_WARNINGS
#warning Need I say it ? This is horrible.
#endif
// FIXME UNICODE
Alert::error(_("Error setting multicolumn"),
_("You cannot set multicolumn vertically."));
return;
}
if (!cur.selection()) {
// just multicol for one single cell
// check whether we are completely in a multicol
if (tabular.isMultiColumn(cur.idx()))
tabular.unsetMultiColumn(cur.idx());
else
tabular.setMultiColumn(bv.buffer(), cur.idx(), 1);
break;
}
// we have a selection so this means we just add all this
// cells to form a multicolumn cell
idx_type const s_start = cur.selBegin().idx();
idx_type const s_end = cur.selEnd().idx();
tabular.setMultiColumn(bv.buffer(), s_start, s_end - s_start + 1);
cur.idx() = s_start;
cur.pit() = 0;
cur.pos() = 0;
cur.selection() = false;
break;
}
case LyXTabular::SET_ALL_LINES:
setLines = true;
case LyXTabular::UNSET_ALL_LINES:
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setAllLines(
tabular.getCellNumber(i,j), setLines);
break;
case LyXTabular::SET_LONGTABULAR:
tabular.setLongTabular(true);
break;
case LyXTabular::UNSET_LONGTABULAR:
tabular.setLongTabular(false);
break;
case LyXTabular::SET_ROTATE_TABULAR:
tabular.setRotateTabular(true);
break;
case LyXTabular::UNSET_ROTATE_TABULAR:
tabular.setRotateTabular(false);
break;
case LyXTabular::SET_ROTATE_CELL:
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setRotateCell(
tabular.getCellNumber(i, j), true);
break;
case LyXTabular::UNSET_ROTATE_CELL:
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setRotateCell(
tabular.getCellNumber(i, j), false);
break;
case LyXTabular::SET_USEBOX: {
LyXTabular::BoxType val = LyXTabular::BoxType(convert<int>(value));
if (val == tabular.getUsebox(cur.idx()))
val = LyXTabular::BOX_NONE;
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
for (col_type j = sel_col_start; j <= sel_col_end; ++j)
tabular.setUsebox(tabular.getCellNumber(i, j), val);
break;
}
case LyXTabular::UNSET_LTFIRSTHEAD:
flag = false;
case LyXTabular::SET_LTFIRSTHEAD:
tabular.getRowOfLTFirstHead(row, ltt);
checkLongtableSpecial(ltt, value, flag);
tabular.setLTHead(row, flag, ltt, true);
break;
case LyXTabular::UNSET_LTHEAD:
flag = false;
case LyXTabular::SET_LTHEAD:
tabular.getRowOfLTHead(row, ltt);
checkLongtableSpecial(ltt, value, flag);
tabular.setLTHead(row, flag, ltt, false);
break;
case LyXTabular::UNSET_LTFOOT:
flag = false;
case LyXTabular::SET_LTFOOT:
tabular.getRowOfLTFoot(row, ltt);
checkLongtableSpecial(ltt, value, flag);
tabular.setLTFoot(row, flag, ltt, false);
break;
case LyXTabular::UNSET_LTLASTFOOT:
flag = false;
case LyXTabular::SET_LTLASTFOOT:
tabular.getRowOfLTLastFoot(row, ltt);
checkLongtableSpecial(ltt, value, flag);
tabular.setLTFoot(row, flag, ltt, true);
break;
case LyXTabular::SET_LTNEWPAGE:
tabular.setLTNewPage(row, !tabular.getLTNewPage(row));
break;
case LyXTabular::SET_BOOKTABS:
tabular.setBookTabs(true);
break;
case LyXTabular::UNSET_BOOKTABS:
tabular.setBookTabs(false);
break;
case LyXTabular::SET_TOP_SPACE: {
LyXLength len;
if (value == "default")
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
tabular.row_info[i].top_space_default = true;
else if (isValidLength(value, &len))
for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
tabular.row_info[i].top_space_default = false;
tabular.row_info[i].top_space = len;
}
else
for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
tabular.row_info[i].top_space_default = false;
tabular.row_info[i].top_space = len;
}
break;
}
case LyXTabular::SET_BOTTOM_SPACE: {
LyXLength len;
if (value == "default")
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
tabular.row_info[i].bottom_space_default = true;
else if (isValidLength(value, &len))
for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
tabular.row_info[i].bottom_space_default = false;
tabular.row_info[i].bottom_space = len;
}
else
for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
tabular.row_info[i].bottom_space_default = false;
tabular.row_info[i].bottom_space = len;
}
break;
}
case LyXTabular::SET_INTERLINE_SPACE: {
LyXLength len;
if (value == "default")
for (row_type i = sel_row_start; i <= sel_row_end; ++i)
tabular.row_info[i].interline_space_default = true;
else if (isValidLength(value, &len))
for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
tabular.row_info[i].interline_space_default = false;
tabular.row_info[i].interline_space = len;
}
else
for (row_type i = sel_row_start; i <= sel_row_end; ++i) {
tabular.row_info[i].interline_space_default = false;
tabular.row_info[i].interline_space = len;
}
break;
}
// dummy stuff just to avoid warnings
case LyXTabular::LAST_ACTION:
break;
}
InsetTabularMailer(*this).updateDialog(&bv);
}
bool InsetTabular::showInsetDialog(BufferView * bv) const
{
InsetTabularMailer(*this).showDialog(bv);
return true;
}
void InsetTabular::openLayoutDialog(BufferView * bv) const
{
InsetTabularMailer(*this).showDialog(bv);
}
bool InsetTabular::copySelection(LCursor & cur)
{
if (!cur.selection())
return false;
row_type rs, re;
col_type cs, ce;
getSelection(cur, rs, re, cs, ce);
paste_tabular.reset(new LyXTabular(tabular));
for (row_type i = 0; i < rs; ++i)
paste_tabular->deleteRow(0);
row_type const rows = re - rs + 1;
while (paste_tabular->rows() > rows)
paste_tabular->deleteRow(rows);
paste_tabular->setTopLine(0, true, true);
paste_tabular->setBottomLine(paste_tabular->getFirstCellInRow(rows - 1),
true, true);
for (col_type i = 0; i < cs; ++i)
paste_tabular->deleteColumn(0);
col_type const columns = ce - cs + 1;
while (paste_tabular->columns() > columns)
paste_tabular->deleteColumn(columns);
paste_tabular->setLeftLine(0, true, true);
paste_tabular->setRightLine(paste_tabular->getLastCellInRow(0),
true, true);
odocstringstream os;
OutputParams const runparams;
paste_tabular->plaintext(cur.buffer(), os, runparams, 0, true, '\t');
theClipboard().put(os.str());
// mark tabular stack dirty
// FIXME: this is a workaround for bug 1919. Should be removed for 1.5,
// when we (hopefully) have a one-for-all paste mechanism.
cap::dirtyTabularStack(true);
return true;
}
bool InsetTabular::pasteSelection(LCursor & cur)
{
if (!paste_tabular)
return false;
col_type const actcol = tabular.column_of_cell(cur.idx());
row_type const actrow = tabular.row_of_cell(cur.idx());
for (row_type r1 = 0, r2 = actrow;
r1 < paste_tabular->rows() && r2 < tabular.rows();
++r1, ++r2) {
for (col_type c1 = 0, c2 = actcol;
c1 < paste_tabular->columns() && c2 < tabular.columns();
++c1, ++c2) {
if (paste_tabular->isPartOfMultiColumn(r1, c1) &&
tabular.isPartOfMultiColumn(r2, c2))
continue;
if (paste_tabular->isPartOfMultiColumn(r1, c1)) {
--c2;
continue;
}
if (tabular.isPartOfMultiColumn(r2, c2)) {
--c1;
continue;
}
shared_ptr<InsetText> inset(
new InsetText(*paste_tabular->getCellInset(r1, c1)));
tabular.setCellInset(r2, c2, inset);
// FIXME: change tracking (MG)
inset->setChange(Change(cur.buffer().params().trackChanges ?
Change::INSERTED : Change::UNCHANGED));
cur.pos() = 0;
}
}
return true;
}
void InsetTabular::cutSelection(LCursor & cur)
{
if (!cur.selection())
return;
row_type rs, re;
col_type cs, ce;
getSelection(cur, rs, re, cs, ce);
for (row_type i = rs; i <= re; ++i) {
for (col_type j = cs; j <= ce; ++j) {
shared_ptr<InsetText> t
= cell(tabular.getCellNumber(i, j));
if (cur.buffer().params().trackChanges)
// FIXME: Change tracking (MG)
t->setChange(Change(Change::DELETED));
else
t->clear();
}
}
// cursor position might be invalid now
if (cur.pit() > cur.lastpit())
cur.pit() = cur.lastpit();
if (cur.pos() > cur.lastpos())
cur.pos() = cur.lastpos();
cur.clearSelection();
}
bool InsetTabular::isRightToLeft(LCursor & cur) const
{
BOOST_ASSERT(cur.depth() > 1);
Paragraph const & parentpar = cur[cur.depth() - 2].paragraph();
pos_type const parentpos = cur[cur.depth() - 2].pos();
return parentpar.getFontSettings(cur.bv().buffer()->params(),
parentpos).language()->rightToLeft();
}
void InsetTabular::getSelection(LCursor & cur,
row_type & rs, row_type & re, col_type & cs, col_type & ce) const
{
the stuff from the sneak preview: For one, it still contains a few things that are already in CVS (the 'brown paperbag' changes). Secondly, this changes the ParagraphList to a std::vector but does not yet take full advantage of it except removing LyXText::parOffset() and similar. I had an extensive talk with my profiler and we are happy nevertheless. This also moves almost all Cut&Paste specific stuff from text.C to CutAndPaste.C. Much smaller interface now... Namespace CutAndPaste is now lyx::cap::. Was inconsistent with the rest.... Make ParagraphList a proper class. We'll need this later for a specialized erase/insert. Remove some unneeded prototypes and function declarations Use ParameterStruct directly instead of ShareContainer<ParameterStruct> Inline a few accesses to CursorSlice members as suggested by the profiler. Fix commandline conversion crash reported by Kayvan. Replace PosIterator by DocumentIterator. The latter can also iterate through math and nested text in math... Remove math specific hack from Documentiterator Derive InsetCollapsable from InsetText instead of using an InsetText member. This give us the opportunity to get rid of the InsetOld::owner_ backpointer. Cosmetics in CutAndPaste.C and cursor.C. Fix nasty crash (popping slices off an empty selection anchor). Add a few asserts. Remove all 'manual' update calls. We do now one per user interaction which is completely sufficient. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8527 a592a061-630c-0410-9148-cb99ea01b6c8
2004-03-25 09:16:36 +00:00
CursorSlice const & beg = cur.selBegin();
CursorSlice const & end = cur.selEnd();
cs = tabular.column_of_cell(beg.idx());
ce = tabular.column_of_cell(end.idx());
if (cs > ce) {
ce = cs;
cs = tabular.column_of_cell(end.idx());
} else {
ce = tabular.right_column_of_cell(end.idx());
}
rs = tabular.row_of_cell(beg.idx());
re = tabular.row_of_cell(end.idx());
if (rs > re)
swap(rs, re);
}
LyXText * InsetTabular::getText(int idx) const
{
return size_t(idx) < nargs() ? cell(idx)->getText(0) : 0;
}
void InsetTabular::setChange(Change const & change)
{
for (idx_type idx = 0; idx < nargs(); ++idx)
cell(idx)->setChange(change);
}
void InsetTabular::acceptChanges()
{
for (idx_type idx = 0; idx < nargs(); ++idx)
cell(idx)->acceptChanges();
}
void InsetTabular::rejectChanges()
{
for (idx_type idx = 0; idx < nargs(); ++idx)
cell(idx)->rejectChanges();
}
bool InsetTabular::forceDefaultParagraphs(idx_type cell) const
{
return tabular.getPWidth(cell).zero();
}
bool InsetTabular::insertAsciiString(BufferView & bv, docstring const & buf,
bool usePaste)
{
if (buf.length() <= 0)
return true;
col_type cols = 1;
row_type rows = 1;
col_type maxCols = 1;
docstring::size_type const len = buf.length();
docstring::size_type p = 0;
while (p < len &&
(p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos) {
switch (buf[p]) {
case '\t':
++cols;
break;
case '\n':
if (p + 1 < len)
++rows;
maxCols = max(cols, maxCols);
cols = 1;
break;
}
++p;
}
maxCols = max(cols, maxCols);
LyXTabular * loctab;
idx_type cell = 0;
col_type ocol = 0;
row_type row = 0;
if (usePaste) {
paste_tabular.reset(
new LyXTabular(bv.buffer()->params(), rows, maxCols));
loctab = paste_tabular.get();
cols = 0;
dirtyTabularStack(true);
} else {
loctab = &tabular;
cell = bv.cursor().idx();
ocol = tabular.column_of_cell(cell);
row = tabular.row_of_cell(cell);
}
docstring::size_type op = 0;
idx_type const cells = loctab->getNumberOfCells();
p = 0;
cols = ocol;
rows = loctab->rows();
col_type const columns = loctab->columns();
while (cell < cells && p < len && row < rows &&
(p = buf.find_first_of(from_ascii("\t\n"), p)) != docstring::npos)
{
if (p >= len)
break;
switch (buf[p]) {
case '\t':
// we can only set this if we are not too far right
if (cols < columns) {
shared_ptr<InsetText> inset = loctab->getCellInset(cell);
inset->setViewCache(&bv);
Paragraph & par = inset->text_.getPar(0);
LyXFont const font = inset->text_.getFont(par, 0);
inset->setText(buf.substr(op, p - op), font,
bv.buffer()->params().trackChanges);
++cols;
++cell;
}
break;
case '\n':
// we can only set this if we are not too far right
if (cols < columns) {
shared_ptr<InsetText> inset = tabular.getCellInset(cell);
inset->setViewCache(&bv);
Paragraph & par = inset->text_.getPar(0);
LyXFont const font = inset->text_.getFont(par, 0);
inset->setText(buf.substr(op, p - op), font,
bv.buffer()->params().trackChanges);
}
cols = ocol;
++row;
if (row < rows)
cell = loctab->getCellNumber(row, cols);
break;
}
++p;
op = p;
}
// check for the last cell if there is no trailing '\n'
if (cell < cells && op < len) {
shared_ptr<InsetText> inset = loctab->getCellInset(cell);
inset->setViewCache(&bv);
Paragraph & par = inset->text_.getPar(0);
LyXFont const font = inset->text_.getFont(par, 0);
inset->setText(buf.substr(op, len - op), font,
bv.buffer()->params().trackChanges);
}
return true;
}
void InsetTabular::addPreview(PreviewLoader & loader) const
{
row_type const rows = tabular.rows();
col_type const columns = tabular.columns();
for (row_type i = 0; i < rows; ++i) {
for (col_type j = 0; j < columns; ++j)
tabular.getCellInset(i, j)->addPreview(loader);
}
}
bool InsetTabular::tablemode(LCursor & cur) const
{
return cur.selection() && cur.selBegin().idx() != cur.selEnd().idx();
}
string const InsetTabularMailer::name_("tabular");
InsetTabularMailer::InsetTabularMailer(InsetTabular const & inset)
: inset_(const_cast<InsetTabular &>(inset))
{}
string const InsetTabularMailer::inset2string(Buffer const &) const
{
return params2string(inset_);
}
void InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
{
istringstream data(in);
LyXLex lex(0,0);
lex.setStream(data);
if (in.empty())
return;
string token;
lex >> token;
if (!lex || token != name_)
return print_mailer_error("InsetTabularMailer", in, 1,
name_);
// This is part of the inset proper that is usually swallowed
// by Buffer::readInset
lex >> token;
if (!lex || token != "Tabular")
return print_mailer_error("InsetTabularMailer", in, 2,
"Tabular");
Buffer const & buffer = inset.buffer();
inset.read(buffer, lex);
}
string const InsetTabularMailer::params2string(InsetTabular const & inset)
{
ostringstream data;
data << name_ << ' ';
inset.write(inset.buffer(), data);
data << "\\end_inset\n";
return data.str();
}
} // namespace lyx