]> git.lyx.org Git - lyx.git/blobdiff - src/Text2.cpp
Amend 76cdca64223f
[lyx.git] / src / Text2.cpp
index c223ce06e6aa8de612fa802460a795041d8a5473..ed4b133ff53f4fc34fe994bf16264615979815e0 100644 (file)
@@ -42,7 +42,7 @@
 #include "TextClass.h"
 #include "TextMetrics.h"
 
 #include "TextClass.h"
 #include "TextMetrics.h"
 
-#include "insets/InsetCollapsable.h"
+#include "insets/InsetCollapsible.h"
 
 #include "mathed/InsetMathHull.h"
 
 
 #include "mathed/InsetMathHull.h"
 
@@ -182,10 +182,16 @@ void Text::setLayout(pit_type start, pit_type end,
 
        for (pit_type pit = start; pit != end; ++pit) {
                Paragraph & par = pars_[pit];
 
        for (pit_type pit = start; pit != end; ++pit) {
                Paragraph & par = pars_[pit];
-               par.applyLayout(lyxlayout);
+               // Is this a separating paragraph? If so,
+               // this needs to be standard layout
+               bool const is_separator = par.size() == 1
+                               && par.isEnvSeparator(0);
+               par.applyLayout(is_separator ? bp.documentClass().defaultLayout() : lyxlayout);
                if (lyxlayout.margintype == MARGIN_MANUAL)
                        par.setLabelWidthString(par.expandLabel(lyxlayout, bp));
        }
                if (lyxlayout.margintype == MARGIN_MANUAL)
                        par.setLabelWidthString(par.expandLabel(lyxlayout, bp));
        }
+
+       deleteEmptyParagraphMechanism(start, end - 1, bp.track_changes);
 }
 
 
 }
 
 
@@ -198,6 +204,7 @@ void Text::setLayout(Cursor & cur, docstring const & layout)
        pit_type end = cur.selEnd().pit() + 1;
        cur.recordUndoSelection();
        setLayout(start, end, layout);
        pit_type end = cur.selEnd().pit() + 1;
        cur.recordUndoSelection();
        setLayout(start, end, layout);
+       cur.fixIfBroken();
        cur.setCurrentFont();
        cur.forceBufferUpdate();
 }
        cur.setCurrentFont();
        cur.forceBufferUpdate();
 }
@@ -347,6 +354,8 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
                        newfi.setNoun(oldfi.noun() == FONT_OFF ? FONT_ON : FONT_OFF);
                if (newfi.number() == FONT_TOGGLE)
                        newfi.setNumber(oldfi.number() == FONT_OFF ? FONT_ON : FONT_OFF);
                        newfi.setNoun(oldfi.noun() == FONT_OFF ? FONT_ON : FONT_OFF);
                if (newfi.number() == FONT_TOGGLE)
                        newfi.setNumber(oldfi.number() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.nospellcheck() == FONT_TOGGLE)
+                       newfi.setNoSpellcheck(oldfi.nospellcheck() == FONT_OFF ? FONT_ON : FONT_OFF);
        }
 
        setFont(cur.bv(), cur.selectionBegin().top(),
        }
 
        setFont(cur.bv(), cur.selectionBegin().top(),
@@ -432,7 +441,7 @@ void Text::toggleFree(Cursor & cur, Font const & font, bool toggleall)
 }
 
 
 }
 
 
-docstring Text::getStringToIndex(Cursor const & cur)
+docstring Text::getStringForDialog(Cursor & cur)
 {
        LBUFERR(this == cur.text());
 
 {
        LBUFERR(this == cur.text());
 
@@ -442,17 +451,10 @@ docstring Text::getStringToIndex(Cursor const & cur)
        // Try implicit word selection. If there is a change
        // in the language the implicit word selection is
        // disabled.
        // Try implicit word selection. If there is a change
        // in the language the implicit word selection is
        // disabled.
-       Cursor tmpcur = cur;
-       selectWord(tmpcur, PREVIOUS_WORD);
-
-       if (!tmpcur.selection())
-               cur.message(_("Nothing to index!"));
-       else if (tmpcur.selBegin().pit() != tmpcur.selEnd().pit())
-               cur.message(_("Cannot index more than one paragraph!"));
-       else
-               return tmpcur.selectionAsString(false);
-
-       return docstring();
+       selectWordWhenUnderCursor(cur, WHOLE_WORD);
+       docstring const & retval = cur.selectionAsString(false);
+       cur.clearSelection();
+       return retval;
 }
 
 
 }
 
 
@@ -485,7 +487,7 @@ void Text::setLabelWidthStringToSequence(Cursor const & cur,
 }
 
 
 }
 
 
-void Text::setParagraphs(Cursor & cur, docstring arg, bool merge)
+void Text::setParagraphs(Cursor & cur, docstring const & arg, bool merge)
 {
        LBUFERR(cur.text());
 
 {
        LBUFERR(cur.text());
 
@@ -605,7 +607,7 @@ bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool mo
        if (cur.pos() == cur.lastpos())
                return false;
        Paragraph & par = cur.paragraph();
        if (cur.pos() == cur.lastpos())
                return false;
        Paragraph & par = cur.paragraph();
-       Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : 0;
+       Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : nullptr;
        if (!inset || !inset->editable())
                return false;
        if (cur.selection() && cur.realAnchor().find(inset) == -1)
        if (!inset || !inset->editable())
                return false;
        if (cur.selection() && cur.realAnchor().find(inset) == -1)
@@ -784,24 +786,35 @@ bool Text::cursorDownParagraph(Cursor & cur)
        return updated;
 }
 
        return updated;
 }
 
+namespace {
 
 
-// fix the cursor `cur' after a characters has been deleted at `where'
-// position. Called by deleteEmptyParagraphMechanism
-void Text::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where)
+/** delete num_spaces characters between from and to. Return the
+ * number of spaces that got physically deleted (not marked as
+ * deleted) */
+int deleteSpaces(Paragraph & par, pos_type const from, pos_type to,
+                                 int num_spaces, bool const trackChanges)
 {
 {
-       // Do nothing if cursor is not in the paragraph where the
-       // deletion occurred,
-       if (cur.pit() != where.pit())
-               return;
+       if (num_spaces <= 0)
+               return 0;
 
 
-       // If cursor position is after the deletion place update it
-       if (cur.pos() > where.pos())
-               --cur.pos();
+       // First, delete spaces marked as inserted
+       int pos = from;
+       while (pos < to && num_spaces > 0) {
+               Change const & change = par.lookupChange(pos);
+               if (change.inserted() && change.currentAuthor()) {
+                       par.eraseChar(pos, trackChanges);
+                       --num_spaces;
+                       --to;
+               } else
+                       ++pos;
+       }
+
+       // Then remove remaining spaces
+       int const psize = par.size();
+       par.eraseChars(from, from + num_spaces, trackChanges);
+       return psize - par.size();
+}
 
 
-       // Check also if we don't want to set the cursor on a spot behind the
-       // pagragraph because we erased the last character.
-       if (cur.pos() > cur.lastpos())
-               cur.pos() = cur.lastpos();
 }
 
 
 }
 
 
@@ -811,111 +824,124 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
        //LYXERR(Debug::DEBUG, "DEPM: cur:\n" << cur << "old:\n" << old);
 
        Paragraph & oldpar = old.paragraph();
        //LYXERR(Debug::DEBUG, "DEPM: cur:\n" << cur << "old:\n" << old);
 
        Paragraph & oldpar = old.paragraph();
+       bool const trackChanges = cur.buffer()->params().track_changes;
+       bool result = false;
+
+       // We do nothing if cursor did not move
+       if (cur.top() == old.top())
+               return false;
+
+       // We do not do anything on read-only documents
+       if (cur.buffer()->isReadonly())
+               return false;
 
        // We allow all kinds of "mumbo-jumbo" when freespacing.
        if (oldpar.isFreeSpacing())
                return false;
 
 
        // We allow all kinds of "mumbo-jumbo" when freespacing.
        if (oldpar.isFreeSpacing())
                return false;
 
-       /* Ok I'll put some comments here about what is missing.
-          There are still some small problems that can lead to
+       // Whether a common inset is found and whether the cursor is still in
+       // the same paragraph (possibly nested).
+       int const depth = cur.find(&old.inset());
+       bool const same_par = depth != -1 && old.idx() == cur[depth].idx()
+               && old.pit() == cur[depth].pit();
+
+       /*
+        * (1) If the chars around the old cursor were spaces, delete some of
+        * them, but only if the cursor has really moved.
+        */
+
+       /* There are still some small problems that can lead to
           double spaces stored in the document file or space at
           the beginning of paragraphs(). This happens if you have
           double spaces stored in the document file or space at
           the beginning of paragraphs(). This happens if you have
-          the cursor between to spaces and then save. Or if you
-          cut and paste and the selection have a space at the
+          the cursor between two spaces and then save. Or if you
+          cut and paste and the selection has a space at the
           beginning and then save right after the paste. (Lgb)
        */
 
           beginning and then save right after the paste. (Lgb)
        */
 
-       // If old.pos() == 0 and old.pos()(1) == LineSeparator
-       // delete the LineSeparator.
-       // MISSING
-
-       // If old.pos() == 1 and old.pos()(0) == LineSeparator
-       // delete the LineSeparator.
-       // MISSING
-
-       // Find a common inset and the corresponding depth.
-       size_t depth = 0;
-       for (; depth < cur.depth(); ++depth)
-               if (&old.inset() == &cur[depth].inset())
-                       break;
-
-       // Whether a common inset is found and whether the cursor is still in
-       // the same paragraph (possibly nested).
-       bool const same_par = depth < cur.depth() && old.pit() == cur[depth].pit();
-       bool const same_par_pos = depth == cur.depth() - 1 && same_par
-               && old.pos() == cur[depth].pos();
-
-       // If the chars around the old cursor were spaces, delete one of them.
-       if (!same_par_pos) {
-               // Only if the cursor has really moved.
-               if (old.pos() > 0
-                   && old.pos() < oldpar.size()
-                   && oldpar.isLineSeparator(old.pos())
-                   && oldpar.isLineSeparator(old.pos() - 1)
-                   && !oldpar.isDeleted(old.pos() - 1)
-                   && !oldpar.isDeleted(old.pos())) {
-                       oldpar.eraseChar(old.pos() - 1, cur.buffer()->params().track_changes);
-// FIXME: This will not work anymore when we have multiple views of the same buffer
-// In this case, we will have to correct also the cursors held by
-// other bufferviews. It will probably be easier to do that in a more
-// automated way in CursorSlice code. (JMarc 26/09/2001)
-                       // correct all cursor parts
-                       if (same_par) {
-                               fixCursorAfterDelete(cur[depth], old.top());
-                               need_anchor_change = true;
-                       }
-                       return true;
+       // find range of spaces around cursors
+       pos_type from = old.pos();
+       while (from > 0
+                  && oldpar.isLineSeparator(from - 1)
+                  && !oldpar.isDeleted(from - 1))
+               --from;
+       pos_type to = old.pos();
+       while (to < old.lastpos()
+                  && oldpar.isLineSeparator(to)
+                  && !oldpar.isDeleted(to))
+               ++to;
+
+       int num_spaces = to - from;
+       // If we are not at the start of the paragraph, keep one space
+       if (from != to && from > 0)
+               --num_spaces;
+
+       // If cursor is inside range, keep one additional space
+       if (same_par && cur.pos() > from && cur.pos() < to)
+               --num_spaces;
+
+       // Remove spaces and adapt cursor.
+       if (num_spaces > 0) {
+               old.recordUndo();
+               int const deleted =
+                       deleteSpaces(oldpar, from, to, num_spaces, trackChanges);
+               // correct cur position
+               // FIXME: there can be other cursors pointing there, we should update them
+               if (same_par) {
+                       if (cur[depth].pos() >= to)
+                               cur[depth].pos() -= deleted;
+                       else if (cur[depth].pos() > from)
+                               cur[depth].pos() = min(from + 1, old.lastpos());
+                       need_anchor_change = true;
                }
                }
+               result = true;
        }
 
        }
 
-       // only do our magic if we changed paragraph
+       /*
+        * (2) If the paragraph where the cursor was is empty, delete it
+        */
+
+       // only do our other magic if we changed paragraph
        if (same_par)
        if (same_par)
-               return false;
+               return result;
+
+       // only do our magic if the paragraph is empty
+       if (!oldpar.empty())
+               return result;
 
        // don't delete anything if this is the ONLY paragraph!
        if (old.lastpit() == 0)
 
        // don't delete anything if this is the ONLY paragraph!
        if (old.lastpit() == 0)
-               return false;
+               return result;
 
        // Do not delete empty paragraphs with keepempty set.
        if (oldpar.allowEmpty())
 
        // Do not delete empty paragraphs with keepempty set.
        if (oldpar.allowEmpty())
-               return false;
-
-       if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) {
-               // Delete old par.
-               old.recordUndo(max(old.pit() - 1, pit_type(0)),
-                              min(old.pit() + 1, old.lastpit()));
-               ParagraphList & plist = old.text()->paragraphs();
-               bool const soa = oldpar.params().startOfAppendix();
-               plist.erase(lyx::next(plist.begin(), old.pit()));
-               // do not lose start of appendix marker (bug 4212)
-               if (soa && old.pit() < pit_type(plist.size()))
-                       plist[old.pit()].params().startOfAppendix(true);
-
-               // see #warning (FIXME?) above
-               if (cur.depth() >= old.depth()) {
-                       CursorSlice & curslice = cur[old.depth() - 1];
-                       if (&curslice.inset() == &old.inset()
-                           && curslice.pit() > old.pit()) {
-                               --curslice.pit();
-                               // since a paragraph has been deleted, all the
-                               // insets after `old' have been copied and
-                               // their address has changed. Therefore we
-                               // need to `regenerate' cur. (JMarc)
-                               cur.updateInsets(&(cur.bottom().inset()));
-                               need_anchor_change = true;
-                       }
+               return result;
+
+       // Delete old par.
+       old.recordUndo(max(old.pit() - 1, pit_type(0)),
+                      min(old.pit() + 1, old.lastpit()));
+       ParagraphList & plist = old.text()->paragraphs();
+       bool const soa = oldpar.params().startOfAppendix();
+       plist.erase(plist.iterator_at(old.pit()));
+       // do not lose start of appendix marker (bug 4212)
+       if (soa && old.pit() < pit_type(plist.size()))
+               plist[old.pit()].params().startOfAppendix(true);
+
+       // see #warning (FIXME?) above
+       if (cur.depth() >= old.depth()) {
+               CursorSlice & curslice = cur[old.depth() - 1];
+               if (&curslice.inset() == &old.inset()
+                   && curslice.pit() > old.pit()) {
+                       --curslice.pit();
+                       // since a paragraph has been deleted, all the
+                       // insets after `old' have been copied and
+                       // their address has changed. Therefore we
+                       // need to `regenerate' cur. (JMarc)
+                       cur.updateInsets(&(cur.bottom().inset()));
+                       need_anchor_change = true;
                }
                }
-               return true;
-       }
-
-       if (oldpar.stripLeadingSpaces(cur.buffer()->params().track_changes)) {
-               need_anchor_change = true;
-               // We return true here because the Paragraph contents changed and
-               // we need a redraw before further action is processed.
-               return true;
        }
 
        }
 
-       return false;
+       return true;
 }
 
 
 }
 
 
@@ -930,13 +956,30 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
                if (par.isFreeSpacing())
                        continue;
 
                if (par.isFreeSpacing())
                        continue;
 
-               for (pos_type pos = 1; pos < par.size(); ++pos) {
-                       if (par.isLineSeparator(pos) && par.isLineSeparator(pos - 1)
-                           && !par.isDeleted(pos - 1)) {
-                               if (par.eraseChar(pos - 1, trackChanges)) {
-                                       --pos;
-                               }
-                       }
+               pos_type from = 0;
+               while (from < par.size()) {
+                       // skip non-spaces
+                       while (from < par.size()
+                              && (!par.isLineSeparator(from) || par.isDeleted(from)))
+                               ++from;
+                       // find string of spaces
+                       pos_type to = from;
+                       while (to < par.size()
+                              && par.isLineSeparator(to) && !par.isDeleted(to))
+                               ++to;
+                       // empty? We are done
+                       if (from == to)
+                               break;
+
+                       int num_spaces = to - from;
+
+                       // If we are not at the extremity of the paragraph, keep one space
+                       if (from != to && from > 0 && to < par.size())
+                               --num_spaces;
+
+                       // Remove spaces if needed
+                       int const deleted = deleteSpaces(par, from , to, num_spaces, trackChanges);
+                       from = to - deleted;
                }
 
                // don't delete anything if this is the only remaining paragraph
                }
 
                // don't delete anything if this is the only remaining paragraph
@@ -950,13 +993,11 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
                        continue;
 
                if (par.empty() || (par.size() == 1 && par.isLineSeparator(0))) {
                        continue;
 
                if (par.empty() || (par.size() == 1 && par.isLineSeparator(0))) {
-                       pars_.erase(lyx::next(pars_.begin(), pit));
+                       pars_.erase(pars_.iterator_at(pit));
                        --pit;
                        --last;
                        continue;
                }
                        --pit;
                        --last;
                        continue;
                }
-
-               par.stripLeadingSpaces(trackChanges);
        }
 }
 
        }
 }