]> git.lyx.org Git - lyx.git/blobdiff - src/Text2.cpp
Provide proper fallback if a bibliography processor is not found
[lyx.git] / src / Text2.cpp
index 0c96a81a2166bd68caf4d45147764f8b3b851b05..3a7ca6cd9d003da42dea70c87bf77eaa697960c2 100644 (file)
@@ -22,7 +22,6 @@
 
 #include "Text.h"
 
-#include "Bidi.h"
 #include "Buffer.h"
 #include "buffer_funcs.h"
 #include "BufferList.h"
 #include "TextClass.h"
 #include "TextMetrics.h"
 
-#include "insets/InsetCollapsable.h"
+#include "insets/InsetCollapsible.h"
 
 #include "mathed/InsetMathHull.h"
 
 #include "support/lassert.h"
 #include "support/debug.h"
 #include "support/gettext.h"
+#include "support/lyxalgo.h"
 #include "support/textutils.h"
 
-#include <boost/next_prior.hpp>
-
 #include <sstream>
 
 using namespace std;
@@ -184,7 +182,11 @@ void Text::setLayout(pit_type start, pit_type end,
 
        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));
        }
@@ -200,6 +202,7 @@ void Text::setLayout(Cursor & cur, docstring const & layout)
        pit_type end = cur.selEnd().pit() + 1;
        cur.recordUndoSelection();
        setLayout(start, end, layout);
+       cur.setCurrentFont();
        cur.forceBufferUpdate();
 }
 
@@ -264,6 +267,11 @@ void Text::changeDepth(Cursor & cur, DEPTH_CHANGE type)
 void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
 {
        LASSERT(this == cur.text(), return);
+
+       // If there is a selection, record undo before the cursor font is changed.
+       if (cur.selection())
+               cur.recordUndoSelection();
+
        // Set the current_font
        // Determine basis font
        FontInfo layoutfont;
@@ -289,10 +297,9 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
                return;
 
        // Ok, we have a selection.
-       cur.recordUndoSelection();
        Font newfont = font;
 
-       if (toggleall) {        
+       if (toggleall) {
                // Toggling behaves as follows: We check the first character of the
                // selection. If it's (say) got EMPH on, then we set to off; if off,
                // then to on. With families and the like, we set it to INHERIT, if
@@ -300,30 +307,30 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
                CursorSlice const & sl = cur.selBegin();
                Text const & text = *sl.text();
                Paragraph const & par = text.getPar(sl.pit());
-       
+
                // get font at the position
                Font oldfont = par.getFont(cur.bv().buffer().params(), sl.pos(),
                        text.outerFont(sl.pit()));
                FontInfo const & oldfi = oldfont.fontInfo();
-       
+
                FontInfo & newfi = newfont.fontInfo();
-       
+
                FontFamily newfam = newfi.family();
                if (newfam !=   INHERIT_FAMILY && newfam != IGNORE_FAMILY &&
                                newfam == oldfi.family())
                        newfi.setFamily(INHERIT_FAMILY);
-               
+
                FontSeries newser = newfi.series();
                if (newser == BOLD_SERIES && oldfi.series() == BOLD_SERIES)
                        newfi.setSeries(INHERIT_SERIES);
-       
+
                FontShape newshp = newfi.shape();
                if (newshp != INHERIT_SHAPE && newshp != IGNORE_SHAPE &&
                                newshp == oldfi.shape())
                        newfi.setShape(INHERIT_SHAPE);
 
                ColorCode newcol = newfi.color();
-               if (newcol != Color_none && newcol != Color_inherit 
+               if (newcol != Color_none && newcol != Color_inherit
                    && newcol != Color_ignore && newcol == oldfi.color())
                        newfi.setColor(Color_none);
 
@@ -334,6 +341,8 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
                        newfi.setUnderbar(oldfi.underbar() == FONT_OFF ? FONT_ON : FONT_OFF);
                if (newfi.strikeout() == FONT_TOGGLE)
                        newfi.setStrikeout(oldfi.strikeout() == FONT_OFF ? FONT_ON : FONT_OFF);
+               if (newfi.xout() == FONT_TOGGLE)
+                       newfi.setXout(oldfi.xout() == FONT_OFF ? FONT_ON : FONT_OFF);
                if (newfi.uuline() == FONT_TOGGLE)
                        newfi.setUuline(oldfi.uuline() == FONT_OFF ? FONT_ON : FONT_OFF);
                if (newfi.uwave() == FONT_TOGGLE)
@@ -344,7 +353,7 @@ void Text::setFont(Cursor & cur, Font const & font, bool toggleall)
                        newfi.setNumber(oldfi.number() == FONT_OFF ? FONT_ON : FONT_OFF);
        }
 
-       setFont(cur.bv(), cur.selectionBegin().top(), 
+       setFont(cur.bv(), cur.selectionBegin().top(),
                cur.selectionEnd().top(), newfont);
 }
 
@@ -374,7 +383,7 @@ void Text::setFont(BufferView const & bv, CursorSlice const & begin,
                Font f = tm.displayFont(pit, pos);
                f.update(font, language);
                setCharFont(pit, pos, f, tm.font_);
-               // font change may change language... 
+               // font change may change language...
                // spell checker has to know that
                pars_[pit].requestSpellCheck(pos);
        }
@@ -391,7 +400,7 @@ bool Text::cursorTop(Cursor & cur)
 bool Text::cursorBottom(Cursor & cur)
 {
        LBUFERR(this == cur.text());
-       return setCursor(cur, cur.lastpit(), boost::prior(paragraphs().end())->size());
+       return setCursor(cur, cur.lastpit(), prev(paragraphs().end(), 1)->size());
 }
 
 
@@ -446,7 +455,7 @@ docstring Text::getStringToIndex(Cursor const & cur)
                cur.message(_("Cannot index more than one paragraph!"));
        else
                return tmpcur.selectionAsString(false);
-       
+
        return docstring();
 }
 
@@ -480,7 +489,7 @@ void Text::setLabelWidthStringToSequence(Cursor const & cur,
 }
 
 
-void Text::setParagraphs(Cursor & cur, docstring arg, bool merge) 
+void Text::setParagraphs(Cursor & cur, docstring arg, bool merge)
 {
        LBUFERR(cur.text());
 
@@ -498,7 +507,7 @@ void Text::setParagraphs(Cursor & cur, docstring arg, bool merge)
                // with same layout in a sequence.
                // Do this only once for a selected range of paragraphs
                // of the same layout and depth.
-               cur.recordUndo();
+               c.recordUndo();
                par.params().apply(params, par.layout());
                if (par.getDepth() != priordepth || par.layout() != priorlayout)
                        setLabelWidthStringToSequence(c, params.labelWidthString());
@@ -508,7 +517,7 @@ void Text::setParagraphs(Cursor & cur, docstring arg, bool merge)
 }
 
 
-void Text::setParagraphs(Cursor & cur, ParagraphParameters const & p) 
+void Text::setParagraphs(Cursor & cur, ParagraphParameters const & p)
 {
        LBUFERR(cur.text());
 
@@ -544,47 +553,23 @@ void Text::insertInset(Cursor & cur, Inset * inset)
 }
 
 
-bool Text::setCursor(Cursor & cur, pit_type par, pos_type pos,
+bool Text::setCursor(Cursor & cur, pit_type pit, pos_type pos,
                        bool setfont, bool boundary)
 {
        TextMetrics const & tm = cur.bv().textMetrics(this);
-       bool const update_needed = !tm.contains(par);
+       bool const update_needed = !tm.contains(pit);
        Cursor old = cur;
-       setCursorIntern(cur, par, pos, setfont, boundary);
+       setCursorIntern(cur, pit, pos, setfont, boundary);
        return cur.bv().checkDepm(cur, old) || update_needed;
 }
 
 
-void Text::setCursor(CursorSlice & cur, pit_type par, pos_type pos)
-{
-       LASSERT(par != int(paragraphs().size()), return);
-       cur.pit() = par;
-       cur.pos() = pos;
-
-       // now some strict checking
-       Paragraph & para = getPar(par);
-
-       // None of these should happen, but we're scaredy-cats
-       if (pos < 0) {
-               LYXERR0("Don't like -1!");
-               LATTEST(false);
-       }
-
-       if (pos > para.size()) {
-               LYXERR0("Don't like 1, pos: " << pos
-                      << " size: " << para.size()
-                      << " par: " << par);
-               LATTEST(false);
-       }
-}
-
-
-void Text::setCursorIntern(Cursor & cur,
-                             pit_type par, pos_type pos, bool setfont, bool boundary)
+void Text::setCursorIntern(Cursor & cur, pit_type pit, pos_type pos,
+                           bool setfont, bool boundary)
 {
        LBUFERR(this == cur.text());
        cur.boundary(boundary);
-       setCursor(cur.top(), par, pos);
+       cur.top().setPitPos(pit, pos);
        if (setfont)
                cur.setCurrentFont();
 }
@@ -592,8 +577,6 @@ void Text::setCursorIntern(Cursor & cur,
 
 bool Text::checkAndActivateInset(Cursor & cur, bool front)
 {
-       if (cur.selection())
-               return false;
        if (front && cur.pos() == cur.lastpos())
                return false;
        if (!front && cur.pos() == 0)
@@ -601,6 +584,8 @@ bool Text::checkAndActivateInset(Cursor & cur, bool front)
        Inset * inset = front ? cur.nextInset() : cur.prevInset();
        if (!inset || !inset->editable())
                return false;
+       if (cur.selection() && cur.realAnchor().find(inset) == -1)
+               return false;
        /*
         * Apparently, when entering an inset we are expected to be positioned
         * *before* it in the containing paragraph, regardless of the direction
@@ -611,14 +596,14 @@ bool Text::checkAndActivateInset(Cursor & cur, bool front)
        if (!front)
                --cur.pos();
        inset->edit(cur, front);
+       cur.setCurrentFont();
+       cur.boundary(false);
        return true;
 }
 
 
 bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool movingLeft)
 {
-       if (cur.selection())
-               return false;
        if (cur.pos() == -1)
                return false;
        if (cur.pos() == cur.lastpos())
@@ -627,8 +612,12 @@ bool Text::checkAndActivateInsetVisual(Cursor & cur, bool movingForward, bool mo
        Inset * inset = par.isInset(cur.pos()) ? par.getInset(cur.pos()) : 0;
        if (!inset || !inset->editable())
                return false;
-       inset->edit(cur, movingForward, 
+       if (cur.selection() && cur.realAnchor().find(inset) == -1)
+               return false;
+       inset->edit(cur, movingForward,
                movingLeft ? Inset::ENTRY_DIRECTION_RIGHT : Inset::ENTRY_DIRECTION_LEFT);
+       cur.setCurrentFont();
+       cur.boundary(false);
        return true;
 }
 
@@ -656,21 +645,28 @@ bool Text::cursorBackward(Cursor & cur)
                                cur.textRow().pos() == cur.pos() &&
                                !cur.paragraph().isLineSeparator(cur.pos() - 1) &&
                                !cur.paragraph().isNewline(cur.pos() - 1) &&
+                               !cur.paragraph().isEnvSeparator(cur.pos() - 1) &&
                                !cur.paragraph().isSeparator(cur.pos() - 1)) {
                        return setCursor(cur, cur.pit(), cur.pos(), true, true);
                }
-               
+
                // go left and try to enter inset
                if (checkAndActivateInset(cur, false))
                        return false;
-               
+
                // normal character left
                return setCursor(cur, cur.pit(), cur.pos() - 1, true, false);
        }
 
        // move to the previous paragraph or do nothing
-       if (cur.pit() > 0)
-               return setCursor(cur, cur.pit() - 1, getPar(cur.pit() - 1).size(), true, false);
+       if (cur.pit() > 0) {
+               Paragraph & par = getPar(cur.pit() - 1);
+               pos_type lastpos = par.size();
+               if (lastpos > 0 && par.isEnvSeparator(lastpos - 1))
+                       return setCursor(cur, cur.pit() - 1, lastpos - 1, true, false);
+               else
+                       return setCursor(cur, cur.pit() - 1, lastpos, true, false);
+       }
        return false;
 }
 
@@ -683,7 +679,7 @@ bool Text::cursorVisLeft(Cursor & cur, bool skip_inset)
                cur = temp_cur;
                return false;
        }
-       return setCursor(cur, temp_cur.pit(), temp_cur.pos(), 
+       return setCursor(cur, temp_cur.pit(), temp_cur.pos(),
                true, temp_cur.boundary());
 }
 
@@ -718,7 +714,7 @@ bool Text::cursorForward(Cursor & cur)
                if (cur.boundary() && !tm.isRTLBoundary(cur.pit(), cur.pos()))
                        return setCursor(cur, cur.pit(), cur.pos(), true, false);
 
-               // next position is left of boundary, 
+               // next position is left of boundary,
                // but go to next line for special cases like space, newline, linesep
 #if 0
                // some effectless debug code to see the values in the debugger
@@ -734,19 +730,26 @@ bool Text::cursorForward(Cursor & cur)
                        bool sep2 = cur.paragraph().isSeparator(cur.pos()+1);
                }
 #endif
-               if (cur.textRow().endpos() == cur.pos() + 1 &&
-                   cur.textRow().endpos() != cur.lastpos() &&
-                               !cur.paragraph().isNewline(cur.pos()) &&
-                               !cur.paragraph().isLineSeparator(cur.pos()) &&
-                               !cur.paragraph().isSeparator(cur.pos())) {
-                       return setCursor(cur, cur.pit(), cur.pos() + 1, true, true);
+               if (cur.textRow().endpos() == cur.pos() + 1) {
+                       if (cur.paragraph().isEnvSeparator(cur.pos()) &&
+                           cur.pos() + 1 == cur.lastpos() &&
+                           cur.pit() != cur.lastpit()) {
+                               // move to next paragraph
+                               return setCursor(cur, cur.pit() + 1, 0, true, false);
+                       } else if (cur.textRow().endpos() != cur.lastpos() &&
+                                  !cur.paragraph().isNewline(cur.pos()) &&
+                                  !cur.paragraph().isEnvSeparator(cur.pos()) &&
+                                  !cur.paragraph().isLineSeparator(cur.pos()) &&
+                                  !cur.paragraph().isSeparator(cur.pos())) {
+                               return setCursor(cur, cur.pit(), cur.pos() + 1, true, true);
+                       }
                }
-               
+
                // in front of RTL boundary? Stay on this side of the boundary because:
                //   ab|cDDEEFFghi -> abc|DDEEFFghi
                if (tm.isRTLBoundary(cur.pit(), cur.pos() + 1))
                        return setCursor(cur, cur.pit(), cur.pos() + 1, true, true);
-               
+
                // move right
                return setCursor(cur, cur.pit(), cur.pos() + 1, true, false);
        }
@@ -786,18 +789,21 @@ bool Text::cursorDownParagraph(Cursor & cur)
 }
 
 
-// fix the cursor `cur' after a characters has been deleted at `where'
+namespace {
+// fix the cursor `cur' after characters has been deleted at `where'
 // position. Called by deleteEmptyParagraphMechanism
-void Text::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where)
+void fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where,
+                          pos_type from, int num_chars)
 {
        // Do nothing if cursor is not in the paragraph where the
-       // deletion occured,
+       // deletion occurred,
        if (cur.pit() != where.pit())
                return;
 
        // If cursor position is after the deletion place update it
-       if (cur.pos() > where.pos())
-               --cur.pos();
+       // but if we are not at start of line keep it after the space that was kept.
+       if (cur.pos() > from)
+               cur.pos() = max(from + (from > 0), cur.pos() - num_chars);
 
        // Check also if we don't want to set the cursor on a spot behind the
        // pagragraph because we erased the last character.
@@ -805,6 +811,8 @@ void Text::fixCursorAfterDelete(CursorSlice & cur, CursorSlice const & where)
                cur.pos() = cur.lastpos();
 }
 
+}
+
 
 bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
                Cursor & old, bool & need_anchor_change)
@@ -821,8 +829,8 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
           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)
        */
 
@@ -840,36 +848,57 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
                if (&old.inset() == &cur[depth].inset())
                        break;
 
-       // Whether a common inset is found and whether the cursor is still in 
+       // 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 
+       bool const same_par = depth < cur.depth() && old.idx() == cur[depth].idx()
+               && 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 the chars around the old cursor were spaces, delete some of
+       // them, but only if the cursor has really moved.
        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);
+               // find range of spaces around cursors
+               int from = old.pos();
+               while (from > 0
+                      && oldpar.isLineSeparator(from - 1)
+                      && !oldpar.isDeleted(from - 1))
+                       --from;
+               int to = old.pos();
+               while (to < oldpar.size()
+                      && oldpar.isLineSeparator(to)
+                      && !oldpar.isDeleted(to))
+                       ++to;
+
+               // If we are not at the start of the paragraph, keep one space
+               if (from != to && from > 0) {
+                       --to;
+                       // if the new cursor is inside the sequence of spaces, keep one more space
+                       if (same_par && cur.pos() > from && cur.pos() <= to)
+                               --to;
+               }
+
+               // Remove spaces and adapt cursor.
+               if (from < to) {
+                       // we need to remember what the size was because
+                       // eraseChars might mark spaces as deleted instead of
+                       // removing them.
+                       int const oldsize = oldpar.size();
+                       oldpar.eraseChars(from, to, 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());
+                               fixCursorAfterDelete(cur[depth], old.top(), from, oldsize - oldpar.size());
                                need_anchor_change = true;
                        }
                        return true;
                }
        }
 
-       // only do our magic if we changed paragraph
+       // only do our other magic if we changed paragraph
        if (same_par)
                return false;
 
@@ -883,20 +912,20 @@ bool Text::deleteEmptyParagraphMechanism(Cursor & cur,
 
        if (oldpar.empty() || (oldpar.size() == 1 && oldpar.isLineSeparator(0))) {
                // Delete old par.
-               old.recordUndo(ATOMIC_UNDO,
-                          max(old.pit() - 1, pit_type(0)),
-                          min(old.pit() + 1, old.lastpit()));
+               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(boost::next(plist.begin(), old.pit()));
+               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 
+               // see #warning (FIXME?) above
                if (cur.depth() >= old.depth()) {
                        CursorSlice & curslice = cur[old.depth() - 1];
                        if (&curslice.inset() == &old.inset()
+                           && curslice.idx() == old.idx()
                            && curslice.pit() > old.pit()) {
                                --curslice.pit();
                                // since a paragraph has been deleted, all the
@@ -932,13 +961,26 @@ 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;
+                       // if inside the line, keep one space
+                       if (from > 0 && to < par.size())
+                               ++from;
+                       // remove the extra spaces
+                       if (from < to)
+                               par.eraseChars(from, to, trackChanges);
                }
 
                // don't delete anything if this is the only remaining paragraph
@@ -952,7 +994,7 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
                        continue;
 
                if (par.empty() || (par.size() == 1 && par.isLineSeparator(0))) {
-                       pars_.erase(boost::next(pars_.begin(), pit));
+                       pars_.erase(lyx::next(pars_.begin(), pit));
                        --pit;
                        --last;
                        continue;
@@ -963,15 +1005,4 @@ void Text::deleteEmptyParagraphMechanism(pit_type first, pit_type last, bool tra
 }
 
 
-void Text::recUndo(Cursor & cur, pit_type first, pit_type last) const
-{
-       cur.recordUndo(ATOMIC_UNDO, first, last);
-}
-
-
-void Text::recUndo(Cursor & cur, pit_type par) const
-{
-       cur.recordUndo(ATOMIC_UNDO, par, par);
-}
-
 } // namespace lyx