X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView_pimpl.C;h=17e7b83f727d4a9b5fa5ab584168c2e35db23c43;hb=245426421648387f14846f5cbe6002f605d272ec;hp=97b946aedfd33df953309d8caff27ff36dcffbd4;hpb=70d0ba900118ac7e253c1e1969fd7a3d64ec8e03;p=lyx.git diff --git a/src/BufferView_pimpl.C b/src/BufferView_pimpl.C index 97b946aedf..17e7b83f72 100644 --- a/src/BufferView_pimpl.C +++ b/src/BufferView_pimpl.C @@ -4,7 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Asger Alstrup - * \author Alfredo Braustein + * \author Alfredo Braunstein * \author Lars Gullik Bjønnes * \author Jean-Marc Lasgouttes * \author Angus Leeming @@ -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,22 @@ #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/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,16 +66,16 @@ #include "graphics/Previews.h" -#include "mathed/formulabase.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 -using bv_funcs::currentState; +#include using lyx::pos_type; @@ -76,15 +83,19 @@ 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; extern BufferList bufferlist; @@ -108,17 +119,32 @@ boost::signals::connection selectioncon; boost::signals::connection lostcon; +/// Get next inset of this class from 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) - : bv_(bv), owner_(owner), buffer_(0), cursor_timeout(400), - using_xterm_cursor(false), cursor_(bv) +BufferView::Pimpl::Pimpl(BufferView & bv, LyXView * owner, + int width, int height) + : bv_(&bv), owner_(owner), buffer_(0), cursor_timeout(400), + 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 @@ -160,13 +186,33 @@ 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::buffer, this, (Buffer *)0)); + 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)); } @@ -182,20 +228,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(); @@ -203,7 +246,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 " @@ -213,14 +256,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; @@ -245,7 +287,7 @@ bool BufferView::Pimpl::loadLyXFile(string const & filename, bool tolastfiles) return false; } - buffer(b); + setBuffer(b); bv_->showErrorList(_("Parse")); if (tolastfiles) @@ -273,162 +315,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); + + // 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; - par = bv_->cursor().par(); - pos = bv_->cursor().pos(); - selstartpar = bv_->selStart().par(); - selstartpos = bv_->selStart().pos(); - selendpar = bv_->selEnd().par(); - selendpos = bv_->selEnd().pos(); - sel = bv_->selection().set(); - mark_set = bv_->selection().mark(); - text->textwidth_ = bv_->workWidth(); - text->fullRebreak(); + text->init(bv_); update(); - if (par != -1) { - bv_->selection().set(true); - // At this point just to avoid the Delete-Empty-Paragraph- - // Mechanism when setting the cursor. - bv_->selection().mark(mark_set); - if (sel) { - text->setCursor(selstartpar, selstartpos); - bv_->resetAnchor(); - text->setCursor(selendpar, selendpos); - bv_->setSelection(); - text->setCursor(par, pos); - } else { - text->setCursor(par, pos); - bv_->resetAnchor(); - bv_->selection().set(false); - } - } - - fitCursor(); - switchKeyMap(); owner_->busy(false); - // reset the "Formatting..." message + // Reset the "Formatting..." message owner_->clearMessage(); updateScrollbar(); @@ -438,68 +404,105 @@ 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: " << bv_->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 = bv_->cursor(); - LyXText * text = bv_->text(); - if (text->cursorY() < first) - text->setCursorFromCoordinates(0, first); - else if (text->cursorY() > 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).y_; + int const newy = min(last, max(y, first)); + if (y != newy) { + cur.reset(bv_->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()); +// 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()); } @@ -529,24 +532,24 @@ void BufferView::Pimpl::selectionRequested() if (!available()) return; - LyXText * text = bv_->getLyXText(); + LCursor & cur = bv_->cursor(); - if (!bv_->selection().set()) { + if (!cur.selection()) { xsel_cache_.set = false; return; } if (!xsel_cache_.set || - bv_->cursor() != xsel_cache_.cursor || - bv_->anchor() != xsel_cache_.anchor) + cur.back() != xsel_cache_.cursor || + cur.anchor_.back() != xsel_cache_.anchor) { - xsel_cache_.cursor = bv_->cursor(); - xsel_cache_.anchor = bv_->anchor(); - xsel_cache_.set = bv_->selection().set(); - sel = text->selectionAsString(*bv_->buffer(), false); + xsel_cache_.cursor = cur.back(); + xsel_cache_.anchor = cur.anchor_.back(); + xsel_cache_.set = cur.selection(); + sel = cur.selectionAsString(false); if (!sel.empty()) workarea().putClipboard(sel); - } + } } @@ -554,7 +557,7 @@ void BufferView::Pimpl::selectionLost() { if (available()) { screen().hideCursor(); - bv_->clearSelection(); + bv_->cursor().clearSelection(); xsel_cache_.set = false; } } @@ -568,55 +571,92 @@ 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_, bv_->cursor()) == bv_funcs::CUR_INSIDE) { + LyXFont const font = bv_->cursor().getFont(); + int const asc = font_metrics::maxAscent(font); + int const des = font_metrics::maxDescent(font); + Point p = bv_funcs::getPos(bv_->cursor()); + if (p.y_ - asc >= 0 && p.y_ + des < bv_->workHeight()) + return false; } - screen().redraw(*bv_); + bv_->center(); + return true; +} + + +void BufferView::Pimpl::update(bool fitcursor, bool forceupdate) +{ + lyxerr << BOOST_CURRENT_FUNCTION + << "[fitcursor = " << fitcursor << ',' + << " forceupdate = " << forceupdate + << "] buffer: " << buffer_ << endl; + + // Check needed to survive LyX startup + if (buffer_) { + // Update macro store + buffer_->buildMacros(); + // First drawing step + + CoordCache backup; + std::swap(theCoords, backup); + theCoords.startUpdating(); + + ViewMetricsInfo vi = metrics(); + + if (fitcursor && fitCursor()) { + 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(); + bv_->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(); + if (fcc.processesCompleted()) + fcc.handleCompletedProcesses(); } - screen().toggleCursor(*bv_); cursor_timeout.restart(); } @@ -633,12 +673,13 @@ Change const BufferView::Pimpl::getCurrentChange() return Change(Change::UNCHANGED); LyXText * text = bv_->getLyXText(); + LCursor & cur = bv_->cursor(); - if (!bv_->selection().set()) + if (!cur.selection()) return Change(Change::UNCHANGED); - return text->getPar(bv_->selStart()) - ->lookupChangeFull(bv_->selStart().pos()); + return text->getPar(cur.selBegin().pit()). + lookupChangeFull(cur.selBegin().pos()); } @@ -646,11 +687,12 @@ void BufferView::Pimpl::savePosition(unsigned int i) { if (i >= saved_positions_num) return; + BOOST_ASSERT(bv_->cursor().inTexted()); saved_positions[i] = Position(buffer_->fileName(), - bv_->text()->cursorPar()->id(), - bv_->text()->cursor().pos()); + bv_->cursor().paragraph().id(), + bv_->cursor().pos()); if (i > 0) - owner_->message(bformat(_("Saved bookmark %1$s"), tostr(i))); + owner_->message(bformat(_("Saved bookmark %1$d"), i)); } @@ -661,7 +703,7 @@ void BufferView::Pimpl::restorePosition(unsigned int i) string const fname = saved_positions[i].filename; - bv_->clearSelection(); + bv_->cursor().clearSelection(); if (fname != buffer_->fileName()) { Buffer * b = 0; @@ -669,21 +711,22 @@ 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_->text()->setCursor(bv_->cursor(), par.pit(), + 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)); } @@ -711,83 +754,25 @@ void BufferView::Pimpl::switchKeyMap() void BufferView::Pimpl::center() { - LyXText * text = bv_->text(); - - bv_->clearSelection(); - int const half_height = workarea().workHeight() / 2; - int new_y = std::max(0, text->cursorY() - half_height); - - // 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 t->top_y() - top_y(new_y); + CursorSlice & bot = bv_->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(bv_->cursor()).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); + workarea().putClipboard(content); } -InsetOld * BufferView::Pimpl::getInsetByCode(InsetOld::Code code) +void BufferView::Pimpl::MenuInsertLyXFile(string const & filenm) { -#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; - } else 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 -} - - -void BufferView::Pimpl::MenuInsertLyXFile(string const & filen) -{ - string filename = filen; + string filename = filenm; if (filename.empty()) { // Launch a file browser @@ -805,7 +790,7 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filen) 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, @@ -824,269 +809,277 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filen) } } - // 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)); + + bv_->cursor().clearSelection(); + bv_->getLyXText()->breakParagraph(bv_->cursor()); + + BOOST_ASSERT(bv_->cursor().inTexted()); + + string const fname = MakeAbsPath(filename); + bool const res = bv_->buffer()->readFile(fname, bv_->cursor().pit()); + bv_->resize(); + + 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); + Buffer * buf = bv_->buffer(); + bool const tracking = buf->params().tracking_changes; if (!tracking) { - ParIterator const end = buf->par_iterator_end(); - for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) - it->trackChanges(); + for_each(buf->par_iterator_begin(), + buf->par_iterator_end(), + bind(&Paragraph::trackChanges, _1, Change::UNCHANGED)); buf->params().tracking_changes = true; - // we cannot allow undos beyond the freeze point + // We cannot allow undos beyond the freeze point buf->undostack().clear(); } else { update(); - bv_->text()->setCursor(0, 0); + bv_->text()->setCursor(bv_->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(); + for_each(buf->par_iterator_begin(), + buf->par_iterator_end(), + mem_fun_ref(&Paragraph::untrackChanges)); + buf->params().tracking_changes = false; } buf->redostack().clear(); } -#warning remove me -LCursor theTempCursor(0); -namespace { +bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd0) +{ + lyxerr << BOOST_CURRENT_FUNCTION + << "[ cmd0 " << cmd0 << "]" << endl; - InsetOld * insetFromCoords(BufferView * bv, int x, int y) - { - lyxerr << "insetFromCoords" << endl; - LyXText * text = bv->text(); - InsetOld * inset = 0; - theTempCursor = LCursor(bv); - while (true) { - InsetOld * const inset_hit = text->checkInsetHit(x, y); - if (!inset_hit) { - lyxerr << "no further inset hit" << endl; - break; - } - inset = inset_hit; - if (!inset->descendable()) { - lyxerr << "not descendable" << endl; - break; - } - int const cell = inset->getCell(x, y + bv->top_y()); - if (cell == -1) - break; - text = inset_hit->getText(cell); - lyxerr << "Hit inset: " << inset << " at x: " << x - << " text: " << text << " y: " << y << endl; - theTempCursor.push(static_cast(inset)); - } - lyxerr << "theTempCursor: " << theTempCursor << endl; - return inset; + // This is only called for mouse related events including + // 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 (!bv_->buffer()) + return false; + LCursor cur(*bv_); + cur.push(bv_->buffer()->inset()); + cur.selection() = bv_->cursor().selection(); -bool BufferView::Pimpl::workAreaDispatch(FuncRequest const & cmd) -{ - switch (cmd.action) { - case LFUN_MOUSE_MOTION: { - if (!available()) - return false; - FuncRequest cmd1 = cmd; - UpdatableInset * inset = bv_->fullCursor().innerInset(); - DispatchResult res; - if (inset) { - cmd1.x -= inset->x(); - cmd1.y -= inset->y(); - res = inset->dispatch(*bv_, cmd1); - } else { - cmd1.y += bv_->top_y(); - res = bv_->fullCursor().innerText()->dispatch(*bv_, cmd1); - } + // Doesn't go through lyxfunc, so we need to update + // the layout choice etc. ourselves - if (bv_->fitCursor() || res.update()) { - bv_->update(); - bv_->fullCursor().updatePos(); - } + // E.g. Qt mouse press when no buffer + if (!available()) + return false; - return true; + screen().hideCursor(); + + // Either the inset under the cursor or the + // surrounding LyXText will handle this event. + + // Build temporary cursor. + cmd.y = min(max(cmd.y,-1), bv_->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. + update(cur.result().update(), cur.result().update()); } - 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 + // See workAreaKeyPress + cursor_timeout.restart(); + screen().showCursor(*bv_); - // Doesn't go through lyxfunc, so we need to update - // the layout choice etc. ourselves + // Skip these when selecting + if (cmd.action != LFUN_MOUSE_MOTION) { + owner_->updateLayoutChoice(); + owner_->updateToolbars(); + } - // e.g. Qt mouse press when no buffer - if (!available()) - return false; + // 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; +} - screen().hideCursor(); - // either the inset under the cursor or the surrounding LyXText will - // handle this event. - - // built temporary path to inset - InsetOld * inset = insetFromCoords(bv_, cmd.x, cmd.y); - DispatchResult res; - - // try to dispatch to that inset - if (inset) { - FuncRequest cmd2 = cmd; - lyxerr << "dispatching action " << cmd2.action - << " to inset " << inset << endl; - cmd2.x -= inset->x(); - cmd2.y -= inset->y(); - res = inset->dispatch(*bv_, cmd2); - if (res.update()) { - bv_->update(); - bv_->fullCursor().updatePos(); - } - res.update(false); - switch (res.val()) { - case FINISHED: - case FINISHED_RIGHT: - case FINISHED_UP: - case FINISHED_DOWN: - theTempCursor.pop(); - bv_->fullCursor(theTempCursor); - bv_->fullCursor().innerText() - ->setCursorFromCoordinates(cmd.x, top_y() + cmd.y); - if (bv_->fitCursor()) - bv_->update(); - return true; - default: - lyxerr << "not dispatched by inner inset val: " << res.val() << endl; - break; - } - } +FuncStatus BufferView::Pimpl::getStatus(FuncRequest const & cmd) +{ + Buffer * buf = bv_->buffer(); - // otherwise set cursor to surrounding LyXText - if (!res.dispatched()) { - lyxerr << "temp cursor is: " << theTempCursor << endl; - lyxerr << "dispatching " << cmd - << " to surrounding LyXText " - << theTempCursor.innerText() << endl; - bv_->fullCursor(theTempCursor); - FuncRequest cmd1 = cmd; - cmd1.y += bv_->top_y(); - res = bv_->fullCursor().innerText()->dispatch(*bv_, cmd1); - if (bv_->fitCursor() || res.update()) - bv_->update(); - - //return DispatchResult(true, true); - } - // see workAreaKeyPress - cursor_timeout.restart(); - screen().showCursor(*bv_); + FuncStatus flag; - // skip these when selecting - if (cmd.action != LFUN_MOUSE_MOTION) { - owner_->updateLayoutChoice(); - owner_->updateToolbar(); - } + switch (cmd.action) { - // 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_UNDO: + flag.enabled(!buf->undostack().empty()); + break; + case LFUN_REDO: + flag.enabled(!buf->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_REF_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_WORDS_COUNT: + flag.enabled(true); + break; + + case LFUN_BOOKMARK_GOTO: + flag.enabled(bv_->isSavedPosition(convert(cmd.argument))); + break; + case LFUN_TRACK_CHANGES: + flag.enabled(true); + flag.setOnOff(buf->params().tracking_changes); + break; + + case LFUN_OUTPUT_CHANGES: { + LaTeXFeatures features(*buf, buf->params(), false); + flag.enabled(buf && buf->params().tracking_changes + && features.isAvailable("dvipost")); + flag.setOnOff(buf->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(buf && buf->params().tracking_changes); + break; default: - owner_->dispatch(cmd); - return true; + flag.enabled(false); } + + return flag; } -bool BufferView::Pimpl::dispatch(FuncRequest const & ev) + +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] << "BufferView::Pimpl::Dispatch:" - << " action[" << ev.action << ']' - << " arg[" << ev.argument << ']' - << " x[" << ev.x << ']' - << " y[" << ev.y << ']' - << " button[" << ev.button() << ']' + lyxerr[Debug::ACTION] << BOOST_CURRENT_FUNCTION + << " action[" << cmd.action << ']' + << " arg[" << cmd.argument << ']' + << " x[" << cmd.x << ']' + << " y[" << cmd.y << ']' + << " button[" << cmd.button() << ']' << endl; - LyXTextClass const & tclass = buffer_->params().getLyXTextClass(); + LCursor & cur = bv_->cursor(); + + switch (cmd.action) { - switch (ev.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_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_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(ev.argument); + MenuInsertLyXFile(cmd.argument); break; case LFUN_FILE_INSERT_ASCII_PARA: - InsertAsciiFile(bv_, ev.argument, true); + InsertAsciiFile(bv_, cmd.argument, true); break; case LFUN_FILE_INSERT_ASCII: - InsertAsciiFile(bv_, ev.argument, false); + InsertAsciiFile(bv_, cmd.argument, false); break; case LFUN_FONT_STATE: - owner_->getLyXFunc().setMessage(currentState(bv_)); - break; - - case LFUN_INSERT_LABEL: { - // Try and generate a valid label - string const contents = ev.argument.empty() ? - getPossibleLabel(*bv_) : ev.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(ev.argument)); + savePosition(convert(cmd.argument)); break; case LFUN_BOOKMARK_GOTO: - restorePosition(strToUnsignedInt(ev.argument)); + restorePosition(convert(cmd.argument)); break; case LFUN_REF_GOTO: { - string label = ev.argument; + string label = cmd.argument; if (label.empty()) { InsetRef * inset = - static_cast(getInsetByCode(InsetOld::REF_CODE)); + getInsetByCode(bv_->cursor(), + InsetBase::REF_CODE); if (inset) { label = inset->getContents(); savePosition(0); @@ -1095,269 +1088,193 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev) 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 (ev.argument.empty()) { - // As always... - owner_->getLyXFunc().handleKeyFunc(ev.action); - } else { - owner_->getLyXFunc().handleKeyFunc(ev.action); - owner_->getIntl().getTransManager() - .TranslateAndInsert(ev.argument[0], bv_->getLyXText()); - update(); - } - break; - - case LFUN_MATH_MACRO: - case LFUN_MATH_DELIM: - case LFUN_INSERT_MATRIX: - case LFUN_INSERT_MATH: - case LFUN_MATH_IMPORT_SELECTION: // Imports LaTeX from the X selection - case LFUN_MATH_DISPLAY: // Open or create a displayed math inset - case LFUN_MATH_MODE: // Open or create an inlined math inset - mathDispatch(*bv_, ev); - break; - - case LFUN_INSET_INSERT: { - // Same as above. - BOOST_ASSERT(false); - InsetOld * inset = createInset(bv_, ev); - if (!inset || !insertInset(inset)) - delete inset; break; } - case LFUN_FLOAT_LIST: - if (tclass.floats().typeExist(ev.argument)) { - InsetOld * inset = new InsetFloatList(ev.argument); - if (!insertInset(inset, tclass.defaultLayoutName())) - delete inset; - } else { - lyxerr << "Non-existent float type: " - << ev.argument << endl; - } - break; - - case LFUN_LAYOUT_PARAGRAPH: { - string data; - params2string(*bv_->getLyXText()->cursorPar(), data); - data = "show\n" + data; - bv_->owner()->getDialogs().show("paragraph", data); - break; - } - - case LFUN_PARAGRAPH_UPDATE: - updateParagraphDialog(); - break; - - case LFUN_PARAGRAPH_APPLY: - setParagraphParams(*bv_, ev.argument); + case LFUN_TRACK_CHANGES: + trackChanges(); break; - case LFUN_THESAURUS_ENTRY: { - string arg = ev.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_OUTPUT_CHANGES: { + Buffer * buf = bv_->buffer(); + bool const state = buf->params().output_changes; + buf->params().output_changes = !state; break; } - case LFUN_TRACK_CHANGES: - trackChanges(); - break; - case LFUN_MERGE_CHANGES: owner_->getDialogs().show("changes"); break; case LFUN_ACCEPT_ALL_CHANGES: { - bv_->text()->setCursor(0, 0); + bv_->cursor().reset(bv_->buffer()->inset()); +#ifdef WITH_WARNINGS #warning FIXME changes +#endif while (lyx::find::findNextChange(bv_)) - bv_->getLyXText()->acceptChange(); + bv_->getLyXText()->acceptChange(bv_->cursor()); update(); break; } case LFUN_REJECT_ALL_CHANGES: { - bv_->text()->setCursor(0, 0); + bv_->cursor().reset(bv_->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(bv_->cursor()); break; } case LFUN_WORD_FIND: - lyx::find::find(bv_, ev); + lyx::find::find(bv_, cmd); break; case LFUN_WORD_REPLACE: - lyx::find::replace(bv_, ev); + lyx::find::replace(bv_, cmd); break; case LFUN_MARK_OFF: - bv_->clearSelection(); - bv_->update(); - bv_->resetAnchor(); - ev.message(N_("Mark off")); + cur.clearSelection(); + cur.resetAnchor(); + cur.message(N_("Mark off")); break; case LFUN_MARK_ON: - bv_->clearSelection(); - bv_->selection().mark(true); - bv_->update(); - bv_->resetAnchor(); - ev.message(N_("Mark on")); + cur.clearSelection(); + cur.mark() = true; + cur.resetAnchor(); + cur.message(N_("Mark on")); break; case LFUN_SETMARK: - bv_->clearSelection(); - if (bv_->selection().mark()) { - ev.message(N_("Mark removed")); + cur.clearSelection(); + if (cur.mark()) { + cur.mark() = false; + cur.message(N_("Mark removed")); } else { - bv_->selection().mark(true); - ev.message(N_("Mark set")); + cur.mark() = true; + cur.message(N_("Mark set")); } - bv_->resetAnchor(); - bv_->update(); + cur.resetAnchor(); break; - case LFUN_UNKNOWN_ACTION: - ev.errorMessage(N_("Unknown function!")); + case LFUN_CENTER: + bv_->center(); break; + case LFUN_WORDS_COUNT: { + DocIterator from, to; + if (cur.selection()) { + from = cur.selectionBegin(); + to = cur.selectionEnd(); + } else { + from = doc_iterator_begin(bv_->buffer()->inset()); + to = doc_iterator_end(bv_->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 bv_->getLyXText()->dispatch(*bv_, ev).dispatched(); - } // end of switch + return false; + } return true; } -bool BufferView::Pimpl::insertInset(InsetOld * inset, string const & lout) +ViewMetricsInfo BufferView::Pimpl::metrics() { - // not quite sure if we want this... - bv_->text()->recUndo(bv_->text()->cursor().par()); - freezeUndo(); - - bv_->clearSelection(); - if (!lout.empty()) { - bv_->text()->breakParagraph(bv_->buffer()->paragraphs()); - - 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); + // 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_->text()->setLayout(hasLayout ? lres : tclass.defaultLayoutName()); - bv_->text()->setParagraph(Spacing(), LYX_ALIGN_LAYOUT, string(), 0); + lyx::pit_type const pit = anchor_ref_; + int pit1 = pit; + int pit2 = pit; + size_t const npit = text->paragraphs().size(); + + lyxerr << 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 (y1 > 0 && pit1 > 0) { + y1 -= text->getPar(pit1).ascent(); + --pit1; + text->redoParagraph(pit1); + y1 -= text->getPar(pit1).descent(); } - bv_->fullCursor().innerText()->insertInset(inset); - unFreezeUndo(); - return true; -} -bool BufferView::Pimpl::ChangeInsets(InsetOld::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; + // Take care of ascent of first line + y1 -= text->getPar(pit1).ascent(); - // FIXME + // Normalize anchor for next time + anchor_ref_ = pit1; + offset_ref_ = -y1; - // 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()); - } - } + // Grey at the beginning is ugly + if (pit1 == 0 && y1 > 0) { + y0 -= y1; + y1 = 0; + anchor_ref_ = 0; + } + + // Redo paragraphs below cursor if necessary + int y2 = y0; + while (y2 < bv.workHeight() && pit2 < int(npit) - 1) { + y2 += text->getPar(pit2).descent(); + ++pit2; + text->redoParagraph(pit2); + y2 += text->getPar(pit2).ascent(); } - bv_->text()->setCursorIntern(cur.par(), cur.pos()); - return need_update; -} + // Take care of descent of last line + y2 += text->getPar(pit2).descent(); -void BufferView::Pimpl::updateParagraphDialog() -{ - if (!bv_->owner()->getDialogs().visible("paragraph")) - return; - Paragraph const & par = *bv_->getLyXText()->cursorPar(); - string data; - params2string(par, data); + // 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(); + } - // Will the paragraph accept changes from the dialog? - InsetOld * const inset = par.inInset(); - bool const accept = - !(inset && inset->forceDefaultParagraphs(inset)); + lyxerr << BOOST_CURRENT_FUNCTION + << " y1: " << y1 + << " y2: " << y2 + << endl; - data = "update " + tostr(accept) + '\n' + data; - bv_->owner()->getDialogs().update("paragraph", data); + return ViewMetricsInfo(pit1, pit2, y1, y2); }