1 /*
2   FXiTe - The Free eXtensIble Text Editor
3   Copyright (c) 2009-2013 Jeffrey Pohlmeyer <yetanothergeek@gmail.com>
4 
5   This program is free software; you can redistribute it and/or modify it
6   under the terms of the GNU General Public License version 3 as
7   published by the Free Software Foundation.
8 
9   This software is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 
14   You should have received a copy of the GNU General Public License
15   along with this program; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18 
19 
20 #include <fx.h>
21 #include <fxkeys.h>
22 
23 #include "compat.h"
24 #include "scidoc.h"
25 #include "scisrch.h"
26 #include "histbox.h"
27 
28 #include "appwin_pub.h"
29 
30 #include "intl.h"
31 #include "search.h"
32 
33 
34 
35 #define SetPadLRTB(o,l,r,t,b) \
36   o->setPadLeft(l); \
37   o->setPadRight(r); \
38   o->setPadTop(t); \
39   o->setPadBottom(b);
40 
41 #define SetPad(o,p) SetPadLRTB(o,p,p,p,p)
42 
43 
44 
45 FXDEFMAP(SciSearchOptions) SciSearchOptionsMap[]={
46   FXMAPFUNC(SEL_COMMAND,SciSearchOptions::ID_TOGGLE_CHK,SciSearchOptions::onToggleChk),
47 };
48 
49 FXIMPLEMENT(SciSearchOptions,FXHorizontalFrame,SciSearchOptionsMap,ARRAYNUMBER(SciSearchOptionsMap))
50 
51 
52 enum {
53   MODELIST_NORMAL,
54   MODELIST_REGEXP,
55   MODELIST_WHOLEWORD
56 };
57 
SetSciFlags(FXuint n)58 void SciSearchOptions::SetSciFlags(FXuint n)
59 {
60   // Favor REGEXP over WHOLEWORD
61   if ( (n&SCFIND_WHOLEWORD) && (n&SCFIND_REGEXP) ) { n&=!SCFIND_WHOLEWORD; }
62   matchcase->setCheck((n & SCFIND_MATCHCASE)?1:0);
63   if (n & SCFIND_WHOLEWORD) {
64     modelist->setCurrentItem(MODELIST_WHOLEWORD);
65   } else if (n & SCFIND_REGEXP) {
66     modelist->setCurrentItem(MODELIST_REGEXP);
67   } else {
68     modelist->setCurrentItem(MODELIST_NORMAL);
69   }
70 }
71 
72 
73 
onToggleChk(FXObject * o,FXSelector sel,void * p)74 long SciSearchOptions::onToggleChk(FXObject*o, FXSelector sel, void*p)
75 {
76   FXuval n=(FXuval)modelist->getItemData(modelist->getCurrentItem());
77   if ((o==modelist) && (modelist->getCurrentItem()==MODELIST_REGEXP)) { matchcase->setCheck(true); }
78   if (matchcase->getCheck()) { n|=SCFIND_MATCHCASE; }
79   if (target) { target->handle(this, FXSEL(SEL_COMMAND,message), (void*)(FXuval)n); }
80   return 1;
81 }
82 
83 
84 
SciSearchOptions(FXComposite * p,FXObject * tgt,FXSelector sel)85 SciSearchOptions::SciSearchOptions(FXComposite *p, FXObject *tgt, FXSelector sel):FXHorizontalFrame(p, 0)
86 {
87   target=tgt;
88   message=sel;
89   new FXLabel(this,_(" M&ode:"));
90   modelist=new FXListBox(this,this,ID_TOGGLE_CHK);
91   modelist->appendItem(FXString::null);
92   modelist->appendItem(FXString::null);
93   modelist->appendItem(FXString::null);
94   modelist->setNumVisible(modelist->getNumItems());
95   modelist->setItem(MODELIST_NORMAL,    _("normal"),     NULL, (void*)(FXuval)0);
96   modelist->setItem(MODELIST_REGEXP,    _("reg. expr."), NULL, (void*)(FXuval)SCFIND_REGEXP);
97   modelist->setItem(MODELIST_WHOLEWORD, _("whole word"), NULL, (void*)(FXuval)SCFIND_WHOLEWORD);
98   matchcase = new FXCheckButton(this, _("&Match case "), this, ID_TOGGLE_CHK);
99 }
100 
101 
102 
103 class SciReplGui: public FXMatrix {
104 FXDECLARE(SciReplGui)
SciReplGui()105 SciReplGui(){}
106 private:
107   FXVerticalFrame *txt_fields;
108   FXVerticalFrame *btn_ctrls;
109   FXLabel*srch_lab;
110   HistoryTextField*srch_hist;
111   FXLabel*repl_lab;
112   HistoryTextField*repl_hist;
113   SciSearchOptions*opts;
114   FXCheckButton* rev_chk;
115   FXuint sciflags;
116   FXHorizontalFrame *btns;
117   FXButton*fwd_btn;
118   FXButton*bwd_btn;
119   FXButton*cncl_btn;
120   FXButton*repall_indoc_btn;
121   FXButton*repall_insel_btn;
122   FXButton*repl_once_btn;
123   FXObject*target;
124   FXSelector message;
125   void EnableSearch();
126 public:
127   SciReplGui(FXComposite*p, FXObject*tgt, FXSelector sel, bool find_only, bool floating);
~SciReplGui()128   ~SciReplGui() { target=NULL; stop(DONE); }
129   void stop(FXuint stopval);
130   long onSciOpts(FXObject*o, FXSelector sel, void*p);
131   long onSrchHist(FXObject*o, FXSelector sel, void*p);
132   long onButton(FXObject*o, FXSelector sel, void*p);
133   long onFakeBtnUp(FXObject*o, FXSelector sel, void*p);
134 
135   long onKeyPress(FXObject*o, FXSelector sel, void*p);
136   long onConfigure(FXObject*o, FXSelector sel, void*p);
137   long onFocusIn(FXObject*o, FXSelector sel, void*p);
138 
139   void setSearchText(const FXString& text);
140   FXString getSearchText() const;
141   void setReplaceText(const FXString& text);
142   FXString getReplaceText() const;
143   void setHaveSelection(bool have_sel);
getSearchMode()144   FXuint getSearchMode() { return sciflags; }
145   void setSearchMode(FXuint mode);
getSearchReverse()146   FXuint getSearchReverse() { return rev_chk->getCheck(); }
setSearchReverse(bool reverse)147   void setSearchReverse(bool reverse) { rev_chk->setCheck(reverse); }
148   void AppendHist(const FXString& search,const FXString& replace,FXuint mode);
149   void DoExecute();
150   void HandleKeyPress(FXEvent*ev);
151   virtual void create();
152   virtual void destroy();
153   enum {
154     ID_SCI_OPTS=1,
155     ID_SRCH_HIST,
156     ID_REPL_HIST,
157     ID_PREV,
158     ID_NEXT,
159     ID_REPLACE,
160     ID_ALL_INDOC,
161     ID_ALL_INSEL,
162     ID_CANCEL_SRCH,
163     ID_REV_CHK,
164     ID_FAKE_BTN_UP,
165     ID_LAST
166   };
167   enum {
168     DONE           = 0,  // Cancel search
169     SEARCH         = 1,  // Search first occurrence
170     SEARCH_NEXT    = 2,  // Search next occurrence
171     REPL_ALL_INDOC = 3,  // Replace all occurrences in document
172     REPL_ALL_INSEL = 4   // Replace all occurrences in selection
173   };
174 };
175 
176 
177 
178 FXDEFMAP(SciReplGui) SciReplGuiMap[]={
179   FXMAPFUNC(  SEL_COMMAND,  SciReplGui::ID_SCI_OPTS,    SciReplGui::onSciOpts),
180   FXMAPFUNCS( SEL_COMMAND,  SciReplGui::ID_SRCH_HIST,   SciReplGui::ID_REPL_HIST,   SciReplGui::onSrchHist),
181   FXMAPFUNC(  SEL_CHANGED,  SciReplGui::ID_SRCH_HIST,   SciReplGui::onSrchHist),
182   FXMAPFUNC(  SEL_PICKED,   SciReplGui::ID_SRCH_HIST,   SciReplGui::onSrchHist),
183   FXMAPFUNCS( SEL_COMMAND,  SciReplGui::ID_PREV,        SciReplGui::ID_CANCEL_SRCH, SciReplGui::onButton),
184   FXMAPFUNC(  SEL_TIMEOUT,  SciReplGui::ID_FAKE_BTN_UP, SciReplGui::onFakeBtnUp),
185   FXMAPFUNC(  SEL_KEYPRESS,  0, SciReplGui::onKeyPress),
186   FXMAPFUNC(  SEL_CONFIGURE, 0, SciReplGui::onConfigure),
187   FXMAPFUNC(  SEL_FOCUSIN,   0, SciReplGui::onFocusIn),
188 };
189 
190 FXIMPLEMENT(SciReplGui,FXMatrix,SciReplGuiMap,ARRAYNUMBER(SciReplGuiMap))
191 
192 
193 
194 #define ICO_SIZE 8
195 
196 static const char close_icon[] =
197   "X_____X_"
198   "_X___X__"
199   "__X_X___"
200   "___X____"
201   "__X_X___"
202   "_X___X__"
203   "X_____X_"
204   "________"
205 ;
206 
207 
SciReplGui(FXComposite * p,FXObject * tgt,FXSelector sel,bool find_only,bool floating)208 SciReplGui::SciReplGui(FXComposite*p, FXObject*tgt, FXSelector sel, bool find_only, bool floating):FXMatrix(p,2)
209 {
210   sciflags=0;
211   target=tgt;
212   message=sel;
213   setLayoutHints(floating?LAYOUT_FILL:LAYOUT_FILL_X);
214   setMatrixStyle(floating?MATRIX_BY_ROWS:MATRIX_BY_COLUMNS);
215   setFrameStyle(floating?FRAME_NONE:FRAME_GROOVE);
216   FXuint textopts=TEXTFIELD_ENTER_ONLY|FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X;
217   const char*group=find_only?"Search":"Replace";
218 
219   txt_fields=new FXVerticalFrame(this,FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
220   btn_ctrls=new  FXVerticalFrame(this,FRAME_NONE);
221 
222   SetPad(txt_fields,0);
223 
224   srch_lab=new FXLabel(txt_fields, _("Se&arch for:"));
225   srch_hist=new HistoryTextField(txt_fields,48,group,"SM",this,ID_SRCH_HIST,textopts);
226   if (find_only) {
227     repl_hist=NULL;
228   } else {
229     repl_lab=new FXLabel(txt_fields, _("Replace &with:"));
230     repl_hist=new HistoryTextField(txt_fields,48,group,"R",this,ID_REPL_HIST,textopts);
231   }
232 
233   SetPad(btn_ctrls,0);
234 
235   opts=new SciSearchOptions(btn_ctrls,this,ID_SCI_OPTS);
236   rev_chk=new FXCheckButton(opts, _("&Backward"),this,ID_REV_CHK);
237   srch_hist->setWatch(&sciflags);
238 
239   btns=new FXHorizontalFrame(btn_ctrls,LAYOUT_FILL_X);
240   FXHorizontalFrame*nav_btns=new FXHorizontalFrame(btns);
241   SetPadLRTB(nav_btns,DEFAULT_SPACING,DEFAULT_SPACING*2,0,0);
242   bwd_btn=new FXButton(nav_btns," &< ",NULL,this,ID_PREV);
243   fwd_btn=new FXButton(nav_btns," &> ",NULL,this,ID_NEXT);
244   if (find_only) {
245     repl_once_btn=new FXButton(btns,_("F&ind"),NULL,this,ID_REPLACE);
246     repall_indoc_btn=NULL;
247     repall_insel_btn=NULL;
248   } else {
249     repl_once_btn=new FXButton(btns,_("Rep&lace"),NULL,this,ID_REPLACE);
250     repall_indoc_btn=new FXButton(btns,_("Re&place All"),NULL,this,ID_ALL_INDOC);
251     repall_insel_btn=new FXButton(btns,_("All in Sele&cted"),NULL,this,ID_ALL_INSEL);
252   }
253 
254   if (!floating) {
255     FXVerticalFrame*cncl_box=new FXVerticalFrame(btns,LAYOUT_RIGHT|LAYOUT_SIDE_BOTTOM|PACK_UNIFORM_HEIGHT|LAYOUT_FILL_Y);
256     cncl_box->setVSpacing(0);
257     SetPad(cncl_box,0);
258     cncl_btn=new FXButton(cncl_box,FXString::null,NULL,this,ID_CANCEL_SRCH,BUTTON_NORMAL|LAYOUT_BOTTOM);
259     if (!find_only) {
260       new FXVerticalFrame(cncl_box,FRAME_NONE);
261       FXHorizontalFrame*cncl_frm=new FXHorizontalFrame(btn_ctrls,LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_SIDE_BOTTOM);
262       SetPad(cncl_frm,0);
263       cncl_box->reparent(cncl_frm);
264     }
265     cncl_btn->setTipText(_("Close   {ESC}"));
266     FXColor ico_buf[ICO_SIZE*ICO_SIZE];
267     FXColor bg=cncl_btn->getBackColor();
268     FXColor fg=cncl_btn->getTextColor();
269     for (FXint i=0; i<ICO_SIZE*ICO_SIZE; i++) { ico_buf[i]=close_icon[i]=='_'?bg:fg; }
270     FXIcon *ico=new FXIcon(cncl_btn->getApp(),ico_buf,0,IMAGE_OPAQUE,ICO_SIZE,ICO_SIZE);
271     ico->create();
272     cncl_btn->setIcon(ico);
273   } else {
274     btn_ctrls->setLayoutHints(LAYOUT_FILL_X);
275     new FXHorizontalFrame(btns,LAYOUT_FILL_X);
276     cncl_btn=new FXButton(btns,_("Close"),NULL,this,ID_CANCEL_SRCH,BUTTON_NORMAL|LAYOUT_BOTTOM);
277   }
278   SetPad(btns,0);
279   if (repl_hist) { srch_hist->enslave(repl_hist); }
280   setSearchText(FXString::null);
281 }
282 
283 
284 
AppendHist(const FXString & search,const FXString & replace,FXuint mode)285 void SciReplGui::AppendHist(const FXString& search,const FXString& replace,FXuint mode)
286 {
287   FXString tmp;
288   FXuint oldmode=sciflags;
289   sciflags=mode;
290   if (!search.empty()) {
291     tmp=getSearchText();
292     setSearchText(search);
293     srch_hist->append();
294     setSearchText(tmp);
295   }
296   if (!replace.empty()) {
297     tmp=getReplaceText();
298     setReplaceText(replace);
299     if (repl_hist) { repl_hist->append(); }
300     setSearchText(tmp);
301   }
302   sciflags=oldmode;
303 }
304 
305 
306 
stop(FXuint stopval)307 void SciReplGui::stop(FXuint stopval)
308 {
309   srch_hist->append();
310   if (repl_hist) { repl_hist->append(); }
311   if (target) { target->handle(this,FXSEL(SEL_COMMAND,message),(void*)(FXuval)stopval); }
312 }
313 
314 
315 
onFakeBtnUp(FXObject * o,FXSelector sel,void * p)316 long SciReplGui::onFakeBtnUp(FXObject*o, FXSelector sel, void*p)
317 {
318  ((FXButton*)p)->setState(STATE_UP);
319   return 0;
320 }
321 
322 
323 
onButton(FXObject * o,FXSelector sel,void * p)324 long SciReplGui::onButton(FXObject*o, FXSelector sel, void*p)
325 {
326   if ( getSearchText().empty() && (FXSELID(sel)!=ID_CANCEL_SRCH) ) { return 0; }
327   FXButton*btn=NULL;
328   switch (FXSELID(sel)) {
329     case ID_PREV:
330     {
331       rev_chk->setCheck(true);
332       btn=bwd_btn;
333       stop(SEARCH_NEXT);
334       break;
335     }
336     case ID_NEXT:
337     {
338       rev_chk->setCheck(false);
339       btn=fwd_btn;
340       stop(SEARCH_NEXT);
341       break;
342     }
343     case ID_REPLACE: {
344       stop(SEARCH);
345       break;
346     }
347     case ID_ALL_INDOC: {
348       stop(REPL_ALL_INDOC);
349       break;
350     }
351     case ID_ALL_INSEL: {
352       stop(REPL_ALL_INSEL);
353       break;
354     }
355     case ID_CANCEL_SRCH: {
356        stop(DONE);
357       break;
358     }
359     default: {return 0; }
360   }
361   if (btn && !o) { // If sender was NULL, fake the appearance of a button press.
362     btn->setFocus();
363     btn->setState(STATE_DOWN);
364     btn->update();
365     btn->getApp()->addTimeout(this,ID_FAKE_BTN_UP,ONE_SECOND/10,(void*)btn);
366   }
367   return 1;
368 }
369 
370 
371 
HandleKeyPress(FXEvent * ev)372 void SciReplGui::HandleKeyPress(FXEvent*ev)
373 {
374   switch (ev->code) {
375     case KEY_less:
376     case KEY_comma: {
377       if (ev->state&ALTMASK) { handle(NULL,FXSEL(SEL_COMMAND,SciReplGui::ID_PREV),NULL); }
378       break;
379     }
380     case KEY_period:
381     case KEY_greater: {
382       if (ev->state&ALTMASK) { handle(NULL,FXSEL(SEL_COMMAND,SciReplGui::ID_NEXT),NULL); }
383       break;
384     }
385     case KEY_Escape: {
386       stop(SciReplGui::DONE);
387       break;
388     }
389   }
390 }
391 
392 
393 
EnableSearch()394 void SciReplGui::EnableSearch()
395 {
396   if (srch_hist->getText().empty()) {
397     bwd_btn->disable();
398     fwd_btn->disable();
399     repl_once_btn->disable();
400     if (repall_indoc_btn) { repall_indoc_btn->disable(); }
401     if (repall_insel_btn) { repall_insel_btn->disable(); }
402   } else {
403     bwd_btn->enable();
404     fwd_btn->enable();
405     repl_once_btn->enable();
406     if (repall_indoc_btn) { repall_indoc_btn->enable(); }
407     if (repall_insel_btn) { repall_insel_btn->enable(); }
408   }
409 }
410 
411 
412 
onSrchHist(FXObject * o,FXSelector sel,void * p)413 long SciReplGui::onSrchHist(FXObject*o, FXSelector sel, void*p)
414 {
415   if (FXSELID(sel)!=ID_SRCH_HIST) { return 0; }
416   switch (FXSELTYPE(sel)) {
417     case SEL_CHANGED: {
418       EnableSearch();
419       return 1;
420     }
421     case SEL_PICKED: {
422       sciflags=(FXuint)((FXival)p);
423       opts->SetSciFlags(sciflags);
424       EnableSearch();
425       return 1;
426     }
427     case SEL_COMMAND: {
428       if (!getSearchText().empty()) {
429         if (repl_hist && repl_hist->isEnabled()) {
430            repl_hist->setFocus();
431         } else {
432           stop(SEARCH);
433         }
434       }
435       return 1;
436     }
437     default: return 0;
438   }
439 }
440 
441 
442 
onSciOpts(FXObject * o,FXSelector sel,void * p)443 long SciReplGui::onSciOpts(FXObject*o, FXSelector sel, void*p)
444 {
445   sciflags=(FXuint)((FXival)p);
446   return 1;
447 }
448 
449 
450 
onConfigure(FXObject * o,FXSelector sel,void * p)451 long SciReplGui::onConfigure(FXObject*o, FXSelector sel, void*p)
452 {
453   setLayoutHints((getDefaultWidth()>getParent()->getWidth())?LAYOUT_FILL_X:0);
454   return FXMatrix::onConfigure(o,sel,p);
455 }
456 
457 
458 
onKeyPress(FXObject * o,FXSelector sel,void * p)459 long SciReplGui::onKeyPress(FXObject*o, FXSelector sel, void*p)
460 {
461   HandleKeyPress(((FXEvent*)p));
462   return FXMatrix::onKeyPress(o,sel,p);
463 }
464 
465 
466 
onFocusIn(FXObject * o,FXSelector sel,void * p)467 long SciReplGui::onFocusIn(FXObject*o, FXSelector sel, void*p)
468 {
469   FXMatrix::onFocusIn(o,sel,p);
470   TopWinPub::ActiveWidget(id());
471   return 1;
472 }
473 
474 
475 
setSearchText(const FXString & text)476 void SciReplGui::setSearchText(const FXString& text)
477 {
478   srch_hist->setText(text);
479   EnableSearch();
480 }
481 
482 
483 
getSearchText() const484 FXString SciReplGui::getSearchText() const
485 {
486   return srch_hist->getText();
487 }
488 
489 
490 
setReplaceText(const FXString & text)491 void SciReplGui::setReplaceText(const FXString& text)
492 {
493   if (repl_hist) { repl_hist->setText(text); }
494 }
495 
496 
497 
getReplaceText() const498 FXString SciReplGui::getReplaceText() const
499 {
500   return repl_hist?repl_hist->getText():FXString::null;
501 }
502 
503 
504 
setHaveSelection(bool have_sel)505 void SciReplGui::setHaveSelection(bool have_sel)
506 {
507   if (repall_insel_btn) {
508     if (have_sel) { repall_insel_btn->enable(); } else { repall_insel_btn->disable(); }
509   }
510 }
511 
512 
513 
setSearchMode(FXuint mode)514 void SciReplGui::setSearchMode(FXuint mode)
515 {
516   sciflags=mode;
517   opts->SetSciFlags(mode);
518 }
519 
520 
521 
create()522 void SciReplGui::create()
523 {
524   FXMatrix::create();
525   srch_hist->setFocus();
526 }
527 
528 
529 
destroy()530 void SciReplGui::destroy()
531 {
532   srch_hist->killSelection();
533   if (repl_hist) repl_hist->killSelection();
534 }
535 
536 
537 
DoExecute()538 void SciReplGui::DoExecute()
539 {
540   if ( (!bwd_btn->hasFocus())&&!fwd_btn->hasFocus() ) { srch_hist->setFocus(); }
541   srch_hist->start();
542   if (repl_hist) { repl_hist->start(); }
543 }
544 
545 
546 
547 
548 class MainPanel: public FXHorizontalFrame {
549   FXDECLARE(MainPanel)
MainPanel()550   MainPanel() {}
551 public:
onConfigure(FXObject * o,FXSelector sel,void * p)552   long onConfigure(FXObject*o, FXSelector sel, void*p) {
553     for (FXWindow*w=getFirst(); w; w=w->getNext()) { w->handle(o,sel,p); }
554     return FXHorizontalFrame::onConfigure(o,sel,p);
555   }
MainPanel(FXComposite * p)556   MainPanel(FXComposite *p):FXHorizontalFrame(p,FRAME_NONE|LAYOUT_FILL_X) { setBaseColor(FXRGB(255,0,0)); }
557 };
558 
559 
560 
561 FXDEFMAP(MainPanel) MainPanelMap[]={
562   FXMAPFUNC(SEL_CONFIGURE, 0, MainPanel::onConfigure)
563 };
564 
565 FXIMPLEMENT(MainPanel,FXHorizontalFrame,MainPanelMap,ARRAYNUMBER(MainPanelMap));
566 
567 
568 
569 static FXint srch_dlg_box_prev_x=0;
570 static FXint srch_dlg_box_prev_y=0;
571 static bool srch_dlg_box_placed=false;
572 
573 
574 class SrchDlgBox:public FXDialogBox {
575 public:
SrchDlgBox(FXWindow * o)576   SrchDlgBox(FXWindow*o):FXDialogBox(o,FXString::null) {}
show()577   virtual void show() {
578     if (srch_dlg_box_placed) {
579       position(srch_dlg_box_prev_x,srch_dlg_box_prev_y,getFirst()->getDefaultWidth(),getFirst()->getDefaultHeight());
580       FXDialogBox::show();
581     } else {
582       resize(getFirst()->getDefaultWidth(),getFirst()->getDefaultHeight());
583       FXDialogBox::show(PLACEMENT_OWNER);
584     }
585     srch_dlg_box_placed=true;
586     raise();
587   }
show(FXuint placement)588   virtual void show(FXuint placement) { SrchDlgBox::show(); }
hide()589   virtual void hide() {
590     srch_dlg_box_prev_x=getX();
591     srch_dlg_box_prev_y=getY();
592     FXDialogBox::hide();
593   }
destroy()594   virtual void destroy() {
595     srch_dlg_box_prev_x=getX();
596     srch_dlg_box_prev_y=getY();
597     FXDialogBox::destroy();
598   }
599 };
600 
601 
602 
603 FXDEFMAP(SearchDialogs) SearchDialogsMap[] = {
604   FXMAPFUNC(SEL_COMMAND, SearchDialogs::ID_SEARCH,        SearchDialogs::onSearch),
605   FXMAPFUNC(SEL_CHORE,   SearchDialogs::ID_SEARCH_DONE,   SearchDialogs::onSearchDone),
606 };
607 
608 FXIMPLEMENT(SearchDialogs, FXObject, SearchDialogsMap, ARRAYNUMBER(SearchDialogsMap));
609 
610 
SearchDialogs(FXComposite * p,FXObject * trg,FXSelector sel)611 SearchDialogs::SearchDialogs(FXComposite*p, FXObject*trg, FXSelector sel) {
612   defaultsearchmode=0;
613   searchdirn=SCI_SEARCHNEXT;
614   searchstring=FXString::null;
615   target=trg;
616   message=sel;
617   parent=p;
618   find_initial=true;
619   repl_initial=true;
620   srchdlg=NULL;
621   srchpan=NULL;
622   repl_gui=NULL;
623   find_gui=NULL;
624 }
625 
626 
627 
SetGuiStyle(FXuint style)628 void SearchDialogs::SetGuiStyle(FXuint style)
629 {
630   delete repl_gui;
631   repl_gui=NULL;
632   delete find_gui;
633   find_gui=NULL;
634   gui_style=(SearchDialogStyle)style;
635   if (style==SEARCH_GUI_FLOAT) {
636     if (!srchdlg) { srchdlg=new SrchDlgBox(parent->getShell()); }
637     SetPad(srchdlg,0);
638     container=srchdlg;
639     delete srchpan;
640     srchpan=NULL;
641   } else {
642     if (!srchpan) { srchpan=new MainPanel(parent); }
643     SetPad(srchpan,0);
644     container=srchpan;
645     delete srchdlg;
646     srchdlg=NULL;
647   }
648 }
649 
650 
651 
~SearchDialogs()652 SearchDialogs::~SearchDialogs()
653 {
654   delete repl_gui;
655   repl_gui=NULL;
656   if (hist_queue.no()) {
657     if (!find_gui) {
658       find_gui=new SciReplGui(container, this, ID_SEARCH, true, container==srchdlg);
659     }
660     SaveHistoryQueue();
661   }
662   delete find_gui;
663   find_gui=NULL;
664 }
665 
666 
667 
SetPrefs(FXuint mode,FXuint wrap,bool verbose,FXuint style)668 void SearchDialogs::SetPrefs(FXuint mode, FXuint wrap, bool verbose, FXuint style)
669 {
670   searchmode=mode;
671   defaultsearchmode=mode;
672   searchwrap=(SearchWrapPolicy)wrap;
673   searchverbose=verbose;
674   SetGuiStyle(style);
675 }
676 
677 
678 
SearchFailed(FXWindow * w)679 void SearchDialogs::SearchFailed(FXWindow*w)
680 {
681   FXMessageBox::error(w->getShell(), MBOX_OK, _("Not found"), "%s.", _("Search term not found"));
682 }
683 
684 
685 
SearchFailed()686 bool SearchDialogs::SearchFailed()
687 {
688   if (searchverbose) { SearchFailed(parent); }
689   return false;
690 }
691 
692 
SearchWrapAsk(FXWindow * w)693 bool SearchDialogs::SearchWrapAsk(FXWindow*w)
694 {
695   return (FXMessageBox::question(w->getShell(), MBOX_YES_NO, _("Wrap search?"), "%s:\n%s",
696             _("Search term not found"),
697             _("Wrap search and try again?"))==MBOX_CLICKED_YES);
698 }
699 
700 
701 
SaveHistoryQueue()702 void SearchDialogs::SaveHistoryQueue()
703 {
704   for (FXint i=0; i<hist_queue.no(); i++) {
705     FXString*s=(FXString*)hist_queue[i];
706     find_gui->AppendHist(*s, FXString::null, defaultsearchmode);
707     delete s;
708     hist_queue[i]=NULL;
709   }
710   hist_queue.clear();
711 }
712 
713 
714 
ShowFindDialog()715 void SearchDialogs::ShowFindDialog()
716 {
717   delete repl_gui;
718   repl_gui=NULL;
719   if (!find_gui) {
720     find_gui=new SciReplGui(container, this, ID_SEARCH, true, container==srchdlg);
721     SaveHistoryQueue();
722     container->create();
723     if (srchdlg) {
724       srchdlg->setTitle(_("Search"));
725     } else {
726       srchpan->reparent(parent,(gui_style==SEARCH_GUI_ABOVE)?parent->getFirst():NULL);
727     }
728   } else {
729     find_gui->setSearchText(FXString::null);
730   }
731   if (srchdlg) {
732     srchdlg->hide();
733     srchdlg->show();
734   }
735   parent->layout();
736   find_gui->setFocus();
737   find_gui->setSearchMode(searchmode);
738   find_gui->DoExecute();
739 }
740 
741 
742 
ShowReplaceDialog()743 void SearchDialogs::ShowReplaceDialog()
744 {
745   delete find_gui;
746   find_gui=NULL;
747   if (!repl_gui) {
748     repl_gui=new SciReplGui(container, this, ID_SEARCH, false, container==srchdlg);
749     container->create();
750     if (srchdlg) {
751       srchdlg->setTitle(_("Replace"));
752       srchdlg->show();
753     } else {
754       srchpan->reparent(parent,(gui_style==SEARCH_GUI_ABOVE)?parent->getFirst():NULL);
755     }
756   }
757   if (srchdlg) {
758     srchdlg->hide();
759     srchdlg->show();
760   }
761   repl_gui->setSearchMode(searchmode);
762   repl_ready=false;
763   repl_gui->setHaveSelection(TopWinPub::FocusedDoc()->GetSelLength()>0);
764   repl_gui->DoExecute();
765   repl_initial=false;
766 }
767 
768 
769 
FindText(bool forward,bool wrap)770 bool SearchDialogs::FindText(bool forward, bool wrap)
771 {
772   SciDoc*sci=TopWinPub::FocusedDoc();
773   if (sci->search->FindText(searchstring,searchmode,forward,wrap)) {
774     if (target) { target->handle(this,FXSEL(SEL_COMMAND,message),NULL); }
775     return true;
776   } else {
777     return false;
778   }
779 }
780 
781 
782 
DoFind(bool forward)783 bool SearchDialogs::DoFind(bool forward)
784 {
785   SciDoc*sci=TopWinPub::FocusedDoc();
786   searchdirn=forward?SCI_SEARCHNEXT:SCI_SEARCHPREV; // <= this is only used for the macro recorder
787   switch (searchwrap) {
788     case SEARCH_WRAP_NEVER: {
789       return FindText(forward,false)?true:SearchFailed();
790     }
791     case SEARCH_WRAP_ALWAYS: {
792       return FindText(forward,true)?true:SearchFailed();
793     }
794     case SEARCH_WRAP_ASK: {
795       if (FindText(forward,false)) { return true; }
796       long pos=sci->sendMessage(SCI_GETCURRENTPOS,0,0);
797       if (forward) {
798         if (pos==0) { return SearchFailed(); }
799       } else {
800         if (pos==sci->sendMessage(SCI_GETLENGTH,0,0)) { return SearchFailed(); }
801       }
802       if (SearchWrapAsk(parent)) { return (FindText(forward,true))?true:SearchFailed(); }
803     }
804     default: { return false; }
805   }
806 }
807 
808 
809 
FindNext()810 void SearchDialogs::FindNext()
811 {
812   searchmode &= ~SEARCH_BACKWARD;
813   if (searchstring.empty()) {
814     ShowFindDialog();
815   } else {
816     DoFind(true);
817   }
818 }
819 
820 
821 
FindPrev()822 void SearchDialogs::FindPrev()
823 {
824   searchmode |= SEARCH_BACKWARD;
825   if (searchstring.empty()) {
826     ShowFindDialog();
827   } else {
828     DoFind(false);
829   }
830 }
831 
832 
833 
FindPhrase(const char * searchfor,FXuint mode,bool forward)834 void SearchDialogs::FindPhrase(const char* searchfor, FXuint mode, bool forward)
835 {
836   searchstring=searchfor;
837   searchmode=mode;
838   if (forward) { FindNext(); } else { FindPrev(); }
839 }
840 
841 
842 
FindAndReplace(const char * searchfor,const char * replacewith,FXuint mode,bool forward)843 void SearchDialogs::FindAndReplace(const char*searchfor, const char*replacewith, FXuint mode, bool forward)
844 {
845   searchstring=searchfor;
846   replacestring=replacewith;
847   searchmode=mode;
848   repl_ready=false;
849   NextReplace(SciReplGui::SEARCH,forward);
850 }
851 
852 
853 
ReplaceAllInSelection(const char * searchfor,const char * replacewith,FXuint mode)854 void SearchDialogs::ReplaceAllInSelection(const char*searchfor, const char*replacewith, FXuint mode)
855 {
856   searchstring=searchfor;
857   replacestring=replacewith;
858   searchmode=mode;
859   NextReplace(SciReplGui::REPL_ALL_INSEL,true);
860 }
861 
862 
863 
ReplaceAllInDocument(const char * searchfor,const char * replacewith,FXuint mode)864 void SearchDialogs::ReplaceAllInDocument(const char*searchfor, const char*replacewith, FXuint mode)
865 {
866   searchstring=searchfor;
867   replacestring=replacewith;
868   searchmode=mode;
869   NextReplace(SciReplGui::REPL_ALL_INDOC,true);
870 }
871 
872 
873 
GetPrimarySelection(SciDoc * sci,FXString & target)874 bool GetPrimarySelection(SciDoc*sci, FXString&target)
875 {
876   return sci->getShell()->getDNDData(FROM_SELECTION,FXWindow::stringType, target);
877 }
878 
879 
880 
FindSelected(bool forward)881 void SearchDialogs::FindSelected(bool forward)
882 {
883   SciDoc*sci=TopWinPub::FocusedDoc();
884   FXString srch=FXString::null;
885   if (!GetPrimarySelection(sci,srch)) {
886     if (sci->GetSelLength()>0) { sci->GetSelText(srch); }
887   }
888   if (!srch.empty()) {
889     searchmode=defaultsearchmode;
890     searchstring=srch;
891     DoFind(forward);
892     if (find_gui) {
893       find_gui->AppendHist(searchstring, FXString::null, defaultsearchmode);
894       find_gui->setSearchText(srch);
895     } else {
896       hist_queue.append((FXObject*)(new FXString(searchstring)));
897     }
898   }
899 }
900 
901 
902 
GoToSelected()903 bool SearchDialogs::GoToSelected()
904 {
905   SciDoc*sci=TopWinPub::FocusedDoc();
906   FXString tmp;
907   if (sci && GetPrimarySelection(sci,tmp)) {
908     tmp.trim();
909     return sci->GoToStringCoords(tmp.text());
910   } else {
911     return false;
912   }
913 }
914 
915 
916 
ShowGoToDialog()917 bool SearchDialogs::ShowGoToDialog()
918 {
919   SciDoc*sci=TopWinPub::FocusedDoc();
920   FXInputDialog dlg(sci->getShell(),_("Go to line"), _("Enter line number\n(or line:column)"));
921   bool rv=dlg.execute(PLACEMENT_OWNER);
922   if (rv) { sci->GoToStringCoords(dlg.getText().text()); }
923   sci->setFocus();
924   return rv;
925 }
926 
927 
928 
NextSearch(FXuint code)929 FXuint SearchDialogs::NextSearch(FXuint code)
930 {
931   searchstring=find_gui->getSearchText();
932   searchmode=find_gui->getSearchMode();
933   if (code!=SciReplGui::DONE) {
934     find_initial=false;
935     switch(code) {
936       case SciReplGui::DONE:{
937         break;
938       }
939       case SciReplGui::SEARCH:
940       case SciReplGui::SEARCH_NEXT: {
941         DoFind(!find_gui->getSearchReverse());
942         break;
943       }
944     }
945   }
946   TopWinPub::FocusedDoc()->update();
947   return code;
948 }
949 
950 
951 
NextReplace(FXuint code,bool forward)952 FXuint SearchDialogs::NextReplace(FXuint code, bool forward)
953 {
954   SciDoc*sci=TopWinPub::FocusedDoc();
955   switch (code) {
956     case SciReplGui::SEARCH:{ // Replace selection
957       if (!repl_ready) { repl_ready=DoFind(forward); }
958       if (repl_ready) {
959         sci->search->ReplaceSelection(replacestring,searchmode);
960         repl_ready=false;
961       }
962       break;
963     }
964     case SciReplGui::SEARCH_NEXT:{ // Find next
965       repl_ready=DoFind(forward);
966       break;
967     }
968     case SciReplGui::REPL_ALL_INDOC:{ // Replace all
969       if (sci->search->ReplaceAllInDoc(searchstring, replacestring, searchmode)==0) {
970         SearchFailed();
971       }
972       break;
973     }
974     case SciReplGui::REPL_ALL_INSEL: { // Replace all in selection
975       if (sci->search->ReplaceAllInSel(searchstring,replacestring,searchmode)==0) {
976         SearchFailed();
977       }
978       break;
979     }
980     default:{ // Cancel
981       break;
982     }
983   }
984   return code;
985 }
986 
987 
988 
onSearchDone(FXObject * o,FXSelector sel,void * p)989 long SearchDialogs::onSearchDone(FXObject*o, FXSelector sel, void *p)
990 {
991   SciReplGui**gui=(SciReplGui**)p;
992   delete *gui;
993   *gui=NULL;
994   TopWinPub::FocusedDoc()->setFocus();
995   return 1;
996 }
997 
998 
999 
onSearch(FXObject * o,FXSelector sel,void * p)1000 long SearchDialogs::onSearch(FXObject*o, FXSelector sel, void *p)
1001 {
1002   FXuint code=(FXuint)(FXuval)p;
1003   if (repl_gui) {
1004     if (code==SciReplGui::DONE) {
1005       container->getApp()->addChore(this,ID_SEARCH_DONE,&repl_gui);
1006     } else {
1007       searchmode=repl_gui->getSearchMode();
1008       searchstring=repl_gui->getSearchText();
1009       replacestring=repl_gui->getReplaceText();
1010       NextReplace(code,!repl_gui->getSearchReverse());
1011     }
1012   } else {
1013     switch (code) {
1014       case SciReplGui::SEARCH:
1015       case SciReplGui::SEARCH_NEXT: {
1016         NextSearch(code);
1017         break;
1018       }
1019       case SciReplGui::DONE: {
1020         container->getApp()->addChore(this,ID_SEARCH_DONE,&find_gui);
1021         break;
1022       }
1023     }
1024   }
1025   if (srchdlg&&(code==SciReplGui::DONE)) { srchdlg->hide(); }
1026   return 1;
1027 }
1028 
1029 
1030 
setHaveSelection(bool have_sel)1031 void SearchDialogs::setHaveSelection(bool have_sel)
1032 {
1033   if (repl_gui) { repl_gui->setHaveSelection(have_sel); }
1034 }
1035 
1036 
1037 
hide()1038 void SearchDialogs::hide()
1039 {
1040   delete repl_gui;
1041   repl_gui=NULL;
1042   delete find_gui;
1043   find_gui=NULL;
1044   if (srchdlg) { srchdlg->hide(); }
1045 }
1046 
1047