]> git.lyx.org Git - lyx.git/blobdiff - src/Text2.cpp
update tex2lyx tests
[lyx.git] / src / Text2.cpp
index c223ce06e6aa8de612fa802460a795041d8a5473..07839a748d016e4d6609a9354bd41e014aecd424 100644 (file)
@@ -42,7 +42,7 @@
 #include "TextClass.h"
 #include "TextMetrics.h"
 
-#include "insets/InsetCollapsable.h"
+#include "insets/InsetCollapsible.h"
 
 #include "mathed/InsetMathHull.h"
 
@@ -186,6 +186,8 @@ void Text::setLayout(pit_type start, pit_type end,
                if (lyxlayout.margintype == MARGIN_MANUAL)
                        par.setLabelWidthString(par.expandLabel(lyxlayout, bp));
        }
+
+       deleteEmptyParagraphMechanism(start, end - 1, bp.track_changes);
 }
 
 
@@ -198,6 +200,7 @@ void Text::setLayout(Cursor & cur, docstring const & layout)
        pit_type end = cur.selEnd().pit() + 1;
        cur.recordUndoSelection();
        setLayout(start, end, layout);
+       cur.fixIfBroken();
        cur.setCurrentFont();
        cur.forceBufferUpdate();
 }
@@ -347,6 +350,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);
+               if (newfi.nospellcheck() == FONT_TOGGLE)
+                       newfi.setNoSpellcheck(oldfi.nospellcheck() == FONT_OFF ? FONT_ON : FONT_OFF);
        }
 
        setFont(cur.bv(), cur.selectionBegin().top(),
@@ -432,7 +437,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());
 
@@ -442,17 +447,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.
-       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 +483,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());
 
@@ -784,24 +782,35 @@ bool Text::cursorDownParagraph(Cursor & cur)
        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 +820,124 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
        //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;
 
-       /* 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
-          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)
        */
 
-       // 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)
-               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)
-               return false;
+               return result;
 
        // 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(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 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 +952,30 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
                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
@@ -955,8 +994,6 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
                        --last;
                        continue;
                }
-
-               par.stripLeadingSpaces(trackChanges);
        }
 }