X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView.cpp;h=957a0b067307d63b13c0a65fef4e317c9488fb6e;hb=fe8c185a6e23b590e084f21ea06ce622ea99820d;hp=ac22a4e618996a53145199735e6c0df51b551425;hpb=397c03b433a91d000668da68cc38e190173daaa3;p=lyx.git diff --git a/src/BufferView.cpp b/src/BufferView.cpp index ac22a4e618..957a0b0673 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -51,7 +51,6 @@ #include "TextMetrics.h" #include "TexRow.h" #include "TocBackend.h" -#include "VSpace.h" #include "WordLangTuple.h" #include "insets/InsetBibtex.h" @@ -69,13 +68,12 @@ #include "frontends/Painter.h" #include "frontends/Selection.h" -#include "graphics/Previews.h" - #include "support/convert.h" #include "support/debug.h" #include "support/ExceptionMessage.h" #include "support/filetools.h" #include "support/gettext.h" +#include "support/lassert.h" #include "support/lstrings.h" #include "support/Package.h" #include "support/types.h" @@ -563,7 +561,7 @@ docstring BufferView::toolTip(int x, int y) const } -docstring BufferView::contextMenu(int x, int y) const +string BufferView::contextMenu(int x, int y) const { //If there is a selection, return the containing inset menu if (d->cursor_.selection()) @@ -669,7 +667,10 @@ void BufferView::setCursorFromScrollbar() // FIXME: Care about the d->cursor_ flags to redraw if needed Cursor old = d->cursor_; mouseSetCursor(cur); - bool badcursor = notifyCursorLeavesOrEnters(old, d->cursor_); + // the DEPM call in mouseSetCursor() might have destroyed the + // paragraph the cursor is in. + bool badcursor = old.fixIfBroken(); + badcursor |= notifyCursorLeavesOrEnters(old, d->cursor_); if (badcursor) d->cursor_.fixIfBroken(); } @@ -700,7 +701,6 @@ 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; @@ -885,20 +885,28 @@ bool BufferView::scrollToCursor(DocIterator const & dit, bool recenter) if (recenter) scrolled = scroll(ypos - height_/2); + // We try to visualize the whole row, if the row height is larger than + // the screen height, we scroll to a heuristic value of height_ / 4. + // FIXME: This heuristic value should be replaced by a recursive search + // for a row in the inset that can be visualized completely. + else if (row_dim.height() > height_) { + if (ypos < defaultRowHeight()) + scrolled = scroll(ypos - height_ / 4); + else if (ypos > height_ - defaultRowHeight()) + scrolled = scroll(ypos - 3 * height_ / 4); + } + // 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.ascent() < 0 && ypos < height_) { + int ynew = row_dim.ascent(); + scrolled = scrollUp(ynew - ypos); + } // 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_) { + else if (ypos + row_dim.descent() > height_ && ypos > 0) { int ynew = height_ - row_dim.descent(); - if (ynew < row_dim.ascent()) - ynew = row_dim.ascent(); - int const scroll = ypos - ynew; - scrolled = scrollDown(scroll); + scrolled = scrollDown(ypos - ynew); } // else, nothing to do, the cursor is already visible so we just return. @@ -1026,9 +1034,17 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) // buffer clean/dirty status by itself. flag.setEnabled(!buffer_.isReadonly() && buffer_.undo().hasRedoStack()); break; - case LFUN_FILE_INSERT: case LFUN_FILE_INSERT_PLAINTEXT_PARA: - case LFUN_FILE_INSERT_PLAINTEXT: + case LFUN_FILE_INSERT_PLAINTEXT: { + docstring const fname = cmd.argument(); + if (!FileName::isAbsolute(to_utf8(fname))) { + flag.message(_("Absolute filename expected.")); + return false; + } + flag.setEnabled(cur.inTexted()); + break; + } + case LFUN_FILE_INSERT: case LFUN_BOOKMARK_SAVE: // FIXME: Actually, these LFUNS should be moved to Text flag.setEnabled(cur.inTexted()); @@ -1152,6 +1168,17 @@ bool BufferView::getStatus(FuncRequest const & cmd, FuncStatus & flag) break; } + // FIXME We do not really want this here, but at present we need to + // handle their dispatch here, for reasons explained there, so we'll + // handle this here, too, for consistency. + case LFUN_BRANCH_ACTIVATE: + case LFUN_BRANCH_DEACTIVATE: { + BranchList const & branchList = buffer().params().branchlist(); + docstring const branchName = cmd.argument(); + flag.setEnabled(!branchName.empty() && branchList.find(branchName)); + break; + } + default: return false; } @@ -1457,6 +1484,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) buffer_.text().cursorBottom(cur); // accept everything in a single step to support atomic undo buffer_.text().acceptOrRejectChanges(cur, Text::ACCEPT); + cur.resetAnchor(); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); @@ -1470,6 +1498,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) // reject everything in a single step to support atomic undo // Note: reject does not work recursively; the user may have to repeat the operation buffer_.text().acceptOrRejectChanges(cur, Text::REJECT); + cur.resetAnchor(); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); @@ -1676,7 +1705,8 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) p = Point(width_, height_); Cursor old = cur; bool const in_texted = cur.inTexted(); - cur.reset(); + cur.setCursor(doc_iterator_begin(cur.buffer())); + cur.selHandle(false); buffer_.changed(true); updateHoveredInset(); @@ -1685,17 +1715,37 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) //FIXME: what to do with cur.x_target()? bool update = in_texted && cur.bv().checkDepm(cur, old); cur.finishUndo(); - if (update) { + if (update || cur.selection()) { dr.screenUpdate(Update::Force | Update::FitCursor); dr.forceBufferUpdate(); } break; } - case LFUN_SCROLL: - lfunScroll(cmd); + case LFUN_SCROLL: { + string const scroll_type = cmd.getArg(0); + int scroll_step = 0; + if (scroll_type == "line") + scroll_step = d->scrollbarParameters_.single_step; + else if (scroll_type == "page") + scroll_step = d->scrollbarParameters_.page_step; + else + return; + string const scroll_quantity = cmd.getArg(1); + if (scroll_quantity == "up") + scrollUp(scroll_step); + else if (scroll_quantity == "down") + scrollDown(scroll_step); + else { + int const scroll_value = convert(scroll_quantity); + if (scroll_value) + scroll(scroll_step * scroll_value); + } + buffer_.changed(true); + updateHoveredInset(); dr.forceBufferUpdate(); break; + } case LFUN_SCREEN_UP_SELECT: { cur.selHandle(true); @@ -1752,7 +1802,7 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) Inset * ins = cur.nextInset(); if (!ins) break; - docstring insname = ins->name(); + docstring insname = ins->layoutName(); while (!insname.empty()) { if (insname == name || name == from_utf8("*")) { cur.recordUndo(); @@ -1879,6 +1929,70 @@ void BufferView::dispatch(FuncRequest const & cmd, DispatchResult & dr) break; } + // FIXME: + // The change of language of buffer belongs to the Buffer class. + // We have to do it here because we need a cursor for Undo. + // When Undo::recordUndoBufferParams() is implemented someday + // LFUN_BUFFER_LANGUAGE should be handled by the Buffer class. + case LFUN_BUFFER_LANGUAGE: { + Language const * oldL = buffer_.params().language; + Language const * newL = languages.getLanguage(argument); + if (!newL || oldL == newL) + break; + if (oldL->rightToLeft() == newL->rightToLeft()) { + cur.recordUndoFullDocument(); + buffer_.changeLanguage(oldL, newL); + cur.setCurrentFont(); + dr.forceBufferUpdate(); + } + } + + case LFUN_FILE_INSERT_PLAINTEXT_PARA: + case LFUN_FILE_INSERT_PLAINTEXT: { + bool const as_paragraph = (act == LFUN_FILE_INSERT_PLAINTEXT_PARA); + string const fname = to_utf8(cmd.argument()); + if (!FileName::isAbsolute(fname)) + dr.setMessage(_("Absolute filename expected.")); + else + insertPlaintextFile(FileName(fname), as_paragraph); + break; + } + + // FIXME We do not really want this here, but it has to be at present + // because we need a cursor for the recordUndoFullDocument call. What + // we would really like is a recordUndoBufferParams call that did not + // need a cursor, but we do not have that yet. + // So, if this does get fixed, this code can be moved back to Buffer.cpp, + // and the corresponding code in getStatus() should be moved back, too. + case LFUN_BRANCH_ACTIVATE: + case LFUN_BRANCH_DEACTIVATE: { + BranchList & branch_list = buffer().params().branchlist(); + docstring const branch_name = cmd.argument(); + // the case without a branch name is handled elsewhere + if (branch_name.empty()) { + dispatched = false; + break; + } + Branch * branch = branch_list.find(branch_name); + if (!branch) { + LYXERR0("Branch " << branch_name << " does not exist."); + dr.setError(true); + docstring const msg = + bformat(_("Branch \"%1$s\" does not exist."), branch_name); + dr.setMessage(msg); + break; + } + bool activate = cmd.action() == LFUN_BRANCH_ACTIVATE; + if (branch->isSelected() != activate) { + branch->setSelected(activate); + cur.recordUndoFullDocument(); + dr.setError(false); + dr.screenUpdate(Update::Force); + dr.forceBufferUpdate(); + } + break; + } + default: // OK, so try the Buffer itself... buffer_.dispatch(cmd, dr); @@ -2084,37 +2198,17 @@ void BufferView::mouseEventDispatch(FuncRequest const & cmd0) // Do we have a selection? theSelection().haveSelection(cursor().selection()); + if (cur.needBufferUpdate()) { + cur.clearBufferUpdate(); + buffer().updateBuffer(); + } + // If the command has been dispatched, if (cur.result().dispatched() || cur.result().screenUpdate()) processUpdateFlags(cur.result().screenUpdate()); } -void BufferView::lfunScroll(FuncRequest const & cmd) -{ - string const scroll_type = cmd.getArg(0); - int scroll_step = 0; - if (scroll_type == "line") - scroll_step = d->scrollbarParameters_.single_step; - else if (scroll_type == "page") - scroll_step = d->scrollbarParameters_.page_step; - else - return; - string const scroll_quantity = cmd.getArg(1); - if (scroll_quantity == "up") - scrollUp(scroll_step); - else if (scroll_quantity == "down") - scrollDown(scroll_step); - else { - int const scroll_value = convert(scroll_quantity); - if (scroll_value) - scroll(scroll_step * scroll_value); - } - buffer_.changed(true); - updateHoveredInset(); -} - - int BufferView::minVisiblePart() { return 2 * defaultRowHeight(); @@ -2181,16 +2275,42 @@ int BufferView::scrollUp(int offset) void BufferView::setCursorFromRow(int row) { - int tmpid = -1; - int tmppos = -1; + int tmpid; + int tmppos; + pit_type newpit = 0; + pos_type newpos = 0; buffer_.texrow().getIdFromRow(row, tmpid, tmppos); + bool posvalid = (tmpid != -1); + if (posvalid) { + // we need to make sure that the row and position + // we got back are valid, because the buffer may well + // have changed since we last generated the LaTeX. + DocIterator const dit = buffer_.getParFromID(tmpid); + if (dit == doc_iterator_end(&buffer_)) + posvalid = false; + else { + newpit = dit.pit(); + // now have to check pos. + newpos = tmppos; + Paragraph const & par = buffer_.text().getPar(newpit); + if (newpos > par.size()) { + LYXERR0("Requested position no longer valid."); + newpos = par.size() - 1; + } + } + } + if (!posvalid) { + frontend::Alert::error(_("Inverse Search Failed"), + _("Invalid position requested by inverse search.\n" + "You need to update the viewed document.")); + return; + } d->cursor_.reset(); - if (tmpid == -1) - buffer_.text().setCursor(d->cursor_, 0, 0); - else - buffer_.text().setCursor(d->cursor_, buffer_.getParFromID(tmpid).pit(), tmppos); + buffer_.text().setCursor(d->cursor_, newpit, newpos); + d->cursor_.setSelection(false); + d->cursor_.resetAnchor(); recenter(); } @@ -2276,6 +2396,11 @@ void BufferView::setCursor(DocIterator const & dit) d->cursor_.setCursor(dit); d->cursor_.setSelection(false); + // FIXME + // It seems on general grounds as if this is probably needed, but + // it is not yet clear. + // See bug #7394 and r38388. + // d->cursor.resetAnchor(); } @@ -2298,7 +2423,7 @@ bool BufferView::checkDepm(Cursor & cur, Cursor & old) d->cursor_ = cur; cur.forceBufferUpdate(); - buffer_.changed(true); + cur.screenUpdateFlags(Update::Force); return true; } @@ -2315,12 +2440,13 @@ bool BufferView::mouseSetCursor(Cursor & cur, bool select) d->cursor_.macroModeClose(); // Has the cursor just left the inset? - bool leftinset = (&d->cursor_.inset() != &cur.inset()); + bool const leftinset = (&d->cursor_.inset() != &cur.inset()); if (leftinset) d->cursor_.fixIfBroken(); // FIXME: shift-mouse selection doesn't work well across insets. - bool do_selection = select && &d->cursor_.normalAnchor().inset() == &cur.inset(); + bool const do_selection = + select && &d->cursor_.normalAnchor().inset() == &cur.inset(); // do the dEPM magic if needed // FIXME: (1) move this to InsetText::notifyCursorLeaves? @@ -2914,7 +3040,7 @@ bool samePar(DocIterator const & a, DocIterator const & b) } -void BufferView::setInlineCompletion(Cursor & cur, DocIterator const & pos, +void BufferView::setInlineCompletion(Cursor const & cur, DocIterator const & pos, docstring const & completion, size_t uniqueChars) { uniqueChars = min(completion.size(), uniqueChars);