]> git.lyx.org Git - lyx.git/blobdiff - src/lyxfind.C
docbook:
[lyx.git] / src / lyxfind.C
index 21d834eab1a40ecc87c3d0f7274166a7ef55eafc..fa6acb468fb2962dacf05f498e971a09e53ed288 100644 (file)
 #include "lyxtext.h"
 #include "lyxfind.h"
 #include "LyXView.h"
-#include "lyx_gui_misc.h"
+#include "frontends/Alert.h"
 #include "support/textutils.h"
 #include "support/lstrings.h"
 #include "BufferView.h"
 #include "buffer.h"
+#include "debug.h"
 #include "gettext.h"
 
+using lyx::pos_type;
+
+
+///
+// locally used enum
+///
+enum SearchResult {
+       //
+       SR_NOT_FOUND = 0,
+       //
+       SR_FOUND,
+       //
+       SR_FOUND_NOUPDATE
+};
+
+
+/// returns true if the specified string is at the specified  position
+bool IsStringInText(Paragraph * par, pos_type pos,
+                   string const & str, bool const & = true,
+                   bool const & = false);
+
+/// if the string is found: return true and set the cursor to the new position
+SearchResult SearchForward(BufferView *, LyXText * text, string const & str,
+                          bool const & = true, bool const & = false);
+///
+SearchResult SearchBackward(BufferView *, LyXText * text, string const & str,
+                           bool const & = true, bool const & = false);
+
+
 int LyXReplace(BufferView * bv,
-              string const & searchstr,
-              string const & replacestr,
-              bool const & casesens,
-              bool const & matchwrd,
-              bool const & forward,
-              bool const & replaceall)
+              string const & searchstr, string const & replacestr,
+              bool forward, bool casesens, bool matchwrd, bool replaceall,
+              bool once)
 {
-   int replace_count = 0;
-   if (!bv->available() || bv->buffer()->isReadonly()) 
-     return replace_count;
-   
-   // CutSelection cannot cut a single space, so we have to stop
-   // in order to avoid endless loop :-(
-   if (searchstr.length() == 0
-       || (searchstr.length() == 1 && searchstr[0] == ' ')) {
-      WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
-                               "nor an empty character."));
-      return replace_count;
-   }
-   // now we can start searching for the first 
-   // start at top if replaceall
-   bool fw = forward;
-   if (replaceall) {
-      bv->text->ClearSelection(bv);
-      bv->text->CursorTop(bv);
-      // override search direction because we search top to bottom
-      fw = true;
-   }
-
-   // if nothing selected or selection does not equal search string
-   // search and select next occurance and return if no replaceall
-   if (searchstr!=bv->text->selectionAsString(bv->buffer())) {
-      LyXFind(bv, searchstr, casesens, matchwrd, fw);
-      if (!replaceall)
+       if (!bv->available() || bv->buffer()->isReadonly())
+               return 0;
+
+       // CutSelection cannot cut a single space, so we have to stop
+       // in order to avoid endless loop :-(
+       if (searchstr.length() == 0
+               || (searchstr.length() == 1 && searchstr[0] == ' '))
+       {
+               Alert::alert(_("Sorry!"), _("You cannot replace a single space, "
+                                         "nor an empty character."));
+               return 0;
+       }
+
+       LyXText * text = bv->getLyXText();
+
+       // now we can start searching for the first
+       // start at top if replaceall
+       bool fw = forward;
+       if (replaceall) {
+               text->clearSelection();
+               if (text->inset_owner) {
+                       bv->unlockInset(bv->theLockingInset());
+                       text = bv->text;
+               }
+               text->cursorTop(bv);
+               // override search direction because we search top to bottom
+               fw = true;
+       }
+
+       // if nothing selected or selection does not equal search string
+       // search and select next occurance and return if no replaceall
+       string str1;
+       string str2;
+       if (casesens) {
+               str1 = searchstr;
+               str2 = text->selectionAsString(bv->buffer(), false);
+       } else {
+               str1 = lowercase(searchstr);
+               str2 = lowercase(text->selectionAsString(bv->buffer(), false));
+       }
+       if (str1 != str2) {
+               if (!LyXFind(bv, searchstr, fw, false, casesens, matchwrd) ||
+                       !replaceall)
+               {
+                       return 0;
+               }
+       }
+
+       bool found = false;
+       int replace_count = 0;
+       do {
+               bv->hideCursor();
+               bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
+               bv->toggleSelection(false);
+               bv->getLyXText()->replaceSelectionWithString(bv, replacestr);
+               bv->getLyXText()->setSelectionOverString(bv, replacestr);
+               bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
+               ++replace_count;
+               if (!once)
+                       found = LyXFind(bv, searchstr, fw, false, casesens, matchwrd);
+       } while (!once && replaceall && found);
+
+       if (bv->focus())
+               bv->showCursor();
+
        return replace_count;
-   }
-   
-   bool found;
-   do {
-      bv->hideCursor();
-      bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
-      bv->toggleSelection(false);
-      bv->text->ReplaceSelectionWithString(bv, replacestr);
-      bv->text->SetSelectionOverString(bv, replacestr);
-      bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
-      ++replace_count;
-      found = LyXFind(bv, searchstr, casesens, matchwrd, fw);
-   } while (replaceall && found);
-   
-   if (bv->focus())
-     bv->showCursor();
-
-   return replace_count;
 }
 
 bool LyXFind(BufferView * bv,
-            string const & searchstr,
-            bool const & casesens,
-            bool const & matchwrd,
-            bool const & forward)
+            string const & searchstr, bool forward,
+            bool frominset, bool casesens, bool matchwrd)
 {
-   bool found = false;
-   
-   if (!bv->available() || searchstr.empty())
-     return found;
-
-   bv->hideCursor();
-   bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
-   
-   LyXText * ltCur = bv->text;
-   if (ltCur->selection)
-     ltCur->cursor = forward ? ltCur->sel_end_cursor
-     : ltCur->sel_start_cursor;
-
-   if (forward 
-       ? SearchForward(bv, searchstr, casesens, matchwrd)
-       : SearchBackward(bv, searchstr, casesens, matchwrd)) {
-      bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
-      bv->toggleSelection();
-      bv->text->ClearSelection(bv);
-      bv->text->SetSelectionOverString(bv, searchstr);
-      bv->toggleSelection(false);
-      found = true;
-   };
-   
-   if (bv->focus())
-     bv->showCursor();
-   
-   return found;
+       if (!bv->available() || searchstr.empty())
+               return false;
+
+       LyXText * text = bv->getLyXText();
+
+       bv->hideCursor();
+       bv->update(text, BufferView::SELECT|BufferView::FITCUR);
+
+       if (text->selection.set())
+               text->cursor = forward ?
+                       text->selection.end : text->selection.start;
+
+       SearchResult result = SR_NOT_FOUND;
+
+       if (!frominset && bv->theLockingInset()) {
+               bool found = forward ?
+                       bv->theLockingInset()->searchForward(bv, searchstr, casesens, matchwrd) :
+                       bv->theLockingInset()->searchBackward(bv, searchstr, casesens, matchwrd);
+               if (found)
+                       result = SR_FOUND_NOUPDATE;
+               else {
+                       text = bv->getLyXText();
+                       Paragraph * par = text->cursor.par();
+                       pos_type pos = text->cursor.pos();
+                       if (forward) {
+                               if (pos < par->size() - 1)
+                                       ++pos;
+                               else {
+                                       pos = 0;
+                                       par = par->next();
+                               }
+                               if (par)
+                                       text->setCursor(bv, par, pos);
+                       }
+                       if (par) {
+                               result = forward ?
+                                       SearchForward(bv, text, searchstr, casesens, matchwrd) :
+                                       SearchBackward(bv, text, searchstr, casesens, matchwrd);
+                       }
+               }
+       } else {
+               result = forward ?
+                       SearchForward(bv, text, searchstr, casesens, matchwrd) :
+                       SearchBackward(bv, text, searchstr, casesens, matchwrd);
+       }
+
+       bool found = true;
+       if (result == SR_FOUND) {
+               // the actual text pointer could have changed!
+               bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
+               bv->toggleSelection();
+               bv->getLyXText()->clearSelection();
+               bv->getLyXText()->setSelectionOverString(bv, searchstr);
+               bv->toggleSelection(false);
+               bv->update(bv->getLyXText(), BufferView::SELECT|BufferView::FITCUR);
+       } else if (result == SR_NOT_FOUND)
+               found = false;
+
+       if (bv->focus())
+               bv->showCursor();
+
+       return found;
 }
 
 
 // returns true if the specified string is at the specified position
-bool IsStringInText(LyXParagraph * par, LyXParagraph::size_type pos,
+bool IsStringInText(Paragraph * par, pos_type pos,
                    string const & str, bool const & cs,
                    bool const & mw)
 {
        if (!par)
                return false;
-   
+
        string::size_type size = str.length();
-       LyXParagraph::size_type i = 0;
+       pos_type i = 0;
        while (((pos + i) < par->size())
               && (string::size_type(i) < size)
-              && (cs ? (str[i] == par->GetChar(pos + i))
-                  : (toupper(str[i]) == toupper(par->GetChar(pos + i)))))
+              && (cs ? (str[i] == par->getChar(pos + i))
+                  : (uppercase(str[i]) == uppercase(par->getChar(pos + i)))))
        {
                ++i;
        }
        if (size == string::size_type(i)) {
-         // if necessary, check whether string matches word
-         if (!mw || 
-             (mw && ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
-                     && (pos + size >= par->size()
-                         || !IsLetterCharOrDigit(par->GetChar(pos + size))))
-              )
-             )
-           return true;
+               // if necessary, check whether string matches word
+               if (!mw)
+                       return true;
+               if ((pos <= 0 || !IsLetterCharOrDigit(par->getChar(pos - 1)))
+                       && (pos + pos_type(size) >= par->size()
+                       || !IsLetterCharOrDigit(par->getChar(pos + size)))) {
+                       return true;
+               }
        }
        return false;
 }
@@ -141,42 +219,64 @@ bool IsStringInText(LyXParagraph * par, LyXParagraph::size_type pos,
 // forward search:
 // if the string can be found: return true and set the cursor to
 // the new position, cs = casesensitive, mw = matchword
-bool SearchForward(BufferView * bv, string const & str,
-                  bool const & cs, bool const & mw)
+SearchResult SearchForward(BufferView * bv, LyXText * text, string const & str,
+                          bool const & cs, bool const & mw)
 {
-       LyXParagraph * par = bv->text->cursor.par();
-       LyXParagraph::size_type pos = bv->text->cursor.pos();
-   
+       Paragraph * par = text->cursor.par();
+       pos_type pos = text->cursor.pos();
+       Paragraph * prev_par = par;
+       UpdatableInset * inset;
+
        while (par && !IsStringInText(par, pos, str, cs, mw)) {
-               if (pos < par->size() - 1)
-                       ++pos;
-               else {
-                       pos = 0;
+               if (par->isInset(pos) &&
+                       (inset = (UpdatableInset *)par->getInset(pos)) &&
+                       (inset->isTextInset()))
+               {
+                       // lock the inset!
+                       text->setCursor(bv, par, pos);
+                       inset->edit(bv);
+                       if (inset->searchForward(bv, str, cs, mw))
+                               return SR_FOUND_NOUPDATE;
+                       text = bv->getLyXText();
+               }
+
+               ++pos;
+
+               if (pos >= par->size()) {
+                       prev_par = par;
                        par = par->next();
+                       pos = 0;
                }
        }
+
        if (par) {
-               bv->text->SetCursor(bv, par, pos);
-               return true;
+               text->setCursor(bv, par, pos);
+               return SR_FOUND;
+       } else {
+               // make sure we end up at the end of the text,
+               // not the start point of the last search
+               text->setCursor(bv, prev_par, prev_par->size());
+               return SR_NOT_FOUND;
        }
-       else
-               return false;
 }
 
 
 // backward search:
 // if the string can be found: return true and set the cursor to
 // the new position, cs = casesensitive, mw = matchword
-bool SearchBackward(BufferView * bv, string const & str,
-                   bool const & cs, bool const & mw)
+SearchResult SearchBackward(BufferView * bv, LyXText * text,
+                           string const & str,
+                           bool const & cs, bool const & mw)
 {
-       LyXParagraph * par = bv->text->cursor.par();
-       LyXParagraph::size_type pos = bv->text->cursor.pos();
+       Paragraph * par = text->cursor.par();
+       pos_type pos = text->cursor.pos();
+       Paragraph * prev_par = par;
 
        do {
                if (pos > 0)
                        --pos;
                else {
+                       prev_par = par;
                        // We skip empty paragraphs (Asger)
                        do {
                                par = par->previous();
@@ -184,12 +284,26 @@ bool SearchBackward(BufferView * bv, string const & str,
                                        pos = par->size() - 1;
                        } while (par && pos < 0);
                }
+               UpdatableInset * inset;
+               if (par && par->isInset(pos) &&
+                       (inset = (UpdatableInset *)par->getInset(pos)) &&
+                       (inset->isTextInset()))
+               {
+                       // lock the inset!
+                       text->setCursor(bv, par, pos);
+                       inset->edit(bv, false);
+                       if (inset->searchBackward(bv, str, cs, mw))
+                               return SR_FOUND_NOUPDATE;
+                       text = bv->getLyXText();
+               }
        } while (par && !IsStringInText(par, pos, str, cs, mw));
-  
+
        if (par) {
-               bv->text->SetCursor(bv, par, pos);
-               return true;
-       } else
-               return false;
+               text->setCursor(bv, par, pos);
+               return SR_FOUND;
+       } else {
+               // go to the last part of the unsuccessful search
+               text->setCursor(bv, prev_par, 0);
+               return SR_NOT_FOUND;
+       }
 }
-