X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView_pimpl.C;h=1c52d6e331492a1cd2398a980ab57fe763a184ee;hb=41ecabf5197a74719dd125e974b062184208c96b;hp=27adc9dcfb9699d2e89532111ed2f659499eb5b7;hpb=99aacdad5ce32c5905149d800405ff48ffb3a3d6;p=lyx.git diff --git a/src/BufferView_pimpl.C b/src/BufferView_pimpl.C index 27adc9dcfb..1c52d6e331 100644 --- a/src/BufferView_pimpl.C +++ b/src/BufferView_pimpl.C @@ -23,15 +23,18 @@ #include "buffer_funcs.h" #include "bufferlist.h" #include "bufferparams.h" +#include "coordcache.h" #include "cursor.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 "iterators.h" +#include "insetiterator.h" +#include "LaTeXFeatures.h" #include "lyx_cb.h" // added for Dispatch functions #include "lyx_main.h" #include "lyxfind.h" @@ -39,18 +42,23 @@ #include "lyxtext.h" #include "lyxrc.h" #include "lastfiles.h" +#include "metricsinfo.h" #include "paragraph.h" #include "paragraph_funcs.h" #include "ParagraphParameters.h" +#include "pariterator.h" +#include "rowpainter.h" #include "undo.h" #include "vspace.h" -#include "insets/insetfloatlist.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" @@ -59,14 +67,18 @@ #include "graphics/Previews.h" +#include "support/convert.h" +#include "support/filefilterlist.h" #include "support/filetools.h" -#include "support/globbing.h" -#include "support/path_defines.h" -#include "support/tostr.h" +#include "support/forkedcontr.h" +#include "support/package.h" +#include "support/types.h" #include +#include -using bv_funcs::currentState; +#include +#include using lyx::pos_type; @@ -74,15 +86,20 @@ 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::strToUnsignedInt; -using lyx::support::system_lyxdir; +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; @@ -106,17 +123,31 @@ boost::signals::connection selectioncon; boost::signals::connection lostcon; +/// Return an inset of this class if it exists at the current cursor position +template +T * getInsetByCode(LCursor & cur, InsetBase::Code code) +{ + T * inset = 0; + DocIterator it = cur; + if (it.nextInset() && + it.nextInset()->lyxCode() == code) { + inset = static_cast(it.nextInset()); + } + return inset; +} + } // anon namespace BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner, - int xpos, int ypos, int width, int height) + int width, int height) : bv_(&bv), owner_(owner), buffer_(0), cursor_timeout(400), - using_xterm_cursor(false), cursor_(bv) + using_xterm_cursor(false), cursor_(bv) , + anchor_ref_(0), offset_ref_(0) { xsel_cache_.set = false; - workarea_.reset(WorkAreaFactory::create(xpos, ypos, width, height)); + workarea_.reset(WorkAreaFactory::create(*owner_, width, height)); screen_.reset(LyXScreenFactory::create(workarea())); // Setup the signals @@ -159,19 +190,32 @@ void BufferView::Pimpl::connectBuffer(Buffer & buf) disconnectBuffer(); errorConnection_ = - buf.error.connect(boost::bind(&BufferView::Pimpl::addError, this, _1)); + buf.error.connect( + boost::bind(&BufferView::Pimpl::addError, this, _1)); + messageConnection_ = - buf.message.connect(boost::bind(&LyXView::message, owner_, _1)); + buf.message.connect( + boost::bind(&LyXView::message, owner_, _1)); + busyConnection_ = - buf.busy.connect(boost::bind(&LyXView::busy, owner_, _1)); + buf.busy.connect( + boost::bind(&LyXView::busy, owner_, _1)); + titleConnection_ = - buf.updateTitles.connect(boost::bind(&LyXView::updateWindowTitle, owner_)); + buf.updateTitles.connect( + boost::bind(&LyXView::updateWindowTitle, owner_)); + timerConnection_ = - buf.resetAutosaveTimers.connect(boost::bind(&LyXView::resetAutosaveTimer, owner_)); + buf.resetAutosaveTimers.connect( + boost::bind(&LyXView::resetAutosaveTimer, owner_)); + readonlyConnection_ = - buf.readonly.connect(boost::bind(&BufferView::Pimpl::showReadonly, this, _1)); + buf.readonly.connect( + boost::bind(&BufferView::Pimpl::showReadonly, this, _1)); + closingConnection_ = - buf.closing.connect(boost::bind(&BufferView::Pimpl::buffer, this, (Buffer *)0)); + buf.closing.connect( + boost::bind(&BufferView::Pimpl::setBuffer, this, (Buffer *)0)); } @@ -187,20 +231,17 @@ void BufferView::Pimpl::disconnectBuffer() } -bool BufferView::Pimpl::newFile(string const & filename, - string const & tname, - bool isNamed) +void BufferView::Pimpl::newFile(string const & filename, string const & tname, + bool isNamed) { - Buffer * b = ::newFile(filename, tname, isNamed); - buffer(b); - return true; + 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 + // Get absolute path of file and add ".lyx" + // to the filename if necessary string s = FileSearch(string(), filename, "lyx"); bool const found = !s.empty(); @@ -208,7 +249,7 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles) if (!found) s = filename; - // file already open? + // File already open? if (bufferlist.exists(s)) { string const file = MakeDisplayPath(s, 20); string text = bformat(_("The document %1$s is already " @@ -218,14 +259,13 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles) text, 0, 1, _("&Revert"), _("&Switch to document")); if (ret != 0) { - buffer(bufferlist.getBuffer(s)); + setBuffer(bufferlist.getBuffer(s)); return true; - } else { - // FIXME: should be LFUN_REVERT - if (!bufferlist.close(bufferlist.getBuffer(s), false)) - return false; - // Fall through to new load. (Asger) } + // FIXME: should be LFUN_REVERT + if (!bufferlist.close(bufferlist.getBuffer(s), false)) + return false; + // Fall through to new load. (Asger) } Buffer * b; @@ -250,7 +290,7 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles) return false; } - buffer(b); + setBuffer(b); bv_->showErrorList(_("Parse")); if (tolastfiles) @@ -278,166 +318,86 @@ Painter & BufferView::Pimpl::painter() const } -void BufferView::Pimpl::top_y(int y) -{ - top_y_ = y; -} - - -int BufferView::Pimpl::top_y() const +void BufferView::Pimpl::setBuffer(Buffer * b) { - return top_y_; -} + lyxerr[Debug::INFO] << BOOST_CURRENT_FUNCTION + << "[ b = " << b << "]" << endl; - -void BufferView::Pimpl::buffer(Buffer * b) -{ - lyxerr[Debug::INFO] << "Setting buffer in BufferView (" - << b << ')' << endl; - if (buffer_) { + if (buffer_) disconnectBuffer(); - //delete bv_->text(); - //bv_->setText(0); - } - // reset old cursor - cursor_.reset(); + // 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; + } - // set current buffer - buffer_ = b; + // Reset old cursor + cursor_ = LCursor(*bv_); + anchor_ref_ = 0; + offset_ref_ = 0; - top_y_ = 0; - // if we're quitting lyx, don't bother updating stuff + // If we're quitting lyx, don't bother updating stuff if (quitting) return; - // if we are closing the buffer, use the first buffer as current - if (!buffer_) - buffer_ = bufferlist.first(); - if (buffer_) { - lyxerr[Debug::INFO] << "Buffer addr: " << buffer_ << endl; + lyxerr[Debug::INFO] << BOOST_CURRENT_FUNCTION + << "Buffer addr: " << buffer_ << endl; connectBuffer(*buffer_); + cursor_.push(buffer_->inset()); + cursor_.resetAnchor(); buffer_->text().init(bv_); - buffer_->text().textwidth_ = workarea().workWidth(); - buffer_->text().fullRebreak(); - - // If we don't have a text object for this, we make one - if (bv_->text() == 0) - resizeCurrentBuffer(); - - // FIXME: needed when ? - fitCursor(); + buffer_->text().setCurrentFont(cursor_); // Buffer-dependent dialogs should be updated or // hidden. This should go here because some dialogs (eg ToC) // require bv_->text. owner_->getDialogs().updateBufferDependent(true); - } else { - lyxerr[Debug::INFO] << " No Buffer!" << endl; - owner_->getDialogs().hideBufferDependent(); } update(); updateScrollbar(); owner_->updateMenubar(); - owner_->updateToolbar(); + owner_->updateToolbars(); owner_->updateLayoutChoice(); owner_->updateWindowTitle(); - // Don't forget to update the Layout + // This is done after the layout combox has been populated if (buffer_) - owner_->setLayout(bv_->text()->cursorPar()->layout()->name()); + owner_->setLayout(cursor_.paragraph().layout()->name()); - if (lyx::graphics::Previews::activated() && buffer_) + if (buffer_ && lyx::graphics::Previews::status() != LyXRC::PREVIEW_OFF) lyx::graphics::Previews::get().generateBufferPreviews(*buffer_); } -bool BufferView::Pimpl::fitCursor() -{ - lyxerr << "BufferView::Pimpl::fitCursor." << endl; - if (screen().fitCursor(bv_)) { - updateScrollbar(); - return true; - } - return false; -} - - -void BufferView::Pimpl::redoCurrentBuffer() -{ - lyxerr[Debug::INFO] << "BufferView::redoCurrentBuffer" << endl; - if (buffer_ && bv_->text()) { - resizeCurrentBuffer(); - updateScrollbar(); - owner_->updateLayoutChoice(); - } -} - - void BufferView::Pimpl::resizeCurrentBuffer() { - lyxerr[Debug::INFO] << "resizeCurrentBuffer" << endl; - - int par = -1; - int selstartpar = -1; - int selendpar = -1; - - pos_type pos = 0; - pos_type selstartpos = 0; - pos_type selendpos = 0; - bool sel = false; - bool mark_set = false; - + lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl; owner_->busy(true); - owner_->message(_("Formatting document...")); LyXText * text = bv_->text(); - lyxerr << "### resizeCurrentBuffer: text " << text << endl; if (!text) return; - LCursor & cur = bv_->cursor(); - par = cur.par(); - pos = cur.pos(); - selstartpar = cur.selBegin().par(); - selstartpos = cur.selBegin().pos(); - selendpar = cur.selEnd().par(); - selendpos = cur.selEnd().pos(); - sel = cur.selection(); - mark_set = cur.mark(); - text->textwidth_ = bv_->workWidth(); - text->fullRebreak(); + text->init(bv_); update(); - if (par != -1) { - cur.selection() = true; - // At this point just to avoid the Delete-Empty-Paragraph- - // Mechanism when setting the cursor. - cur.mark() = mark_set; - if (sel) { - text->setCursor(selstartpar, selstartpos); - cur.resetAnchor(); - text->setCursor(selendpar, selendpos); - cur.setSelection(); - text->setCursor(par, pos); - } else { - text->setCursor(par, pos); - cur.resetAnchor(); - cur.selection() = false; - } - } - - fitCursor(); - switchKeyMap(); owner_->busy(false); - // reset the "Formatting..." message + // Reset the "Formatting..." message owner_->clearMessage(); updateScrollbar(); @@ -447,76 +407,112 @@ void BufferView::Pimpl::resizeCurrentBuffer() void BufferView::Pimpl::updateScrollbar() { if (!bv_->text()) { - lyxerr[Debug::GUI] << "no text in updateScrollbar" << endl; + lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION + << " no text in updateScrollbar" << endl; workarea().setScrollbarParams(0, 0, 0); return; } - LyXText const & t = *bv_->text(); - - lyxerr[Debug::GUI] << "Updating scrollbar: h " << t.height << ", top_y() " - << top_y() << ", default height " << defaultRowHeight() << endl; + LyXText & t = *bv_->text(); + if (anchor_ref_ > int(t.paragraphs().size()) - 1) { + anchor_ref_ = int(t.paragraphs().size()) - 1; + offset_ref_ = 0; + } - workarea().setScrollbarParams(t.height, top_y(), defaultRowHeight()); + 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 + int const wh = workarea().workHeight() / 4; + int const h = t.getPar(anchor_ref_).height(); + workarea().setScrollbarParams(t.paragraphs().size() * wh, anchor_ref_ * wh + int(offset_ref_ * wh / float(h)), int (wh * defaultRowHeight() / float(h))); +// workarea().setScrollbarParams(t.paragraphs().size(), anchor_ref_, 1); } void BufferView::Pimpl::scrollDocView(int value) { - lyxerr[Debug::GUI] << "scrollDocView of " << value << endl; + lyxerr[Debug::GUI] << BOOST_CURRENT_FUNCTION + << "[ value = " << value << "]" << endl; if (!buffer_) return; screen().hideCursor(); - top_y(value); - screen().redraw(*bv_); + int const wh = workarea().workHeight() / 4; + + LyXText & t = *bv_->text(); + + float const bar = value / float(wh * t.paragraphs().size()); + + anchor_ref_ = int(bar * 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; - int const height = defaultRowHeight(); - int const first = top_y() + height; - int const last = top_y() + workarea().workHeight() - height; + int const height = 2 * defaultRowHeight(); + int const first = height; + int const last = workarea().workHeight() - height; + LCursor & cur = cursor_; - LyXText * text = bv_->text(); - int y = text->cursorY(bv_->cursor().cursor_.front()); - if (y < first) - text->setCursorFromCoordinates(0, first); - else if (y > last) - text->setCursorFromCoordinates(0, last); + 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) +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()); +// 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) { - bv_->owner()->getLyXFunc().processKeySym(key, 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 @@ -525,10 +521,8 @@ void BufferView::Pimpl::workAreaKeyPress(LyXKeySymPtr key, * of the cursor. Note we cannot do this inside * dispatch() itself, because that's called recursively. */ - if (available()) { - cursor_timeout.restart(); + if (available()) screen().showCursor(*bv_); - } } @@ -539,7 +533,7 @@ void BufferView::Pimpl::selectionRequested() if (!available()) return; - LCursor & cur = bv_->cursor(); + LCursor & cur = cursor_; if (!cur.selection()) { xsel_cache_.set = false; @@ -547,16 +541,16 @@ void BufferView::Pimpl::selectionRequested() } if (!xsel_cache_.set || - cur.cursor_.back() != xsel_cache_.cursor || - cur.anchor_.back() != xsel_cache_.anchor) + cur.top() != xsel_cache_.cursor || + cur.anchor_.top() != xsel_cache_.anchor) { - xsel_cache_.cursor = cur.cursor_.back(); - xsel_cache_.anchor = cur.anchor_.back(); + xsel_cache_.cursor = cur.top(); + xsel_cache_.anchor = cur.anchor_.top(); xsel_cache_.set = cur.selection(); - sel = bv_->getLyXText()->selectionAsString(*bv_->buffer(), false); + sel = cur.selectionAsString(false); if (!sel.empty()) workarea().putClipboard(sel); - } + } } @@ -564,7 +558,7 @@ void BufferView::Pimpl::selectionLost() { if (available()) { screen().hideCursor(); - bv_->cursor().clearSelection(); + cursor_.clearSelection(); xsel_cache_.set = false; } } @@ -578,55 +572,99 @@ void BufferView::Pimpl::workAreaResize() bool const widthChange = workarea().workWidth() != work_area_width; bool const heightChange = workarea().workHeight() != work_area_height; - // update from work area + // Update from work area work_area_width = workarea().workWidth(); work_area_height = workarea().workHeight(); - if (buffer_ != 0) { - if (widthChange) { - // The visible LyXView need a resize - resizeCurrentBuffer(); - } + if (buffer_ && widthChange) { + // The visible LyXView need a resize + resizeCurrentBuffer(); } if (widthChange || heightChange) update(); - // always make sure that the scrollbar is sane. + // Always make sure that the scrollbar is sane. updateScrollbar(); owner_->updateLayoutChoice(); } -void BufferView::Pimpl::update() +bool BufferView::Pimpl::fitCursor() { - //lyxerr << "BufferView::update()" << endl; - // fix cursor coordinate cache in case something went wrong - - // check needed to survive LyX startup - if (bv_->getLyXText()) { - // update all 'visible' paragraphs - ParagraphList::iterator beg; - ParagraphList::iterator end; - getParsInRange(buffer_->paragraphs(), - top_y(), top_y() + workarea().workHeight(), - beg, end); - bv_->text()->redoParagraphs(beg, end); - updateScrollbar(); + 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; } - screen().redraw(*bv_); + center(); + return true; +} + + +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(); + bool forceupdate(flags & Update::Force); + + if ((flags & Update::FitCursor) && fitCursor()) { + forceupdate = true; + vi = metrics(flags & Update::SinglePar); + } + 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_) { - cursor_timeout.restart(); - return; + 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(); } - screen().toggleCursor(*bv_); cursor_timeout.restart(); } @@ -639,17 +677,17 @@ bool BufferView::Pimpl::available() const Change const BufferView::Pimpl::getCurrentChange() { - if (!bv_->buffer()->params().tracking_changes) + if (!buffer_->params().tracking_changes) return Change(Change::UNCHANGED); LyXText * text = bv_->getLyXText(); - LCursor & cur = bv_->cursor(); + LCursor & cur = cursor_; if (!cur.selection()) return Change(Change::UNCHANGED); - return text->getPar(cur.selBegin()) - ->lookupChangeFull(cur.selBegin().pos()); + return text->getPar(cur.selBegin().pit()). + lookupChangeFull(cur.selBegin().pos()); } @@ -657,11 +695,12 @@ void BufferView::Pimpl::savePosition(unsigned int i) { if (i >= saved_positions_num) return; + BOOST_ASSERT(cursor_.inTexted()); saved_positions[i] = Position(buffer_->fileName(), - bv_->text()->cursorPar()->id(), - bv_->text()->cursor().pos()); + cursor_.paragraph().id(), + cursor_.pos()); if (i > 0) - owner_->message(bformat(_("Saved bookmark %1$s"), tostr(i))); + owner_->message(bformat(_("Saved bookmark %1$d"), i)); } @@ -672,7 +711,7 @@ void BufferView::Pimpl::restorePosition(unsigned int i) string const fname = saved_positions[i].filename; - bv_->cursor().clearSelection(); + cursor_.clearSelection(); if (fname != buffer_->fileName()) { Buffer * b = 0; @@ -680,21 +719,21 @@ void BufferView::Pimpl::restorePosition(unsigned int i) b = bufferlist.getBuffer(fname); else { b = bufferlist.newBuffer(fname); - ::loadLyXFile(b, fname); // don't ask, just load it + // Don't ask, just load it + ::loadLyXFile(b, fname); } if (b) - buffer(b); + setBuffer(b); } ParIterator par = buffer_->getParFromID(saved_positions[i].par_id); if (par == buffer_->par_iterator_end()) return; - bv_->text()->setCursor(par.pit(), - min(par->size(), saved_positions[i].par_pos)); + bv_->setCursor(makeDocIterator(par, min(par->size(), saved_positions[i].par_pos))); if (i > 0) - owner_->message(bformat(_("Moved to bookmark %1$s"), tostr(i))); + owner_->message(bformat(_("Moved to bookmark %1$d"), i)); } @@ -722,79 +761,19 @@ void BufferView::Pimpl::switchKeyMap() void BufferView::Pimpl::center() { - LyXText * text = bv_->text(); - - bv_->cursor().clearSelection(); - int const half_height = workarea().workHeight() / 2; - int new_y = text->cursorY(bv_->cursor().cursor_.front()) - half_height; - if (new_y < 0) - new_y = 0; - - // FIXME: look at this comment again ... - // This updates top_y() but means the fitCursor() call - // from the update(FITCUR) doesn't realise that we might - // have moved (e.g. from GOTOPARAGRAPH), so doesn't cause - // the scrollbar to be updated as it should, so we have - // to do it manually. Any operation that does a center() - // and also might have moved top_y() must make sure to call - // updateScrollbar() currently. Never mind that this is a - // pretty obfuscated way of updating text->top_y() - top_y(new_y); + 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 & stuff) const +void BufferView::Pimpl::stuffClipboard(string const & content) const { - workarea().putClipboard(stuff); -} - - -InsetBase * BufferView::Pimpl::getInsetByCode(InsetBase::Code code) -{ -#if 0 - CursorSlice cursor = bv_->getLyXText()->cursor; - Buffer::inset_iterator it = - find_if(Buffer::inset_iterator( - cursorPar(), cursor().pos()), - buffer_->inset_iterator_end(), - lyx::compare_memfun(&Inset::lyxCode, code)); - return it != buffer_->inset_iterator_end() ? (*it) : 0; -#else - // Ok, this is a little bit too brute force but it - // should work for now. Better infrastructure is coming. (Lgb) - - Buffer * b = bv_->buffer(); - LyXText * text = bv_->getLyXText(); - - Buffer::inset_iterator beg = b->inset_iterator_begin(); - Buffer::inset_iterator end = b->inset_iterator_end(); - - bool cursor_par_seen = false; - - for (; beg != end; ++beg) { - if (beg.getPar() == text->cursorPar()) { - cursor_par_seen = true; - } - if (cursor_par_seen) { - if (beg.getPar() == text->cursorPar() - && beg.getPos() >= text->cursor().pos()) { - break; - } - if (beg.getPar() != text->cursorPar()) { - break; - } - } - - } - if (beg != end) { - // Now find the first inset that matches code. - for (; beg != end; ++beg) { - if (beg->lyxCode() == code) - return &(*beg); - } - } - return 0; -#endif + workarea().putClipboard(content); } @@ -818,7 +797,7 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm) make_pair(string(_("Documents|#o#O")), string(lyxrc.document_path)), make_pair(string(_("Examples|#E#e")), - string(AddPath(system_lyxdir(), "examples")))); + string(AddPath(package().system_support(), "examples")))); FileDialog::Result result = fileDlg.open(initpath, @@ -837,152 +816,224 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm) } } - // get absolute path of file and add ".lyx" to the filename if - // necessary + // 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)); - if (bv_->insertLyXFile(filename)) - owner_->message(bformat(_("Document %1$s inserted."), - disp_fn)); - else - owner_->message(bformat(_("Could not insert document %1$s"), - disp_fn)); + + cursor_.clearSelection(); + bv_->getLyXText()->breakParagraph(cursor_); + + BOOST_ASSERT(cursor_.inTexted()); + + string const fname = MakeAbsPath(filename); + bool const res = buffer_->readFile(fname, cursor_.pit()); + resizeCurrentBuffer(); + + string s = res ? _("Document %1$s inserted.") + : _("Could not insert document %1$s"); + owner_->message(bformat(s, disp_fn)); } void BufferView::Pimpl::trackChanges() { - Buffer * buf = bv_->buffer(); - bool const tracking(buf->params().tracking_changes); + bool const tracking = buffer_->params().tracking_changes; if (!tracking) { - ParIterator const end = buf->par_iterator_end(); - for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) - it->trackChanges(); - buf->params().tracking_changes = true; + 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 - buf->undostack().clear(); + // We cannot allow undos beyond the freeze point + buffer_->undostack().clear(); } else { update(); - bv_->text()->setCursor(0, 0); + bv_->text()->setCursor(cursor_, 0, 0); +#ifdef WITH_WARNINGS #warning changes FIXME - bool found = lyx::find::findNextChange(bv_); +#endif + bool const found = lyx::find::findNextChange(bv_); if (found) { owner_->getDialogs().show("changes"); return; } - ParIterator const end = buf->par_iterator_end(); - for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) - it->untrackChanges(); - buf->params().tracking_changes = false; + for_each(buffer_->par_iterator_begin(), + buffer_->par_iterator_end(), + mem_fun_ref(&Paragraph::untrackChanges)); + + buffer_->params().tracking_changes = false; } - buf->redostack().clear(); + buffer_->redostack().clear(); } bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0) { - // - // this is only called for mouse related events. - // + //lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl; + + // This is only called for mouse related events including + // LFUN_FILE_OPEN generated by drag-and-drop. FuncRequest cmd = cmd0; - cmd.y += bv_->top_y(); - lyxerr << "*** workAreaDispatch: request: " << cmd << std::endl; - LCursor cur(*bv_); - switch (cmd.action) { -#if 0 - case LFUN_MOUSE_MOTION: { - if (!available()) - return false; - FuncRequest cmd1 = cmd; - InsetBase * inset = cur.inset(); - DispatchResult res; - if (inset) { - res = inset->dispatch(cur, cmd); - } else { - res = cur.innerText()->dispatch(cur, cmd); - } - if (bv_->fitCursor() || res.update()) { - bv_->update(); - cur.updatePos(); - } + // Handle drag&drop + if (cmd.action == LFUN_FILE_OPEN) { + owner_->dispatch(cmd); return true; } -#endif - case LFUN_MOUSE_MOTION: - case LFUN_MOUSE_PRESS: - case LFUN_MOUSE_RELEASE: - case LFUN_MOUSE_DOUBLE: - case LFUN_MOUSE_TRIPLE: { - // We pass those directly to the Bufferview, since - // otherwise selection handling breaks down + if (!buffer_) + return false; - // Doesn't go through lyxfunc, so we need to update - // the layout choice etc. ourselves + LCursor cur(*bv_); + cur.push(buffer_->inset()); + cur.selection() = cursor_.selection(); - // e.g. Qt mouse press when no buffer - if (!available()) - return false; + // Doesn't go through lyxfunc, so we need to update + // the layout choice etc. ourselves - screen().hideCursor(); + // E.g. Qt mouse press when no buffer + if (!available()) + return false; - // either the inset under the cursor or the surrounding LyXText will - // handle this event. + screen().hideCursor(); - // built temporary path to inset - LyXText * text = bv_->text(); - InsetBase * const inset_hit = text->checkInsetHit(cmd.x, cmd.y); - if (inset_hit) - inset_hit->edit(cur, cmd.x, cmd.y); + // Either the inset under the cursor or the + // surrounding LyXText will handle this event. + + // Build temporary cursor. + cmd.y = min(max(cmd.y,-1), workarea().workHeight()); + 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; + + // Put anchor at the same position. + cur.resetAnchor(); + + // Try to dispatch to an non-editable inset near this position + // via the temp cursor. If the inset wishes to change the real + // cursor it has to do so explicitly by using + // cur.bv().cursor() = cur; (or similar) + 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); + + if (cur.result().dispatched()) { + // Redraw if requested or necessary. + if (cur.result().update()) + update(Update::FitCursor | Update::Force); else - text->setCursorFromCoordinates(cur.current(), cmd.x, cmd.y); - lyxerr << "created temp cursor: " << cur << endl; + update(); + } - // Dispatch to the temp cursor. - // An inset (or LyXText) can assign this to bv->cursor() - // if it wishes to do so. - DispatchResult res = cur.dispatch(cmd); + // See workAreaKeyPress + cursor_timeout.restart(); + screen().showCursor(*bv_); - if (bv_->fitCursor() || res.update()) - bv_->update(); + // Skip these when selecting + if (cmd.action != LFUN_MOUSE_MOTION) { + owner_->updateLayoutChoice(); + owner_->updateToolbars(); + } - // see workAreaKeyPress - cursor_timeout.restart(); - screen().showCursor(*bv_); + // 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; +} - // skip these when selecting - if (cmd.action != LFUN_MOUSE_MOTION) { - owner_->updateLayoutChoice(); - owner_->updateToolbar(); - } - // 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; +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: + case LFUN_FONT_STATE: + case LFUN_INSERT_LABEL: + case LFUN_BOOKMARK_SAVE: + case LFUN_GOTO_PARAGRAPH: + case LFUN_GOTOERROR: + case LFUN_GOTONOTE: + case LFUN_REFERENCE_GOTO: + case LFUN_WORD_FIND: + case LFUN_WORD_REPLACE: + case LFUN_MARK_OFF: + case LFUN_MARK_ON: + case LFUN_SETMARK: + case LFUN_CENTER: + case LFUN_BIBDB_ADD: + case LFUN_BIBDB_DEL: + case LFUN_WORDS_COUNT: + flag.enabled(true); + break; + + case LFUN_LABEL_GOTO: { + flag.enabled(!cmd.argument.empty() + || getInsetByCode(cursor_, InsetBase::REF_CODE)); + break; + } + + case LFUN_BOOKMARK_GOTO: + flag.enabled(isSavedPosition(convert(cmd.argument))); + break; + case LFUN_TRACK_CHANGES: + flag.enabled(true); + flag.setOnOff(buffer_->params().tracking_changes); + break; + + case LFUN_OUTPUT_CHANGES: { + LaTeXFeatures features(*buffer_, buffer_->params(), false); + flag.enabled(buffer_ && buffer_->params().tracking_changes + && features.isAvailable("dvipost")); + flag.setOnOff(buffer_->params().output_changes); + break; } + case LFUN_MERGE_CHANGES: + case LFUN_ACCEPT_CHANGE: // what about these two + case LFUN_REJECT_CHANGE: // what about these two + case LFUN_ACCEPT_ALL_CHANGES: + case LFUN_REJECT_ALL_CHANGES: + flag.enabled(buffer_ && buffer_->params().tracking_changes); + break; default: - lyxerr << "*** UNDISPATCHED: " << cmd; - //owner_->dispatch(cmd); + flag.enabled(false); } - return true; + + return flag; } + bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) { - lyxerr << "*** BufferView::Pimpl: request: " << cmd << std::endl; + //lyxerr << BOOST_CURRENT_FUNCTION + // << [ cmd = " << cmd << "]" << endl; + // Make sure that the cached BufferView is correct. - lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:" + lyxerr[Debug::ACTION] << BOOST_CURRENT_FUNCTION << " action[" << cmd.action << ']' << " arg[" << cmd.argument << ']' << " x[" << cmd.x << ']' @@ -990,15 +1041,30 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) << " button[" << cmd.button() << ']' << endl; - LyXTextClass const & tclass = buffer_->params().getLyXTextClass(); - LCursor & cur = bv_->cursor(); + LCursor & cur = cursor_; switch (cmd.action) { - case LFUN_SCROLL_INSET: - // this is not handled here as this function is only active - // if we have a locking_inset and that one is (or contains) - // a tabular-inset + 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: @@ -1014,32 +1080,23 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) break; case LFUN_FONT_STATE: - owner_->getLyXFunc().setMessage(currentState(bv_)); - break; - - case LFUN_INSERT_LABEL: { - // Try and generate a valid label - string const contents = cmd.argument.empty() ? - getPossibleLabel(*bv_) : cmd.argument; - InsetCommandParams icp("label", contents); - string data = InsetCommandMailer::params2string("label", icp); - owner_->getDialogs().show("label", data, 0); + cur.message(cur.currentState()); break; - } case LFUN_BOOKMARK_SAVE: - savePosition(strToUnsignedInt(cmd.argument)); + savePosition(convert(cmd.argument)); break; case LFUN_BOOKMARK_GOTO: - restorePosition(strToUnsignedInt(cmd.argument)); + restorePosition(convert(cmd.argument)); break; - case LFUN_REF_GOTO: { + case LFUN_LABEL_GOTO: { string label = cmd.argument; if (label.empty()) { InsetRef * inset = - static_cast(getInsetByCode(InsetBase::REF_CODE)); + getInsetByCode(cursor_, + InsetBase::REF_CODE); if (inset) { label = inset->getContents(); savePosition(0); @@ -1048,92 +1105,42 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) if (!label.empty()) bv_->gotoLabel(label); - } - break; - - // --- accented characters --------------------------- - - case LFUN_UMLAUT: - case LFUN_CIRCUMFLEX: - case LFUN_GRAVE: - case LFUN_ACUTE: - case LFUN_TILDE: - case LFUN_CEDILLA: - case LFUN_MACRON: - case LFUN_DOT: - case LFUN_UNDERDOT: - case LFUN_UNDERBAR: - case LFUN_CARON: - case LFUN_SPECIAL_CARON: - case LFUN_BREVE: - case LFUN_TIE: - case LFUN_HUNG_UMLAUT: - case LFUN_CIRCLE: - case LFUN_OGONEK: - if (cmd.argument.empty()) { - // As always... - owner_->getLyXFunc().handleKeyFunc(cmd.action); - } else { - owner_->getLyXFunc().handleKeyFunc(cmd.action); - owner_->getIntl().getTransManager() - .TranslateAndInsert(cmd.argument[0], bv_->getLyXText()); - update(); - } - break; - - case LFUN_INSET_INSERT: { - // Same as above. - BOOST_ASSERT(false); - InsetBase * inset = createInset(bv_, cmd); - if (!inset || !insertInset(inset)) - delete inset; break; } - case LFUN_FLOAT_LIST: - if (tclass.floats().typeExist(cmd.argument)) { - InsetBase * inset = new InsetFloatList(cmd.argument); - if (!insertInset(inset, tclass.defaultLayoutName())) - delete inset; + case LFUN_GOTO_PARAGRAPH: { + int const id = convert(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 << "Non-existent float type: " - << cmd.argument << endl; + lyxerr[Debug::INFO] << "Paragraph " << par->id() + << " found." << endl; } - break; - case LFUN_LAYOUT_PARAGRAPH: { - string data; - params2string(*bv_->getLyXText()->cursorPar(), data); - data = "show\n" + data; - bv_->owner()->getDialogs().show("paragraph", data); + // Set the cursor + bv_->setCursor(makeDocIterator(par, 0)); + + update(); + switchKeyMap(); break; } - case LFUN_PARAGRAPH_UPDATE: - updateParagraphDialog(); + case LFUN_GOTOERROR: + bv_funcs::gotoInset(bv_, InsetBase::ERROR_CODE, false); break; - case LFUN_PARAGRAPH_APPLY: - setParagraphParams(*bv_, cmd.argument); + case LFUN_GOTONOTE: + bv_funcs::gotoInset(bv_, InsetBase::NOTE_CODE, false); break; - case LFUN_THESAURUS_ENTRY: { - string arg = cmd.argument; - - if (arg.empty()) { - arg = bv_->getLyXText()->selectionAsString(*buffer_, - false); - - // FIXME - if (arg.size() > 100 || arg.empty()) { - // Get word or selection - bv_->getLyXText()->selectWordWhenUnderCursor(lyx::WHOLE_WORD); - arg = bv_->getLyXText()->selectionAsString(*buffer_, false); - // FIXME: where is getLyXText()->unselect(bv_) ? - } - } - - bv_->owner()->getDialogs().show("thesaurus", arg); + case LFUN_REFERENCE_GOTO: { + vector tmp; + tmp.push_back(InsetBase::LABEL_CODE); + tmp.push_back(InsetBase::REF_CODE); + bv_funcs::gotoInset(bv_, tmp, true); break; } @@ -1141,37 +1148,34 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) trackChanges(); break; + case LFUN_OUTPUT_CHANGES: { + bool const state = buffer_->params().output_changes; + buffer_->params().output_changes = !state; + break; + } + case LFUN_MERGE_CHANGES: owner_->getDialogs().show("changes"); break; case LFUN_ACCEPT_ALL_CHANGES: { - bv_->text()->setCursor(0, 0); + cursor_.reset(buffer_->inset()); +#ifdef WITH_WARNINGS #warning FIXME changes +#endif while (lyx::find::findNextChange(bv_)) - bv_->getLyXText()->acceptChange(); + bv_->getLyXText()->acceptChange(cursor_); update(); break; } case LFUN_REJECT_ALL_CHANGES: { - bv_->text()->setCursor(0, 0); + cursor_.reset(buffer_->inset()); +#ifdef WITH_WARNINGS #warning FIXME changes +#endif while (lyx::find::findNextChange(bv_)) - bv_->getLyXText()->rejectChange(); - update(); - break; - } - - case LFUN_ACCEPT_CHANGE: { - bv_->getLyXText()->acceptChange(); - update(); - break; - } - - case LFUN_REJECT_CHANGE: { - bv_->getLyXText()->rejectChange(); - update(); + bv_->getLyXText()->rejectChange(cursor_); break; } @@ -1185,124 +1189,166 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & cmd) case LFUN_MARK_OFF: cur.clearSelection(); - bv_->update(); cur.resetAnchor(); - cmd.message(N_("Mark off")); + cur.message(N_("Mark off")); break; case LFUN_MARK_ON: cur.clearSelection(); cur.mark() = true; - bv_->update(); cur.resetAnchor(); - cmd.message(N_("Mark on")); + cur.message(N_("Mark on")); break; case LFUN_SETMARK: cur.clearSelection(); if (cur.mark()) { - cmd.message(N_("Mark removed")); + cur.mark() = false; + cur.message(N_("Mark removed")); } else { cur.mark() = true; - cmd.message(N_("Mark set")); + cur.message(N_("Mark set")); } cur.resetAnchor(); - bv_->update(); break; - case LFUN_UNKNOWN_ACTION: - cmd.errorMessage(N_("Unknown function!")); + case LFUN_CENTER: + center(); + break; + + case LFUN_BIBDB_ADD: { + LCursor tmpcur = cursor_; + bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false); + InsetBibtex * inset = getInsetByCode(tmpcur, + InsetBase::BIBTEX_CODE); + if (inset) + inset->addDatabase(cmd.argument); + break; + } + + case LFUN_BIBDB_DEL: { + LCursor tmpcur = cursor_; + bv_funcs::findInset(tmpcur, InsetBase::BIBTEX_CODE, false); + InsetBibtex * inset = getInsetByCode(tmpcur, + InsetBase::BIBTEX_CODE); + if (inset) + inset->delDatabase(cmd.argument); 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; default: - return cur.dispatch(cmd).dispatched(); + return false; } return true; } -bool BufferView::Pimpl::insertInset(InsetBase * inset, string const & lout) +ViewMetricsInfo BufferView::Pimpl::metrics(bool singlepar) { - // not quite sure if we want this... - bv_->text()->recUndo(bv_->text()->cursor().par()); - freezeUndo(); + // Remove old position cache + theCoords.clear(); + BufferView & bv = *bv_; + LyXText * const text = bv.text(); + if (anchor_ref_ > int(text->paragraphs().size() - 1)) { + anchor_ref_ = int(text->paragraphs().size() - 1); + offset_ref_ = 0; + } - bv_->cursor().clearSelection(); - if (!lout.empty()) { - bv_->text()->breakParagraph(bv_->buffer()->paragraphs()); + lyx::pit_type const pit = anchor_ref_; + int pit1 = pit; + int pit2 = pit; + size_t const npit = text->paragraphs().size(); + + lyxerr[Debug::DEBUG] + << BOOST_CURRENT_FUNCTION + << " npit: " << npit + << " pit1: " << pit1 + << " pit2: " << pit2 + << endl; + + // Rebreak anchor par + text->redoParagraph(pit); + int y0 = text->getPar(pit1).ascent() - offset_ref_; + + // Redo paragraphs above cursor if necessary + int y1 = y0; + while (!singlepar && y1 > 0 && pit1 > 0) { + y1 -= text->getPar(pit1).ascent(); + --pit1; + text->redoParagraph(pit1); + y1 -= text->getPar(pit1).descent(); + } - if (!bv_->text()->cursorPar()->empty()) { - bv_->text()->cursorLeft(bv_); - bv_->text()->breakParagraph(bv_->buffer()->paragraphs()); - } - string lres = lout; - LyXTextClass const & tclass = buffer_->params().getLyXTextClass(); - bool hasLayout = tclass.hasLayout(lres); + // Take care of ascent of first line + y1 -= text->getPar(pit1).ascent(); - bv_->text()->setLayout(hasLayout ? lres : tclass.defaultLayoutName()); - bv_->text()->setParagraph(Spacing(), LYX_ALIGN_LAYOUT, string(), 0); - } - bv_->cursor().innerText()->insertInset(inset); - unFreezeUndo(); - return true; -} + // 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; + } -bool BufferView::Pimpl::ChangeInsets(InsetBase::Code code, - string const & from, string const & to) -{ - bool need_update = false; - CursorSlice cur = bv_->text()->cursor(); - - ParIterator end = bv_->buffer()->par_iterator_end(); - for (ParIterator it = bv_->buffer()->par_iterator_begin(); - it != end; ++it) { - bool changed_inset = false; - for (InsetList::iterator it2 = it->insetlist.begin(); - it2 != it->insetlist.end(); ++it2) { - if (it2->inset->lyxCode() == code) { - InsetCommand * inset = static_cast(it2->inset); - if (inset->getContents() == from) { - inset->setContents(to); - changed_inset = true; - } - } - } - if (changed_inset) { - need_update = true; + // Redo paragraphs below cursor if necessary + int y2 = y0; + while (!singlepar && y2 < bv.workHeight() && pit2 < int(npit) - 1) { + y2 += text->getPar(pit2).descent(); + ++pit2; + text->redoParagraph(pit2); + y2 += text->getPar(pit2).ascent(); + } - // FIXME + // Take care of descent of last line + y2 += text->getPar(pit2).descent(); - // The test it.size() == 1 was needed to prevent crashes. - // How to set the cursor correctly when it.size() > 1 ?? - if (it.size() == 1) { - bv_->text()->setCursorIntern(bv_->text()->parOffset(it.pit()), 0); - bv_->text()->redoParagraph(bv_->text()->cursorPar()); - } - } + // 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); + y += text->getPar(pit).descent(); } - bv_->text()->setCursorIntern(cur.par(), cur.pos()); - return need_update; -} + lyxerr[Debug::DEBUG] + << BOOST_CURRENT_FUNCTION + << " y1: " << y1 + << " y2: " << y2 + << endl; -void BufferView::Pimpl::updateParagraphDialog() -{ - if (!bv_->owner()->getDialogs().visible("paragraph")) - return; - CursorSlice const & cur = bv_->cursor().innerTextSlice(); - LyXText * text = bv_->cursor().innerText(); - Paragraph const & par = *text->getPar(cur.par()); - string data; - params2string(par, data); - - // Will the paragraph accept changes from the dialog? - InsetBase * const inset = cur.inset(); - bool const accept = - !(inset && inset->forceDefaultParagraphs(inset)); - - data = "update " + tostr(accept) + '\n' + data; - bv_->owner()->getDialogs().update("paragraph", data); + return ViewMetricsInfo(pit1, pit2, y1, y2, singlepar); }