X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.cpp;h=dcaabbefe33ab669853bb85daaf56dddac1e2f4a;hb=a84b8ca6bea87573e77d76aae9bbd25ccf8942f5;hp=388b0c60a91bb228a22503ec82e0c6812f2cc2a1;hpb=f370da411306112060c52335dbd33bf28692ddd0;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 388b0c60a9..dcaabbefe3 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -23,7 +23,6 @@ #include "CoordCache.h" #include "Cursor.h" #include "CutAndPaste.h" -#include "debug.h" #include "DispatchResult.h" #include "EmbeddedFiles.h" #include "ErrorList.h" @@ -31,7 +30,6 @@ #include "FloatList.h" #include "FuncRequest.h" #include "FuncStatus.h" -#include "gettext.h" #include "Intl.h" #include "InsetIterator.h" #include "Language.h" @@ -54,7 +52,6 @@ #include "VSpace.h" #include "WordLangTuple.h" - #include "insets/InsetBibtex.h" #include "insets/InsetCommand.h" // ChangeRefs #include "insets/InsetRef.h" @@ -62,7 +59,6 @@ #include "frontends/alert.h" #include "frontends/Delegates.h" -#include "frontends/FileDialog.h" #include "frontends/FontMetrics.h" #include "frontends/Painter.h" #include "frontends/Selection.h" @@ -70,47 +66,25 @@ #include "graphics/Previews.h" #include "support/convert.h" +#include "support/debug.h" #include "support/FileFilterList.h" #include "support/filetools.h" +#include "support/gettext.h" +#include "support/lstrings.h" #include "support/Package.h" #include "support/types.h" -#include "support/fs_extras.h" - -#include -#include -#include -#include #include #include #include +#include #include -using std::distance; -using std::endl; -using std::ifstream; -using std::istringstream; -using std::istream_iterator; -using std::make_pair; -using std::min; -using std::max; -using std::mem_fun_ref; -using std::string; -using std::vector; - -namespace fs = boost::filesystem; +using namespace std; +using namespace lyx::support; namespace lyx { -using support::addPath; -using support::bformat; -using support::FileFilterList; -using support::FileName; -using support::fileSearch; -using support::makeDisplayPath; -using support::makeAbsPath; -using support::package; - namespace Alert = frontend::Alert; namespace { @@ -212,132 +186,16 @@ void gotoInset(BufferView * bv, InsetCode code, bool same_content) } +/// A map from a Text to the associated text metrics +typedef map TextMetricsCache; -/// the type of outline operation -enum OutlineOp { - OutlineUp, // Move this header with text down - OutlineDown, // Move this header with text up - OutlineIn, // Make this header deeper - OutlineOut // Make this header shallower +enum ScreenUpdateStrategy { + NoScreenUpdate, + SingleParUpdate, + FullScreenUpdate, + DecorationUpdate }; - -void outline(OutlineOp mode, Cursor & cur) -{ - Buffer & buf = cur.buffer(); - pit_type & pit = cur.pit(); - ParagraphList & pars = buf.text().paragraphs(); - ParagraphList::iterator bgn = pars.begin(); - // The first paragraph of the area to be copied: - ParagraphList::iterator start = boost::next(bgn, pit); - // The final paragraph of area to be copied: - ParagraphList::iterator finish = start; - ParagraphList::iterator end = pars.end(); - - TextClass::const_iterator lit = - buf.params().getTextClass().begin(); - TextClass::const_iterator const lend = - buf.params().getTextClass().end(); - - int const thistoclevel = start->layout()->toclevel; - int toclevel; - switch (mode) { - case OutlineUp: { - // Move out (down) from this section header - if (finish != end) - ++finish; - // Seek the one (on same level) below - for (; finish != end; ++finish) { - toclevel = finish->layout()->toclevel; - if (toclevel != Layout::NOT_IN_TOC - && toclevel <= thistoclevel) { - break; - } - } - ParagraphList::iterator dest = start; - // Move out (up) from this header - if (dest == bgn) - break; - // Search previous same-level header above - do { - --dest; - toclevel = dest->layout()->toclevel; - } while(dest != bgn - && (toclevel == Layout::NOT_IN_TOC - || toclevel > thistoclevel)); - // Not found; do nothing - if (toclevel == Layout::NOT_IN_TOC || toclevel > thistoclevel) - break; - pit_type const newpit = std::distance(bgn, dest); - pit_type const len = std::distance(start, finish); - pit_type const deletepit = pit + len; - buf.undo().recordUndo(cur, ATOMIC_UNDO, newpit, deletepit - 1); - pars.insert(dest, start, finish); - start = boost::next(pars.begin(), deletepit); - pit = newpit; - pars.erase(start, finish); - break; - } - case OutlineDown: { - // Go down out of current header: - if (finish != end) - ++finish; - // Find next same-level header: - for (; finish != end; ++finish) { - toclevel = finish->layout()->toclevel; - if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel) - break; - } - ParagraphList::iterator dest = finish; - // Go one down from *this* header: - if (dest != end) - ++dest; - else - break; - // Go further down to find header to insert in front of: - for (; dest != end; ++dest) { - toclevel = dest->layout()->toclevel; - if (toclevel != Layout::NOT_IN_TOC && toclevel <= thistoclevel) - break; - } - // One such was found: - pit_type newpit = std::distance(bgn, dest); - pit_type const len = std::distance(start, finish); - buf.undo().recordUndo(cur, ATOMIC_UNDO, pit, newpit - 1); - pars.insert(dest, start, finish); - start = boost::next(bgn, pit); - pit = newpit - len; - pars.erase(start, finish); - break; - } - case OutlineIn: - buf.undo().recordUndo(cur); - for (; lit != lend; ++lit) { - if ((*lit)->toclevel == thistoclevel + 1 && - start->layout()->labeltype == (*lit)->labeltype) { - start->layout((*lit)); - break; - } - } - break; - case OutlineOut: - buf.undo().recordUndo(cur); - for (; lit != lend; ++lit) { - if ((*lit)->toclevel == thistoclevel - 1 && - start->layout()->labeltype == (*lit)->labeltype) { - start->layout((*lit)); - break; - } - } - break; - default: - break; - } -} - -/// A map from a Text to the associated text metrics -typedef std::map TextMetricsCache; - } // anon namespace @@ -350,14 +208,14 @@ typedef std::map TextMetricsCache; struct BufferView::Private { Private(BufferView & bv): wh_(0), cursor_(bv), - multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0), - need_centering_(false), last_inset_(0), gui_(0) + anchor_ref_(0), offset_ref_(0), need_centering_(false), + last_inset_(0), gui_(0) {} /// ScrollbarParameters scrollbarParameters_; /// - ViewMetricsInfo metrics_info_; + ScreenUpdateStrategy update_strategy_; /// CoordCache coord_cache_; @@ -372,8 +230,6 @@ struct BufferView::Private /// Cursor cursor_; /// - bool multiparsel_cache_; - /// pit_type anchor_ref_; /// int offset_ref_; @@ -423,8 +279,7 @@ BufferView::~BufferView() LastFilePosSection::FilePos fp; fp.pit = d->cursor_.bottom().pit(); fp.pos = d->cursor_.bottom().pos(); - LyX::ref().session().lastFilePos().save( - support::FileName(buffer_.absFileName()), fp); + LyX::ref().session().lastFilePos().save(buffer_.fileName(), fp); delete d; } @@ -482,17 +337,6 @@ bool BufferView::fitCursor() } -bool BufferView::multiParSel() -{ - if (!d->cursor_.selection()) - return false; - bool ret = d->multiparsel_cache_; - d->multiparsel_cache_ = d->cursor_.selBegin().pit() != d->cursor_.selEnd().pit(); - // Either this, or previous selection spans paragraphs - return ret || d->multiparsel_cache_; -} - - void BufferView::processUpdateFlags(Update::flags flags) { // last_inset_ points to the last visited inset. This pointer may become @@ -500,12 +344,11 @@ void BufferView::processUpdateFlags(Update::flags flags) // causes screen update(), I reset last_inset_ to avoid such a problem. d->last_inset_ = 0; // This is close to a hot-path. - LYXERR(Debug::DEBUG) - << BOOST_CURRENT_FUNCTION + LYXERR(Debug::DEBUG, "BufferView::processUpdateFlags()" << "[fitcursor = " << (flags & Update::FitCursor) << ", forceupdate = " << (flags & Update::Force) << ", singlepar = " << (flags & Update::SinglePar) - << "] buffer: " << &buffer_ << endl; + << "] buffer: " << &buffer_); // Update macro store if (!(cursor().inMathed() && cursor().inMacroMode())) @@ -518,12 +361,12 @@ void BufferView::processUpdateFlags(Update::flags flags) // Case when no explicit update is requested. if (!flags) { // no need to redraw anything. - d->metrics_info_.update_strategy = NoScreenUpdate; + d->update_strategy_ = NoScreenUpdate; return; } if (flags == Update::Decoration) { - d->metrics_info_.update_strategy = DecorationUpdate; + d->update_strategy_ = DecorationUpdate; buffer_.changed(); return; } @@ -533,26 +376,32 @@ void BufferView::processUpdateFlags(Update::flags flags) bool const fit_cursor = fitCursor(); // tell the frontend to update the screen if needed. if (fit_cursor) { - updateMetrics(false); + updateMetrics(); buffer_.changed(); return; } if (flags & Update::Decoration) { - d->metrics_info_.update_strategy = DecorationUpdate; + d->update_strategy_ = DecorationUpdate; buffer_.changed(); return; } // no screen update is needed. - d->metrics_info_.update_strategy = NoScreenUpdate; + d->update_strategy_ = NoScreenUpdate; return; } - bool full_metrics = flags & Update::Force; - if (flags & Update::MultiParSel) - full_metrics |= multiParSel(); + bool const full_metrics = flags & Update::Force; - bool const single_par = !full_metrics; - updateMetrics(single_par); + if (full_metrics || !singleParUpdate()) { + if (flags & Update::FitCursor) { + CursorSlice const & bot = d->cursor_.bottom(); + TextMetrics const & tm = d->text_metrics_[bot.text()]; + if (!tm.has(bot.pit())) + center(); + } + // We have to update the full screen metrics. + updateMetrics(); + } if (!(flags & Update::FitCursor)) { buffer_.changed(); @@ -561,6 +410,7 @@ void BufferView::processUpdateFlags(Update::flags flags) //FIXME: updateMetrics() does not update paragraph position // This is done at draw() time. So we need a redraw! + buffer_.changed(); if (!fitCursor()) // The screen has already been updated thanks to the @@ -570,7 +420,7 @@ void BufferView::processUpdateFlags(Update::flags flags) // The screen has been recentered around the cursor position so // refresh it: - updateMetrics(false); + updateMetrics(); buffer_.changed(); } @@ -586,11 +436,10 @@ void BufferView::updateScrollbar() d->offset_ref_ = 0; } - LYXERR(Debug::GUI) - << BOOST_CURRENT_FUNCTION - << " Updating scrollbar: height: " << t.paragraphs().size() + LYXERR(Debug::GUI, " Updating scrollbar: height: " + << t.paragraphs().size() << " curr par: " << d->cursor_.bottom().pit() - << " default height " << defaultRowHeight() << endl; + << " default height " << defaultRowHeight()); // It would be better to fix the scrollbar to understand // values in [0..1] and divide everything by wh @@ -601,12 +450,6 @@ void BufferView::updateScrollbar() int h = tm.parMetrics(d->anchor_ref_).height(); - // Normalize anchor/offset (MV): - while (d->offset_ref_ > h && d->anchor_ref_ < parsize) { - d->anchor_ref_++; - d->offset_ref_ -= h; - h = tm.parMetrics(d->anchor_ref_).height(); - } // Look at paragraph heights on-screen int sumh = 0; int nh = 0; @@ -639,8 +482,7 @@ ScrollbarParameters const & BufferView::scrollbarParameters() const void BufferView::scrollDocView(int value) { - LYXERR(Debug::GUI) << BOOST_CURRENT_FUNCTION - << "[ value = " << value << "]" << endl; + LYXERR(Debug::GUI, "[ value = " << value << "]"); Text & t = buffer_.text(); TextMetrics & tm = d->text_metrics_[&t]; @@ -654,7 +496,7 @@ void BufferView::scrollDocView(int value) tm.redoParagraph(d->anchor_ref_); int const h = tm.parMetrics(d->anchor_ref_).height(); d->offset_ref_ = int((bar * t.paragraphs().size() - d->anchor_ref_) * h); - updateMetrics(false); + updateMetrics(); buffer_.changed(); } @@ -724,7 +566,7 @@ void BufferView::saveBookmark(unsigned int idx) // pit and pos will be updated with bottom level pit/pos // when lyx exits. LyX::ref().session().bookmarks().save( - FileName(buffer_.absFileName()), + buffer_.fileName(), d->cursor_.bottom().pit(), d->cursor_.bottom().pos(), d->cursor_.paragraph().id(), @@ -786,8 +628,13 @@ bool BufferView::moveToPosition(pit_type bottom_pit, pos_type bottom_pos, setCursor(doc_it); // set the current font. d->cursor_.setCurrentFont(); - // center the screen on this new position. - center(); + // To center the screen on this new position we need the + // paragraph position which is computed at draw() time. + // So we need a redraw! + buffer_.changed(); + if (fitCursor()) + // We need another redraw because of the screen recentering. + buffer_.changed(); } return success; @@ -827,13 +674,20 @@ void BufferView::updateOffsetRef() if (height_ == 0) return; + d->need_centering_ = false; + CursorSlice & bot = d->cursor_.bottom(); TextMetrics & tm = d->text_metrics_[bot.text()]; ParagraphMetrics const & pm = tm.parMetrics(bot.pit()); - int y = coordOffset(d->cursor_, d->cursor_.boundary()).y_; - d->offset_ref_ = y + pm.ascent() - height_ / 2; - - d->need_centering_ = false; + if (d->anchor_ref_ == 0) + d->offset_ref_ = 0; + else if (d->anchor_ref_ >= pos_type(bot.text()->paragraphs().size() - 1)) { + d->anchor_ref_ = bot.text()->paragraphs().size() - 1; + d->offset_ref_ = pm.height() - height_; + } else { + int y = coordOffset(d->cursor_, d->cursor_.boundary()).y_; + d->offset_ref_ = y + pm.ascent() - height_ / 2; + } } @@ -869,11 +723,6 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_LABEL_INSERT: case LFUN_INFO_INSERT: case LFUN_PARAGRAPH_GOTO: - // FIXME handle non-trivially - case LFUN_OUTLINE_UP: - case LFUN_OUTLINE_DOWN: - case LFUN_OUTLINE_IN: - case LFUN_OUTLINE_OUT: case LFUN_NOTE_NEXT: case LFUN_REFERENCE_NEXT: case LFUN_WORD_FIND: @@ -1002,17 +851,14 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) Update::flags BufferView::dispatch(FuncRequest const & cmd) { - //lyxerr << BOOST_CURRENT_FUNCTION - // << [ cmd = " << cmd << "]" << endl; + //lyxerr << [ cmd = " << cmd << "]" << endl; // Make sure that the cached BufferView is correct. - LYXERR(Debug::ACTION) << BOOST_CURRENT_FUNCTION - << " action[" << cmd.action << ']' + LYXERR(Debug::ACTION, " action[" << cmd.action << ']' << " arg[" << to_utf8(cmd.argument()) << ']' << " x[" << cmd.x << ']' << " y[" << cmd.y << ']' - << " button[" << cmd.button() << ']' - << endl; + << " button[" << cmd.button() << ']'); Cursor & cur = d->cursor_; // Default Update flags. @@ -1038,21 +884,6 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) } break; - case LFUN_FILE_INSERT: - // FIXME UNICODE - menuInsertLyXFile(to_utf8(cmd.argument())); - break; - - case LFUN_FILE_INSERT_PLAINTEXT_PARA: - // FIXME UNICODE - insertPlaintextFile(to_utf8(cmd.argument()), true); - break; - - case LFUN_FILE_INSERT_PLAINTEXT: - // FIXME UNICODE - insertPlaintextFile(to_utf8(cmd.argument()), false); - break; - case LFUN_FONT_STATE: cur.message(cur.currentState()); break; @@ -1087,14 +918,11 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) ParIterator par = b->getParFromID(id); if (par == b->par_iterator_end()) { - LYXERR(Debug::INFO) - << "No matching paragraph found! [" - << id << "]." << endl; + LYXERR(Debug::INFO, "No matching paragraph found! [" << id << "]."); } else { - LYXERR(Debug::INFO) - << "Paragraph " << par->id() + LYXERR(Debug::INFO, "Paragraph " << par->id() << " found in buffer `" - << b->absFileName() << "'." << endl; + << b->absFileName() << "'."); if (b == &buffer_) { // Set the cursor @@ -1113,25 +941,6 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) break; } - case LFUN_OUTLINE_UP: - outline(OutlineUp, d->cursor_); - d->cursor_.text()->setCursor(d->cursor_, d->cursor_.pit(), 0); - updateLabels(buffer_); - break; - case LFUN_OUTLINE_DOWN: - outline(OutlineDown, d->cursor_); - d->cursor_.text()->setCursor(d->cursor_, d->cursor_.pit(), 0); - updateLabels(buffer_); - break; - case LFUN_OUTLINE_IN: - outline(OutlineIn, d->cursor_); - updateLabels(buffer_); - break; - case LFUN_OUTLINE_OUT: - outline(OutlineOut, d->cursor_); - updateLabels(buffer_); - break; - case LFUN_NOTE_NEXT: gotoInset(this, NOTE_CODE, false); break; @@ -1321,7 +1130,7 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) if (inset) { if (inset->isActive()) { Cursor tmpcur = cur; - tmpcur.pushLeft(*inset); + tmpcur.pushBackward(*inset); inset->dispatch(tmpcur, tmpcmd); if (tmpcur.result().dispatched()) { cur.dispatched(); @@ -1346,9 +1155,11 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) if (p.y_ < 0 || p.y_ > height_) { // The cursor is off-screen so recenter before proceeding. center(); - updateMetrics(false); + updateMetrics(); //FIXME: updateMetrics() does not update paragraph position // This is done at draw() time. So we need a redraw! + // But no screen update is needed. + d->update_strategy_ = NoScreenUpdate; buffer_.changed(); p = getPos(cur, cur.boundary()); } @@ -1376,6 +1187,8 @@ Update::flags BufferView::dispatch(FuncRequest const & cmd) cur.forwardInset(); } // FIXME: we need to do a redraw again because of the selection + // But no screen update is needed. + d->update_strategy_ = NoScreenUpdate; buffer_.changed(); updateFlags = Update::Force | Update::FitCursor; break; @@ -1431,7 +1244,7 @@ void BufferView::resize(int width, int height) width_ = width; height_ = height; - updateMetrics(false); + updateMetrics(); } @@ -1466,7 +1279,7 @@ Inset const * BufferView::getCoveringInset(Text const & text, int x, int y) void BufferView::mouseEventDispatch(FuncRequest const & cmd0) { - //lyxerr << BOOST_CURRENT_FUNCTION << "[ cmd0 " << cmd0 << "]" << endl; + //lyxerr << "[ cmd0 " << cmd0 << "]" << endl; // This is only called for mouse related events including // LFUN_FILE_OPEN generated by drag-and-drop. @@ -1504,23 +1317,10 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0) if (!need_redraw) return; - // if last metrics update was in singlepar mode, WorkArea::redraw() will - // not expose the button for redraw. We adjust here the metrics dimension - // to enable a full redraw in any case as this is not costly. - TextMetrics & tm = d->text_metrics_[&buffer_.text()]; - std::pair firstpm = tm.first(); - std::pair lastpm = tm.last(); - int y1 = firstpm.second->position() - firstpm.second->ascent(); - int y2 = lastpm.second->position() + lastpm.second->descent(); - d->metrics_info_ = ViewMetricsInfo(firstpm.first, lastpm.first, y1, y2, - FullScreenUpdate, buffer_.text().paragraphs().size()); - // Reinitialize anchor to first pit. - d->anchor_ref_ = firstpm.first; - d->offset_ref_ = -y1; - LYXERR(Debug::PAINTING) - << "Mouse hover detected at: (" << cmd.x << ", " << cmd.y << ")" - << "\nTriggering redraw: y1: " << y1 << " y2: " << y2 - << " pit1: " << firstpm.first << " pit2: " << lastpm.first << endl; + LYXERR(Debug::PAINTING, "Mouse hover detected at: (" + << cmd.x << ", " << cmd.y << ")"); + + d->update_strategy_ = DecorationUpdate; // This event (moving without mouse click) is not passed further. // This should be changed if it is further utilized. @@ -1572,7 +1372,7 @@ void BufferView::scrollDown(int offset) TextMetrics & tm = d->text_metrics_[text]; int ymax = height_ + offset; while (true) { - std::pair last = tm.last(); + pair last = tm.last(); int bottom_pos = last.second->position() + last.second->descent(); if (last.first + 1 == int(text->paragraphs().size())) { if (bottom_pos <= height_) @@ -1585,7 +1385,7 @@ void BufferView::scrollDown(int offset) tm.newParMetricsDown(); } d->offset_ref_ += offset; - updateMetrics(false); + updateMetrics(); buffer_.changed(); } @@ -1596,7 +1396,7 @@ void BufferView::scrollUp(int offset) TextMetrics & tm = d->text_metrics_[text]; int ymin = - offset; while (true) { - std::pair first = tm.first(); + pair first = tm.first(); int top_pos = first.second->position() - first.second->ascent(); if (first.first == 0) { if (top_pos >= 0) @@ -1609,7 +1409,7 @@ void BufferView::scrollUp(int offset) tm.newParMetricsUp(); } d->offset_ref_ -= offset; - updateMetrics(false); + updateMetrics(); buffer_.changed(); } @@ -1634,7 +1434,7 @@ void BufferView::gotoLabel(docstring const & label) for (InsetIterator it = inset_iterator_begin(buffer_.inset()); it; ++it) { vector labels; it->getLabelList(buffer_, labels); - if (std::find(labels.begin(), labels.end(), label) != labels.end()) { + if (find(labels.begin(), labels.end(), label) != labels.end()) { setCursor(it); processUpdateFlags(Update::FitCursor); return; @@ -1702,7 +1502,7 @@ bool BufferView::checkDepm(Cursor & cur, Cursor & old) updateLabels(buffer_); - updateMetrics(false); + updateMetrics(); buffer_.changed(); return true; } @@ -1741,7 +1541,7 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select) // For an example, see bug 2933: // http://bugzilla.lyx.org/show_bug.cgi?id=2933 // The code below could maybe be moved to a DocIterator method. - //lyxerr << "cur before " << cur <cursor_.setCursor(dit); d->cursor_.boundary(cur.boundary()); @@ -1799,12 +1599,6 @@ pit_type BufferView::anchor_ref() const } -ViewMetricsInfo const & BufferView::viewMetricsInfo() -{ - return d->metrics_info_; -} - - bool BufferView::singleParUpdate() { Text & buftext = buffer_.text(); @@ -1823,27 +1617,18 @@ bool BufferView::singleParUpdate() // the singlePar optimisation. return false; - int y1 = pm.position() - pm.ascent(); - int y2 = pm.position() + pm.descent(); - d->metrics_info_ = ViewMetricsInfo(bottom_pit, bottom_pit, y1, y2, - SingleParUpdate, buftext.paragraphs().size()); - LYXERR(Debug::PAINTING) - << BOOST_CURRENT_FUNCTION - << "\ny1: " << y1 - << " y2: " << y2 + d->update_strategy_ = SingleParUpdate; + + LYXERR(Debug::PAINTING, "\ny1: " << pm.position() - pm.ascent() + << " y2: " << pm.position() + pm.descent() << " pit: " << bottom_pit - << " singlepar: 1" - << endl; + << " singlepar: 1"); return true; } -void BufferView::updateMetrics(bool singlepar) +void BufferView::updateMetrics() { - if (singlepar && singleParUpdate()) - // No need to update the full screen metrics. - return; - Text & buftext = buffer_.text(); pit_type const npit = int(buftext.paragraphs().size()); @@ -1909,77 +1694,39 @@ void BufferView::updateMetrics(bool singlepar) // Take care of descent of last line y2 += tm.parMetrics(pit2).descent(); - LYXERR(Debug::PAINTING) - << BOOST_CURRENT_FUNCTION - << "\n y1: " << y1 + LYXERR(Debug::PAINTING, "\n y1: " << y1 << " y2: " << y2 << " pit1: " << pit1 << " pit2: " << pit2 << " npit: " << npit - << " singlepar: 0" - << endl; + << " singlepar: 0"); - d->metrics_info_ = ViewMetricsInfo(pit1, pit2, y1, y2, - FullScreenUpdate, npit); + d->update_strategy_ = FullScreenUpdate; + + updateScrollbar(); if (lyxerr.debugging(Debug::WORKAREA)) { - LYXERR(Debug::WORKAREA) << "BufferView::updateMetrics" << endl; + LYXERR(Debug::WORKAREA, "BufferView::updateMetrics"); d->coord_cache_.dump(); } } -void BufferView::menuInsertLyXFile(string const & filenm) +void BufferView::insertLyXFile(FileName const & fname) { BOOST_ASSERT(d->cursor_.inTexted()); - string filename = filenm; - - if (filename.empty()) { - // Launch a file browser - // FIXME UNICODE - string initpath = lyxrc.document_path; - string const trypath = buffer_.filePath(); - // If directory is writeable, use this as default. - if (FileName(trypath).isDirWritable()) - initpath = trypath; - - // FIXME UNICODE - FileDialog dlg(_("Select LyX document to insert"), LFUN_FILE_INSERT); - dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path)); - dlg.setButton2(_("Examples|#E#e"), - from_utf8(addPath(package().system_support().absFilename(), - "examples"))); - - FileDialog::Result result = - dlg.open(from_utf8(initpath), - FileFilterList(_("LyX Documents (*.lyx)")), - docstring()); - - if (result.first == FileDialog::Later) - return; - - // FIXME UNICODE - filename = to_utf8(result.second); - - // check selected filename - if (filename.empty()) { - // emit message signal. - message(_("Canceled.")); - return; - } - } // Get absolute path of file and add ".lyx" // to the filename if necessary - filename = fileSearch(string(), filename, "lyx").absFilename(); + FileName filename = fileSearch(string(), fname.absFilename(), "lyx"); - docstring const disp_fn = makeDisplayPath(filename); + docstring const disp_fn = makeDisplayPath(filename.absFilename()); // emit message signal. message(bformat(_("Inserting document %1$s..."), disp_fn)); docstring res; Buffer buf("", false); - if (buf.loadLyXFile(FileName(filename))) { + if (buf.loadLyXFile(filename)) { ErrorList & el = buffer_.errorList("Parse"); // Copy the inserted document error list into the current buffer one. el = buf.errorList("Parse"); @@ -1991,10 +1738,11 @@ void BufferView::menuInsertLyXFile(string const & filenm) res = _("Could not insert document %1$s"); } + updateMetrics(); + buffer_.changed(); // emit message signal. message(bformat(res, disp_fn)); buffer_.errors("Parse"); - updateMetrics(false); } @@ -2060,7 +1808,7 @@ Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const int pos = sl.pos(); if (pos && boundary) --pos; -// lyxerr << "coordOffset: boundary:" << boundary << " depth:" << dit.depth() << " pos:" << pos << " sl.pos:" << sl.pos() << std::endl; +// lyxerr << "coordOffset: boundary:" << boundary << " depth:" << dit.depth() << " pos:" << pos << " sl.pos:" << sl.pos() << endl; rend = pm.pos2row(pos); } else rend = pm.pos2row(sl.pos()); @@ -2103,41 +1851,53 @@ Point BufferView::getPos(DocIterator const & dit, bool boundary) const void BufferView::draw(frontend::Painter & pain) { - PainterInfo pi(this, pain); - // Should the whole screen, including insets, be refreshed? - // FIXME: We should also distinguish DecorationUpdate to avoid text - // drawing if possible. This is not possible to do easily right now - // because of the single backing pixmap. - pi.full_repaint = d->metrics_info_.update_strategy != SingleParUpdate; - - if (pi.full_repaint) - // Clear background (if not delegated to rows) - pain.fillRectangle(0, d->metrics_info_.y1, width_, - d->metrics_info_.y2 - d->metrics_info_.y1, - buffer_.inset().backgroundColor()); - - LYXERR(Debug::PAINTING) << "\t\t*** START DRAWING ***" << endl; + LYXERR(Debug::PAINTING, "\t\t*** START DRAWING ***"); Text & text = buffer_.text(); TextMetrics const & tm = d->text_metrics_[&text]; - int y = d->metrics_info_.y1 + tm.parMetrics(d->metrics_info_.p1).ascent(); - if (!pi.full_repaint) - tm.drawParagraph(pi, d->metrics_info_.p1, 0, y); - else + int const y = - d->offset_ref_ + tm.parMetrics(d->anchor_ref_).ascent(); + PainterInfo pi(this, pain); + + switch (d->update_strategy_) { + + case NoScreenUpdate: + // If no screen painting is actually needed, only some the different + // coordinates of insets and paragraphs needs to be updated. + pi.full_repaint = true; + pi.pain.setDrawingEnabled(false); + tm.draw(pi, 0, y); + break; + + case SingleParUpdate: + pi.full_repaint = false; + // In general, only the current row of the outermost paragraph + // will be redrawn. Particular cases where selection spans + // multiple paragraph are correctly detected in TextMetrics. + tm.draw(pi, 0, y); + break; + + case DecorationUpdate: + // FIXME: We should also distinguish DecorationUpdate to avoid text + // drawing if possible. This is not possible to do easily right now + // because of the single backing pixmap. + + case FullScreenUpdate: + // The whole screen, including insets, will be refreshed. + pi.full_repaint = true; + + // Clear background. + pain.fillRectangle(0, 0, width_, height_, + buffer_.inset().backgroundColor()); tm.draw(pi, 0, y); - LYXERR(Debug::PAINTING) << "\n\t\t*** END DRAWING ***" << endl; - // and grey out above (should not happen later) -// lyxerr << "par ascent: " << text.getPar(d->metrics_info_.p1).ascent() << endl; - if (d->metrics_info_.y1 > 0 - && d->metrics_info_.update_strategy == FullScreenUpdate) - pain.fillRectangle(0, 0, width_, d->metrics_info_.y1, Color_bottomarea); + // and possibly grey out below + pair lastpm = tm.last(); + int const y2 = lastpm.second->position() + lastpm.second->descent(); + if (y2 < height_) + pain.fillRectangle(0, y2, width_, height_ - y2, Color_bottomarea); + break; + } - // and possibly grey out below -// lyxerr << "par descent: " << text.getPar(d->metrics_info_.p1).ascent() << endl; - if (d->metrics_info_.y2 < height_ - && d->metrics_info_.update_strategy == FullScreenUpdate) - pain.fillRectangle(0, d->metrics_info_.y2, width_, - height_ - d->metrics_info_.y2, Color_bottomarea); + LYXERR(Debug::PAINTING, "\n\t\t*** END DRAWING ***"); } @@ -2148,30 +1908,22 @@ void BufferView::message(docstring const & msg) } -void BufferView::showDialog(std::string const & name) -{ - if (d->gui_) - d->gui_->showDialog(name); -} - - -void BufferView::showDialogWithData(std::string const & name, - std::string const & data) +void BufferView::showDialog(string const & name) { if (d->gui_) - d->gui_->showDialogWithData(name, data); + d->gui_->showDialog(name, string()); } -void BufferView::showInsetDialog(std::string const & name, - std::string const & data, Inset * inset) +void BufferView::showDialog(string const & name, + string const & data, Inset * inset) { if (d->gui_) - d->gui_->showInsetDialog(name, data, inset); + d->gui_->showDialog(name, data, inset); } -void BufferView::updateDialog(std::string const & name, std::string const & data) +void BufferView::updateDialog(string const & name, string const & data) { if (d->gui_) d->gui_->updateDialog(name, data); @@ -2185,31 +1937,9 @@ void BufferView::setGuiDelegate(frontend::GuiBufferViewDelegate * gui) // FIXME: Move this out of BufferView again -docstring BufferView::contentsOfPlaintextFile(string const & f, - bool asParagraph) +docstring BufferView::contentsOfPlaintextFile(FileName const & fname) { - FileName fname(f); - - if (fname.empty()) { - FileDialog dlg(_("Select file to insert"), - ( asParagraph - ? LFUN_FILE_INSERT_PLAINTEXT_PARA - : LFUN_FILE_INSERT_PLAINTEXT) ); - - FileDialog::Result result = - dlg.open(from_utf8(buffer().filePath()), - FileFilterList(), docstring()); - - if (result.first == FileDialog::Later) - return docstring(); - - fname = makeAbsPath(to_utf8(result.second)); - - if (fname.empty()) - return docstring(); - } - - if (!fs::is_readable(fname.toFilesystemEncoding())) { + if (!fname.isReadableFile()) { docstring const error = from_ascii(strerror(errno)); docstring const file = makeDisplayPath(fname.absFilename(), 50); docstring const text = @@ -2219,36 +1949,16 @@ docstring BufferView::contentsOfPlaintextFile(string const & f, return docstring(); } - ifstream ifs(fname.toFilesystemEncoding().c_str()); - if (!ifs) { - docstring const error = from_ascii(strerror(errno)); + if (!fname.isReadableFile()) { docstring const file = makeDisplayPath(fname.absFilename(), 50); docstring const text = - bformat(_("Could not open the specified document\n" - "%1$s\ndue to the error: %2$s"), file, error); + bformat(_("%1$s\n is not readable."), file); Alert::error(_("Could not open file"), text); return docstring(); } - ifs.unsetf(std::ios::skipws); - istream_iterator ii(ifs); - istream_iterator end; -#if !defined(USE_INCLUDED_STRING) && !defined(STD_STRING_IS_GOOD) - // We use this until the compilers get better... - std::vector tmp; - copy(ii, end, back_inserter(tmp)); - string const tmpstr(tmp.begin(), tmp.end()); -#else - // This is what we want to use and what we will use once the - // compilers get good enough. - //string tmpstr(ii, end); // yet a reason for using std::string - // alternate approach to get the file into a string: - string tmpstr; - copy(ii, end, back_inserter(tmpstr)); -#endif - // FIXME UNICODE: We don't know the encoding of the file - docstring file_content = from_utf8(tmpstr); + docstring file_content = fname.fileContents("UTF-8"); if (file_content.empty()) { Alert::error(_("Reading not UTF-8 encoded file"), _("The file is not UTF-8 encoded.\n" @@ -2256,16 +1966,16 @@ docstring BufferView::contentsOfPlaintextFile(string const & f, "If this does not give the correct result\n" "then please change the encoding of the file\n" "to UTF-8 with a program other than LyX.\n")); - file_content = from_local8bit(tmpstr); + file_content = fname.fileContents("local8bit"); } return normalize_c(file_content); } -void BufferView::insertPlaintextFile(string const & f, bool asParagraph) +void BufferView::insertPlaintextFile(FileName const & f, bool asParagraph) { - docstring const tmpstr = contentsOfPlaintextFile(f, asParagraph); + docstring const tmpstr = contentsOfPlaintextFile(f); if (tmpstr.empty()) return; @@ -2277,6 +1987,9 @@ void BufferView::insertPlaintextFile(string const & f, bool asParagraph) cur.innerText()->insertStringAsParagraphs(cur, tmpstr); else cur.innerText()->insertStringAsLines(cur, tmpstr); + + updateMetrics(); + buffer_.changed(); } } // namespace lyx