]> git.lyx.org Git - lyx.git/blobdiff - src/text.C
bug 2298: cursorTop/Bottom/Home/End does not redraw after dEPM
[lyx.git] / src / text.C
index 96849d22e03dcff9e918fe63bead9bd55b021241..9746afc7b25d30288466e8e429ddf42dbdc2d48c 100644 (file)
@@ -315,8 +315,10 @@ void readParToken(Buffer const & buf, Paragraph & par, LyXLex & lex,
        } else if (token == "\\change_unchanged") {
                // Hack ! Needed for empty paragraphs :/
                // FIXME: is it still ??
+               /*
                if (!par.size())
                        par.cleanChanges();
+               */
                change = Change(Change::UNCHANGED);
        } else if (token == "\\change_inserted") {
                lex.eatLine();
@@ -375,6 +377,9 @@ void readParagraph(Buffer const & buf, Paragraph & par, LyXLex & lex)
                        break;
                }
        }
+       // Final change goes to paragraph break:
+       par.setChangeFull(par.size(), change);
+       
        // Initialize begin_of_body_ on load; redoParagraph maintains
        par.setBeginOfBody();
 }
@@ -1026,14 +1031,10 @@ namespace {
 void LyXText::breakParagraph(LCursor & cur, bool keep_layout)
 {
        BOOST_ASSERT(this == cur.text());
-       // allow only if at start or end, or all previous is new text
+
        Paragraph & cpar = cur.paragraph();
        pit_type cpit = cur.pit();
 
-       if (cur.pos() != 0 && cur.pos() != cur.lastpos()
-           && cpar.isChangeEdited(0, cur.pos()))
-               return;
-
        LyXTextClass const & tclass = cur.buffer().params().getLyXTextClass();
        LyXLayout_ptr const & layout = cpar.layout();
 
@@ -1088,6 +1089,12 @@ void LyXText::breakParagraph(LCursor & cur, bool keep_layout)
 
        updateCounters(cur.buffer());
 
+       // Mark "carriage return" as inserted if change tracking:
+       if (cur.buffer().params().tracking_changes) {
+               cur.paragraph().setChange(cur.paragraph().size(), 
+                       Change::INSERTED);
+       }
+
        // This check is necessary. Otherwise the new empty paragraph will
        // be deleted automatically. And it is more friendly for the user!
        if (cur.pos() != 0 || isempty)
@@ -1326,13 +1333,12 @@ bool LyXText::cursorRightOneWord(LCursor & cur)
                ++old.pit();
                old.pos() = 0;
        } else {
-               // Skip through initial nonword stuff.
-               // Treat floats and insets as words.
-               while (old.pos() != old.lastpos() && !old.paragraph().isLetter(old.pos()))
-                       ++old.pos();
                // Advance through word.
                while (old.pos() != old.lastpos() && old.paragraph().isLetter(old.pos()))
                        ++old.pos();
+               // Skip through trailing nonword stuff.
+               while (old.pos() != old.lastpos() && !old.paragraph().isLetter(old.pos()))
+                       ++old.pos();
        }
        return setCursor(cur, old.pit(), old.pos());
 }
@@ -1349,7 +1355,6 @@ bool LyXText::cursorLeftOneWord(LCursor & cur)
                old.pos() = old.lastpos();
        } else {
                // Skip through initial nonword stuff.
-               // Treat floats and insets as words.
                while (old.pos() != 0 && !old.paragraph().isLetter(old.pos() - 1))
                        --old.pos();
                // Advance through word.
@@ -1394,18 +1399,34 @@ void LyXText::acceptChange(LCursor & cur)
        if (!cur.selection() && cur.lastpos() != 0)
                return;
 
-       CursorSlice const & startc = cur.selBegin();
-       CursorSlice const & endc = cur.selEnd();
-       if (startc.pit() == endc.pit()) {
-               recordUndoSelection(cur, Undo::INSERT);
-               pars_[startc.pit()].acceptChange(startc.pos(), endc.pos());
-               finishUndo();
-               cur.clearSelection();
-               setCursorIntern(cur, startc.pit(), 0);
+       recordUndoSelection(cur, Undo::INSERT);
+       
+       DocIterator it = cur.selectionBegin();
+       DocIterator et = cur.selectionEnd();
+       pit_type pit = it.pit();
+       Change::Type const type = pars_[pit].lookupChange(it.pos());
+       for (; pit <= et.pit(); ++pit) {
+               pos_type left  = ( pit == it.pit() ? it.pos() : 0 );
+               pos_type right = 
+                   ( pit == et.pit() ? et.pos() : pars_[pit].size() + 1 );
+               pars_[pit].acceptChange(left, right);
        }
-#ifdef WITH_WARNINGS
-#warning handle multi par selection
-#endif
+       if (type == Change::DELETED) {
+               ParagraphList & plist = paragraphs();
+               if (it.pit() + 1 < et.pit())
+                       pars_.erase(plist.begin() + it.pit() + 1,
+                                   plist.begin() + et.pit());
+               
+               // Paragraph merge if appropriate:
+               if (pars_[it.pit()].lookupChange(pars_[it.pit()].size()) 
+                       == Change::DELETED) {
+                       setCursorIntern(cur, it.pit() + 1, 0);
+                       backspacePos0(cur);
+               }
+       }
+       finishUndo();
+       cur.clearSelection();
+       setCursorIntern(cur, it.pit(), 0);
 }
 
 
@@ -1415,18 +1436,33 @@ void LyXText::rejectChange(LCursor & cur)
        if (!cur.selection() && cur.lastpos() != 0)
                return;
 
-       CursorSlice const & startc = cur.selBegin();
-       CursorSlice const & endc = cur.selEnd();
-       if (startc.pit() == endc.pit()) {
-               recordUndoSelection(cur, Undo::INSERT);
-               pars_[startc.pit()].rejectChange(startc.pos(), endc.pos());
-               finishUndo();
-               cur.clearSelection();
-               setCursorIntern(cur, startc.pit(), 0);
+       recordUndoSelection(cur, Undo::INSERT);
+
+       DocIterator it = cur.selectionBegin();
+       DocIterator et = cur.selectionEnd();
+       pit_type pit = it.pit();
+       Change::Type const type = pars_[pit].lookupChange(it.pos());
+       for (; pit <= et.pit(); ++pit) {
+               pos_type left  = ( pit == it.pit() ? it.pos() : 0 );
+               pos_type right = 
+                   ( pit == et.pit() ? et.pos() : pars_[pit].size() + 1 );
+               pars_[pit].rejectChange(left, right);
        }
-#ifdef WITH_WARNINGS
-#warning handle multi par selection
-#endif
+       if (type == Change::INSERTED) {
+               ParagraphList & plist = paragraphs();
+               if (it.pit() + 1 < et.pit())
+                       pars_.erase(plist.begin() + it.pit() + 1,
+                                   plist.begin() + et.pit());
+               // Paragraph merge if appropriate:
+               if (pars_[it.pit()].lookupChange(pars_[it.pit()].size()) 
+                       == Change::INSERTED) {
+                       setCursorIntern(cur, it.pit() + 1, 0);
+                       backspacePos0(cur);
+               }
+       }
+       finishUndo();
+       cur.clearSelection();
+       setCursorIntern(cur, it.pit(), 0);
 }
 
 
@@ -1495,7 +1531,7 @@ void LyXText::changeCase(LCursor & cur, LyXText::TextCase action)
        } else {
                from = cur.top();
                getWord(from, to, lyx::PARTIAL_WORD);
-               setCursor(cur, to.pit(), to.pos() + 1);
+               cursorRightOneWord(cur);
        }
 
        recordUndoSelection(cur);
@@ -1558,86 +1594,103 @@ bool LyXText::Delete(LCursor & cur)
 }
 
 
-bool LyXText::backspace(LCursor & cur)
+bool LyXText::backspacePos0(LCursor & cur)
 {
        BOOST_ASSERT(this == cur.text());
        bool needsUpdate = false;
-       if (cur.pos() == 0) {
-               // The cursor is at the beginning of a paragraph, so
-               // the the backspace will collapse two paragraphs into
-               // one.
 
-               // but it's not allowed unless it's new
-               Paragraph & par = cur.paragraph();
-               if (par.isChangeEdited(0, par.size()))
-                       return false;
+       Paragraph & par = cur.paragraph();
+       // is it an empty paragraph?
+       pos_type lastpos = cur.lastpos();
+       if (lastpos == 0 || (lastpos == 1 && par.isSeparator(0))) {
+               // This is an empty paragraph and we delete it just
+               // by moving the cursor one step
+               // left and let the DeleteEmptyParagraphMechanism
+               // handle the actual deletion of the paragraph.
 
-               // we may paste some paragraphs
-
-               // is it an empty paragraph?
-               pos_type lastpos = cur.lastpos();
-               if (lastpos == 0 || (lastpos == 1 && par.isSeparator(0))) {
-                       // This is an empty paragraph and we delete it just
-                       // by moving the cursor one step
-                       // left and let the DeleteEmptyParagraphMechanism
-                       // handle the actual deletion of the paragraph.
-
-                       if (cur.pit() != 0) {
-                                // For KeepEmpty layouts we need to get
-                                // rid of the keepEmpty setting first.
-                                // And the only way to do this is to
-                                // reset the layout to something
-                                // else: f.ex. the default layout.
-                                if (par.allowEmpty()) {
-                                        Buffer & buf = cur.buffer();
-                                        BufferParams const & bparams = buf.params();
-                                        par.layout(bparams.getLyXTextClass().defaultLayout());
-                                }
-                                
-                               cursorLeft(cur);
-                               return true;
+               if (cur.pit() != 0) {
+                       // For KeepEmpty layouts we need to get
+                       // rid of the keepEmpty setting first.
+                       // And the only way to do this is to
+                       // reset the layout to something
+                       // else: f.ex. the default layout.
+                       if (par.allowEmpty()) {
+                               Buffer & buf = cur.buffer();
+                               BufferParams const & bparams = buf.params();
+                               par.layout(bparams.getLyXTextClass().defaultLayout());
                        }
+                                
+                       cursorLeft(cur);
+                       return true;
                }
+       }
 
-               if (cur.pit() != 0)
-                       recordUndo(cur, Undo::DELETE, cur.pit() - 1);
+       if (cur.pit() != 0)
+               recordUndo(cur, Undo::DELETE, cur.pit() - 1);
+
+       pit_type tmppit = cur.pit();
+       // We used to do cursorLeftIntern() here, but it is
+       // not a good idea since it triggers the auto-delete
+       // mechanism. So we do a cursorLeftIntern()-lite,
+       // without the dreaded mechanism. (JMarc)
+       if (cur.pit() != 0) {
+               // steps into the above paragraph.
+               setCursorIntern(cur, cur.pit() - 1,
+                               pars_[cur.pit() - 1].size(),
+                               false);
+       }
 
-               pit_type tmppit = cur.pit();
-               // We used to do cursorLeftIntern() here, but it is
-               // not a good idea since it triggers the auto-delete
-               // mechanism. So we do a cursorLeftIntern()-lite,
-               // without the dreaded mechanism. (JMarc)
-               if (cur.pit() != 0) {
-                       // steps into the above paragraph.
-                       setCursorIntern(cur, cur.pit() - 1,
-                                       pars_[cur.pit() - 1].size(),
-                                       false);
-               }
+       // Pasting is not allowed, if the paragraphs have different
+       // layout. I think it is a real bug of all other
+       // word processors to allow it. It confuses the user.
+       // Correction: Pasting is always allowed with standard-layout
+       // Correction (Jug 20050717): Remove check about alignment!
+       Buffer & buf = cur.buffer();
+       BufferParams const & bufparams = buf.params();
+       LyXTextClass const & tclass = bufparams.getLyXTextClass();
+       pit_type const cpit = cur.pit();
 
-               // Pasting is not allowed, if the paragraphs have different
-               // layout. I think it is a real bug of all other
-               // word processors to allow it. It confuses the user.
-               // Correction: Pasting is always allowed with standard-layout
-               // Correction (Jug 20050717): Remove check about alignment!
-               Buffer & buf = cur.buffer();
-               BufferParams const & bufparams = buf.params();
-               LyXTextClass const & tclass = bufparams.getLyXTextClass();
-               pit_type const cpit = cur.pit();
-
-               if (cpit != tmppit
-                   && (pars_[cpit].layout() == pars_[tmppit].layout()
-                       || pars_[tmppit].layout() == tclass.defaultLayout()))
-               {
-                       mergeParagraph(bufparams, pars_, cpit);
-                       needsUpdate = true;
+       if (cpit != tmppit
+           && (pars_[cpit].layout() == pars_[tmppit].layout()
+               || pars_[tmppit].layout() == tclass.defaultLayout()))
+       {
+               mergeParagraph(bufparams, pars_, cpit);
+               needsUpdate = true;
 
-                       if (cur.pos() != 0 && pars_[cpit].isSeparator(cur.pos() - 1))
+               if (cur.pos() != 0 && pars_[cpit].isSeparator(cur.pos() - 1))
                                --cur.pos();
 
-                       // the counters may have changed
-                       updateCounters(cur.buffer());
-                       setCursor(cur, cur.pit(), cur.pos(), false);
+               // the counters may have changed
+               updateCounters(cur.buffer());
+               setCursor(cur, cur.pit(), cur.pos(), false);
+       }
+       return needsUpdate;
+}
+
+
+bool LyXText::backspace(LCursor & cur)
+{
+       BOOST_ASSERT(this == cur.text());
+       bool needsUpdate = false;
+       if (cur.pos() == 0) {
+               // The cursor is at the beginning of a paragraph, so
+               // the the backspace will collapse two paragraphs into
+               // one.
+
+               if (cur.buffer().params().tracking_changes) {
+                       // Previous paragraph, mark "carriage return" as
+                       // deleted:
+                       Paragraph & par = pars_[cur.pit() - 1];
+                       // Take care of a just inserted para break:
+                       if (par.lookupChange(par.size()) != Change::INSERTED) {
+                               par.setChange(par.size(), Change::DELETED);
+                               setCursorIntern(cur, cur.pit() - 1, par.size());
+                               return false;
+                       }
                }
+
+               needsUpdate = backspacePos0(cur);
+
        } else {
                // this is the code for a normal backspace, not pasting
                // any paragraphs
@@ -2184,9 +2237,11 @@ string LyXText::currentState(LCursor & cur)
        std::ostringstream os;
 
        bool const show_change = buf.params().tracking_changes
-               && cur.pos() != cur.lastpos()
                && par.lookupChange(cur.pos()) != Change::UNCHANGED;
 
+       if (buf.params().tracking_changes)
+               os << "[C] ";
+
        if (show_change) {
                Change change = par.lookupChangeFull(cur.pos());
                Author const & a = buf.params().authors().get(change.author);
@@ -2266,8 +2321,25 @@ string LyXText::getPossibleLabel(LCursor & cur) const
                }
        }
 
-       string text = layout->latexname().substr(0, 3);
-       if (layout->latexname() == "theorem")
+       string name = layout->latexname();
+
+       // for captions, we want the abbreviation of the float type
+       if (layout->labeltype == LABEL_SENSITIVE) {
+               // Search for the first float or wrap inset in the iterator
+               size_t i = cur.depth();
+               while (i > 0) {
+                       --i;
+                       InsetBase * const in = &cur[i].inset();
+                       if (in->lyxCode() == InsetBase::FLOAT_CODE
+                           || in->lyxCode() == InsetBase::WRAP_CODE) {
+                               name = in->getInsetName();
+                               break;
+                       }
+               }
+       }
+
+       string text = name.substr(0, 3);
+       if (name == "theorem")
                text = "thm"; // Create a correct prefix for prettyref
 
        text += ':';