1 /********************************************************************************
2 * *
3 * T e x t R e p l a c e D i a l o g *
4 * *
5 *********************************************************************************
6 * Copyright (C) 2000,2020 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as published by *
10 * the Free Software Foundation; either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/> *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "fxkeys.h"
26 #include "FXArray.h"
27 #include "FXHash.h"
28 #include "FXMutex.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXStringDictionary.h"
35 #include "FXSettings.h"
36 #include "FXRegistry.h"
37 #include "FXAccelTable.h"
38 #include "FXFont.h"
39 #include "FXEvent.h"
40 #include "FXWindow.h"
41 #include "FXApp.h"
42 #include "FXGIFIcon.h"
43 #include "FXWindow.h"
44 #include "FXFrame.h"
45 #include "FXArrowButton.h"
46 #include "FXSeparator.h"
47 #include "FXLabel.h"
48 #include "FXButton.h"
49 #include "FXCheckButton.h"
50 #include "FXRadioButton.h"
51 #include "FXPacker.h"
52 #include "FXScrollBar.h"
53 #include "FXTextField.h"
54 #include "FXVerticalFrame.h"
55 #include "FXHorizontalFrame.h"
56 #include "FXReplaceDialog.h"
57
58
59
60 /*
61 Notes:
62
63 - Keep history of strings previously searched, and allow up/down arrows
64 to "scroll" back to this history.
65 - Simplified: just keep dialog open until explicitly closed. This allows
66 you to hammer return repeatedly to search and replace.
67 - We think ^N and ^P is more natural to scroll through history; then we
68 can use the arrows to search up and down in the content.
69 */
70
71 // Padding for buttons
72 #define HORZ_PAD 12
73 #define VERT_PAD 2
74
75 using namespace FX;
76
77 /*******************************************************************************/
78
79 namespace FX {
80
81
82 // Search and replace dialog registry section name
83 const FXchar FXReplaceDialog::sectionName[]="SearchReplace";
84
85 // Value key names
86 static const FXchar skey[20][3]={"SA","SB","SC","SD","SE","SF","SG","SH","SI","SJ","SK","SL","SM","SN","SO","SP","SQ","SR","SS","ST"};
87 static const FXchar rkey[20][3]={"RA","RB","RC","RD","RE","RF","RG","RH","RI","RJ","RK","RL","RM","RN","RO","RP","RQ","RR","RS","RT"};
88 static const FXchar mkey[20][3]={"MA","MB","MC","MD","ME","MF","MG","MH","MI","MJ","MK","ML","MM","MN","MO","MP","MQ","MR","MS","MT"};
89
90
91 // Map
92 FXDEFMAP(FXReplaceDialog) FXReplaceDialogMap[]={
93 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_SEARCH,FXReplaceDialog::onUpdSearch),
94 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_SEARCH,FXReplaceDialog::onCmdSearch),
95 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_REPLACE,FXReplaceDialog::onUpdSearch),
96 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REPLACE,FXReplaceDialog::onCmdReplace),
97 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_SEARCH_TEXT,FXReplaceDialog::onCmdSearch),
98 FXMAPFUNC(SEL_KEYPRESS,FXReplaceDialog::ID_SEARCH_TEXT,FXReplaceDialog::onSearchKey),
99 FXMAPFUNC(SEL_MOUSEWHEEL,FXReplaceDialog::ID_SEARCH_TEXT,FXReplaceDialog::onWheelSearch),
100 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REPLACE_TEXT,FXReplaceDialog::onCmdReplace),
101 FXMAPFUNC(SEL_KEYPRESS,FXReplaceDialog::ID_REPLACE_TEXT,FXReplaceDialog::onReplaceKey),
102 FXMAPFUNC(SEL_MOUSEWHEEL,FXReplaceDialog::ID_REPLACE_TEXT,FXReplaceDialog::onWheelReplace),
103 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_REPLACE_SEL,FXReplaceDialog::onUpdSearch),
104 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REPLACE_SEL,FXReplaceDialog::onCmdReplaceSel),
105 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_REPLACE_ALL,FXReplaceDialog::onUpdSearch),
106 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REPLACE_ALL,FXReplaceDialog::onCmdReplaceAll),
107 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_DIR,FXReplaceDialog::onUpdDir),
108 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_DIR,FXReplaceDialog::onCmdDir),
109 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_WRAP,FXReplaceDialog::onUpdWrap),
110 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_WRAP,FXReplaceDialog::onCmdWrap),
111 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_CASE,FXReplaceDialog::onUpdCase),
112 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_CASE,FXReplaceDialog::onCmdCase),
113 FXMAPFUNC(SEL_UPDATE,FXReplaceDialog::ID_REGEX,FXReplaceDialog::onUpdRegex),
114 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REGEX,FXReplaceDialog::onCmdRegex),
115 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_SEARCH_UP,FXReplaceDialog::onCmdSearchHistUp),
116 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_SEARCH_DN,FXReplaceDialog::onCmdSearchHistDn),
117 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REPLACE_UP,FXReplaceDialog::onCmdReplaceHistUp),
118 FXMAPFUNC(SEL_COMMAND,FXReplaceDialog::ID_REPLACE_DN,FXReplaceDialog::onCmdReplaceHistDn),
119 };
120
121
122 // Object implementation
FXIMPLEMENT(FXReplaceDialog,FXDialogBox,FXReplaceDialogMap,ARRAYNUMBER (FXReplaceDialogMap))123 FXIMPLEMENT(FXReplaceDialog,FXDialogBox,FXReplaceDialogMap,ARRAYNUMBER(FXReplaceDialogMap))
124
125
126 // Search and Replace Dialog
127 FXReplaceDialog::FXReplaceDialog(FXWindow* own,const FXString& caption,FXIcon* icn,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXDialogBox(own,caption,opts|DECOR_TITLE|DECOR_BORDER|DECOR_RESIZE,x,y,w,h,10,10,10,10, 10,10){
128 FXHorizontalFrame* buttons=new FXHorizontalFrame(this,LAYOUT_SIDE_BOTTOM|LAYOUT_RIGHT,0,0,0,0,0,0,0,0);
129 search=new FXButton(buttons,tr("&Search\tSearch\tSearch for pattern."),NULL,this,ID_SEARCH,BUTTON_INITIAL|BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_Y,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
130 replace=new FXButton(buttons,tr("&Replace\tReplace\tSearch and replace pattern."),NULL,this,ID_REPLACE,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_Y,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
131 replacesel=new FXButton(buttons,tr("Replace Sel\tReplace in selection\tReplace all in selection."),NULL,this,ID_REPLACE_SEL,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_Y,0,0,0,0,6,6,VERT_PAD,VERT_PAD);
132 replaceall=new FXButton(buttons,tr("Replace All\tReplace all\tReplace all."),NULL,this,ID_REPLACE_ALL,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_CENTER_Y,0,0,0,0,6,6,VERT_PAD,VERT_PAD);
133 cancel=new FXButton(buttons,tr("&Close"),NULL,this,ID_CANCEL,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_Y,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
134 new FXHorizontalSeparator(this,SEPARATOR_GROOVE|LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X);
135 FXHorizontalFrame* toppart=new FXHorizontalFrame(this,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|LAYOUT_CENTER_Y,0,0,0,0, 0,0,0,0, 10,10);
136 new FXLabel(toppart,FXString::null,icn,ICON_BEFORE_TEXT|JUSTIFY_CENTER_X|JUSTIFY_CENTER_Y|LAYOUT_FILL_Y|LAYOUT_FILL_X);
137 FXVerticalFrame* entry=new FXVerticalFrame(toppart,LAYOUT_FILL_X|LAYOUT_CENTER_Y,0,0,0,0, 0,0,0,0);
138 searchlabel=new FXLabel(entry,tr("Search &For:"),NULL,JUSTIFY_LEFT|ICON_BEFORE_TEXT|LAYOUT_TOP|LAYOUT_LEFT|LAYOUT_FILL_X);
139 searchbox=new FXHorizontalFrame(entry,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_CENTER_Y,0,0,0,0, 0,0,0,0, 0,0);
140 searchtext=new FXTextField(searchbox,26,this,ID_SEARCH_TEXT,TEXTFIELD_ENTER_ONLY|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,4,4,2,2);
141 FXVerticalFrame* searcharrows=new FXVerticalFrame(searchbox,LAYOUT_RIGHT|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0, 0,0);
142 FXArrowButton* ar1=new FXArrowButton(searcharrows,this,ID_SEARCH_UP,FRAME_RAISED|FRAME_THICK|ARROW_UP|ARROW_REPEAT|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH, 0,0,16,0, 1,1,1,1);
143 FXArrowButton* ar2=new FXArrowButton(searcharrows,this,ID_SEARCH_DN,FRAME_RAISED|FRAME_THICK|ARROW_DOWN|ARROW_REPEAT|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH, 0,0,16,0, 1,1,1,1);
144 ar1->setArrowSize(3);
145 ar2->setArrowSize(3);
146 replacelabel=new FXLabel(entry,tr("Re&place With:"),NULL,LAYOUT_LEFT);
147 replacebox=new FXHorizontalFrame(entry,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_CENTER_Y,0,0,0,0, 0,0,0,0, 0,0);
148 replacetext=new FXTextField(replacebox,26,this,ID_REPLACE_TEXT,TEXTFIELD_ENTER_ONLY|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,4,4,2,2);
149 FXVerticalFrame* replacearrows=new FXVerticalFrame(replacebox,LAYOUT_RIGHT|LAYOUT_FILL_Y,0,0,0,0, 0,0,0,0, 0,0);
150 FXArrowButton* ar3=new FXArrowButton(replacearrows,this,ID_REPLACE_UP,FRAME_RAISED|FRAME_THICK|ARROW_UP|ARROW_REPEAT|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH, 0,0,16,0, 1,1,1,1);
151 FXArrowButton* ar4=new FXArrowButton(replacearrows,this,ID_REPLACE_DN,FRAME_RAISED|FRAME_THICK|ARROW_DOWN|ARROW_REPEAT|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH, 0,0,16,0, 1,1,1,1);
152 ar3->setArrowSize(3);
153 ar4->setArrowSize(3);
154 FXHorizontalFrame* options1=new FXHorizontalFrame(entry,LAYOUT_FILL_X,0,0,0,0, 0,0,0,0);
155 new FXCheckButton(options1,tr("&Expression\tRegular Expression\tPerform regular-expression match."),this,ID_REGEX,ICON_BEFORE_TEXT|LAYOUT_CENTER_X);
156 new FXCheckButton(options1,tr("&Ignore Case\tCase Insensitive\tPerform case-insentive match."),this,ID_CASE,ICON_BEFORE_TEXT|LAYOUT_CENTER_X);
157 new FXCheckButton(options1,tr("&Wrap\tWrap Around\tWrap around when searching."),this,ID_WRAP,ICON_BEFORE_TEXT|LAYOUT_CENTER_X);
158 new FXCheckButton(options1,tr("&Backward\tSearch Direction\tChange search direction."),this,ID_DIR,ICON_BEFORE_TEXT|LAYOUT_CENTER_X);
159 replacetext->setHelpText(tr("Text to replace with."));
160 searchmode=SEARCH_EXACT|SEARCH_FORWARD|SEARCH_WRAP;
161 loadHistory();
162 }
163
164
165 // Set text or pattern to search for
setSearchText(const FXString & text)166 void FXReplaceDialog::setSearchText(const FXString& text){
167 searchtext->setText(text);
168 }
169
170
171 // Return text or pattern the user has entered
getSearchText() const172 FXString FXReplaceDialog::getSearchText() const {
173 return searchtext->getText();
174 }
175
176
177 // Set text or pattern to search with
setReplaceText(const FXString & text)178 void FXReplaceDialog::setReplaceText(const FXString& text){
179 replacetext->setText(text);
180 }
181
182
183 // Return text or pattern the user has entered
getReplaceText() const184 FXString FXReplaceDialog::getReplaceText() const {
185 return replacetext->getText();
186 }
187
188
189 // Change search text color
setSearchTextColor(FXColor clr)190 void FXReplaceDialog::setSearchTextColor(FXColor clr){
191 searchtext->setBackColor(clr);
192 }
193
194
195 // Return search text color
getSearchTextColor() const196 FXColor FXReplaceDialog::getSearchTextColor() const {
197 return searchtext->getBackColor();
198 }
199
200
201 // Change replace text color
setReplaceTextColor(FXColor clr)202 void FXReplaceDialog::setReplaceTextColor(FXColor clr){
203 replacetext->setBackColor(clr);
204 }
205
206
207 // Return replace text color
getReplaceTextColor() const208 FXColor FXReplaceDialog::getReplaceTextColor() const {
209 return replacetext->getBackColor();
210 }
211
212
213 // Append entry
appendHistory(const FXString & pat,const FXString & sub,FXuint opt)214 void FXReplaceDialog::appendHistory(const FXString& pat,const FXString& sub,FXuint opt){
215 if(!pat.empty()){
216 if(searchHistory[0]!=pat){
217 for(FXuval i=ARRAYNUMBER(searchHistory)-1; i>0; --i){
218 swap(searchHistory[i],searchHistory[i-1]);
219 swap(replacHistory[i],replacHistory[i-1]);
220 swap(optionHistory[i],optionHistory[i-1]);
221 }
222 }
223 searchHistory[0]=pat;
224 replacHistory[0]=sub;
225 optionHistory[0]=opt;
226 activeHistory=-1;
227 }
228 }
229
230
231 // Load registy
loadHistory()232 void FXReplaceDialog::loadHistory(){
233 for(FXuval i=0; i<ARRAYNUMBER(searchHistory); ++i){
234 searchHistory[i]=getApp()->reg().readStringEntry(sectionName,skey[i],FXString::null);
235 if(searchHistory[i].empty()) break;
236 replacHistory[i]=getApp()->reg().readStringEntry(sectionName,rkey[i],FXString::null);
237 optionHistory[i]=getApp()->reg().readUIntEntry(sectionName,mkey[i],SEARCH_EXACT|SEARCH_FORWARD|SEARCH_WRAP);
238 }
239 activeHistory=-1;
240 }
241
242
243 // Save registry
saveHistory()244 void FXReplaceDialog::saveHistory(){
245 for(FXuval i=0; i<ARRAYNUMBER(searchHistory); ++i){
246 if(!searchHistory[i].empty()){
247 getApp()->reg().writeStringEntry(sectionName,skey[i],searchHistory[i].text());
248 getApp()->reg().writeStringEntry(sectionName,rkey[i],replacHistory[i].text());
249 getApp()->reg().writeUIntEntry(sectionName,mkey[i],optionHistory[i]);
250 }
251 else{
252 getApp()->reg().deleteEntry(sectionName,skey[i]);
253 getApp()->reg().deleteEntry(sectionName,rkey[i]);
254 getApp()->reg().deleteEntry(sectionName,mkey[i]);
255 }
256 }
257 }
258
259
260 // Return with code for search, and close dialog
onCmdSearch(FXObject *,FXSelector,void *)261 long FXReplaceDialog::onCmdSearch(FXObject*,FXSelector,void*){
262 appendHistory(getSearchText(),getReplaceText(),getSearchMode());
263 getApp()->stopModal(this,SEARCH);
264 return 1;
265 }
266
267
268 // Grey out buttons if no search text
onUpdSearch(FXObject * sender,FXSelector,void *)269 long FXReplaceDialog::onUpdSearch(FXObject* sender,FXSelector,void*){
270 sender->handle(this,searchtext->getText().empty()?FXSEL(SEL_COMMAND,ID_DISABLE):FXSEL(SEL_COMMAND,ID_ENABLE),NULL);
271 return 1;
272 }
273
274
275 // Return with code for replace, and close dialog
onCmdReplace(FXObject *,FXSelector,void *)276 long FXReplaceDialog::onCmdReplace(FXObject*,FXSelector,void*){
277 appendHistory(getSearchText(),getReplaceText(),getSearchMode());
278 getApp()->stopModal(this,REPLACE);
279 return 1;
280 }
281
282
283 // Return with code for replace-in-selection, and close dialog
onCmdReplaceSel(FXObject *,FXSelector,void *)284 long FXReplaceDialog::onCmdReplaceSel(FXObject*,FXSelector,void*){
285 appendHistory(getSearchText(),getReplaceText(),getSearchMode());
286 getApp()->stopModal(this,REPLACE_SEL);
287 return 1;
288 }
289
290
291 // Return with code for replace-all, and close dialog
onCmdReplaceAll(FXObject *,FXSelector,void *)292 long FXReplaceDialog::onCmdReplaceAll(FXObject*,FXSelector,void*){
293 appendHistory(getSearchText(),getReplaceText(),getSearchMode());
294 getApp()->stopModal(this,REPLACE_ALL);
295 return 1;
296 }
297
298
299 // Change search direction
onCmdDir(FXObject *,FXSelector,void *)300 long FXReplaceDialog::onCmdDir(FXObject*,FXSelector,void*){
301 searchmode^=(SEARCH_FORWARD|SEARCH_BACKWARD);
302 return 1;
303 }
304
305
306 // Update search direction
onUpdDir(FXObject * sender,FXSelector,void *)307 long FXReplaceDialog::onUpdDir(FXObject* sender,FXSelector,void*){
308 sender->handle(this,(searchmode&SEARCH_BACKWARD)?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
309 return 1;
310 }
311
312
313 // Change wrap mode
onCmdWrap(FXObject *,FXSelector,void *)314 long FXReplaceDialog::onCmdWrap(FXObject*,FXSelector,void*){
315 searchmode^=SEARCH_WRAP;
316 return 1;
317 }
318
319
320 // Update wrap mode
onUpdWrap(FXObject * sender,FXSelector,void *)321 long FXReplaceDialog::onUpdWrap(FXObject* sender,FXSelector,void*){
322 sender->handle(this,(searchmode&SEARCH_WRAP)?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
323 return 1;
324 }
325
326
327 // Change case sensitive mode
onCmdCase(FXObject *,FXSelector,void *)328 long FXReplaceDialog::onCmdCase(FXObject*,FXSelector,void*){
329 searchmode^=SEARCH_IGNORECASE;
330 return 1;
331 }
332
333
334 // Update case sensitive mode
onUpdCase(FXObject * sender,FXSelector,void *)335 long FXReplaceDialog::onUpdCase(FXObject* sender,FXSelector,void*){
336 sender->handle(this,(searchmode&SEARCH_IGNORECASE)?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
337 return 1;
338 }
339
340
341 // Change search mode
onCmdRegex(FXObject *,FXSelector,void *)342 long FXReplaceDialog::onCmdRegex(FXObject*,FXSelector,void*){
343 searchmode^=SEARCH_REGEX;
344 return 1;
345 }
346
347
348 // Update search mode
onUpdRegex(FXObject * sender,FXSelector,void *)349 long FXReplaceDialog::onUpdRegex(FXObject* sender,FXSelector,void*){
350 sender->handle(this,(searchmode&SEARCH_REGEX)?FXSEL(SEL_COMMAND,ID_CHECK):FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
351 return 1;
352 }
353
354
355 // Scroll back in search history
onCmdSearchHistUp(FXObject *,FXSelector,void *)356 long FXReplaceDialog::onCmdSearchHistUp(FXObject*,FXSelector,void*){
357 if(activeHistory+1<(FXint)ARRAYNUMBER(searchHistory) && !searchHistory[activeHistory+1].empty()){
358 activeHistory++;
359 FXASSERT(0<=activeHistory && activeHistory<(FXint)ARRAYNUMBER(searchHistory));
360 setSearchText(searchHistory[activeHistory]);
361 setReplaceText(replacHistory[activeHistory]);
362 setSearchMode(optionHistory[activeHistory]);
363 }
364 else{
365 getApp()->beep();
366 }
367 return 1;
368 }
369
370
371 // Scroll forward in search history
onCmdSearchHistDn(FXObject *,FXSelector,void *)372 long FXReplaceDialog::onCmdSearchHistDn(FXObject*,FXSelector,void*){
373 if(0<activeHistory){
374 activeHistory--;
375 FXASSERT(0<=activeHistory && activeHistory<(FXint)ARRAYNUMBER(searchHistory));
376 setSearchText(searchHistory[activeHistory]);
377 setReplaceText(replacHistory[activeHistory]);
378 setSearchMode(optionHistory[activeHistory]);
379 }
380 else{
381 activeHistory=-1;
382 setSearchText(FXString::null);
383 setReplaceText(FXString::null);
384 setSearchMode(SEARCH_EXACT|SEARCH_FORWARD|SEARCH_WRAP);
385 }
386 return 1;
387 }
388
389
390 // Scroll back in replace history
onCmdReplaceHistUp(FXObject *,FXSelector,void *)391 long FXReplaceDialog::onCmdReplaceHistUp(FXObject*,FXSelector,void*){
392 if(activeHistory+1<(FXint)ARRAYNUMBER(searchHistory) && !searchHistory[activeHistory+1].empty()){
393 activeHistory++;
394 FXASSERT(0<=activeHistory && activeHistory<(FXint)ARRAYNUMBER(searchHistory));
395 setReplaceText(replacHistory[activeHistory]);
396 }
397 else{
398 getApp()->beep();
399 }
400 return 1;
401 }
402
403
404 // Scroll back in replace history
onCmdReplaceHistDn(FXObject *,FXSelector,void *)405 long FXReplaceDialog::onCmdReplaceHistDn(FXObject*,FXSelector,void*){
406 if(0<activeHistory){
407 activeHistory--;
408 FXASSERT(0<=activeHistory && activeHistory<(FXint)ARRAYNUMBER(searchHistory));
409 setReplaceText(replacHistory[activeHistory]);
410 }
411 else{
412 activeHistory=-1;
413 setReplaceText(FXString::null);
414 }
415 return 1;
416 }
417
418
419 // Keyboard press in search text field
onSearchKey(FXObject *,FXSelector,void * ptr)420 long FXReplaceDialog::onSearchKey(FXObject*,FXSelector,void* ptr){
421 setSearchTextColor(getApp()->getBackColor());
422 setReplaceTextColor(getApp()->getBackColor());
423 switch(((FXEvent*)ptr)->code){
424 case KEY_Page_Up:
425 searchmode=(searchmode&~SEARCH_FORWARD)|SEARCH_BACKWARD;
426 return onCmdSearch(this,FXSEL(SEL_COMMAND,ID_SEARCH),NULL);
427 case KEY_Page_Down:
428 searchmode=(searchmode&~SEARCH_BACKWARD)|SEARCH_FORWARD;
429 return onCmdSearch(this,FXSEL(SEL_COMMAND,ID_SEARCH),NULL);
430 case KEY_Up:
431 case KEY_KP_Up:
432 return onCmdSearchHistUp(this,FXSEL(SEL_COMMAND,ID_SEARCH_UP),NULL);
433 case KEY_Down:
434 case KEY_KP_Down:
435 return onCmdSearchHistDn(this,FXSEL(SEL_COMMAND,ID_SEARCH_DN),NULL);
436 case KEY_i:
437 if(!(((FXEvent*)ptr)->state&CONTROLMASK)) return 0;
438 searchmode^=SEARCH_IGNORECASE;
439 return 1;
440 case KEY_e:
441 if(!(((FXEvent*)ptr)->state&CONTROLMASK)) return 0;
442 searchmode^=SEARCH_REGEX;
443 return 1;
444 case KEY_w:
445 if(!(((FXEvent*)ptr)->state&CONTROLMASK)) return 0;
446 searchmode^=SEARCH_WRAP;
447 return 1;
448 case KEY_b:
449 if(!(((FXEvent*)ptr)->state&CONTROLMASK)) return 0;
450 searchmode^=(SEARCH_FORWARD|SEARCH_BACKWARD);
451 return 1;
452 }
453 return 0;
454 }
455
456
457 // Keyboard press in replace text field
onReplaceKey(FXObject *,FXSelector,void * ptr)458 long FXReplaceDialog::onReplaceKey(FXObject*,FXSelector,void* ptr){
459 setReplaceTextColor(getApp()->getBackColor());
460 switch(((FXEvent*)ptr)->code){
461 case KEY_Up:
462 case KEY_KP_Up:
463 return onCmdReplaceHistUp(this,FXSEL(SEL_COMMAND,ID_REPLACE_UP),NULL);
464 case KEY_Down:
465 case KEY_KP_Down:
466 return onCmdReplaceHistDn(this,FXSEL(SEL_COMMAND,ID_REPLACE_DN),NULL);
467 }
468 return 0;
469 }
470
471
472 // Wheeled in search text
onWheelSearch(FXObject *,FXSelector,void * ptr)473 long FXReplaceDialog::onWheelSearch(FXObject*,FXSelector,void* ptr){
474 if(((FXEvent*)ptr)->code>0){
475 return onCmdSearchHistUp(this,FXSEL(SEL_COMMAND,ID_SEARCH_UP),NULL);
476 }
477 if(((FXEvent*)ptr)->code<0){
478 return onCmdSearchHistDn(this,FXSEL(SEL_COMMAND,ID_SEARCH_DN),NULL);
479 }
480 return 1;
481 }
482
483
484 // Wheeled in replace text
onWheelReplace(FXObject *,FXSelector,void * ptr)485 long FXReplaceDialog::onWheelReplace(FXObject*,FXSelector,void* ptr){
486 if(((FXEvent*)ptr)->code>0){
487 return onCmdReplaceHistUp(this,FXSEL(SEL_COMMAND,ID_REPLACE_UP),NULL);
488 }
489 if(((FXEvent*)ptr)->code<0){
490 return onCmdReplaceHistDn(this,FXSEL(SEL_COMMAND,ID_REPLACE_DN),NULL);
491 }
492 return 1;
493 }
494
495
496 // Force the initial text to be seleced
execute(FXuint placement)497 FXuint FXReplaceDialog::execute(FXuint placement){
498 create();
499 searchtext->setFocus();
500 show(placement);
501 activeHistory=-1;
502 return getApp()->runModalFor(this);
503 }
504
505
506 // Save data
save(FXStream & store) const507 void FXReplaceDialog::save(FXStream& store) const {
508 FXDialogBox::save(store);
509 store << searchlabel;
510 store << searchtext;
511 store << searchbox;
512 store << replacelabel;
513 store << replacetext;
514 store << replacebox;
515 store << search;
516 store << replace;
517 store << replacesel;
518 store << replaceall;
519 store << cancel;
520 store << searchmode;
521 }
522
523
524 // Load data
load(FXStream & store)525 void FXReplaceDialog::load(FXStream& store){
526 FXDialogBox::load(store);
527 store >> searchlabel;
528 store >> searchtext;
529 store >> searchbox;
530 store >> replacelabel;
531 store >> replacetext;
532 store >> replacebox;
533 store >> search;
534 store >> replace;
535 store >> replacesel;
536 store >> replaceall;
537 store >> cancel;
538 store >> searchmode;
539 }
540
541
542 // Cleanup
~FXReplaceDialog()543 FXReplaceDialog::~FXReplaceDialog(){
544 saveHistory();
545 searchlabel=(FXLabel*)-1L;
546 searchtext=(FXTextField*)-1L;
547 searchbox=(FXHorizontalFrame*)-1L;
548 replacelabel=(FXLabel*)-1L;
549 replacetext=(FXTextField*)-1L;
550 replacebox=(FXHorizontalFrame*)-1L;
551 search=(FXButton*)-1L;
552 replace=(FXButton*)-1L;
553 replacesel=(FXButton*)-1L;
554 replaceall=(FXButton*)-1L;
555 cancel=(FXButton*)-1L;
556 }
557
558 }
559