X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBufferView2.C;h=da33665c2797885bfbff2d4212e47fc0091ec5f3;hb=d11fd01ce743c4974a96f241a99853f46078c80c;hp=cf53e9b2ee8d3c94e79ea8d248b2c1d088326060;hpb=de78a7b2d67e90c70ecb23984d3298c385faa65d;p=lyx.git diff --git a/src/BufferView2.C b/src/BufferView2.C index cf53e9b2ee..da33665c27 100644 --- a/src/BufferView2.C +++ b/src/BufferView2.C @@ -1,8 +1,8 @@ /* This file is part of - * ====================================================== - * + * ====================================================== + * * LyX, The Document Processor - * + * * Copyright 1995 Matthias Ettrich * Copyright 1995-2001 The LyX Team. * @@ -34,9 +34,9 @@ #include "support/filetools.h" #include "support/lyxfunctional.h" //equal_1st_in_pair #include "support/types.h" +#include "support/lyxalgo.h" // lyx_count #include -#include extern BufferList bufferlist; @@ -47,7 +47,6 @@ using std::endl; using std::ifstream; using std::vector; using std::find; -using std::count; using std::count_if; @@ -74,7 +73,7 @@ bool BufferView::insertLyXFile(string const & filen) MakeDisplayPath(fname, 50)); return false; } - + beforeChange(text); ifstream ifs(fname.c_str()); @@ -84,9 +83,9 @@ bool BufferView::insertLyXFile(string const & filen) MakeDisplayPath(fname, 50)); return false; } - + int const c = ifs.peek(); - + LyXLex lex(0, 0); lex.setStream(ifs); @@ -96,7 +95,7 @@ bool BufferView::insertLyXFile(string const & filen) lyxerr[Debug::INFO] << "Will insert file with header" << endl; res = buffer()->readFile(lex, text->cursor.par()); } else { - lyxerr[Debug::INFO] << "Will insert file without header" + lyxerr[Debug::INFO] << "Will insert file without header" << endl; res = buffer()->readLyXformat2(lex, text->cursor.par()); } @@ -108,31 +107,106 @@ bool BufferView::insertLyXFile(string const & filen) bool BufferView::removeAutoInsets() { - LyXCursor tmpcursor = text->cursor; - Paragraph * cur_par = tmpcursor.par(); - pos_type cur_pos = tmpcursor.pos(); - + // keep track of which pos and par the cursor was on + Paragraph * cursor_par = text->cursor.par(); + Paragraph * cursor_par_prev = cursor_par ? cursor_par->previous() : 0; + Paragraph * cursor_par_next = cursor_par ? cursor_par->next() : 0; + pos_type cursor_pos = text->cursor.pos(); + bool found = false; + // Trap the deletion of the paragraph the cursor is in. + // Iterate until we find a paragraph that won't be immediately deleted. + // In reality this should mean we only execute the body of the while + // loop once at most. However for safety we iterate rather than just + // make this an if () conditional. + while ((cursor_par_prev || cursor_par_next) + && text->setCursor(this, + cursor_par_prev ? cursor_par_prev : cursor_par_next, + 0)) { + // We just removed cursor_par so have to fix the "cursor" + if (cursor_par_prev) { + // '.' = cursor_par + // a -> a. + // . + cursor_par = cursor_par_prev; + cursor_pos = cursor_par->size(); + } else { + // . -> .a + // a + cursor_par = cursor_par_next; + cursor_pos = 0; + } + cursor_par_prev = cursor_par->previous(); + cursor_par_next = cursor_par->next(); + } + + // Iterate through the paragraphs removing autoDelete insets as we go. + // If the paragraph ends up empty after all the autoDelete insets are + // removed that paragraph will be removed by the next setCursor() call. ParIterator it = buffer()->par_iterator_begin(); ParIterator end = buffer()->par_iterator_end(); for (; it != end; ++it) { Paragraph * par = *it; + Paragraph * par_prev = par ? par->previous() : 0; bool removed = false; - text->setCursor(this, par, 0); - + if (text->setCursor(this, par, 0) + && cursor_par == par_prev) { + // The previous setCursor line was deleted and that + // was the cursor_par line. This can only happen if an + // error box was the sole item on cursor_par. + // It is possible for cursor_par_prev to be stray if + // the line it pointed to only had a error box on it + // so we have to set it to a known correct value. + // This is often the same value it already had. + cursor_par_prev = par->previous(); + if (cursor_par_prev) { + // '|' = par, '.' = cursor_par, 'E' = error box + // First step below may occur before while{} + // a |a a a a. + // E -> .E -> |.E -> . -> |b + // . b b |b + // b + cursor_par = cursor_par_prev; + cursor_pos = cursor_par_prev->size(); + cursor_par_prev = cursor_par->previous(); + // cursor_par_next remains the same + } else if (cursor_par_next) { + // First step below may occur before while{} + // . + // E -> |.E -> |. -> . -> .|a + // a a a |a + cursor_par = cursor_par_next; + cursor_pos = 0; + // cursor_par_prev remains unset + cursor_par_next = cursor_par->next(); + } else { + // I can't find a way to trigger this + // so it should be unreachable code + // unless the buffer is corrupted. + lyxerr << "BufferView::removeAutoInsets() is bad\n"; + } + } + Paragraph::inset_iterator pit = par->inset_iterator_begin(); Paragraph::inset_iterator pend = par->inset_iterator_end(); while (pit != pend) { if (pit->autoDelete()) { removed = true; pos_type const pos = pit.getPos(); - + par->erase(pos); - if (cur_par == par) { - if (cur_pos > pos) - --cur_pos; + // We just invalidated par's inset iterators so + // we get the next valid iterator position + pit = par->InsetIterator(pos); + // and ensure we have a valid end iterator. + pend = par->inset_iterator_end(); + + if (cursor_par == par) { + // update the saved cursor position + if (cursor_pos > pos) + --cursor_pos; } } else { ++pit; @@ -144,7 +218,23 @@ bool BufferView::removeAutoInsets() } } - text->setCursorIntern(this, cur_par, cur_pos); + // It is possible that the last line is empty if it was cursor_par + // and/or only had an error inset on it. So we set the cursor to the + // start of the doc to force its removal and ensure a valid saved cursor + if (text->setCursor(this, text->ownerParagraph(), 0) + && 0 == cursor_par_next) { + cursor_par = cursor_par_prev; + cursor_pos = cursor_par->size(); + } else if (cursor_pos > cursor_par->size()) { + // Some C-Enter lines were removed by the setCursor call which + // then invalidated cursor_pos. It could still be "wrong" because + // the cursor may appear to have jumped but since we collapsed + // some C-Enter lines this should be a reasonable compromise. + cursor_pos = cursor_par->size(); + } + + // restore the original cursor in its corrected location. + text->setCursorIntern(this, cursor_par, cursor_pos); return found; } @@ -164,17 +254,17 @@ void BufferView::insertErrors(TeXErrors & terr) int const errorrow = cit->error_in_line; // Insert error string for row number - int tmpid = -1; + int tmpid = -1; int tmppos = -1; if (buffer()->texrow.getIdFromRow(errorrow, tmpid, tmppos)) { buffer()->texrow.increasePos(tmpid, tmppos); } - + Paragraph * texrowpar = 0; if (tmpid == -1) { - texrowpar = text->firstParagraph(); + texrowpar = text->ownerParagraph(); tmppos = 0; } else { texrowpar = buffer()->getParFromID(tmpid); @@ -195,7 +285,7 @@ void BufferView::insertErrors(TeXErrors & terr) void BufferView::setCursorFromRow(int row) { - int tmpid = -1; + int tmpid = -1; int tmppos = -1; buffer()->texrow.getIdFromRow(row, tmpid, tmppos); @@ -203,7 +293,7 @@ void BufferView::setCursorFromRow(int row) Paragraph * texrowpar; if (tmpid == -1) { - texrowpar = text->firstParagraph(); + texrowpar = text->ownerParagraph(); tmppos = 0; } else { texrowpar = buffer()->getParFromID(tmpid); @@ -266,7 +356,7 @@ void BufferView::menuRedo() return; } #endif - + if (available()) { owner()->message(_("Redo")); hideCursor(); @@ -303,7 +393,7 @@ void BufferView::pasteEnvironment() void BufferView::copy() { if (available()) { - text->copySelection(this); + getLyXText()->copySelection(this); owner()->message(_("Copy")); } } @@ -323,7 +413,8 @@ void BufferView::cut(bool realcut) void BufferView::paste() { - if (!available()) return; + if (!available()) + return; owner()->message(_("Paste")); @@ -332,19 +423,22 @@ void BufferView::paste() toggleSelection(); text->clearSelection(); update(text, BufferView::SELECT|BufferView::FITCUR); - + // paste text->pasteSelection(this); update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE); - - // clear the selection +// why fake a selection only I think it should be a real one and not only +// a painted one (Jug 20020318). +#if 0 + // clear the selection toggleSelection(); text->clearSelection(); update(text, BufferView::SELECT|BufferView::FITCUR); +#endif } -/* these functions are for the spellchecker */ +/* these functions are for the spellchecker */ string const BufferView::nextWord(float & value) { if (!available()) { @@ -355,11 +449,11 @@ string const BufferView::nextWord(float & value) return text->selectNextWordToSpellcheck(this, value); } - + void BufferView::selectLastWord() { if (!available()) return; - + LyXCursor cur = text->selection.cursor; hideCursor(); beforeChange(text); @@ -373,7 +467,7 @@ void BufferView::selectLastWord() void BufferView::endOfSpellCheck() { if (!available()) return; - + hideCursor(); beforeChange(text); text->selectSelectedWord(this); @@ -389,15 +483,15 @@ void BufferView::replaceWord(string const & replacestring) LyXText * tt = getLyXText(); hideCursor(); update(tt, BufferView::SELECT|BufferView::FITCUR); - - /* clear the selection (if there is any) */ + + /* clear the selection (if there is any) */ toggleSelection(false); update(tt, BufferView::SELECT|BufferView::FITCUR); - - /* clear the selection (if there is any) */ + + /* clear the selection (if there is any) */ toggleSelection(false); tt->replaceSelectionWithString(this, replacestring); - + tt->setSelectionOverString(this, replacestring); // Go back so that replacement string is also spellchecked @@ -443,7 +537,7 @@ bool BufferView::lockInset(UpdatableInset * inset) } if ((*it)->getInsetFromID(id)) { text->setCursorIntern(this, par, it.getPos()); - theLockingInset(static_cast(*it)); + (*it)->edit(this); return theLockingInset()->lockInsetInInset(this, inset); } } @@ -457,7 +551,7 @@ bool BufferView::lockInset(UpdatableInset * inset) void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc) { - if (available() && theLockingInset()) { + if (available() && theLockingInset() && !theLockingInset()->nodraw()) { LyXCursor cursor = text->cursor; Inset * locking_inset = theLockingInset()->getLockingInset(); @@ -466,7 +560,7 @@ void BufferView::showLockedInsetCursor(int x, int y, int asc, int desc) (cursor.par()->getInset(cursor.pos() - 1) == locking_inset)) text->setCursor(this, cursor, - cursor.par(), cursor.pos() - 1); + cursor.par(), cursor.pos() - 1); LyXScreen::Cursor_Shape shape = LyXScreen::BAR_SHAPE; LyXText * txt = getLyXText(); if (locking_inset->isTextInset() && @@ -511,12 +605,12 @@ int BufferView::unlockInset(UpdatableInset * inset) inset->insetUnlock(this); theLockingInset(0); // make sure we update the combo ! - owner()->setLayout(getLyXText()->cursor.par()->getLayout()); + owner()->setLayout(getLyXText()->cursor.par()->layout()); finishUndo(); return 0; } else if (inset && theLockingInset() && theLockingInset()->unlockInsetInInset(this, inset)) { - // owner inset has updated the layout combo + // owner inset has updated the layout combo finishUndo(); return 0; } @@ -531,8 +625,8 @@ void BufferView::lockedInsetStoreUndo(Undo::undo_kind kind) if (kind == Undo::EDIT) // in this case insets would not be stored! kind = Undo::FINISH; setUndo(this, kind, - text->cursor.par(), - text->cursor.par()->next()); + text->cursor.par(), + text->cursor.par()->next()); } @@ -568,9 +662,9 @@ bool BufferView::ChangeInsets(Inset::Code code, } if (changed_inset) { need_update = true; -#ifdef WITH_WARNINGS -#warning FIXME -#endif + + // FIXME + // The test it.size()==1 was needed to prevent crashes. // How to set the cursor corretly when it.size()>1 ?? if (it.size() == 1) { @@ -590,19 +684,22 @@ bool BufferView::ChangeRefsIfUnique(string const & from, string const & to) { // Check if the label 'from' appears more than once vector labels = buffer()->getLabelList(); - if (count(labels.begin(), labels.end(), from) > 1) + + if (lyx::count(labels.begin(), labels.end(), from) > 1) return false; return ChangeInsets(Inset::REF_CODE, from, to); } -bool BufferView::ChangeCitationsIfUnique(string const & from, string const & to) +bool BufferView::ChangeCitationsIfUnique(string const & from, + string const & to) { + typedef pair StringPair; - vector > keys = buffer()->getBibkeyList(); - if (count_if(keys.begin(), keys.end(), - lyx::equal_1st_in_pair(from)) + vector keys = buffer()->getBibkeyList(); + if (count_if(keys.begin(), keys.end(), + lyx::equal_1st_in_pair(from)) > 1) return false;