* \author André Pönitz
* \author Dekel Tsur
* \author Jürgen Vigna
+ * \author Abdelrazak Younes
*
* Full author contact details are available in file CREDITS.
*/
#include "CutAndPaste.h"
#include "debug.h"
#include "dispatchresult.h"
+#include "errorlist.h"
#include "factory.h"
#include "FloatList.h"
#include "funcrequest.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/insettext.h"
#include "frontends/Alert.h"
-#include "frontends/Clipboard.h"
#include "frontends/Dialogs.h"
#include "frontends/FileDialog.h"
#include "frontends/font_metrics.h"
#include "frontends/Gui.h"
#include "frontends/LyXView.h"
-#include "frontends/Painter.h"
-#include "frontends/WorkArea.h"
+#include "frontends/Selection.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 <functional>
#include <vector>
-using lyx::frontend::WorkArea;
using lyx::frontend::Clipboard;
using lyx::frontend::Gui;
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;
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>
} // anon namespace
-BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner, WorkArea * workArea)
- : bv_(&bv), owner_(owner), workArea_(workArea), buffer_(0), wh_(0), cursor_timeout(400),
- using_xterm_cursor(false), cursor_(bv),
- anchor_ref_(0), offset_ref_(0)
+BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner)
+ : bv_(&bv), owner_(owner), buffer_(0), wh_(0),
+ cursor_(bv),
+ multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0)
{
xsel_cache_.set = false;
- // 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();
}
-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"
if (found) {
b = bufferlist.newBuffer(s);
- connectBuffer(*b);
if (!::loadLyXFile(b, s)) {
bufferlist.release(b);
return false;
int const ret = Alert::prompt(_("Create new document?"),
text, 0, 1, _("&Create"), _("Cancel"));
- if (ret == 0)
- b = ::newFile(s, string(), true);
- else
+ if (ret == 0) {
+ b = newFile(s, string(), true);
+ if (!b)
+ return false;
+ } else
return false;
}
setBuffer(b);
- bv_->showErrorList(_("Parse"));
+ // Send the "errors" signal in case of parsing errors
+ b->errors("Parse");
// scroll to the position when the file was last closed
if (lyxrc.use_lastfilepos) {
}
-lyx::frontend::Gui & BufferView::Pimpl::gui() const
-{
- return owner_->gui();
-}
-
-
-lyx::frontend::WorkArea & BufferView::Pimpl::workarea() const
-{
- return *workArea_;
-}
-
-
-lyx::frontend::Clipboard & BufferView::Pimpl::clipboard() const
-{
- return owner_->gui().clipboard();
-}
-
-
-lyx::frontend::Painter & BufferView::Pimpl::painter() const
-{
- return workArea_->getPainter();
-}
-
-
int BufferView::Pimpl::width() const
{
return width_;
<< "[ 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.
boost::tie(cursor_.pit(), cursor_.pos()) );
}
+ // If we're quitting lyx, don't bother updating stuff
+ if (quitting) {
+ buffer_ = 0;
+ return;
+ }
+
// If we are closing current buffer, switch to the first in
// buffer list.
if (!b) {
<< " 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;
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_);
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();
- owner_->updateMenubar();
- owner_->updateToolbars();
- owner_->updateLayoutChoice();
- owner_->updateWindowTitle();
+
+ if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF)
+ lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
+}
+
+string BufferView::Pimpl::firstLayout()
+{
+ string firstlayout;
// This is done after the layout combox has been populated
if (buffer_) {
CursorSlice const & slice = cursor_[i];
if (!slice.inset().inMathed()) {
LyXLayout_ptr const layout = slice.paragraph().layout();
- owner_->setLayout(layout->name());
+ firstlayout = layout->name();
break;
}
BOOST_ASSERT(i>0);
--i;
}
}
-
- if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF)
- lyx::graphics::Previews::get().generateBufferPreviews(*buffer_);
+ return firstlayout;
}
void BufferView::Pimpl::resizeCurrentBuffer()
{
lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl;
- owner_->busy(true);
- owner_->message(_("Formatting document..."));
LyXText * text = bv_->text();
if (!text)
text->init(bv_);
update();
-
switchKeyMap();
- owner_->busy(false);
-
- // Reset the "Formatting..." message
- owner_->clearMessage();
}
if (!buffer_)
return;
- owner_->gui().guiCursor().hide();
-
LyXText & t = *bv_->text();
float const bar = value / float(wh_ * t.paragraphs().size());
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;
+
+void BufferView::Pimpl::setCursorFromScrollbar()
+{
+ LyXText & t = *bv_->text();
int const height = 2 * defaultRowHeight();
int const first = height;
t.setCursorFromCoordinates(cur, 0, newy);
}
}
- owner_->updateLayoutChoice();
}
// 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())
- owner_->gui().guiCursor().show(*bv_);
+// workArea_->setScrollbarParams(t->height(), top_y(), defaultRowHeight());}
}
xsel_cache_.set = cur.selection();
sel = cur.selectionAsString(false);
if (!sel.empty())
- clipboard().put(sel);
+ owner_->gui().selection().put(sel);
}
}
void BufferView::Pimpl::selectionLost()
{
if (available()) {
- owner_->gui().guiCursor().hide();
cursor_.clearSelection();
xsel_cache_.set = false;
}
height_ = height;
if (buffer_ && widthChange) {
- // The visible LyXView need a resize
+ // The WorkArea content needs a resize
resizeCurrentBuffer();
}
if (widthChange || heightChange)
update();
-
- owner_->updateLayoutChoice();
}
}
-void BufferView::Pimpl::update(Update::flags flags)
+ViewMetricsInfo const & BufferView::Pimpl::viewMetricsInfo()
{
- 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();
+ return metrics_info_;
+}
- // 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
- workArea_->redraw(*bv_, vi);
- } else {
- // Abort updating of the coord
- // cache - just restore the old one
- std::swap(theCoords, backup);
- }
- } else
- workArea_->greyOut();
+bool BufferView::Pimpl::update(Update::flags flags)
+{
+ // This is close to a hot-path.
+ if (lyxerr.debugging(Debug::DEBUG)) {
+ lyxerr[Debug::DEBUG]
+ << BOOST_CURRENT_FUNCTION
+ << "[fitcursor = " << (flags & Update::FitCursor)
+ << ", forceupdate = " << (flags & Update::Force)
+ << ", singlepar = " << (flags & Update::SinglePar)
+ << "] buffer: " << buffer_ << endl;
+ }
- owner_->view_state_changed();
-}
+ // Check needed to survive LyX startup
+ if (!buffer_)
+ return false;
+ // Update macro store
+ buffer_->buildMacros();
-// Callback for cursor timer
-void BufferView::Pimpl::cursorToggle()
-{
- if (buffer_) {
- owner_->gui().guiCursor().toggle(*bv_);
+ // First drawing step
+ updateMetrics(flags & Update::SinglePar);
- // 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();
- }
+ // The second drawing step is done in WorkArea::redraw() if needed.
+ bool const need_second_step =
+ (flags & (Update::Force | Update::FitCursor | Update::MultiParSel))
+ && (fitCursor() || multiParSel());
- cursor_timeout.restart();
+ return need_second_step;
}
}
-void BufferView::Pimpl::stuffClipboard(string const & content) const
-{
- clipboard().put(content);
-}
-
-
void BufferView::Pimpl::menuInsertLyXFile(string const & filenm)
{
BOOST_ASSERT(cursor_.inTexted());
string initpath = lyxrc.document_path;
if (available()) {
- string const trypath = owner_->buffer()->filePath();
+ string const trypath = buffer_->filePath();
// If directory is writeable, use this as default.
if (isDirWriteable(trypath))
initpath = trypath;
string res;
Buffer buf("", false);
- buf.error.connect(boost::bind(&BufferView::Pimpl::addError, this, _1));
if (::loadLyXFile(&buf, makeAbsPath(filename))) {
+ ErrorList & el = buffer_->errorList("Parse");
+ // Copy the inserted document error list into the current buffer one.
+ el = buf.errorList("Parse");
lyx::cap::pasteParagraphList(cursor_, buf.paragraphs(),
- buf.params().textclass);
+ buf.params().textclass, el);
res = _("Document %1$s inserted.");
} else
res = _("Could not insert document %1$s");
owner_->message(bformat(res, disp_fn));
- bv_->showErrorList(_("Document insertion"));
+ buffer_->errors("Parse");
resizeCurrentBuffer();
}
// LFUN_FILE_OPEN generated by drag-and-drop.
FuncRequest cmd = cmd0;
- // Handle drag&drop
- if (cmd.action == LFUN_FILE_OPEN) {
- owner_->dispatch(cmd);
- return true;
- }
-
if (!buffer_)
return false;
if (!available())
return false;
- owner_->gui().guiCursor().hide();
-
// Either the inset under the cursor or the
// surrounding LyXText will handle this event.
update(Update::FitCursor | Update::MultiParSel);
}
- // See workAreaKeyPress
- cursor_timeout.restart();
- owner_->gui().guiCursor().show(*bv_);
-
- // Skip these when selecting
- if (cmd.action != LFUN_MOUSE_MOTION) {
- owner_->updateLayoutChoice();
- owner_->updateToolbars();
- }
-
- // Slight hack: this is only called currently when we
- // clicked somewhere, so we force through the display
- // of the new status here.
- owner_->clearMessage();
return true;
}
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_BIBTEX_DATABASE_ADD:
case LFUN_BIBTEX_DATABASE_DEL:
case LFUN_WORDS_COUNT:
+ case LFUN_NEXT_INSET_TOGGLE:
flag.enabled(true);
break;
case LFUN_OUTLINE_IN:
lyx::toc::outline(lyx::toc::In, cursor_);
updateLabels(*buffer_);
- break;
+ 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;
buffer_->params().compressed = !buffer_->params().compressed;
break;
+ case LFUN_NEXT_INSET_TOGGLE: {
+ // this is the real function we want to invoke
+ FuncRequest tmpcmd = FuncRequest(LFUN_INSET_TOGGLE, cmd.origin);
+ // if there is an inset at cursor, see whether it
+ // wants to toggle.
+ InsetBase * inset = cur.nextInset();
+ if (inset && inset->isActive()) {
+ LCursor tmpcur = cur;
+ tmpcur.pushLeft(*inset);
+ inset->dispatch(tmpcur, tmpcmd);
+ if (tmpcur.result().dispatched()) {
+ cur.dispatched();
+ }
+ }
+ // if it did not work, try the underlying inset.
+ if (!cur.result().dispatched())
+ cur.dispatch(tmpcmd);
+
+ if (cur.result().dispatched())
+ cur.clearSelection();
+
+ break;
+ }
+
default:
return false;
}
}
-ViewMetricsInfo BufferView::Pimpl::metrics(bool singlepar)
+void BufferView::Pimpl::updateMetrics(bool singlepar)
{
// Remove old position cache
theCoords.clear();
// The coordinates of all these paragraphs are correct, cache them
int y = y1;
+ CoordCache::InnerParPosCache & parPos = theCoords.parPos()[text];
for (lyx::pit_type pit = pit1; pit <= pit2; ++pit) {
- y += text->getPar(pit).ascent();
- theCoords.parPos()[text][pit] = Point(0, y);
+ Paragraph const & par = text->getPar(pit);
+ y += par.ascent();
+ parPos[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();
+ y1 = y - par.ascent();
+ y2 = y + par.descent();
}
- y += text->getPar(pit).descent();
+ y += par.descent();
}
if (singlepar) {
<< "size: " << size
<< endl;
- return ViewMetricsInfo(pit1, pit2, y1, y2, singlepar, size);
+ metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2, singlepar, size);
}