lyx_mirror/src/BufferView_pimpl.C

1517 lines
36 KiB
C++
Raw Normal View History

/**
* \file BufferView_pimpl.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author Asger Alstrup
* \author Alfredo Braunstein
* \author Lars Gullik Bj<EFBFBD>nnes
* \author Jean-Marc Lasgouttes
* \author Angus Leeming
* \author John Levon
* \author Andr<EFBFBD> P<EFBFBD>nitz
* \author Dekel Tsur
* \author J<EFBFBD>rgen Vigna
*
* Full author contact details are available in file CREDITS.
*/
#include <config.h>
#include "BufferView_pimpl.h"
#include "buffer.h"
#include "buffer_funcs.h"
#include "bufferlist.h"
#include "bufferparams.h"
#include "coordcache.h"
#include "cursor.h"
#include "CutAndPaste.h"
#include "debug.h"
#include "dispatchresult.h"
#include "factory.h"
#include "FloatList.h"
#include "funcrequest.h"
#include "FuncStatus.h"
#include "gettext.h"
#include "intl.h"
#include "insetiterator.h"
#include "LaTeXFeatures.h"
#include "lyx_cb.h" // added for Dispatch functions
#include "lyx_main.h"
#include "lyxfind.h"
#include "lyxfunc.h"
#include "lyxtext.h"
#include "lyxrc.h"
#include "session.h"
#include "metricsinfo.h"
#include "paragraph.h"
#include "paragraph_funcs.h"
#include "ParagraphParameters.h"
#include "pariterator.h"
#include "rowpainter.h"
#include "toc.h"
#include "undo.h"
#include "vspace.h"
#include "insets/insetbibtex.h"
#include "insets/insetref.h"
#include "insets/insettext.h"
#include "frontends/Alert.h"
#include "frontends/Dialogs.h"
#include "frontends/FileDialog.h"
#include "frontends/font_metrics.h"
#include "frontends/LyXView.h"
#include "frontends/LyXScreenFactory.h"
#include "frontends/screen.h"
#include "frontends/WorkArea.h"
#include "frontends/WorkAreaFactory.h"
#include "graphics/Previews.h"
#include "support/convert.h"
#include "support/filefilterlist.h"
#include "support/filetools.h"
#include "support/forkedcontr.h"
#include "support/package.h"
#include "support/types.h"
#include <boost/bind.hpp>
#include <boost/current_function.hpp>
#include <functional>
#include <vector>
using lyx::pos_type;
using lyx::support::addPath;
using lyx::support::bformat;
using lyx::support::FileFilterList;
using lyx::support::fileSearch;
using lyx::support::ForkedcallsController;
using lyx::support::isDirWriteable;
using lyx::support::makeDisplayPath;
using lyx::support::makeAbsPath;
using lyx::support::package;
using std::endl;
using std::istringstream;
using std::make_pair;
using std::min;
using std::max;
using std::string;
using std::mem_fun_ref;
using std::vector;
extern BufferList bufferlist;
namespace {
unsigned int const saved_positions_num = 20;
// All the below connection objects are needed because of a bug in some
// versions of GCC (<=2.96 are on the suspects list.) By having and assigning
// to these connections we avoid a segfault upon startup, and also at exit.
// (Lgb)
boost::signals::connection timecon;
/// Return an inset of this class if it exists at the current cursor position
template <class T>
T * getInsetByCode(LCursor & cur, InsetBase::Code code)
{
T * inset = 0;
DocIterator it = cur;
if (it.nextInset() &&
it.nextInset()->lyxCode() == code) {
inset = static_cast<T*>(it.nextInset());
}
return inset;
}
} // anon namespace
BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner,
int width, int height)
: bv_(&bv), owner_(owner), buffer_(0), wh_(0), cursor_timeout(400),
using_xterm_cursor(false), cursor_(bv),
anchor_ref_(0), offset_ref_(0)
{
xsel_cache_.set = false;
workarea_.reset(WorkAreaFactory::create(*owner_, width, height));
screen_.reset(LyXScreenFactory::create(workarea()));
// Setup the signals
timecon = cursor_timeout.timeout
.connect(boost::bind(&BufferView::Pimpl::cursorToggle, this));
cursor_timeout.start();
saved_positions.resize(saved_positions_num);
// load saved bookmarks
lyx::Session::BookmarkList & bmList = LyX::ref().session().loadBookmarks();
for (lyx::Session::BookmarkList::iterator bm = bmList.begin();
bm != bmList.end(); ++bm)
if (bm->get<0>() < saved_positions_num)
saved_positions[bm->get<0>()] = Position( bm->get<1>(), bm->get<2>(), bm->get<3>() );
// and then clear them
bmList.clear();
}
void BufferView::Pimpl::addError(ErrorItem const & ei)
{
errorlist_.push_back(ei);
}
void BufferView::Pimpl::showReadonly(bool)
{
owner_->updateWindowTitle();
owner_->getDialogs().updateBufferDependent(false);
}
void BufferView::Pimpl::connectBuffer(Buffer & buf)
{
if (errorConnection_.connected())
disconnectBuffer();
errorConnection_ =
buf.error.connect(
boost::bind(&BufferView::Pimpl::addError, this, _1));
messageConnection_ =
buf.message.connect(
boost::bind(&LyXView::message, owner_, _1));
busyConnection_ =
buf.busy.connect(
boost::bind(&LyXView::busy, owner_, _1));
titleConnection_ =
buf.updateTitles.connect(
boost::bind(&LyXView::updateWindowTitle, owner_));
timerConnection_ =
buf.resetAutosaveTimers.connect(
boost::bind(&LyXView::resetAutosaveTimer, owner_));
readonlyConnection_ =
buf.readonly.connect(
boost::bind(&BufferView::Pimpl::showReadonly, this, _1));
closingConnection_ =
buf.closing.connect(
boost::bind(&BufferView::Pimpl::setBuffer, this, (Buffer *)0));
}
void BufferView::Pimpl::disconnectBuffer()
{
errorConnection_.disconnect();
messageConnection_.disconnect();
busyConnection_.disconnect();
titleConnection_.disconnect();
timerConnection_.disconnect();
readonlyConnection_.disconnect();
closingConnection_.disconnect();
}
void BufferView::Pimpl::newFile(string const & filename, string const & tname,
bool isNamed)
{
setBuffer(::newFile(filename, tname, isNamed));
}
bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles)
{
// Get absolute path of file and add ".lyx"
// to the filename if necessary
string s = fileSearch(string(), filename, "lyx");
bool const found = !s.empty();
if (!found)
s = filename;
// File already open?
if (bufferlist.exists(s)) {
string const file = makeDisplayPath(s, 20);
string text = bformat(_("The document %1$s is already "
"loaded.\n\nDo you want to revert "
"to the saved version?"), file);
int const ret = Alert::prompt(_("Revert to saved document?"),
text, 0, 1, _("&Revert"), _("&Switch to document"));
if (ret != 0) {
setBuffer(bufferlist.getBuffer(s));
return true;
}
// FIXME: should be LFUN_REVERT
if (!bufferlist.close(bufferlist.getBuffer(s), false))
return false;
// Fall through to new load. (Asger)
}
Buffer * b = 0;
if (found) {
b = bufferlist.newBuffer(s);
connectBuffer(*b);
if (!::loadLyXFile(b, s)) {
bufferlist.release(b);
return false;
}
} else {
string text = bformat(_("The document %1$s does not yet "
"exist.\n\nDo you want to create "
"a new document?"), s);
int const ret = Alert::prompt(_("Create new document?"),
text, 0, 1, _("&Create"), _("Cancel"));
if (ret == 0)
b = ::newFile(s, string(), true);
else
return false;
}
setBuffer(b);
bv_->showErrorList(_("Parse"));
// scroll to the position when the file was last closed
if (lyxrc.use_lastfilepos) {
lyx::pit_type pit;
lyx::pos_type pos;
boost::tie(pit, pos) = LyX::ref().session().loadFilePosition(s);
// I am not sure how to separate the following part to a function
// so I will leave this to Lars.
//
// check pit since the document may be externally changed.
if ( static_cast<size_t>(pit) < b->paragraphs().size() ) {
ParIterator it = b->par_iterator_begin();
ParIterator const end = b->par_iterator_end();
for (; it != end; ++it)
if (it.pit() == pit) {
// restored pos may be bigger than it->size
bv_->setCursor(makeDocIterator(it, min(pos, it->size())));
bv_->update(Update::FitCursor);
break;
}
}
}
if (tolastfiles)
LyX::ref().session().addLastFile(b->fileName());
return true;
}
WorkArea & BufferView::Pimpl::workarea() const
{
return *workarea_.get();
}
LyXScreen & BufferView::Pimpl::screen() const
{
return *screen_.get();
}
Painter & BufferView::Pimpl::painter() const
{
return workarea().getPainter();
}
void BufferView::Pimpl::setBuffer(Buffer * b)
{
lyxerr[Debug::INFO] << BOOST_CURRENT_FUNCTION
<< "[ b = " << b << "]" << endl;
if (buffer_) {
disconnectBuffer();
// Save the actual cursor position and anchor inside the
// buffer so that it can be restored in case we rechange
// to this buffer later on.
buffer_->saveCursor(cursor_.selectionBegin(),
cursor_.selectionEnd());
// current buffer is going to be switched-off, save cursor pos
LyX::ref().session().saveFilePosition(buffer_->fileName(),
boost::tie(cursor_.pit(), cursor_.pos()) );
}
// If we are closing current buffer, switch to the first in
// buffer list.
if (!b) {
lyxerr[Debug::INFO] << BOOST_CURRENT_FUNCTION
<< " No Buffer!" << endl;
// We are closing the buffer, use the first buffer as current
buffer_ = bufferlist.first();
owner_->getDialogs().hideBufferDependent();
} else {
// Set current buffer
buffer_ = b;
}
// Reset old cursor
cursor_ = LCursor(*bv_);
anchor_ref_ = 0;
offset_ref_ = 0;
// If we're quitting lyx, don't bother updating stuff
if (quitting)
return;
if (buffer_) {
lyxerr[Debug::INFO] << BOOST_CURRENT_FUNCTION
<< "Buffer addr: " << buffer_ << endl;
connectBuffer(*buffer_);
cursor_.push(buffer_->inset());
cursor_.resetAnchor();
buffer_->text().init(bv_);
buffer_->text().setCurrentFont(cursor_);
if (buffer_->getCursor().size() > 0 &&
buffer_->getAnchor().size() > 0)
{
cursor_.setCursor(buffer_->getAnchor().asDocIterator(&(buffer_->inset())));
cursor_.resetAnchor();
cursor_.setCursor(buffer_->getCursor().asDocIterator(&(buffer_->inset())));
cursor_.setSelection();
}
// Buffer-dependent dialogs should be updated or
// hidden. This should go here because some dialogs (eg ToC)
// require bv_->text.
owner_->getDialogs().updateBufferDependent(true);
}
update();
updateScrollbar();
owner_->updateMenubar();
owner_->updateToolbars();
owner_->updateLayoutChoice();
owner_->updateWindowTitle();
// This is done after the layout combox has been populated
if (buffer_) {
size_t i = cursor_.depth() - 1;
// we know we'll eventually find a paragraph
while (true) {
CursorSlice const & slice = cursor_[i];
if (!slice.inset().inMathed()) {
LyXLayout_ptr const layout = slice.paragraph().layout();
owner_->setLayout(layout->name());
break;
}
BOOST_ASSERT(i>0);
--i;
}
}
if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF)
lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
}
void BufferView::Pimpl::resizeCurrentBuffer()
{
lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl;
owner_->busy(true);
owner_->message(_("Formatting document..."));
LyXText * text = bv_->text();
if (!text)
return;
text->init(bv_);
update();
switchKeyMap();
owner_->busy(false);
// Reset the "Formatting..." message
owner_->clearMessage();
updateScrollbar();
}
void BufferView::Pimpl::updateScrollbar()
{
if (!bv_->text()) {
lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION
<< " no text in updateScrollbar" << endl;
workarea().setScrollbarParams(0, 0, 0);
return;
}
LyXText & t = *bv_->text();
int const parsize = int(t.paragraphs().size() - 1);
if (anchor_ref_ > parsize) {
anchor_ref_ = parsize;
offset_ref_ = 0;
}
lyxerr[Debug::GUI]
<< BOOST_CURRENT_FUNCTION
<< " Updating scrollbar: height: " << t.paragraphs().size()
<< " curr par: " << cursor_.bottom().pit()
<< " default height " << defaultRowHeight() << endl;
// It would be better to fix the scrollbar to understand
// values in [0..1] and divide everything by wh
// estimated average paragraph height:
if (wh_ == 0)
wh_ = workarea().workHeight() / 4;
int h = t.getPar(anchor_ref_).height();
// Normalize anchor/offset (MV):
while (offset_ref_ > h && anchor_ref_ < parsize) {
anchor_ref_++;
offset_ref_ -= h;
h = t.getPar(anchor_ref_).height();
}
// Look at paragraph heights on-screen
int sumh = 0;
int nh = 0;
for (lyx::pit_type pit = anchor_ref_; pit <= parsize; ++pit) {
if (sumh > workarea().workHeight())
break;
int const h2 = t.getPar(pit).height();
sumh += h2;
nh++;
}
int const hav = sumh / nh;
// More realistic average paragraph height
if (hav > wh_)
wh_ = hav;
workarea().setScrollbarParams((parsize + 1) * wh_,
anchor_ref_ * wh_ + int(offset_ref_ * wh_ / float(h)),
int(wh_ * defaultRowHeight() / float(h)));
}
void BufferView::Pimpl::scrollDocView(int value)
{
lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION
<< "[ value = " << value << "]" << endl;
if (!buffer_)
return;
screen().hideCursor();
LyXText & t = *bv_->text();
float const bar = value / float(wh_ * t.paragraphs().size());
anchor_ref_ = int(bar * t.paragraphs().size());
if (anchor_ref_ > int(t.paragraphs().size()) - 1)
anchor_ref_ = int(t.paragraphs().size()) - 1;
t.redoParagraph(anchor_ref_);
int const h = t.getPar(anchor_ref_).height();
offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h);
update();
if (!lyxrc.cursor_follows_scrollbar)
return;
int const height = 2 * defaultRowHeight();
int const first = height;
int const last = workarea().workHeight() - height;
LCursor & cur = cursor_;
bv_funcs::CurStatus st = bv_funcs::status(bv_, cur);
switch (st) {
case bv_funcs::CUR_ABOVE:
t.setCursorFromCoordinates(cur, 0, first);
cur.clearSelection();
break;
case bv_funcs::CUR_BELOW:
t.setCursorFromCoordinates(cur, 0, last);
cur.clearSelection();
break;
case bv_funcs::CUR_INSIDE:
int const y = bv_funcs::getPos(cur, cur.boundary()).y_;
int const newy = min(last, max(y, first));
if (y != newy) {
cur.reset(buffer_->inset());
t.setCursorFromCoordinates(cur, 0, newy);
}
}
owner_->updateLayoutChoice();
}
void BufferView::Pimpl::scroll(int /*lines*/)
{
// if (!buffer_)
// return;
//
// LyXText const * t = bv_->text();
// int const line_height = defaultRowHeight();
//
// // The new absolute coordinate
// int new_top_y = top_y() + lines * line_height;
//
// // Restrict to a valid value
// new_top_y = std::min(t->height() - 4 * line_height, new_top_y);
// new_top_y = std::max(0, new_top_y);
//
// scrollDocView(new_top_y);
//
// // Update the scrollbar.
// workarea().setScrollbarParams(t->height(), top_y(), defaultRowHeight());
}
void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key,
key_modifier::state state)
{
owner_->getLyXFunc().processKeySym(key, state);
/* This is perhaps a bit of a hack. When we move
* around, or type, it's nice to be able to see
* the cursor immediately after the keypress. So
* we reset the toggle timeout and force the visibility
* of the cursor. Note we cannot do this inside
* dispatch() itself, because that's called recursively.
*/
if (available())
screen().showCursor(*bv_);
}
void BufferView::Pimpl::selectionRequested()
{
static string sel;
if (!available())
return;
LCursor & cur = cursor_;
if (!cur.selection()) {
xsel_cache_.set = false;
return;
}
if (!xsel_cache_.set ||
cur.top() != xsel_cache_.cursor ||
cur.anchor_.top() != xsel_cache_.anchor)
{
xsel_cache_.cursor = cur.top();
xsel_cache_.anchor = cur.anchor_.top();
xsel_cache_.set = cur.selection();
sel = cur.selectionAsString(false);
if (!sel.empty())
workarea().putClipboard(sel);
}
}
void BufferView::Pimpl::selectionLost()
{
if (available()) {
screen().hideCursor();
cursor_.clearSelection();
xsel_cache_.set = false;
}
}
void BufferView::Pimpl::workAreaResize()
{
static int work_area_width;
static int work_area_height;
bool const widthChange = workarea().workWidth() != work_area_width;
bool const heightChange = workarea().workHeight() != work_area_height;
// Update from work area
work_area_width = workarea().workWidth();
work_area_height = workarea().workHeight();
if (buffer_ && widthChange) {
// The visible LyXView need a resize
resizeCurrentBuffer();
}
if (widthChange || heightChange)
update();
// Always make sure that the scrollbar is sane.
updateScrollbar();
owner_->updateLayoutChoice();
}
bool BufferView::Pimpl::fitCursor()
{
if (bv_funcs::status(bv_, cursor_) == bv_funcs::CUR_INSIDE) {
LyXFont const font = cursor_.getFont();
int const asc = font_metrics::maxAscent(font);
int const des = font_metrics::maxDescent(font);
Point const p = bv_funcs::getPos(cursor_, cursor_.boundary());
if (p.y_ - asc >= 0 && p.y_ + des < workarea().workHeight())
return false;
}
center();
return true;
}
bool BufferView::Pimpl::multiParSel()
{
if (!cursor_.selection())
return false;
bool ret = multiparsel_cache_;
multiparsel_cache_ = cursor_.selBegin().pit() != cursor_.selEnd().pit();
// Either this, or previous selection spans paragraphs
return ret || multiparsel_cache_;
}
void BufferView::Pimpl::update(Update::flags flags)
{
lyxerr[Debug::DEBUG]
<< BOOST_CURRENT_FUNCTION
<< "[fitcursor = " << (flags & Update::FitCursor)
<< ", forceupdate = " << (flags & Update::Force)
<< ", singlepar = " << (flags & Update::SinglePar)
<< "] buffer: " << buffer_ << endl;
// Check needed to survive LyX startup
if (buffer_) {
// Update macro store
buffer_->buildMacros();
CoordCache backup;
std::swap(theCoords, backup);
// This, together with doneUpdating(), verifies (using
// asserts) that screen redraw is not called from
// within itself.
theCoords.startUpdating();
// First drawing step
ViewMetricsInfo vi = metrics(flags & Update::SinglePar);
bool forceupdate(flags & (Update::Force | Update::SinglePar));
if ((flags & Update::FitCursor) && fitCursor()) {
forceupdate = true;
vi = metrics();
}
if ((flags & Update::MultiParSel) && multiParSel()) {
forceupdate = true;
vi = metrics();
}
if (forceupdate) {
// Second drawing step
screen().redraw(*bv_, vi);
} else {
// Abort updating of the coord
// cache - just restore the old one
std::swap(theCoords, backup);
}
} else
screen().greyOut();
// And the scrollbar
updateScrollbar();
owner_->view_state_changed();
}
// Callback for cursor timer
void BufferView::Pimpl::cursorToggle()
{
if (buffer_) {
screen().toggleCursor(*bv_);
// Use this opportunity to deal with any child processes that
// have finished but are waiting to communicate this fact
// to the rest of LyX.
ForkedcallsController & fcc = ForkedcallsController::get();
fcc.handleCompletedProcesses();
}
cursor_timeout.restart();
}
bool BufferView::Pimpl::available() const
{
return buffer_ && bv_->text();
}
Change const BufferView::Pimpl::getCurrentChange()
{
if (!buffer_->params().tracking_changes)
return Change(Change::UNCHANGED);
LyXText * text = bv_->getLyXText();
LCursor & cur = cursor_;
if (!cur.selection())
return Change(Change::UNCHANGED);
return text->getPar(cur.selBegin().pit()).
lookupChange(cur.selBegin().pos());
}
void BufferView::Pimpl::savePosition(unsigned int i)
{
if (i >= saved_positions_num)
return;
BOOST_ASSERT(cursor_.inTexted());
saved_positions[i] = Position(buffer_->fileName(),
cursor_.paragraph().id(),
cursor_.pos());
if (i > 0)
owner_->message(bformat(_("Saved bookmark %1$d"), i));
}
void BufferView::Pimpl::restorePosition(unsigned int i)
{
if (i >= saved_positions_num)
return;
string const fname = saved_positions[i].filename;
cursor_.clearSelection();
if (fname != buffer_->fileName()) {
Buffer * b = 0;
if (bufferlist.exists(fname))
b = bufferlist.getBuffer(fname);
else {
b = bufferlist.newBuffer(fname);
// Don't ask, just load it
::loadLyXFile(b, fname);
}
if (b)
setBuffer(b);
}
ParIterator par = buffer_->getParFromID(saved_positions[i].par_id);
if (par == buffer_->par_iterator_end())
return;
bv_->setCursor(makeDocIterator(par, min(par->size(), saved_positions[i].par_pos)));
if (i > 0)
owner_->message(bformat(_("Moved to bookmark %1$d"), i));
}
bool BufferView::Pimpl::isSavedPosition(unsigned int i)
{
return i < saved_positions_num && !saved_positions[i].filename.empty();
}
void BufferView::Pimpl::saveSavedPositions()
{
// save bookmarks. It is better to use the pit interface
// but I do not know how to effectively convert between
// par_id and pit.
for (unsigned int i=1; i < saved_positions_num; ++i) {
if ( isSavedPosition(i) )
LyX::ref().session().saveBookmark( boost::tie(
i,
saved_positions[i].filename,
saved_positions[i].par_id,
saved_positions[i].par_pos) );
}
}
void BufferView::Pimpl::switchKeyMap()
{
if (!lyxrc.rtl_support)
return;
Intl & intl = owner_->getIntl();
if (bv_->getLyXText()->real_current_font.isRightToLeft()) {
if (intl.keymap == Intl::PRIMARY)
intl.keyMapSec();
} else {
if (intl.keymap == Intl::SECONDARY)
intl.keyMapPrim();
}
}
void BufferView::Pimpl::center()
{
CursorSlice & bot = cursor_.bottom();
lyx::pit_type const pit = bot.pit();
bot.text()->redoParagraph(pit);
Paragraph const & par = bot.text()->paragraphs()[pit];
anchor_ref_ = pit;
offset_ref_ = bv_funcs::coordOffset(cursor_, cursor_.boundary()).y_
+ par.ascent() - workarea().workHeight() / 2;
}
void BufferView::Pimpl::stuffClipboard(string const & content) const
{
workarea().putClipboard(content);
}
void BufferView::Pimpl::menuInsertLyXFile(string const & filenm)
{
BOOST_ASSERT(cursor_.inTexted());
string filename = filenm;
if (filename.empty()) {
// Launch a file browser
string initpath = lyxrc.document_path;
if (available()) {
string const trypath = owner_->buffer()->filePath();
// If directory is writeable, use this as default.
if (isDirWriteable(trypath))
initpath = trypath;
}
FileDialog fileDlg(_("Select LyX document to insert"),
LFUN_FILE_INSERT,
make_pair(string(_("Documents|#o#O")),
string(lyxrc.document_path)),
make_pair(string(_("Examples|#E#e")),
string(addPath(package().system_support(), "examples"))));
FileDialog::Result result =
fileDlg.open(initpath,
FileFilterList(_("LyX Documents (*.lyx)")),
string());
if (result.first == FileDialog::Later)
return;
filename = result.second;
// check selected filename
if (filename.empty()) {
owner_->message(_("Canceled."));
return;
}
}
// Get absolute path of file and add ".lyx"
// to the filename if necessary
filename = fileSearch(string(), filename, "lyx");
string const disp_fn = makeDisplayPath(filename);
owner_->message(bformat(_("Inserting document %1$s..."), disp_fn));
string res;
Buffer buf("", false);
buf.error.connect(boost::bind(&BufferView::Pimpl::addError, this, _1));
if (::loadLyXFile(&buf, makeAbsPath(filename))) {
lyx::cap::pasteParagraphList(cursor_, buf.paragraphs(),
buf.params().textclass);
res = _("Document %1$s inserted.");
} else
res = _("Could not insert document %1$s");
owner_->message(bformat(res, disp_fn));
bv_->showErrorList(_("Document insertion"));
resizeCurrentBuffer();
}
void BufferView::Pimpl::trackChanges()
{
bool const tracking = buffer_->params().tracking_changes;
if (!tracking) {
for_each(buffer_->par_iterator_begin(),
buffer_->par_iterator_end(),
bind(&Paragraph::trackChanges, _1, Change::UNCHANGED));
buffer_->params().tracking_changes = true;
// We cannot allow undos beyond the freeze point
buffer_->undostack().clear();
} else {
cursor_.setCursor(doc_iterator_begin(buffer_->inset()));
if (lyx::find::findNextChange(bv_)) {
owner_->getDialogs().show("changes");
return;
}
for_each(buffer_->par_iterator_begin(),
buffer_->par_iterator_end(),
mem_fun_ref(&Paragraph::untrackChanges));
buffer_->params().tracking_changes = false;
}
buffer_->redostack().clear();
}
bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0)
{
//lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl;
// This is only called for mouse related events including
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
// LFUN_FILE_OPEN generated by drag-and-drop.
FuncRequest cmd = cmd0;
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
// Handle drag&drop
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 (cmd.action == LFUN_FILE_OPEN) {
owner_->dispatch(cmd);
return true;
}
if (!buffer_)
return false;
LCursor cur(*bv_);
cur.push(buffer_->inset());
cur.selection() = cursor_.selection();
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
// Doesn't go through lyxfunc, so we need to update
// the layout choice etc. ourselves
// E.g. Qt mouse press when no buffer
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 (!available())
return false;
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
screen().hideCursor();
// Either the inset under the cursor or the
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
// surrounding LyXText will handle this event.
// Build temporary cursor.
cmd.y = min(max(cmd.y,-1), workarea().workHeight());
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
InsetBase * inset = bv_->text()->editXY(cur, cmd.x, cmd.y);
//lyxerr << BOOST_CURRENT_FUNCTION
// << " * hit inset at tip: " << inset << endl;
//lyxerr << BOOST_CURRENT_FUNCTION
// << " * created temp cursor:" << cur << endl;
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
// Put anchor at the same position.
cur.resetAnchor();
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
// Try to dispatch to an non-editable inset near this position
// via the temp cursor. If the inset wishes to change the real
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
// cursor it has to do so explicitly by using
// cur.bv().cursor() = cur; (or similar)
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 (inset)
inset->dispatch(cur, cmd);
// Now dispatch to the temporary cursor. If the real cursor should
// be modified, the inset's dispatch has to do so explicitly.
if (!cur.result().dispatched())
cur.dispatch(cmd);
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 (cur.result().dispatched()) {
// Redraw if requested or necessary.
if (cur.result().update())
update(Update::FitCursor | Update::Force);
else
update(Update::FitCursor | Update::MultiParSel);
}
// See workAreaKeyPress
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
cursor_timeout.restart();
screen().showCursor(*bv_);
// Skip these when selecting
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 (cmd.action != LFUN_MOUSE_MOTION) {
owner_->updateLayoutChoice();
owner_->updateToolbars();
}
// Slight hack: this is only called currently when we
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
// clicked somewhere, so we force through the display
// of the new status here.
owner_->clearMessage();
return true;
}
FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd)
{
FuncStatus flag;
switch (cmd.action) {
case LFUN_UNDO:
flag.enabled(!buffer_->undostack().empty());
break;
case LFUN_REDO:
flag.enabled(!buffer_->redostack().empty());
break;
case LFUN_FILE_INSERT:
case LFUN_FILE_INSERT_ASCII_PARA:
case LFUN_FILE_INSERT_ASCII:
// FIXME: Actually, these LFUNS should be moved to LyXText
flag.enabled(cursor_.inTexted());
break;
case LFUN_FONT_STATE:
case LFUN_LABEL_INSERT:
case LFUN_BOOKMARK_SAVE:
case LFUN_PARAGRAPH_GOTO:
// FIXME handle non-trivially
case LFUN_OUTLINE_UP:
case LFUN_OUTLINE_DOWN:
case LFUN_OUTLINE_IN:
case LFUN_OUTLINE_OUT:
case LFUN_ERROR_NEXT:
case LFUN_NOTE_NEXT:
case LFUN_REFERENCE_NEXT:
case LFUN_WORD_FIND:
case LFUN_WORD_REPLACE:
case LFUN_MARK_OFF:
case LFUN_MARK_ON:
case LFUN_MARK_TOGGLE:
case LFUN_SCREEN_RECENTER:
case LFUN_BIBTEX_DATABASE_ADD:
case LFUN_BIBTEX_DATABASE_DEL:
case LFUN_WORDS_COUNT:
flag.enabled(true);
break;
case LFUN_LABEL_GOTO: {
flag.enabled(!cmd.argument.empty()
|| getInsetByCode<InsetRef>(cursor_, InsetBase::REF_CODE));
break;
}
case LFUN_BOOKMARK_GOTO:
flag.enabled(isSavedPosition(convert<unsigned int>(cmd.argument)));
break;
case LFUN_CHANGES_TRACK:
flag.enabled(true);
flag.setOnOff(buffer_->params().tracking_changes);
break;
case LFUN_CHANGES_OUTPUT: {
OutputParams runparams;
LaTeXFeatures features(*buffer_, buffer_->params(), runparams);
flag.enabled(buffer_ && buffer_->params().tracking_changes
&& features.isAvailable("dvipost"));
flag.setOnOff(buffer_->params().output_changes);
break;
}
case LFUN_CHANGES_MERGE:
case LFUN_CHANGE_ACCEPT: // what about these two
case LFUN_CHANGE_REJECT: // what about these two
case LFUN_ALL_CHANGES_ACCEPT:
case LFUN_ALL_CHANGES_REJECT:
flag.enabled(buffer_ && buffer_->params().tracking_changes);
break;
case LFUN_BUFFER_TOGGLE_COMPRESSION: {
flag.setOnOff(buffer_->params().compressed);
break;
}
default:
flag.enabled(false);
}
return flag;
}
bool BufferView::Pimpl::dispatch(FuncRequest const & cmd)
{
//lyxerr << BOOST_CURRENT_FUNCTION
// << [ cmd = " << cmd << "]" << endl;
// Make sure that the cached BufferView is correct.
lyxerr[Debug::ACTION] << BOOST_CURRENT_FUNCTION
<< " action[" << cmd.action << ']'
<< " arg[" << cmd.argument << ']'
<< " x[" << cmd.x << ']'
<< " y[" << cmd.y << ']'
<< " button[" << cmd.button() << ']'
<< endl;
LCursor & cur = cursor_;
switch (cmd.action) {
case LFUN_UNDO:
if (available()) {
cur.message(_("Undo"));
cur.clearSelection();
if (!textUndo(*bv_))
cur.message(_("No further undo information"));
update();
switchKeyMap();
}
break;
case LFUN_REDO:
if (available()) {
cur.message(_("Redo"));
cur.clearSelection();
if (!textRedo(*bv_))
cur.message(_("No further redo information"));
update();
switchKeyMap();
}
break;
case LFUN_FILE_INSERT:
menuInsertLyXFile(cmd.argument);
break;
case LFUN_FILE_INSERT_ASCII_PARA:
insertAsciiFile(bv_, cmd.argument, true);
break;
case LFUN_FILE_INSERT_ASCII:
insertAsciiFile(bv_, cmd.argument, false);
break;
case LFUN_FONT_STATE:
cur.message(cur.currentState());
break;
case LFUN_BOOKMARK_SAVE:
savePosition(convert<unsigned int>(cmd.argument));
break;
case LFUN_BOOKMARK_GOTO:
restorePosition(convert<unsigned int>(cmd.argument));
break;
case LFUN_LABEL_GOTO: {
string label = cmd.argument;
if (label.empty()) {
InsetRef * inset =
getInsetByCode<InsetRef>(cursor_,
InsetBase::REF_CODE);
if (inset) {
label = inset->getContents();
savePosition(0);
}
}
if (!label.empty())
bv_->gotoLabel(label);
break;
}
case LFUN_PARAGRAPH_GOTO: {
int const id = convert<int>(cmd.argument);
ParIterator par = buffer_->getParFromID(id);
if (par == buffer_->par_iterator_end()) {
lyxerr[Debug::INFO] << "No matching paragraph found! ["
<< id << ']' << endl;
break;
} else {
lyxerr[Debug::INFO] << "Paragraph " << par->id()
<< " found." << endl;
}
// Set the cursor
bv_->setCursor(makeDocIterator(par, 0));
update();
switchKeyMap();
break;
}
case LFUN_OUTLINE_UP:
lyx::toc::outline(lyx::toc::Up, cursor_);
cursor_.text()->setCursor(cursor_, cursor_.pit(), 0);
updateLabels(*buffer_);
break;
case LFUN_OUTLINE_DOWN:
lyx::toc::outline(lyx::toc::Down, cursor_);
cursor_.text()->setCursor(cursor_, cursor_.pit(), 0);
updateLabels(*buffer_);
break;
case LFUN_OUTLINE_IN:
lyx::toc::outline(lyx::toc::In, cursor_);
updateLabels(*buffer_);
break;
case LFUN_OUTLINE_OUT:
lyx::toc::outline(lyx::toc::Out, cursor_);
updateLabels(*buffer_);
break;
case LFUN_ERROR_NEXT:
bv_funcs::gotoInset(bv_, InsetBase::ERROR_CODE, false);
break;
case LFUN_NOTE_NEXT:
bv_funcs::gotoInset(bv_, InsetBase::NOTE_CODE, false);
break;
case LFUN_REFERENCE_NEXT: {
vector<InsetBase_code> tmp;
tmp.push_back(InsetBase::LABEL_CODE);
tmp.push_back(InsetBase::REF_CODE);
bv_funcs::gotoInset(bv_, tmp, true);
break;
}
case LFUN_CHANGES_TRACK:
trackChanges();
break;
case LFUN_CHANGES_OUTPUT: {
bool const state = buffer_->params().output_changes;
buffer_->params().output_changes = !state;
break;
}
case LFUN_CHANGES_MERGE:
if (lyx::find::findNextChange(bv_))
owner_->getDialogs().show("changes");
break;
case LFUN_ALL_CHANGES_ACCEPT: {
cursor_.reset(buffer_->inset());
#ifdef WITH_WARNINGS
#warning FIXME changes
#endif
while (lyx::find::findNextChange(bv_))
bv_->getLyXText()->acceptChange(cursor_);
update();
break;
}
case LFUN_ALL_CHANGES_REJECT: {
cursor_.reset(buffer_->inset());
#ifdef WITH_WARNINGS
#warning FIXME changes
#endif
while (lyx::find::findNextChange(bv_))
bv_->getLyXText()->rejectChange(cursor_);
break;
}
case LFUN_WORD_FIND:
lyx::find::find(bv_, cmd);
break;
case LFUN_WORD_REPLACE:
lyx::find::replace(bv_, cmd);
break;
case LFUN_MARK_OFF:
cur.clearSelection();
cur.resetAnchor();
cur.message(N_("Mark off"));
break;
case LFUN_MARK_ON:
cur.clearSelection();
cur.mark() = true;
cur.resetAnchor();
cur.message(N_("Mark on"));
break;
case LFUN_MARK_TOGGLE:
cur.clearSelection();
if (cur.mark()) {
cur.mark() = false;
cur.message(N_("Mark removed"));
} else {
cur.mark() = true;
cur.message(N_("Mark set"));
}
cur.resetAnchor();
break;
case LFUN_SCREEN_RECENTER:
center();
break;
case LFUN_BIBTEX_DATABASE_ADD: {
LCursor tmpcur = cursor_;
bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false);
InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
InsetBase::BIBTEX_CODE);
if (inset) {
if (inset->addDatabase(cmd.argument))
buffer_->updateBibfilesCache();
}
break;
}
case LFUN_BIBTEX_DATABASE_DEL: {
LCursor tmpcur = cursor_;
bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false);
InsetBibtex * inset = getInsetByCode<InsetBibtex>(tmpcur,
InsetBase::BIBTEX_CODE);
if (inset) {
if (inset->delDatabase(cmd.argument))
buffer_->updateBibfilesCache();
}
break;
}
case LFUN_WORDS_COUNT: {
DocIterator from, to;
if (cur.selection()) {
from = cur.selectionBegin();
to = cur.selectionEnd();
} else {
from = doc_iterator_begin(buffer_->inset());
to = doc_iterator_end(buffer_->inset());
}
int const count = countWords(from, to);
string message;
if (count != 1) {
if (cur.selection())
message = bformat(_("%1$d words in selection."),
count);
else
message = bformat(_("%1$d words in document."),
count);
}
else {
if (cur.selection())
message = _("One word in selection.");
else
message = _("One word in document.");
}
Alert::information(_("Count words"), message);
}
break;
case LFUN_BUFFER_TOGGLE_COMPRESSION:
// turn compression on/off
buffer_->params().compressed = !buffer_->params().compressed;
break;
default:
return false;
}
return true;
}
ViewMetricsInfo BufferView::Pimpl::metrics(bool singlepar)
{
// Remove old position cache
theCoords.clear();
BufferView & bv = *bv_;
LyXText * const text = bv.text();
lyx::pit_type size = int(text->paragraphs().size());
if (anchor_ref_ > int(text->paragraphs().size() - 1)) {
anchor_ref_ = int(text->paragraphs().size() - 1);
offset_ref_ = 0;
}
lyx::pit_type const pit = anchor_ref_;
int pit1 = pit;
int pit2 = pit;
size_t const npit = text->paragraphs().size();
// Rebreak anchor paragraph. In Single Paragraph mode, rebreak only
// the (main text, not inset!) paragraph containing the cursor.
// (if this paragraph contains insets etc., rebreaking will
// recursively descend)
if (!singlepar || pit == cursor_.bottom().pit())
text->redoParagraph(pit);
int y0 = text->getPar(pit).ascent() - offset_ref_;
// Redo paragraphs above anchor if necessary; again, in Single Par
// mode, only if we encounter the (main text) one having the cursor.
int y1 = y0;
while (y1 > 0 && pit1 > 0) {
y1 -= text->getPar(pit1).ascent();
--pit1;
if (!singlepar || pit1 == cursor_.bottom().pit())
text->redoParagraph(pit1);
y1 -= text->getPar(pit1).descent();
}
// Take care of ascent of first line
y1 -= text->getPar(pit1).ascent();
// Normalize anchor for next time
anchor_ref_ = pit1;
offset_ref_ = -y1;
// Grey at the beginning is ugly
if (pit1 == 0 && y1 > 0) {
y0 -= y1;
y1 = 0;
anchor_ref_ = 0;
}
// Redo paragraphs below the anchor if necessary. Single par mode:
// only the one containing the cursor if encountered.
int y2 = y0;
while (y2 < bv.workHeight() && pit2 < int(npit) - 1) {
y2 += text->getPar(pit2).descent();
++pit2;
if (!singlepar || pit2 == cursor_.bottom().pit())
text->redoParagraph(pit2);
y2 += text->getPar(pit2).ascent();
}
// Take care of descent of last line
y2 += text->getPar(pit2).descent();
// The coordinates of all these paragraphs are correct, cache them
int y = y1;
for (lyx::pit_type pit = pit1; pit <= pit2; ++pit) {
y += text->getPar(pit).ascent();
theCoords.parPos()[text][pit] = Point(0, y);
if (singlepar && pit == cursor_.bottom().pit()) {
// In Single Paragraph mode, collect here the
// y1 and y2 of the (one) paragraph the cursor is in
y1 = y - text->getPar(pit).ascent();
y2 = y + text->getPar(pit).descent();
}
y += text->getPar(pit).descent();
}
if (singlepar) {
// collect cursor paragraph iter bounds
pit1 = cursor_.bottom().pit();
pit2 = cursor_.bottom().pit();
}
lyxerr[Debug::DEBUG]
<< BOOST_CURRENT_FUNCTION
<< " y1: " << y1
<< " y2: " << y2
<< " pit1: " << pit1
<< " pit2: " << pit2
<< " npit: " << npit
<< " singlepar: " << singlepar
<< "size: " << size
<< endl;
return ViewMetricsInfo(pit1, pit2, y1, y2, singlepar, size);
}