X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.C;h=2ff1ec0a0736a88c10920b725bf23ac2072a96af;hb=ca6838b288daf07eec7d7a381d74c639c0de3a46;hp=1ba092af0dcb3272003d2e7a1e9c045463e1e953;hpb=a1d0ad06df8fa42fab030569a5d04949c5de9a47;p=lyx.git diff --git a/src/BufferView.C b/src/BufferView.C index 1ba092af0d..2ff1ec0a07 100644 --- a/src/BufferView.C +++ b/src/BufferView.C @@ -83,10 +83,11 @@ namespace lyx { using support::addPath; using support::bformat; using support::FileFilterList; +using support::FileName; using support::fileSearch; using support::isDirWriteable; +using support::isFileReadable; using support::makeDisplayPath; -using support::makeAbsPath; using support::package; using std::distance; @@ -123,7 +124,7 @@ BufferView::BufferView() : width_(0), height_(0), buffer_(0), wh_(0), cursor_(*this), multiparsel_cache_(false), anchor_ref_(0), offset_ref_(0), - intl_(new Intl) + intl_(new Intl), last_inset_(0) { xsel_cache_.set = false; intl_->initKeyMapper(lyxrc.use_kbmap); @@ -153,7 +154,7 @@ void BufferView::setBuffer(Buffer * b) buffer_->saveCursor(cursor_.selectionBegin(), cursor_.selectionEnd()); // current buffer is going to be switched-off, save cursor pos - LyX::ref().session().lastFilePos().save(buffer_->fileName(), + LyX::ref().session().lastFilePos().save(FileName(buffer_->fileName()), boost::tie(cursor_.pit(), cursor_.pos()) ); } @@ -197,27 +198,19 @@ void BufferView::setBuffer(Buffer * b) } } - update(); + if (buffer_) + updateMetrics(false); if (buffer_ && graphics::Previews::status() != LyXRC::PREVIEW_OFF) graphics::Previews::get().generateBufferPreviews(*buffer_); } -bool BufferView::loadLyXFile(string const & filename, bool tolastfiles) +bool BufferView::loadLyXFile(FileName const & filename, bool tolastfiles) { - // Get absolute path of file and add ".lyx" - // to the filename if necessary - string s = fileSearch(string(), filename, "lyx"); - - bool const found = !s.empty(); - - if (!found) - s = filename; - // File already open? - if (theBufferList().exists(s)) { - docstring const file = makeDisplayPath(s, 20); + if (theBufferList().exists(filename.absFilename())) { + docstring const file = makeDisplayPath(filename.absFilename(), 20); docstring text = bformat(_("The document %1$s is already " "loaded.\n\nDo you want to revert " "to the saved version?"), file); @@ -225,11 +218,11 @@ bool BufferView::loadLyXFile(string const & filename, bool tolastfiles) text, 0, 1, _("&Revert"), _("&Switch to document")); if (ret != 0) { - setBuffer(theBufferList().getBuffer(s)); + setBuffer(theBufferList().getBuffer(filename.absFilename())); return true; } // FIXME: should be LFUN_REVERT - if (!theBufferList().close(theBufferList().getBuffer(s), false)) + if (!theBufferList().close(theBufferList().getBuffer(filename.absFilename()), false)) return false; // Fall through to new load. (Asger) buffer_ = 0; @@ -237,21 +230,21 @@ bool BufferView::loadLyXFile(string const & filename, bool tolastfiles) Buffer * b = 0; - if (found) { - b = theBufferList().newBuffer(s); - if (!lyx::loadLyXFile(b, s)) { + if (isFileReadable(filename)) { + b = theBufferList().newBuffer(filename.absFilename()); + if (!lyx::loadLyXFile(b, filename)) { theBufferList().release(b); return false; } } else { docstring text = bformat(_("The document %1$s does not yet " "exist.\n\nDo you want to create " - "a new document?"), from_utf8(s)); + "a new document?"), from_utf8(filename.absFilename())); int const ret = Alert::prompt(_("Create new document?"), text, 0, 1, _("&Create"), _("Cancel")); if (ret == 0) { - b = newFile(s, string(), true); + b = newFile(filename.absFilename(), string(), true); if (!b) return false; } else @@ -266,7 +259,7 @@ bool BufferView::loadLyXFile(string const & filename, bool tolastfiles) if (lyxrc.use_lastfilepos) { pit_type pit; pos_type pos; - boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(s); + boost::tie(pit, pos) = LyX::ref().session().lastFilePos().load(filename); // I am not sure how to separate the following part to a function // so I will leave this to Lars. // @@ -278,14 +271,16 @@ bool BufferView::loadLyXFile(string const & filename, bool tolastfiles) if (it.pit() == pit) { // restored pos may be bigger than it->size setCursor(makeDocIterator(it, min(pos, it->size()))); - update(Update::FitCursor); + // No need to update the metrics if fitCursor returns false. + if (fitCursor()) + updateMetrics(false); break; } } } if (tolastfiles) - LyX::ref().session().lastFiles().add(b->fileName()); + LyX::ref().session().lastFiles().add(FileName(b->fileName())); return true; } @@ -293,9 +288,8 @@ bool BufferView::loadLyXFile(string const & filename, bool tolastfiles) void BufferView::reload() { - string const fn = buffer_->fileName(); if (theBufferList().close(buffer_, false)) - loadLyXFile(fn); + loadLyXFile(FileName(buffer_->fileName())); } @@ -307,7 +301,7 @@ void BufferView::resize() lyxerr[Debug::DEBUG] << BOOST_CURRENT_FUNCTION << endl; buffer_->text().init(this); - update(); + updateMetrics(false); switchKeyMap(); } @@ -362,15 +356,36 @@ bool BufferView::update(Update::flags flags) // Update macro store buffer_->buildMacros(); - // First drawing step - updateMetrics(flags & Update::SinglePar); - + // Now do the first drawing step if needed. This consists on updating + // the CoordCache in updateMetrics(). // The second drawing step is done in WorkArea::redraw() if needed. - bool const need_second_step = - (flags & (Update::SinglePar | Update::Force | Update::FitCursor | Update::MultiParSel)) - && (fitCursor() || multiParSel()); - return need_second_step; + // Case when no explicit update is requested. + if (!flags) { + // no need to redraw anything. + return false; + } + + if (flags == Update::FitCursor) { + bool const fit_cursor = fitCursor(); + if (fit_cursor) + updateMetrics(false); + // tell the frontend to update the screen if needed. + return fit_cursor; + } + + bool full_metrics = flags & Update::Force; + if (flags & Update::MultiParSel) + full_metrics |= multiParSel(); + + bool const single_par = !full_metrics; + updateMetrics(single_par); + + if (flags & Update::FitCursor && fitCursor()) + updateMetrics(false); + + // tell the frontend to update the screen. + return true; } @@ -460,6 +475,7 @@ void BufferView::scrollDocView(int value) t.redoParagraph(*this, anchor_ref_); int const h = t.getPar(anchor_ref_).height(); offset_ref_ = int((bar * t.paragraphs().size() - anchor_ref_) * h); + updateMetrics(false); } @@ -507,7 +523,7 @@ Change const BufferView::getCurrentChange() const void BufferView::saveBookmark(bool persistent) { LyX::ref().session().bookmarks().save( - buffer_->fileName(), + FileName(buffer_->fileName()), cursor_.paragraph().id(), cursor_.pos(), persistent @@ -628,7 +644,11 @@ FuncStatus BufferView::getStatus(FuncRequest const & cmd) case LFUN_CHANGE_NEXT: case LFUN_ALL_CHANGES_ACCEPT: case LFUN_ALL_CHANGES_REJECT: - flag.enabled(buffer_); // FIXME: Change tracking (MG) + // TODO: context-sensitive enabling of LFUNs + // In principle, these command should only be enabled if there + // is a change in the document. However, without proper + // optimizations, this will inevitably result in poor performance. + flag.enabled(buffer_); break; case LFUN_BUFFER_TOGGLE_COMPRESSION: { @@ -685,22 +705,22 @@ bool BufferView::dispatch(FuncRequest const & cmd) break; case LFUN_FILE_INSERT: - // FIXME: We don't know the encoding of filenames + // FIXME UNICODE menuInsertLyXFile(to_utf8(cmd.argument())); break; case LFUN_FILE_INSERT_ASCII_PARA: - // FIXME: We don't know the encoding of filenames + // FIXME UNICODE insertAsciiFile(this, to_utf8(cmd.argument()), true); break; case LFUN_FILE_INSERT_ASCII: - // FIXME: We don't know the encoding of filenames + // FIXME UNICODE insertAsciiFile(this, to_utf8(cmd.argument()), false); break; case LFUN_FONT_STATE: - cur.message(from_utf8(cur.currentState())); + cur.message(cur.currentState()); break; case LFUN_BOOKMARK_SAVE: @@ -727,21 +747,34 @@ bool BufferView::dispatch(FuncRequest const & cmd) case LFUN_PARAGRAPH_GOTO: { int const id = convert(to_utf8(cmd.argument())); - ParIterator par = buffer_->getParFromID(id); - if (par == buffer_->par_iterator_end()) { - lyxerr[Debug::INFO] << "No matching paragraph found! [" - << id << ']' << endl; - break; - } else { - lyxerr[Debug::INFO] << "Paragraph " << par->id() - << " found." << endl; + int i = 0; + for (Buffer * b = buffer_; i == 0 || b != buffer_; b = theBufferList().next(b)) { + ParIterator par = b->getParFromID(id); + if (par == b->par_iterator_end()) { + lyxerr[Debug::INFO] + << "No matching paragraph found! [" + << id << "]." << endl; + } else { + lyxerr[Debug::INFO] + << "Paragraph " << par->id() + << " found in buffer `" + << b->fileName() << "'." << endl; + + if (b == buffer_) { + // Set the cursor + setCursor(makeDocIterator(par, 0)); + update(); + switchKeyMap(); + } else { + // Switch to other buffer view and resend cmd + theLyXFunc().dispatch(FuncRequest( + LFUN_BUFFER_SWITCH, b->fileName())); + theLyXFunc().dispatch(cmd); + } + break; + } + ++i; } - - // Set the cursor - setCursor(makeDocIterator(par, 0)); - - update(); - switchKeyMap(); break; } @@ -979,17 +1012,16 @@ void BufferView::clearSelection() void BufferView::workAreaResize(int width, int height) { - bool const widthChange = width != width_; - bool const heightChange = height != height_; - + // A resize is triggered whenever a window gets focus, + // because of the shared rows() of a buffer in multiple + // buffer views. + // Update from work area width_ = width; height_ = height; if (buffer_) resize(); - - update(); } @@ -1005,12 +1037,9 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) if (!buffer_) return false; - bool needRedraw = false; - LCursor cur(*this); cur.push(buffer_->inset()); cur.selection() = cursor_.selection(); - needRedraw |= cur.selection(); // Either the inset under the cursor or the // surrounding LyXText will handle this event. @@ -1024,6 +1053,52 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) //lyxerr << BOOST_CURRENT_FUNCTION // << " * created temp cursor:" << cur << endl; + // NOTE: editXY returns the top level inset of nested insets. If you happen + // to move from a text (inset=0) to a text inside an inset (e.g. an opened + // footnote inset, again inset=0), that inset will not be redrawn. + if (cmd.action == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) { + bool need_redraw = false; + + if (inset != last_inset_) { + if (last_inset_) + need_redraw |= last_inset_->setMouseHover(false); + if (inset) + need_redraw |= inset->setMouseHover(true); + last_inset_ = inset; + } + + // 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. + // FIXME: It is possible to redraw only the area around the button! + if (need_redraw && metrics_info_.singlepar) { + // FIXME: It should be possible to redraw only the area around + // the button by doing this: + // + //metrics_info_.singlepar = false; + //metrics_info_.y1 = ymin of button; + //metrics_info_.y2 = ymax of button; + // + // Unfortunately, rowpainter.C:paintText() does not distinguish + // between background updates and text updates. So we use the hammer + // solution for now. We could also avoid the updateMetrics() below + // by using the first and last pit of the CoordCache. Have a look + // at LyXText::getPitNearY() to see what I mean. + // + //metrics_info_.pit1 = first pit of CoordCache; + //metrics_info_.pit2 = last pit of CoordCache; + //metrics_info_.singlepar = false; + //metrics_info_.y1 = 0; + //metrics_info_.y2 = height_; + // + updateMetrics(false); + } + + // This event (moving without mouse click) is not passed further. + // This should be changed if it is further utilized. + return need_redraw; + } + // Put anchor at the same position. cur.resetAnchor(); @@ -1033,7 +1108,6 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) // cur.bv().cursor() = cur; (or similar) if (inset) { inset->dispatch(cur, cmd); - needRedraw = true; } // Now dispatch to the temporary cursor. If the real cursor should @@ -1041,17 +1115,11 @@ bool BufferView::workAreaDispatch(FuncRequest const & cmd0) if (!cur.result().dispatched()) cur.dispatch(cmd); - if (cur.result().dispatched()) { - // Redraw if requested or necessary. - if (cur.result().update()) - needRedraw |= update(Update::FitCursor | Update::Force); - else - needRedraw |= update(Update::FitCursor | Update::MultiParSel); - } + // Redraw if requested and necessary. + if (cur.result().dispatched() && cur.result().update()) + return update(cur.result().update()); - // When the above and the inner function are fixed, we can do this: - //return needRedraw; - return true; + return false; } @@ -1138,7 +1206,7 @@ void BufferView::setCursor(DocIterator const & dit) } -void BufferView::mouseSetCursor(LCursor & cur) +bool BufferView::mouseSetCursor(LCursor & cur) { BOOST_ASSERT(&cur.bv() == this); @@ -1149,14 +1217,15 @@ void BufferView::mouseSetCursor(LCursor & cur) // do the dEPM magic if needed // FIXME: move this to InsetText::notifyCursorLeaves? + bool update = false; if (!badcursor && cursor_.inTexted()) - cursor_.text()->deleteEmptyParagraphMechanism(cur, cursor_); + update = cursor_.text()->deleteEmptyParagraphMechanism(cur, cursor_); cursor_ = cur; cursor_.clearSelection(); cursor_.setTargetX(); finishUndo(); - + return update; } @@ -1204,7 +1273,7 @@ ViewMetricsInfo const & BufferView::viewMetricsInfo() void BufferView::updateMetrics(bool singlepar) { // Clear out the position cache in case of full screen redraw. - //if (!singlepar) + if (!singlepar) coord_cache_.clear(); LyXText & buftext = buffer_->text(); @@ -1323,7 +1392,7 @@ void BufferView::menuInsertLyXFile(string const & filenm) if (buffer_) { string const trypath = buffer_->filePath(); // If directory is writeable, use this as default. - if (isDirWriteable(trypath)) + if (isDirWriteable(FileName(trypath))) initpath = trypath; } @@ -1354,7 +1423,7 @@ void BufferView::menuInsertLyXFile(string const & filenm) // Get absolute path of file and add ".lyx" // to the filename if necessary - filename = fileSearch(string(), filename, "lyx"); + filename = fileSearch(string(), filename, "lyx").absFilename(); docstring const disp_fn = makeDisplayPath(filename); // emit message signal. @@ -1362,7 +1431,7 @@ void BufferView::menuInsertLyXFile(string const & filenm) docstring res; Buffer buf("", false); - if (lyx::loadLyXFile(&buf, makeAbsPath(filename))) { + if (lyx::loadLyXFile(&buf, FileName(filename))) { ErrorList & el = buffer_->errorList("Parse"); // Copy the inserted document error list into the current buffer one. el = buf.errorList("Parse");