]> git.lyx.org Git - lyx.git/blob - src/lyxfind.C
Edwins f&r GUII patch with a small fix.
[lyx.git] / src / lyxfind.C
1 #include <config.h>
2
3 #ifdef __GNUG__
4 #pragma implementation
5 #endif
6
7 #include "lyxtext.h"
8 #include "lyxfind.h"
9 #include "LyXView.h"
10 #include "minibuffer.h"
11 #include "lyx_gui_misc.h"
12 #include "support/textutils.h"
13 #include "support/lstrings.h"
14 #include "BufferView.h"
15 #include "buffer.h"
16
17 int LyXReplace(BufferView * bv,
18                 string const & searchstr,
19                 string const & replacestr,
20                 bool const & casesens,
21                 bool const & matchwrd,
22                 bool const & forward,
23                 bool const & replaceall=false)
24 {
25    int replace_count = 0;
26  
27    if (!bv->available() || bv->buffer()->isReadonly()) 
28      return replace_count;
29    
30    // CutSelection cannot cut a single space, so we have to stop
31    // in order to avoid endless loop :-(
32    if (searchstr.length() == 0
33        || (searchstr.length() == 1 && searchstr[0] == ' ')) {
34       WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
35                                 "nor an empty character."));
36       return replace_count;
37    }
38    // now we can start searching for the first 
39    // start at top if replaceall
40    bool fw = forward;
41    if (replaceall) {
42       bv->text->ClearSelection(bv);
43       bv->text->CursorTop(bv);
44       // override search direction because we search top to bottom
45       fw = true;
46    }
47
48    // if nothing selected or selection does not equal search string
49    // search and select next occurance and return if no replaceall
50    if (searchstr!=bv->text->selectionAsString(bv->buffer())) {
51       LyXFind(bv, searchstr, casesens, matchwrd, fw);
52       if (!replaceall)
53         return replace_count;
54    }
55    
56    bool found;
57    do {
58       bv->hideCursor();
59       bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
60       bv->toggleSelection(false);
61       bv->text->ReplaceSelectionWithString(bv, replacestr);
62       bv->text->SetSelectionOverString(bv, replacestr);
63       bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
64       ++replace_count;
65       found = LyXFind(bv, searchstr, casesens, matchwrd, fw);
66    } while (replaceall && found);
67    
68    if (bv->focus())
69      bv->showCursor();
70
71    return replace_count;
72 }
73
74 bool LyXFind(BufferView * bv,
75              string const & searchstr,
76              bool const & casesens,
77              bool const & matchwrd,
78              bool const & forward)
79 {
80    bool found = false;
81    
82    if (!bv->available() || searchstr.empty())
83      return found;
84
85    bv->hideCursor();
86    bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
87    
88    LyXText * ltCur = bv->text;
89    if (ltCur->selection)
90      ltCur->cursor = forward ? ltCur->sel_end_cursor
91      : ltCur->sel_start_cursor;
92
93    if (forward 
94        ? SearchForward(bv, searchstr, casesens, matchwrd)
95        : SearchBackward(bv, searchstr, casesens, matchwrd)) {
96       bv->update(bv->text, BufferView::SELECT|BufferView::FITCUR);
97       bv->toggleSelection();
98       bv->text->ClearSelection(bv);
99       bv->text->SetSelectionOverString(bv, searchstr);
100       bv->toggleSelection(false);
101       found = true;
102    };
103    
104    if (bv->focus())
105      bv->showCursor();
106    
107    return found;
108 }
109
110
111 // returns true if the specified string is at the specified position
112 bool IsStringInText(LyXParagraph * par, LyXParagraph::size_type pos,
113                     string const & str, bool const & cs = true,
114                     bool const & mw = false)
115 {
116         if (!par)
117                 return false;
118    
119         string::size_type size = str.length();
120         LyXParagraph::size_type i = 0;
121         while (((pos + i) < par->Last())
122                && (string::size_type(i) < size)
123                && (cs ? (str[i] == par->GetChar(pos + i))
124                    : (toupper(str[i]) == toupper(par->GetChar(pos + i)))))
125         {
126                 ++i;
127         }
128         if (size == string::size_type(i)) {
129           // if necessary, check whether string matches word
130           if (!mw || 
131               (mw && ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
132                       && (pos + size >= par->Last()
133                           || !IsLetterCharOrDigit(par->GetChar(pos + size))))
134                )
135               )
136             return true;
137         }
138         return false;
139 }
140
141 // forward search:
142 // if the string can be found: return true and set the cursor to
143 // the new position, cs = casesensitive, mw = matchword
144 bool SearchForward(BufferView * bv, string const & str,
145                    bool const & cs = true, bool const & mw = false)
146 {
147         LyXParagraph * par = bv->text->cursor.par();
148         LyXParagraph::size_type pos = bv->text->cursor.pos();
149    
150         while (par && !IsStringInText(par, pos, str, cs, mw)) {
151                 if (pos < par->Last() - 1)
152                         ++pos;
153                 else {
154                         pos = 0;
155                         par = par->Next();
156                 }
157         }
158         if (par) {
159                 bv->text->SetCursor(bv, par, pos);
160                 return true;
161         }
162         else
163                 return false;
164 }
165
166
167 // backward search:
168 // if the string can be found: return true and set the cursor to
169 // the new position, cs = casesensitive, mw = matchword
170 bool SearchBackward(BufferView * bv, string const & str,
171                     bool const & cs = true, bool const & mw = false)
172 {
173         LyXParagraph * par = bv->text->cursor.par();
174         LyXParagraph::size_type pos = bv->text->cursor.pos();
175
176         do {
177                 if (pos > 0)
178                         --pos;
179                 else {
180                         // We skip empty paragraphs (Asger)
181                         do {
182                                 par = par->Previous();
183                                 if (par)
184                                         pos = par->Last() - 1;
185                         } while (par && pos < 0);
186                 }
187         } while (par && !IsStringInText(par, pos, str, cs, mw));
188   
189         if (par) {
190                 bv->text->SetCursor(bv, par, pos);
191                 return true;
192         } else
193                 return false;
194 }
195