]> git.lyx.org Git - lyx.git/blobdiff - src/Text.cpp
reorder.
[lyx.git] / src / Text.cpp
index 47f272fef66d3c33c6e326f9e43beec44064eefc..c758008d530ab073d38a1da0d4e3b3beb6296141 100644 (file)
@@ -4,14 +4,14 @@
  * Licence details can be found in the file COPYING.
  *
  * \author Asger Alstrup
- * \author Lars Gullik Bjønnes
+ * \author Lars Gullik Bjønnes
  * \author Dov Feldstern
  * \author Jean-Marc Lasgouttes
  * \author John Levon
- * \author André Pönitz
+ * \author André Pönitz
  * \author Stefan Schimanski
  * \author Dekel Tsur
- * \author Jürgen Vigna
+ * \author Jürgen Vigna
  *
  * Full author contact details are available in file CREDITS.
  */
@@ -37,6 +37,7 @@
 #include "Language.h"
 #include "Length.h"
 #include "Lexer.h"
+#include "lyxfind.h"
 #include "LyXRC.h"
 #include "Paragraph.h"
 #include "paragraph_funcs.h"
 #include "insets/InsetSpecialChar.h"
 #include "insets/InsetTabular.h"
 
-#include "support/lassert.h"
-#include "support/convert.h"
 #include "support/debug.h"
 #include "support/docstream.h"
 #include "support/gettext.h"
+#include "support/lassert.h"
 #include "support/lstrings.h"
 #include "support/textutils.h"
 
@@ -187,6 +187,15 @@ void readParToken(Buffer const & buf, Paragraph & par, Lexer & lex,
                else
                        lex.printError("Unknown bar font flag "
                                       "`$$Token'");
+       } else if (token == "\\strikeout") {
+               lex.next();
+               font.fontInfo().setStrikeout(font.setLyXMisc(lex.getString()));
+       } else if (token == "\\uuline") {
+               lex.next();
+               font.fontInfo().setUuline(font.setLyXMisc(lex.getString()));
+       } else if (token == "\\uwave") {
+               lex.next();
+               font.fontInfo().setUwave(font.setLyXMisc(lex.getString()));
        } else if (token == "\\noun") {
                lex.next();
                font.fontInfo().setNoun(font.setLyXMisc(lex.getString()));
@@ -293,7 +302,8 @@ class TextCompletionList : public CompletionList
 public:
        ///
        TextCompletionList(Cursor const & cur)
-       : buf_(cur.buffer()), pos_(0) {}
+               : buffer_(cur.buffer()), pos_(0)
+       {}
        ///
        virtual ~TextCompletionList() {}
        
@@ -312,7 +322,7 @@ public:
        
 private:
        ///
-       Buffer const & buf_;
+       Buffer const * buffer_;
        ///
        size_t pos_;
 };
@@ -341,7 +351,7 @@ void Text::breakParagraph(Cursor & cur, bool inverse_logic)
        Paragraph & cpar = cur.paragraph();
        pit_type cpit = cur.pit();
 
-       DocumentClass const & tclass = cur.buffer().params().documentClass();
+       DocumentClass const & tclass = cur.buffer()->params().documentClass();
        Layout const & layout = cpar.layout();
 
        // this is only allowed, if the current paragraph is not empty
@@ -356,7 +366,7 @@ void Text::breakParagraph(Cursor & cur, bool inverse_logic)
        // Always break behind a space
        // It is better to erase the space (Dekel)
        if (cur.pos() != cur.lastpos() && cpar.isLineSeparator(cur.pos()))
-               cpar.eraseChar(cur.pos(), cur.buffer().params().trackChanges);
+               cpar.eraseChar(cur.pos(), cur.buffer()->params().trackChanges);
 
        // What should the layout for the new paragraph be?
        bool keep_layout = inverse_logic ? 
@@ -370,7 +380,7 @@ void Text::breakParagraph(Cursor & cur, bool inverse_logic)
        // we need to set this before we insert the paragraph.
        bool const isempty = cpar.allowEmpty() && cpar.empty();
 
-       lyx::breakParagraph(cur.buffer().params(), paragraphs(), cpit,
+       lyx::breakParagraph(cur.buffer()->params(), paragraphs(), cpit,
                         cur.pos(), keep_layout);
 
        // After this, neither paragraph contains any rows!
@@ -391,11 +401,11 @@ void Text::breakParagraph(Cursor & cur, bool inverse_logic)
        }
 
        while (!pars_[next_par].empty() && pars_[next_par].isNewline(0)) {
-               if (!pars_[next_par].eraseChar(0, cur.buffer().params().trackChanges))
+               if (!pars_[next_par].eraseChar(0, cur.buffer()->params().trackChanges))
                        break; // the character couldn't be deleted physically due to change tracking
        }
 
-       updateLabels(cur.buffer());
+       cur.buffer()->updateLabels();
 
        // A singlePar update is not enough in this case.
        cur.updateFlags(Update::Force);
@@ -418,7 +428,7 @@ void Text::insertChar(Cursor & cur, char_type c)
        cur.recordUndo(INSERT_UNDO);
 
        TextMetrics const & tm = cur.bv().textMetrics(this);
-       Buffer const & buffer = cur.buffer();
+       Buffer const & buffer = *cur.buffer();
        Paragraph & par = cur.paragraph();
        // try to remove this
        pit_type const pit = cur.pit();
@@ -538,7 +548,8 @@ void Text::insertChar(Cursor & cur, char_type c)
                }
        }
 
-       par.insertChar(cur.pos(), c, cur.current_font, cur.buffer().params().trackChanges);
+       par.insertChar(cur.pos(), c, cur.current_font,
+               cur.buffer()->params().trackChanges);
        cur.checkBufferStructure();
 
 //             cur.updateFlags(Update::Force);
@@ -567,7 +578,7 @@ void Text::charInserted(Cursor & cur)
            && !par.isLetter(cur.pos() - 1)) {
                // get the word in front of cursor
                LASSERT(this == cur.text(), /**/);
-               cur.paragraph().updateWords(cur.top());
+               cur.paragraph().updateWords();
        }
 }
 
@@ -689,11 +700,9 @@ bool Text::cursorVisLeftOneWord(Cursor & cur)
                // we should stop when we have an LTR word on our right or an RTL word
                // on our left
                if ((left_is_letter && temp_cur.paragraph().getFontSettings(
-                               temp_cur.bv().buffer().params(), 
-                               left_pos).isRightToLeft())
+                               temp_cur.buffer()->params(), left_pos).isRightToLeft())
                        || (right_is_letter && !temp_cur.paragraph().getFontSettings(
-                               temp_cur.bv().buffer().params(), 
-                               right_pos).isRightToLeft()))
+                               temp_cur.buffer()->params(), right_pos).isRightToLeft()))
                        break;
        }
 
@@ -728,10 +737,10 @@ bool Text::cursorVisRightOneWord(Cursor & cur)
                // we should stop when we have an LTR word on our right or an RTL word
                // on our left
                if ((left_is_letter && temp_cur.paragraph().getFontSettings(
-                               temp_cur.bv().buffer().params(), 
+                               temp_cur.buffer()->params(), 
                                left_pos).isRightToLeft())
                        || (right_is_letter && !temp_cur.paragraph().getFontSettings(
-                               temp_cur.bv().buffer().params(), 
+                               temp_cur.buffer()->params(), 
                                right_pos).isRightToLeft()))
                        break;
        }
@@ -757,6 +766,25 @@ void Text::selectWord(Cursor & cur, word_location loc)
 }
 
 
+void Text::selectAll(Cursor & cur)
+{
+       LASSERT(this == cur.text(), /**/);
+       if (cur.lastpos() == 0 && cur.lastpit() == 0)
+               return;
+       // If the cursor is at the beginning, make sure the cursor ends there
+       if (cur.pit() == 0 && cur.pos() == 0) {
+               setCursor(cur, cur.lastpit(), getPar(cur.lastpit()).size());
+               cur.resetAnchor();
+               setCursor(cur, 0, 0);           
+       } else {
+               setCursor(cur, 0, 0);
+               cur.resetAnchor();
+               setCursor(cur, cur.lastpit(), getPar(cur.lastpit()).size());
+       }
+       cur.setSelection();
+}
+
+
 // Select the word currently under the cursor when no
 // selection is currently set
 bool Text::selectWordWhenUnderCursor(Cursor & cur, word_location loc)
@@ -773,8 +801,11 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
 {
        LASSERT(this == cur.text(), /**/);
 
-       if (!cur.selection())
-               return;
+       if (!cur.selection()) {
+               Change const & change = cur.paragraph().lookupChange(cur.pos());
+               if (!(change.changed() && findNextChange(&cur.bv())))
+                       return;
+       }
 
        cur.recordUndoSelection();
 
@@ -809,9 +840,9 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
                pos_type right = (pit == endPit ? endPos : parSize);
 
                if (op == ACCEPT) {
-                       pars_[pit].acceptChanges(cur.buffer().params(), left, right);
+                       pars_[pit].acceptChanges(cur.buffer()->params(), left, right);
                } else {
-                       pars_[pit].rejectChanges(cur.buffer().params(), left, right);
+                       pars_[pit].rejectChanges(cur.buffer()->params(), left, right);
                }
        }
 
@@ -838,7 +869,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
                                        // instead, we mark it unchanged
                                        pars_[pit].setChange(pos, Change(Change::UNCHANGED));
                                } else {
-                                       mergeParagraph(cur.buffer().params(), pars_, pit);
+                                       mergeParagraph(cur.buffer()->params(), pars_, pit);
                                        --endPit;
                                        --pit;
                                }
@@ -851,7 +882,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
                                        // we mark the par break at the end of the last paragraph unchanged
                                        pars_[pit].setChange(pos, Change(Change::UNCHANGED));
                                } else {
-                                       mergeParagraph(cur.buffer().params(), pars_, pit);
+                                       mergeParagraph(cur.buffer()->params(), pars_, pit);
                                        --endPit;
                                        --pit;
                                }
@@ -861,7 +892,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
 
        // finally, invoke the DEPM
 
-       deleteEmptyParagraphMechanism(begPit, endPit, cur.buffer().params().trackChanges);
+       deleteEmptyParagraphMechanism(begPit, endPit, cur.buffer()->params().trackChanges);
 
        //
 
@@ -869,7 +900,7 @@ void Text::acceptOrRejectChanges(Cursor & cur, ChangeOp op)
        cur.clearSelection();
        setCursorIntern(cur, begPit, begPos);
        cur.updateFlags(Update::Force);
-       updateLabels(cur.buffer());
+       cur.buffer()->updateLabels();
 }
 
 
@@ -979,7 +1010,7 @@ void Text::changeCase(Cursor & cur, TextCase action)
                Paragraph & par = pars_[pit];
                pos_type const pos = (pit == begPit ? begPos : 0);
                right = (pit == endPit ? endPos : par.size());
-               par.changeCase(cur.buffer().params(), pos, right, action);
+               par.changeCase(cur.buffer()->params(), pos, right, action);
        }
 
        // the selection may have changed due to logically-only deleted chars
@@ -1003,7 +1034,7 @@ bool Text::handleBibitems(Cursor & cur)
        if (cur.pos() != 0)
                return false;
 
-       BufferParams const & bufparams = cur.buffer().params();
+       BufferParams const & bufparams = cur.buffer()->params();
        Paragraph const & par = cur.paragraph();
        Cursor prevcur = cur;
        if (cur.pit() > 0) {
@@ -1018,7 +1049,7 @@ bool Text::handleBibitems(Cursor & cur)
                cur.recordUndo(ATOMIC_UNDO, prevcur.pit());
                mergeParagraph(bufparams, cur.text()->paragraphs(),
                                                        prevcur.pit());
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                setCursorIntern(cur, prevcur.pit(), prevcur.pos());
                cur.updateFlags(Update::Force);
                return true;
@@ -1032,7 +1063,7 @@ bool Text::handleBibitems(Cursor & cur)
 
 bool Text::erase(Cursor & cur)
 {
-       LASSERT(this == cur.text(), /**/);
+       LASSERT(this == cur.text(), return false);
        bool needsUpdate = false;
        Paragraph & par = cur.paragraph();
 
@@ -1041,12 +1072,12 @@ bool Text::erase(Cursor & cur)
                // any paragraphs
                cur.recordUndo(DELETE_UNDO);
                bool const was_inset = cur.paragraph().isInset(cur.pos());
-               if(!par.eraseChar(cur.pos(), cur.buffer().params().trackChanges))
+               if(!par.eraseChar(cur.pos(), cur.buffer()->params().trackChanges))
                        // the character has been logically deleted only => skip it
                        cur.top().forwardPos();
 
                if (was_inset)
-                       updateLabels(cur.buffer());
+                       cur.buffer()->updateLabels();
                else
                        cur.checkBufferStructure();
                needsUpdate = true;
@@ -1054,7 +1085,7 @@ bool Text::erase(Cursor & cur)
                if (cur.pit() == cur.lastpit())
                        return dissolveInset(cur);
 
-               if (!par.isMergedOnEndOfParDeletion(cur.buffer().params().trackChanges)) {
+               if (!par.isMergedOnEndOfParDeletion(cur.buffer()->params().trackChanges)) {
                        par.setChange(cur.pos(), Change(Change::DELETED));
                        cur.forwardPos();
                        needsUpdate = true;
@@ -1085,7 +1116,7 @@ bool Text::backspacePos0(Cursor & cur)
 
        bool needsUpdate = false;
 
-       BufferParams const & bufparams = cur.buffer().params();
+       BufferParams const & bufparams = cur.buffer()->params();
        DocumentClass const & tclass = bufparams.documentClass();
        ParagraphList & plist = cur.text()->paragraphs();
        Paragraph const & par = cur.paragraph();
@@ -1122,7 +1153,7 @@ bool Text::backspacePos0(Cursor & cur)
        }
 
        if (needsUpdate) {
-               updateLabels(cur.buffer());
+               cur.buffer()->updateLabels();
                setCursorIntern(cur, prevcur.pit(), prevcur.pos());
        }
 
@@ -1140,7 +1171,7 @@ bool Text::backspace(Cursor & cur)
 
                Paragraph & prev_par = pars_[cur.pit() - 1];
 
-               if (!prev_par.isMergedOnEndOfParDeletion(cur.buffer().params().trackChanges)) {
+               if (!prev_par.isMergedOnEndOfParDeletion(cur.buffer()->params().trackChanges)) {
                        prev_par.setChange(prev_par.size(), Change(Change::DELETED));
                        setCursorIntern(cur, cur.pit() - 1, prev_par.size());
                        return true;
@@ -1160,9 +1191,9 @@ bool Text::backspace(Cursor & cur)
                setCursorIntern(cur, cur.pit(), cur.pos() - 1,
                                false, cur.boundary());
                bool const was_inset = cur.paragraph().isInset(cur.pos());
-               cur.paragraph().eraseChar(cur.pos(), cur.buffer().params().trackChanges);
+               cur.paragraph().eraseChar(cur.pos(), cur.buffer()->params().trackChanges);
                if (was_inset)
-                       updateLabels(cur.buffer());
+                       cur.buffer()->updateLabels();
                else
                        cur.checkBufferStructure();
        }
@@ -1201,7 +1232,7 @@ bool Text::dissolveInset(Cursor & cur)
        if (spit == 0)
                spos += cur.pos();
        spit += cur.pit();
-       Buffer & b = cur.buffer();
+       Buffer & b = *cur.buffer();
        cur.paragraph().eraseChar(cur.pos(), b.params().trackChanges);
        if (!plist.empty()) {
                // ERT paragraphs have the Language latex_language.
@@ -1227,39 +1258,8 @@ bool Text::dissolveInset(Cursor & cur)
 void Text::getWord(CursorSlice & from, CursorSlice & to,
        word_location const loc) const
 {
-       Paragraph const & from_par = pars_[from.pit()];
-       switch (loc) {
-       case WHOLE_WORD_STRICT:
-               if (from.pos() == 0 || from.pos() == from_par.size()
-                   || !from_par.isLetter(from.pos())
-                   || !from_par.isLetter(from.pos() - 1)) {
-                       to = from;
-                       return;
-               }
-               // no break here, we go to the next
-
-       case WHOLE_WORD:
-               // If we are already at the beginning of a word, do nothing
-               if (!from.pos() || !from_par.isLetter(from.pos() - 1))
-                       break;
-               // no break here, we go to the next
-
-       case PREVIOUS_WORD:
-               // always move the cursor to the beginning of previous word
-               while (from.pos() && from_par.isLetter(from.pos() - 1))
-                       --from.pos();
-               break;
-       case NEXT_WORD:
-               LYXERR0("Text::getWord: NEXT_WORD not implemented yet");
-               break;
-       case PARTIAL_WORD:
-               // no need to move the 'from' cursor
-               break;
-       }
        to = from;
-       Paragraph const & to_par = pars_[to.pit()];
-       while (to.pos() < to_par.size() && to_par.isLetter(to.pos()))
-               ++to.pos();
+       pars_[to.pit()].locateWord(from.pos(), to.pos(), loc);
 }
 
 
@@ -1281,6 +1281,7 @@ bool Text::read(Buffer const & buf, Lexer & lex,
                ErrorList & errorList, InsetText * insetPtr)
 {
        depth_type depth = 0;
+       bool res = true;
 
        while (lex.isOK()) {
                lex.nextToken();
@@ -1298,8 +1299,10 @@ bool Text::read(Buffer const & buf, Lexer & lex,
                if (token == "\\begin_body")
                        continue;
 
-               if (token == "\\end_document")
-                       return false;
+               if (token == "\\end_document") {
+                       res = false;
+                       break;
+               }
 
                if (token == "\\begin_layout") {
                        lex.pushToken(token);
@@ -1317,7 +1320,7 @@ bool Text::read(Buffer const & buf, Lexer & lex,
                        // register the words in the global word list
                        CursorSlice sl = CursorSlice(*insetPtr);
                        sl.pit() = pars_.size() - 1;
-                       pars_.back().updateWords(sl);
+                       pars_.back().updateWords();
                } else if (token == "\\begin_deeper") {
                        ++depth;
                } else if (token == "\\end_deeper") {
@@ -1329,14 +1332,26 @@ bool Text::read(Buffer const & buf, Lexer & lex,
                        LYXERR0("Handling unknown body token: `" << token << '\'');
                }
        }
-       return true;
+
+       // avoid a crash on weird documents (bug 4859)
+       if (pars_.empty()) {
+               Paragraph par;
+               par.setInsetOwner(insetPtr);
+               par.params().depth(depth);
+               par.setFont(0, Font(inherit_font, 
+                                   buf.params().language));
+               par.setPlainOrDefaultLayout(buf.params().documentClass());
+               pars_.push_back(par);
+       }
+       
+       return res;
 }
 
 // Returns the current font and depth as a message.
 docstring Text::currentState(Cursor const & cur) const
 {
        LASSERT(this == cur.text(), /**/);
-       Buffer & buf = cur.buffer();
+       Buffer & buf = *cur.buffer();
        Paragraph const & par = cur.paragraph();
        odocstringstream os;
 
@@ -1542,15 +1557,15 @@ void Text::charsTranspose(Cursor & cur)
        // Store the characters to be transposed (including font information).
        char_type const char1 = par.getChar(pos1);
        Font const font1 =
-               par.getFontSettings(cur.buffer().params(), pos1);
+               par.getFontSettings(cur.buffer()->params(), pos1);
 
        char_type const char2 = par.getChar(pos2);
        Font const font2 =
-               par.getFontSettings(cur.buffer().params(), pos2);
+               par.getFontSettings(cur.buffer()->params(), pos2);
 
        // And finally, we are ready to perform the transposition.
        // Track the changes if Change Tracking is enabled.
-       bool const trackChanges = cur.buffer().params().trackChanges;
+       bool const trackChanges = cur.buffer()->params().trackChanges;
 
        cur.recordUndo();