X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.cpp;h=e0c96856ddeb4c2eea6a845d7226d58cf6fb6f77;hb=d866717ef7503a1373dd1cb3925e1ac97b079192;hp=0d5b76a61482d1284b18502ef258c39a0acd0c70;hpb=0b450f40e7c77b5b927c5ce5e14f294fad15adec;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index 0d5b76a614..e0c96856dd 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -58,9 +58,9 @@ #include "insets/InsetCommand.h" // ChangeRefs #include "insets/InsetExternal.h" #include "insets/InsetGraphics.h" +#include "insets/InsetNote.h" #include "insets/InsetRef.h" #include "insets/InsetText.h" -#include "insets/InsetNote.h" #include "frontends/alert.h" #include "frontends/Application.h" @@ -107,10 +107,7 @@ T * getInsetByCode(Cursor const & cur, InsetCode code) return 0; } - -bool findInset(DocIterator & dit, vector const & codes, - bool same_content); - +/// Note that comparing contents can only be used for InsetCommand bool findNextInset(DocIterator & dit, vector const & codes, docstring const & contents) { @@ -118,12 +115,17 @@ bool findNextInset(DocIterator & dit, vector const & codes, while (tmpdit) { Inset const * inset = tmpdit.nextInset(); - if (inset - && std::find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end() - && (contents.empty() || - static_cast(inset)->getFirstNonOptParam() == contents)) { - dit = tmpdit; - return true; + if (inset) { + bool const valid_code = std::find(codes.begin(), codes.end(), + inset->lyxCode()) != codes.end(); + InsetCommand const * ic = inset->asInsetCommand(); + bool const same_or_no_contents = contents.empty() + || (ic && (ic->getFirstNonOptParam() == contents)); + + if (valid_code && same_or_no_contents) { + dit = tmpdit; + return true; + } } tmpdit.forwardInset(); } @@ -133,6 +135,7 @@ bool findNextInset(DocIterator & dit, vector const & codes, /// Looks for next inset with one of the given codes. +/// Note that same_content can only be used for InsetCommand bool findInset(DocIterator & dit, vector const & codes, bool same_content) { @@ -142,11 +145,14 @@ bool findInset(DocIterator & dit, vector const & codes, if (!tmpdit) return false; - if (same_content) { - Inset const * inset = tmpdit.nextInset(); - if (inset - && std::find(codes.begin(), codes.end(), inset->lyxCode()) != codes.end()) { - contents = static_cast(inset)->getFirstNonOptParam(); + Inset const * inset = tmpdit.nextInset(); + if (same_content && inset) { + InsetCommand const * ic = inset->asInsetCommand(); + if (ic) { + bool const valid_code = std::find(codes.begin(), codes.end(), + ic->lyxCode()) != codes.end(); + if (valid_code) + contents = ic->getFirstNonOptParam(); } } @@ -220,8 +226,9 @@ struct BufferView::Private Private(BufferView & bv): wh_(0), cursor_(bv), anchor_pit_(0), anchor_ypos_(0), inlineCompletionUniqueChars_(0), - last_inset_(0), mouse_position_cache_(), - bookmark_edit_position_(0), gui_(0) + last_inset_(0), clickable_inset_(false), + mouse_position_cache_(), + bookmark_edit_position_(-1), gui_(0) {} /// @@ -263,6 +270,8 @@ struct BufferView::Private * Not owned, so don't delete. */ Inset * last_inset_; + /// are we hovering something that we can click + bool clickable_inset_; /// position of the mouse at the time of the last mouse move /// This is used to update the hovering status of inset in @@ -299,8 +308,7 @@ BufferView::BufferView(Buffer & buf) d->cursor_.resetAnchor(); d->cursor_.setCurrentFont(); - if (graphics::Previews::status() != LyXRC::PREVIEW_OFF) - thePreviews().generateBufferPreviews(buffer_); + buffer_.updatePreviews(); } @@ -315,6 +323,9 @@ BufferView::~BufferView() fp.pit = d->cursor_.bottom().pit(); fp.pos = d->cursor_.bottom().pos(); theSession().lastFilePos().save(buffer_.fileName(), fp); + + if (d->last_inset_) + d->last_inset_->setMouseHover(this, false); delete d; } @@ -393,7 +404,7 @@ bool BufferView::fitCursor() theFontMetrics(d->cursor_.getFont().fontInfo()); int const asc = fm.maxAscent(); int const des = fm.maxDescent(); - Point const p = getPos(d->cursor_, d->cursor_.boundary()); + Point const p = getPos(d->cursor_); if (p.y_ - asc >= 0 && p.y_ + des < height_) return false; } @@ -410,6 +421,8 @@ void BufferView::processUpdateFlags(Update::flags flags) << ", singlepar = " << (flags & Update::SinglePar) << "] buffer: " << &buffer_); + // FIXME Does this really need doing here? It's done in updateBuffer, and + // if the Buffer doesn't need updating, then do the macros? buffer_.updateMacros(); // Now do the first drawing step if needed. This consists on updating @@ -565,7 +578,7 @@ docstring BufferView::contextMenu(int x, int y) const } -void BufferView::scrollDocView(int value) +void BufferView::scrollDocView(int value, bool update) { int const offset = value - d->scrollbarParameters_.position; @@ -584,7 +597,7 @@ void BufferView::scrollDocView(int value) // cut off at the top if (value <= d->scrollbarParameters_.min) { DocIterator dit = doc_iterator_begin(&buffer_); - showCursor(dit); + showCursor(dit, false, update); LYXERR(Debug::SCROLLING, "scroll to top"); return; } @@ -593,7 +606,7 @@ void BufferView::scrollDocView(int value) if (value >= d->scrollbarParameters_.max) { DocIterator dit = doc_iterator_end(&buffer_); dit.backwardPos(); - showCursor(dit); + showCursor(dit, false, update); LYXERR(Debug::SCROLLING, "scroll to bottom"); return; } @@ -611,14 +624,14 @@ void BufferView::scrollDocView(int value) // It seems we didn't find the correct pit so stay on the safe side and // scroll to bottom. LYXERR0("scrolling position not found!"); - scrollDocView(d->scrollbarParameters_.max); + scrollDocView(d->scrollbarParameters_.max, update); return; } DocIterator dit = doc_iterator_begin(&buffer_); dit.pit() = i; LYXERR(Debug::SCROLLING, "value = " << value << " -> scroll to pit " << i); - showCursor(dit); + showCursor(dit, false, update); } @@ -641,7 +654,7 @@ void BufferView::setCursorFromScrollbar() newy = last; break; case CUR_INSIDE: - int const y = getPos(oldcur, oldcur.boundary()).y_; + int const y = getPos(oldcur).y_; newy = min(last, max(y, first)); if (y == newy) return; @@ -676,7 +689,7 @@ Change const BufferView::getCurrentChange() const // FIXME: This does not work within mathed! CursorStatus BufferView::cursorStatus(DocIterator const & dit) const { - Point const p = getPos(dit, dit.boundary()); + Point const p = getPos(dit); if (p.y_ < 0) return CUR_ABOVE; if (p.y_ > workHeight()) @@ -687,6 +700,7 @@ CursorStatus BufferView::cursorStatus(DocIterator const & dit) const void BufferView::bookmarkEditPosition() { + d->cursor_.markEditPosition(); // Don't eat cpu time for each keystroke if (d->cursor_.paragraph().id() == d->bookmark_edit_position_) return; @@ -803,19 +817,20 @@ int BufferView::workWidth() const void BufferView::recenter() { - showCursor(d->cursor_, true); + showCursor(d->cursor_, true, true); } void BufferView::showCursor() { - showCursor(d->cursor_, false); + showCursor(d->cursor_, false, true); } -void BufferView::showCursor(DocIterator const & dit, bool recenter) +void BufferView::showCursor(DocIterator const & dit, + bool recenter, bool update) { - if (scrollToCursor(dit, recenter)) { + if (scrollToCursor(dit, recenter) && update) { buffer_.changed(true); updateHoveredInset(); } @@ -862,17 +877,29 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool recenter) LASSERT(!pm.rows().empty(), /**/); // FIXME: smooth scrolling doesn't work in mathed. CursorSlice const & cs = dit.innerTextSlice(); - int offset = coordOffset(dit, dit.boundary()).y_; + int offset = coordOffset(dit).y_; int ypos = pm.position() + offset; Dimension const & row_dim = pm.getRow(cs.pos(), dit.boundary()).dimension(); int scrolled = 0; if (recenter) scrolled = scroll(ypos - height_/2); + + // If the top part of the row falls of the screen, we scroll + // up to align the top of the row with the top of the screen. else if (ypos - row_dim.ascent() < 0) - scrolled = scrollUp(- ypos + row_dim.ascent()); - else if (ypos + row_dim.descent() > height_) - scrolled = scrollDown(ypos - height_ + defaultRowHeight() ); + scrolled = scrollUp(-ypos + row_dim.ascent()); + + // If the bottom of the row falls of the screen, we scroll down. + // However, we have to be careful not to scroll that much that + // the top falls of the screen. + else if (ypos + row_dim.descent() > height_) { + int ynew = height_ - row_dim.descent(); + if (ynew < row_dim.ascent()) + ynew = row_dim.ascent(); + int const scroll = ypos - ynew; + scrolled = scrollDown(scroll); + } // else, nothing to do, the cursor is already visible so we just return. return scrolled != 0; @@ -884,7 +911,7 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool recenter) tm.redoParagraph(bot_pit); ParagraphMetrics const & pm = tm.parMetrics(bot_pit); - int offset = coordOffset(dit, dit.boundary()).y_; + int offset = coordOffset(dit).y_; d->anchor_pit_ = bot_pit; CursorSlice const & cs = dit.innerTextSlice(); @@ -919,7 +946,6 @@ void BufferView::updateDocumentClass(DocumentClass const * const olddc) setCursor(backcur.asDocIterator(&buffer_)); buffer_.errors("Class Switch"); - buffer_.updateBuffer(); } /** Return the change status at cursor position, taking in account the @@ -946,18 +972,21 @@ static Change::Type lookupChangeType(DocIterator const & dit, bool outer = false bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) { + FuncCode const act = cmd.action(); + // Can we use a readonly buffer? if (buffer_.isReadonly() - && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly) - && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) { + && !lyxaction.funcHasFlag(act, LyXAction::ReadOnly) + && !lyxaction.funcHasFlag(act, LyXAction::NoBuffer)) { flag.message(from_utf8(N_("Document is read-only"))); flag.setEnabled(false); return true; } + // Are we in a DELETED change-tracking region? if (lookupChangeType(d->cursor_, true) == Change::DELETED - && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly) - && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) { + && !lyxaction.funcHasFlag(act, LyXAction::ReadOnly) + && !lyxaction.funcHasFlag(act, LyXAction::NoBuffer)) { flag.message(from_utf8(N_("This portion of the document is deleted."))); flag.setEnabled(false); return true; @@ -968,13 +997,13 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) if (cur.getStatus(cmd, flag)) return true; - switch (cmd.action) { + switch (act) { - // FIXME: This is a bit problematic because we don't check is this is a - // document BufferView or not for these LFUNs. We probably have to + // FIXME: This is a bit problematic because we don't check if this is + // a document BufferView or not for these LFUNs. We probably have to // dispatch both to currentBufferView() and, if that fails, - // to documentBufferView(); same as we do know for current Buffer and - // document Buffer. Ideally those LFUN should go to Buffer as they* + // to documentBufferView(); same as we do now for current Buffer and + // document Buffer. Ideally those LFUN should go to Buffer as they // operate on the full Buffer and the cursor is only needed either for // an Undo record or to restore a cursor position. But we don't know // how to do that inside Buffer of course. @@ -988,10 +1017,14 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; case LFUN_UNDO: - flag.setEnabled(buffer_.undo().hasUndoStack()); + // We do not use the LyXAction flag for readonly because Undo sets the + // buffer clean/dirty status by itself. + flag.setEnabled(!buffer_.isReadonly() && buffer_.undo().hasUndoStack()); break; case LFUN_REDO: - flag.setEnabled(buffer_.undo().hasRedoStack()); + // We do not use the LyXAction flag for readonly because Redo sets the + // buffer clean/dirty status by itself. + flag.setEnabled(!buffer_.isReadonly() && buffer_.undo().hasRedoStack()); break; case LFUN_FILE_INSERT: case LFUN_FILE_INSERT_PLAINTEXT_PARA: @@ -1004,7 +1037,6 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_FONT_STATE: case LFUN_LABEL_INSERT: case LFUN_INFO_INSERT: - case LFUN_INSET_EDIT: case LFUN_PARAGRAPH_GOTO: case LFUN_NOTE_NEXT: case LFUN_REFERENCE_NEXT: @@ -1020,7 +1052,6 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) case LFUN_SCREEN_SHOW_CURSOR: case LFUN_BIBTEX_DATABASE_ADD: case LFUN_BIBTEX_DATABASE_DEL: - case LFUN_ALL_INSETS_TOGGLE: case LFUN_STATISTICS: case LFUN_BRANCH_ADD_INSERT: case LFUN_KEYMAP_OFF: @@ -1030,15 +1061,6 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setEnabled(true); break; - case LFUN_LABEL_COPY_AS_REF: { - // if there is an inset at cursor, see whether it - // handles the lfun - Inset * inset = cur.nextInset(); - if (!inset || !inset->getStatus(cur, cmd, flag)) - flag.setEnabled(false); - break; - } - case LFUN_LABEL_GOTO: { flag.setEnabled(!cmd.argument().empty() || getInsetByCode(cur, REF_CODE)); @@ -1071,7 +1093,12 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(buffer_.params().compressed); break; } - + + case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: { + flag.setOnOff(buffer_.params().output_sync); + break; + } + case LFUN_SCREEN_UP: case LFUN_SCREEN_DOWN: case LFUN_SCROLL: @@ -1099,7 +1126,7 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) if (cur.inset().lyxCode() == CAPTION_CODE) return cur.inset().getStatus(cur, cmd, flag); // FIXME we should consider passthru paragraphs too. - flag.setEnabled(!cur.inset().getLayout().isPassThru()); + flag.setEnabled(!(cur.inTexted() && cur.paragraph().isPassThru())); break; case LFUN_CITATION_INSERT: { @@ -1114,21 +1141,18 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) Inset * inset = editedInset(name); if (inset) { FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument()); - FuncStatus fs; - if (!inset->getStatus(cur, fr, fs)) { + if (!inset->getStatus(cur, fr, flag)) { // Every inset is supposed to handle this LASSERT(false, break); } - flag |= fs; } else { FuncRequest fr(LFUN_INSET_INSERT, cmd.argument()); - flag |= lyx::getStatus(fr); + flag = lyx::getStatus(fr); } break; } default: - flag.setEnabled(false); return false; } @@ -1154,10 +1178,10 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) //lyxerr << [ cmd = " << cmd << "]" << endl; // Make sure that the cached BufferView is correct. - LYXERR(Debug::ACTION, " action[" << cmd.action << ']' + LYXERR(Debug::ACTION, " action[" << cmd.action() << ']' << " arg[" << to_utf8(cmd.argument()) << ']' - << " x[" << cmd.x << ']' - << " y[" << cmd.y << ']' + << " x[" << cmd.x() << ']' + << " y[" << cmd.y() << ']' << " button[" << cmd.button() << ']'); string const argument = to_utf8(cmd.argument()); @@ -1165,14 +1189,15 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // Don't dispatch function that does not apply to internal buffers. if (buffer_.isInternal() - && lyxaction.funcHasFlag(cmd.action, LyXAction::NoInternal)) + && lyxaction.funcHasFlag(cmd.action(), LyXAction::NoInternal)) return; // We'll set this back to false if need be. bool dispatched = true; buffer_.undo().beginUndoGroup(); - switch (cmd.action) { + FuncCode const act = cmd.action(); + switch (act) { case LFUN_BUFFER_PARAMS_APPLY: { DocumentClass const * const oldClass = buffer_.params().documentClassPtr(); @@ -1191,7 +1216,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // We are most certainly here because of a change in the document // It is then better to make sure that all dialogs are in sync with // current document settings. - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); break; } @@ -1202,7 +1228,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) buffer_.params().clearLayoutModules(); buffer_.params().makeDocumentClass(); updateDocumentClass(oldClass); - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force); + dr.forceBufferUpdate(); break; } @@ -1219,14 +1246,23 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) buffer_.params().addLayoutModule(argument); buffer_.params().makeDocumentClass(); updateDocumentClass(oldClass); - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force); + dr.forceBufferUpdate(); break; } case LFUN_TEXTCLASS_APPLY: { - if (!LayoutFileList::get().load(argument, buffer_.temppath()) && - !LayoutFileList::get().load(argument, buffer_.filePath())) + // since this shortcircuits, the second call is made only if + // the first fails + bool const success = + LayoutFileList::get().load(argument, buffer_.temppath()) || + LayoutFileList::get().load(argument, buffer_.filePath()); + if (!success) { + docstring s = bformat(_("The document class `%1$s' " + "could not be loaded."), from_utf8(argument)); + frontend::Alert::error(_("Could not load class"), s); break; + } LayoutFile const * old_layout = buffer_.params().baseClass(); LayoutFile const * new_layout = &(LayoutFileList::get()[argument]); @@ -1235,21 +1271,31 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // nothing to do break; - //Save the old, possibly modular, layout for use in conversion. + // Save the old, possibly modular, layout for use in conversion. DocumentClass const * const oldDocClass = buffer_.params().documentClassPtr(); cur.recordUndoFullDocument(); buffer_.params().setBaseClass(argument); buffer_.params().makeDocumentClass(); updateDocumentClass(oldDocClass); - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force); + dr.forceBufferUpdate(); break; } - case LFUN_TEXTCLASS_LOAD: - LayoutFileList::get().load(argument, buffer_.temppath()) || - LayoutFileList::get().load(argument, buffer_.filePath()); + case LFUN_TEXTCLASS_LOAD: { + // since this shortcircuits, the second call is made only if + // the first fails + bool const success = + LayoutFileList::get().load(argument, buffer_.temppath()) || + LayoutFileList::get().load(argument, buffer_.filePath()); + if (!success) { + docstring s = bformat(_("The document class `%1$s' " + "could not be loaded."), from_utf8(argument)); + frontend::Alert::error(_("Could not load class"), s); + } break; + } case LFUN_LAYOUT_RELOAD: { DocumentClass const * const oldClass = buffer_.params().documentClassPtr(); @@ -1258,7 +1304,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) buffer_.params().setBaseClass(bc); buffer_.params().makeDocumentClass(); updateDocumentClass(oldClass); - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force); + dr.forceBufferUpdate(); break; } @@ -1268,7 +1315,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (!cur.textUndo()) dr.setMessage(_("No further undo information")); else - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); break; case LFUN_REDO: @@ -1277,7 +1325,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (!cur.textRedo()) dr.setMessage(_("No further redo information")); else - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); break; case LFUN_FONT_STATE: @@ -1299,30 +1348,16 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) saveBookmark(0); } } - if (!label.empty()) + if (!label.empty()) { gotoLabel(label); + // at the moment, this is redundant, since gotoLabel will + // eventually call LFUN_PARAGRAPH_GOTO, but it seems best + // to have it here. + dr.screenUpdate(Update::Force | Update::FitCursor); + } break; } - case LFUN_INSET_EDIT: { - FuncRequest fr(cmd); - // if there is an inset at cursor, see whether it - // can be modified. - Inset * inset = cur.nextInset(); - if (inset) - inset->dispatch(cur, fr); - // if it did not work, try the underlying inset. - if (!inset || !cur.result().dispatched()) - cur.dispatch(cmd); - - // FIXME I'm adding the last break to solve a crash, - // but that is obviously not right. - if (!cur.result().dispatched()) - // It did not work too; no action needed. - break; - break; - } - case LFUN_PARAGRAPH_GOTO: { int const id = convert(cmd.getArg(0)); int const pos = convert(cmd.getArg(1)); @@ -1344,7 +1379,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // Set the cursor dit.pos() = pos; setCursor(dit); - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); } else { // Switch to other buffer view and resend cmd lyx::dispatch(FuncRequest( @@ -1398,18 +1433,19 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) case LFUN_CHANGE_NEXT: findNextChange(this); // FIXME: Move this LFUN to Buffer so that we don't have to do this: - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); break; case LFUN_CHANGE_PREVIOUS: findPreviousChange(this); // FIXME: Move this LFUN to Buffer so that we don't have to do this: - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); break; case LFUN_CHANGES_MERGE: if (findNextChange(this) || findPreviousChange(this)) { - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); showDialog("changes"); } break; @@ -1422,7 +1458,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // accept everything in a single step to support atomic undo buffer_.text().acceptOrRejectChanges(cur, Text::ACCEPT); // FIXME: Move this LFUN to Buffer so that we don't have to do this: - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); break; case LFUN_ALL_CHANGES_REJECT: @@ -1434,7 +1471,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // Note: reject does not work recursively; the user may have to repeat the operation buffer_.text().acceptOrRejectChanges(cur, Text::REJECT); // FIXME: Move this LFUN to Buffer so that we don't have to do this: - dr.update(Update::Force | Update::FitCursor); + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); break; case LFUN_WORD_FIND_FORWARD: @@ -1452,10 +1490,12 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) if (searched_string.empty()) break; - bool const fw = cmd.action == LFUN_WORD_FIND_FORWARD; + bool const fw = act == LFUN_WORD_FIND_FORWARD; docstring const data = find2string(searched_string, true, false, fw); - find(this, FuncRequest(LFUN_WORD_FIND, data)); + bool found = lyxfind(this, FuncRequest(LFUN_WORD_FIND, data)); + if (found) + dr.screenUpdate(Update::Force | Update::FitCursor); break; } @@ -1467,8 +1507,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) lyx::dispatch(FuncRequest(LFUN_DIALOG_SHOW, "findreplace")); break; } - if (find(this, req)) - showCursor(); + if (lyxfind(this, req)) + dr.screenUpdate(Update::Force | Update::FitCursor); else message(_("String not found!")); d->search_request_cache_ = req; @@ -1482,13 +1522,17 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) DocIterator end = cur.selectionEnd(); if (beg.pit() == end.pit()) { for (pos_type p = beg.pos() ; p < end.pos() ; ++p) { - if (!cur.inMathed() - && cur.paragraph().isDeleted(p)) + if (!cur.inMathed() && cur.paragraph().isDeleted(p)) { has_deleted = true; + break; + } } } } - replace(this, cmd, has_deleted); + if (lyxreplace(this, cmd, has_deleted)) { + dr.forceBufferUpdate(); + dr.screenUpdate(Update::Force | Update::FitCursor); + } break; } @@ -1496,10 +1540,14 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) FindAndReplaceOptions opt; istringstream iss(to_utf8(cmd.argument())); iss >> opt; - if (findAdv(this, opt)) + if (findAdv(this, opt)) { + dr.screenUpdate(Update::Force | Update::FitCursor); cur.dispatched(); - else + dispatched = true; + } else { cur.undispatched(); + dispatched = false; + } break; } @@ -1540,8 +1588,10 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) InsetBibtex * inset = getInsetByCode(tmpcur, BIBTEX_CODE); if (inset) { - if (inset->addDatabase(cmd.argument())) - buffer_.updateBibfilesCache(); + if (inset->addDatabase(cmd.argument())) { + buffer_.invalidateBibfileCache(); + dr.forceBufferUpdate(); + } } break; } @@ -1552,8 +1602,10 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) InsetBibtex * inset = getInsetByCode(tmpcur, BIBTEX_CODE); if (inset) { - if (inset->delDatabase(cmd.argument())) - buffer_.updateBibfilesCache(); + if (inset->delDatabase(cmd.argument())) { + buffer_.invalidateBibfileCache(); + dr.forceBufferUpdate(); + } } break; } @@ -1602,38 +1654,25 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) buffer_.params().compressed = !buffer_.params().compressed; break; - case LFUN_LABEL_COPY_AS_REF: { - // if there is an inset at cursor, try to copy it - Inset * inset = &cur.inset(); - if (!inset || !inset->asInsetMath()) - inset = cur.nextInset(); - if (inset) { - FuncRequest tmpcmd = cmd; - inset->dispatch(cur, tmpcmd); - } - if (!cur.result().dispatched()) - // It did not work too; no action needed. - break; - cur.clearSelection(); - dr.update(Update::SinglePar | Update::FitCursor); + case LFUN_BUFFER_TOGGLE_OUTPUT_SYNC: + buffer_.params().output_sync = !buffer_.params().output_sync; break; - } case LFUN_SCREEN_UP: case LFUN_SCREEN_DOWN: { - Point p = getPos(cur, cur.boundary()); + Point p = getPos(cur); // This code has been commented out to enable to scroll down a // document, even if there are large insets in it (see bug #5465). /*if (p.y_ < 0 || p.y_ > height_) { // The cursor is off-screen so recenter before proceeding. showCursor(); - p = getPos(cur, cur.boundary()); + p = getPos(cur); }*/ - int const scrolled = scroll(cmd.action == LFUN_SCREEN_UP + int const scrolled = scroll(act == LFUN_SCREEN_UP ? -height_ : height_); - if (cmd.action == LFUN_SCREEN_UP && scrolled > -height_) + if (act == LFUN_SCREEN_UP && scrolled > -height_) p = Point(0, 0); - if (cmd.action == LFUN_SCREEN_DOWN && scrolled < height_) + if (act == LFUN_SCREEN_DOWN && scrolled < height_) p = Point(width_, height_); Cursor old = cur; bool const in_texted = cur.inTexted(); @@ -1642,17 +1681,20 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) updateHoveredInset(); d->text_metrics_[&buffer_.text()].editXY(cur, p.x_, p.y_, - true, cmd.action == LFUN_SCREEN_UP); + true, act == LFUN_SCREEN_UP); //FIXME: what to do with cur.x_target()? bool update = in_texted && cur.bv().checkDepm(cur, old); cur.finishUndo(); - if (update) - dr.update(Update::Force | Update::FitCursor); + if (update) { + dr.screenUpdate(Update::Force | Update::FitCursor); + dr.forceBufferUpdate(); + } break; } case LFUN_SCROLL: lfunScroll(cmd); + dr.forceBufferUpdate(); break; case LFUN_SCREEN_UP_SELECT: { @@ -1662,13 +1704,13 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) cur.finishUndo(); break; } - int y = getPos(cur, cur.boundary()).y_; + int y = getPos(cur).y_; int const ymin = y - height_ + defaultRowHeight(); while (y > ymin && cur.up()) - y = getPos(cur, cur.boundary()).y_; + y = getPos(cur).y_; cur.finishUndo(); - dr.update(Update::SinglePar | Update::FitCursor); + dr.screenUpdate(Update::SinglePar | Update::FitCursor); break; } @@ -1679,13 +1721,13 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) cur.finishUndo(); break; } - int y = getPos(cur, cur.boundary()).y_; + int y = getPos(cur).y_; int const ymax = y + height_ - defaultRowHeight(); while (y < ymax && cur.down()) - y = getPos(cur, cur.boundary()).y_; + y = getPos(cur).y_; cur.finishUndo(); - dr.update(Update::SinglePar | Update::FitCursor); + dr.screenUpdate(Update::SinglePar | Update::FitCursor); break; } @@ -1714,7 +1756,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) while (!insname.empty()) { if (insname == name || name == from_utf8("*")) { cur.recordUndo(); - lyx::dispatch(fr); + lyx::dispatch(fr, dr); ++iterations; break; } @@ -1728,7 +1770,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) cur.endUndoGroup(); cur = savecur; cur.fixIfBroken(); - dr.update(Update::Force); + dr.screenUpdate(Update::Force); + dr.forceBufferUpdate(); if (iterations >= max_iter) { dr.setError(true); @@ -1739,29 +1782,6 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) } - case LFUN_ALL_INSETS_TOGGLE: { - string action; - string const name = split(to_utf8(cmd.argument()), action, ' '); - InsetCode const inset_code = insetCode(name); - - FuncRequest fr(LFUN_INSET_TOGGLE, action); - - Inset & inset = cur.buffer()->inset(); - InsetIterator it = inset_iterator_begin(inset); - InsetIterator const end = inset_iterator_end(inset); - for (; it != end; ++it) { - if (it->asInsetCollapsable() - && (inset_code == NO_CODE - || inset_code == it->lyxCode())) { - Cursor tmpcur = cur; - tmpcur.pushBackward(*it); - it->dispatch(tmpcur, fr); - } - } - dr.update(Update::Force | Update::FitCursor); - break; - } - case LFUN_BRANCH_ADD_INSERT: { docstring branch_name = from_utf8(cmd.getArg(0)); if (branch_name.empty()) @@ -1775,7 +1795,14 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) Alert::warning(_("Branch already exists"), drtmp.message()); break; } - lyx::dispatch(FuncRequest(LFUN_BRANCH_INSERT, branch_name)); + BranchList & branch_list = buffer_.params().branchlist(); + vector const branches = + getVectorFromString(branch_name, branch_list.separator()); + for (vector::const_iterator it = branches.begin(); + it != branches.end(); ++it) { + branch_name = *it; + lyx::dispatch(FuncRequest(LFUN_BRANCH_INSERT, branch_name)); + } break; } @@ -1825,7 +1852,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) icp["key"] = from_utf8(arg); if (!opt1.empty()) icp["before"] = from_utf8(opt1); - string icstr = InsetCommand::params2string("citation", icp); + string icstr = InsetCommand::params2string(icp); FuncRequest fr(LFUN_INSET_INSERT, icstr); lyx::dispatch(fr); break; @@ -1846,18 +1873,21 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) cur.recordUndo(); FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument()); inset->dispatch(cur, fr); - dr.update(Update::SinglePar | Update::FitCursor); + dr.screenUpdate(cur.result().screenUpdate()); + if (cur.result().needBufferUpdate()) + dr.forceBufferUpdate(); break; } default: - dispatched = false; + // OK, so try the Buffer itself... + buffer_.dispatch(cmd, dr); + dispatched = dr.dispatched(); break; } buffer_.undo().endUndoGroup(); dr.dispatched(dispatched); - return; } @@ -1874,10 +1904,10 @@ docstring const BufferView::requestSelection() LYXERR(Debug::SELECTION, "requestSelection: xsel_cache.set: " << d->xsel_cache_.set); if (!d->xsel_cache_.set || cur.top() != d->xsel_cache_.cursor || - cur.anchor_.top() != d->xsel_cache_.anchor) + cur.realAnchor().top() != d->xsel_cache_.anchor) { d->xsel_cache_.cursor = cur.top(); - d->xsel_cache_.anchor = cur.anchor_.top(); + d->xsel_cache_.anchor = cur.realAnchor().top(); d->xsel_cache_.set = cur.selection(); return cur.selectionAsString(false); } @@ -1945,25 +1975,33 @@ Inset const * BufferView::getCoveringInset(Text const & text, void BufferView::updateHoveredInset() const { // Get inset under mouse, if there is one. - Inset const * covering_inset = getCoveringInset(buffer_.text(), - d->mouse_position_cache_.x_, d->mouse_position_cache_.y_); + int const x = d->mouse_position_cache_.x_; + int const y = d->mouse_position_cache_.y_; + Inset const * covering_inset = getCoveringInset(buffer_.text(), x, y); + + d->clickable_inset_ = covering_inset && covering_inset->clickable(x, y); + if (covering_inset == d->last_inset_) // Same inset, no need to do anything... return; bool need_redraw = false; - if (d->last_inset_) + if (d->last_inset_) { // Remove the hint on the last hovered inset (if any). - need_redraw |= d->last_inset_->setMouseHover(false); + need_redraw |= d->last_inset_->setMouseHover(this, false); + d->last_inset_ = 0; + } // const_cast because of setMouseHover(). Inset * inset = const_cast(covering_inset); - if (inset) - // Highlight the newly hovered inset (if any). - need_redraw |= inset->setMouseHover(true); + if (inset && inset->setMouseHover(this, true)) { + need_redraw = true; + // Only the insets that accept the hover state, do + // clear the last_inset_, so only set the last_inset_ + // member if the hovered setting is accepted. + d->last_inset_ = inset; + } - d->last_inset_ = inset; - if (need_redraw) { LYXERR(Debug::PAINTING, "Mouse hover detected at: (" << d->mouse_position_cache_.x_ << ", " @@ -1978,6 +2016,16 @@ void BufferView::updateHoveredInset() const } +void BufferView::clearLastInset(Inset * inset) const +{ + if (d->last_inset_ != inset) { + LYXERR0("Wrong last_inset!"); + LASSERT(false, /**/); + } + d->last_inset_ = 0; +} + + void BufferView::mouseEventDispatch(FuncRequest const & cmd0) { //lyxerr << "[ cmd0 " << cmd0 << "]" << endl; @@ -1995,18 +2043,18 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0) // surrounding Text will handle this event. // make sure we stay within the screen... - cmd.y = min(max(cmd.y, -1), height_); + cmd.set_y(min(max(cmd.y(), -1), height_)); - d->mouse_position_cache_.x_ = cmd.x; - d->mouse_position_cache_.y_ = cmd.y; + d->mouse_position_cache_.x_ = cmd.x(); + d->mouse_position_cache_.y_ = cmd.y(); - if (cmd.action == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) { + if (cmd.action() == LFUN_MOUSE_MOTION && cmd.button() == mouse_button::none) { updateHoveredInset(); return; } // Build temporary cursor. - Inset * inset = d->text_metrics_[&buffer_.text()].editXY(cur, cmd.x, cmd.y); + Inset * inset = d->text_metrics_[&buffer_.text()].editXY(cur, cmd.x(), cmd.y()); // Put anchor at the same position. cur.resetAnchor(); @@ -2039,8 +2087,8 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0) theSelection().haveSelection(cursor().selection()); // If the command has been dispatched, - if (cur.result().dispatched() || cur.result().update()) - processUpdateFlags(cur.result().update()); + if (cur.result().dispatched() || cur.result().screenUpdate()) + processUpdateFlags(cur.result().screenUpdate()); } @@ -2171,8 +2219,8 @@ bool BufferView::setCursorFromInset(Inset const * inset) void BufferView::gotoLabel(docstring const & label) { - std::vector bufs = buffer().allRelatives(); - std::vector::iterator it = bufs.begin(); + ListOfBuffers bufs = buffer().allRelatives(); + ListOfBuffers::iterator it = bufs.begin(); for (; it != bufs.end(); ++it) { Buffer const * buf = *it; @@ -2250,7 +2298,7 @@ bool BufferView::checkDepm(Cursor & cur, Cursor & old) d->cursor_ = cur; - buffer_.updateBuffer(); + cur.forceBufferUpdate(); buffer_.changed(true); return true; } @@ -2273,7 +2321,7 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select) d->cursor_.fixIfBroken(); // FIXME: shift-mouse selection doesn't work well across insets. - bool do_selection = select && &d->cursor_.anchor().inset() == &cur.inset(); + bool do_selection = select && &d->cursor_.normalAnchor().inset() == &cur.inset(); // do the dEPM magic if needed // FIXME: (1) move this to InsetText::notifyCursorLeaves? @@ -2294,6 +2342,8 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select) d->cursor_.finishUndo(); d->cursor_.setCurrentFont(); + if (update) + cur.forceBufferUpdate(); return update; } @@ -2312,9 +2362,6 @@ void BufferView::putSelectionAt(DocIterator const & cur, } else d->cursor_.setSelection(d->cursor_, length); } - // Ensure a redraw happens in any case because the new selection could - // possibly be on the same screen as the previous selection. - processUpdateFlags(Update::Force | Update::FitCursor); } @@ -2465,15 +2512,15 @@ void BufferView::insertLyXFile(FileName const & fname) // Get absolute path of file and add ".lyx" // to the filename if necessary - FileName filename = fileSearch(string(), fname.absFilename(), "lyx"); + FileName filename = fileSearch(string(), fname.absFileName(), "lyx"); - docstring const disp_fn = makeDisplayPath(filename.absFilename()); + 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)) { + Buffer buf(filename.absFileName(), false); + if (buf.loadLyXFile() == Buffer::ReadSuccess) { ErrorList & el = buffer_.errorList("Parse"); // Copy the inserted document error list into the current buffer one. el = buf.errorList("Parse"); @@ -2488,11 +2535,10 @@ void BufferView::insertLyXFile(FileName const & fname) buffer_.changed(true); // emit message signal. message(bformat(res, disp_fn)); - buffer_.errors("Parse"); } -Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const +Point BufferView::coordOffset(DocIterator const & dit) const { int x = 0; int y = 0; @@ -2506,7 +2552,7 @@ Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const int yy = 0; // get relative position inside sl.inset() - sl.inset().cursorPos(*this, sl, boundary && (i + 1 == dit.depth()), xx, yy); + sl.inset().cursorPos(*this, sl, dit.boundary() && (i + 1 == dit.depth()), xx, yy); // Make relative position inside of the edited inset relative to sl.inset() x += xx; @@ -2515,7 +2561,7 @@ Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const // In case of an RTL inset, the edited inset will be positioned to the left // of xx:yy if (sl.text()) { - bool boundary_i = boundary && i + 1 == dit.depth(); + bool boundary_i = dit.boundary() && i + 1 == dit.depth(); bool rtl = textMetrics(sl.text()).isRTL(sl, boundary_i); if (rtl) x -= lastw; @@ -2552,9 +2598,9 @@ Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const size_t rend; if (sl.pos() > 0 && dit.depth() == 1) { int pos = sl.pos(); - if (pos && boundary) + if (pos && dit.boundary()) --pos; -// lyxerr << "coordOffset: boundary:" << boundary << " depth:" << dit.depth() << " pos:" << pos << " sl.pos:" << sl.pos() << endl; +// lyxerr << "coordOffset: boundary:" << dit.boundary() << " depth:" << dit.depth() << " pos:" << pos << " sl.pos:" << sl.pos() << endl; rend = pm.pos2row(pos); } else rend = pm.pos2row(sl.pos()); @@ -2568,12 +2614,12 @@ Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const TextMetrics const & bottom_tm = textMetrics(dit.bottom().text()); // Make relative position from the nested inset now bufferview absolute. - int xx = bottom_tm.cursorX(dit.bottom(), boundary && dit.depth() == 1); + int xx = bottom_tm.cursorX(dit.bottom(), dit.boundary() && dit.depth() == 1); x += xx; // In the RTL case place the nested inset at the left of the cursor in // the outer paragraph - bool boundary_1 = boundary && 1 == dit.depth(); + bool boundary_1 = dit.boundary() && 1 == dit.depth(); bool rtl = bottom_tm.isRTL(dit.bottom(), boundary_1); if (rtl) x -= lastw; @@ -2582,7 +2628,7 @@ Point BufferView::coordOffset(DocIterator const & dit, bool boundary) const } -Point BufferView::getPos(DocIterator const & dit, bool boundary) const +Point BufferView::getPos(DocIterator const & dit) const { if (!paragraphVisible(dit)) return Point(-1, -1); @@ -2590,7 +2636,8 @@ Point BufferView::getPos(DocIterator const & dit, bool boundary) const CursorSlice const & bot = dit.bottom(); TextMetrics const & tm = textMetrics(bot.text()); - Point p = coordOffset(dit, boundary); // offset from outer paragraph + // offset from outer paragraph + Point p = coordOffset(dit); p.y_ += tm.parMetrics(bot.pit()).position(); return p; } @@ -2613,7 +2660,7 @@ void BufferView::cursorPosAndHeight(Point & p, int & h) const int const asc = fm.maxAscent(); int const des = fm.maxDescent(); h = asc + des; - p = getPos(cur, cur.boundary()); + p = getPos(cur); p.y_ -= asc; } @@ -2745,7 +2792,7 @@ docstring BufferView::contentsOfPlaintextFile(FileName const & fname) { if (!fname.isReadableFile()) { docstring const error = from_ascii(strerror(errno)); - docstring const file = makeDisplayPath(fname.absFilename(), 50); + docstring const file = makeDisplayPath(fname.absFileName(), 50); docstring const text = bformat(_("Could not read the specified document\n" "%1$s\ndue to the error: %2$s"), file, error); @@ -2754,7 +2801,7 @@ docstring BufferView::contentsOfPlaintextFile(FileName const & fname) } if (!fname.isReadableFile()) { - docstring const file = makeDisplayPath(fname.absFilename(), 50); + docstring const file = makeDisplayPath(fname.absFileName(), 50); docstring const text = bformat(_("%1$s\n is not readable."), file); Alert::error(_("Could not open file"), text); @@ -2814,6 +2861,12 @@ DocIterator const & BufferView::inlineCompletionPos() const } +bool BufferView::fixInlineCompletionPos() +{ + return d->inlineCompletionPos_.fixIfBroken(); +} + + bool samePar(DocIterator const & a, DocIterator const & b) { if (a.empty() && b.empty()) @@ -2853,11 +2906,17 @@ void BufferView::setInlineCompletion(Cursor & cur, DocIterator const & pos, // set update flags if (changed) { - if (singlePar && !(cur.disp_.update() & Update::Force)) - cur.updateFlags(cur.disp_.update() | Update::SinglePar); + if (singlePar && !(cur.result().screenUpdate() & Update::Force)) + cur.screenUpdateFlags(cur.result().screenUpdate() | Update::SinglePar); else - cur.updateFlags(cur.disp_.update() | Update::Force); + cur.screenUpdateFlags(cur.result().screenUpdate() | Update::Force); } } + +bool BufferView::clickableInset() const +{ + return d->clickable_inset_; +} + } // namespace lyx