1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/fdrepdlg.cpp
3 // Purpose:     wxFindReplaceDialog class
4 // Author:      Markus Greither and Vadim Zeitlin
5 // Modified by:
6 // Created:     23/03/2001
7 // Copyright:   (c) Markus Greither
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #if wxUSE_FINDREPLDLG
27 
28 #ifndef WX_PRECOMP
29     #include "wx/msw/wrapcdlg.h"
30     #include "wx/intl.h"
31     #include "wx/log.h"
32 #endif
33 
34 #include "wx/fdrepdlg.h"
35 
36 #include "wx/msw/mslu.h"
37 
38 // ----------------------------------------------------------------------------
39 // functions prototypes
40 // ----------------------------------------------------------------------------
41 
42 UINT_PTR CALLBACK wxFindReplaceDialogHookProc(HWND hwnd,
43                                               UINT uiMsg,
44                                               WPARAM wParam,
45                                               LPARAM lParam);
46 
47 // ----------------------------------------------------------------------------
48 // wxWin macros
49 // ----------------------------------------------------------------------------
50 
51 IMPLEMENT_DYNAMIC_CLASS(wxFindReplaceDialog, wxDialog)
52 
53 // ----------------------------------------------------------------------------
54 // wxFindReplaceDialogImpl: the internals of wxFindReplaceDialog
55 // ----------------------------------------------------------------------------
56 
57 class WXDLLEXPORT wxFindReplaceDialogImpl
58 {
59 public:
60     wxFindReplaceDialogImpl(wxFindReplaceDialog *dialog, int flagsWX);
61     ~wxFindReplaceDialogImpl();
62 
63     void InitFindWhat(const wxString& str);
64     void InitReplaceWith(const wxString& str);
65 
66     // only for passing to ::FindText or ::ReplaceText
GetPtrFindReplace()67     FINDREPLACE *GetPtrFindReplace() { return &m_findReplace; }
68 
69     // set/query the "closed by user" flag
SetClosedByUser()70     void SetClosedByUser() { m_wasClosedByUser = true; }
WasClosedByUser() const71     bool WasClosedByUser() const { return m_wasClosedByUser; }
72 
73 private:
74     // called from window procedure for ms_msgFindDialog
75     static bool FindMessageHandler(wxWindow *win,
76                                    WXUINT nMsg,
77                                    WPARAM wParam,
78                                    LPARAM lParam);
79 
80     // copy string str contents to ppStr and fill pLen with its length
81     void InitString(const wxString& str, LPTSTR *ppStr, WORD *pLen);
82 
83 
84     // the find replace data used by the dialog
85     FINDREPLACE m_findReplace;
86 
87     // true if the user closed us, false otherwise
88     bool m_wasClosedByUser;
89 
90     // registered Message for Dialog
91     static UINT ms_msgFindDialog;
92 
93     wxDECLARE_NO_COPY_CLASS(wxFindReplaceDialogImpl);
94 };
95 
96 UINT wxFindReplaceDialogImpl::ms_msgFindDialog = 0;
97 
98 // ============================================================================
99 // implementation
100 // ============================================================================
101 
102 // ----------------------------------------------------------------------------
103 // wxFindReplaceDialogImpl
104 // ----------------------------------------------------------------------------
105 
wxFindReplaceDialogImpl(wxFindReplaceDialog * dialog,int flagsWX)106 wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog *dialog,
107                                                  int flagsWX)
108 {
109     // get the identifier for the find dialog message if we don't have it yet
110     if ( !ms_msgFindDialog )
111     {
112         ms_msgFindDialog = ::RegisterWindowMessage(FINDMSGSTRING);
113 
114         if ( !ms_msgFindDialog )
115         {
116             wxLogLastError(wxT("RegisterWindowMessage(FINDMSGSTRING)"));
117         }
118 
119         wxWindow::MSWRegisterMessageHandler
120                   (
121                     ms_msgFindDialog,
122                     &wxFindReplaceDialogImpl::FindMessageHandler
123                   );
124     }
125 
126     m_wasClosedByUser = false;
127 
128     wxZeroMemory(m_findReplace);
129 
130     // translate the flags: first the dialog creation flags
131 
132     // always set this to be able to set the title
133     int flags = FR_ENABLEHOOK;
134 
135     int flagsDialog = dialog->GetWindowStyle();
136     if ( flagsDialog & wxFR_NOMATCHCASE)
137         flags |= FR_NOMATCHCASE;
138     if ( flagsDialog & wxFR_NOWHOLEWORD)
139         flags |= FR_NOWHOLEWORD;
140     if ( flagsDialog & wxFR_NOUPDOWN)
141         flags |= FR_NOUPDOWN;
142 
143     // and now the flags governing the initial values of the dialogs controls
144     if ( flagsWX & wxFR_DOWN)
145         flags |= FR_DOWN;
146     if ( flagsWX & wxFR_MATCHCASE)
147         flags |= FR_MATCHCASE;
148     if ( flagsWX & wxFR_WHOLEWORD )
149         flags |= FR_WHOLEWORD;
150 
151     m_findReplace.lStructSize = sizeof(FINDREPLACE);
152     m_findReplace.hwndOwner = GetHwndOf(dialog->GetParent());
153     m_findReplace.Flags = flags;
154 
155     m_findReplace.lCustData = (LPARAM)dialog;
156     m_findReplace.lpfnHook = wxFindReplaceDialogHookProc;
157 }
158 
InitString(const wxString & str,LPTSTR * ppStr,WORD * pLen)159 void wxFindReplaceDialogImpl::InitString(const wxString& str,
160                                          LPTSTR *ppStr, WORD *pLen)
161 {
162     size_t len = str.length() + 1;
163     if ( len < 80 )
164     {
165         // MSDN docs say that the buffer must be at least 80 chars
166         len = 80;
167     }
168 
169     *ppStr = new wxChar[len];
170     wxStrcpy(*ppStr, str);
171     *pLen = (WORD)len;
172 }
173 
InitFindWhat(const wxString & str)174 void wxFindReplaceDialogImpl::InitFindWhat(const wxString& str)
175 {
176     InitString(str, &m_findReplace.lpstrFindWhat, &m_findReplace.wFindWhatLen);
177 }
178 
InitReplaceWith(const wxString & str)179 void wxFindReplaceDialogImpl::InitReplaceWith(const wxString& str)
180 {
181     InitString(str,
182                &m_findReplace.lpstrReplaceWith,
183                &m_findReplace.wReplaceWithLen);
184 }
185 
~wxFindReplaceDialogImpl()186 wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
187 {
188     delete [] m_findReplace.lpstrFindWhat;
189     delete [] m_findReplace.lpstrReplaceWith;
190 }
191 
192 // ----------------------------------------------------------------------------
193 // handler for FINDMSGSTRING message
194 // ----------------------------------------------------------------------------
195 
196 bool
FindMessageHandler(wxWindow * WXUNUSED (win),WXUINT WXUNUSED_UNLESS_DEBUG (nMsg),WPARAM WXUNUSED (wParam),LPARAM lParam)197 wxFindReplaceDialogImpl::FindMessageHandler(wxWindow * WXUNUSED(win),
198                                             WXUINT WXUNUSED_UNLESS_DEBUG(nMsg),
199                                             WPARAM WXUNUSED(wParam),
200                                             LPARAM lParam)
201 {
202 #if wxUSE_UNICODE_MSLU
203     static unsigned long s_lastMsgFlags = 0;
204 
205     // This flag helps us to identify the bogus ANSI message
206     // sent by UNICOWS.DLL (see below)
207     // while we're sending our message to the dialog
208     // we ignore possible messages sent in between
209     static bool s_blockMsg = false;
210 #endif // wxUSE_UNICODE_MSLU
211 
212     wxASSERT_MSG( nMsg == ms_msgFindDialog, wxT("unexpected message received") );
213 
214     FINDREPLACE *pFR = (FINDREPLACE *)lParam;
215 
216 #if wxUSE_UNICODE_MSLU
217     // This is a hack for a MSLU problem: Versions up to 1.0.4011
218     // of UNICOWS.DLL send the correct UNICODE item after button press
219     // and a bogus ANSI mode item right after this, so let's ignore
220     // the second bogus message
221     if ( wxUsingUnicowsDll() && s_lastMsgFlags == pFR->Flags )
222     {
223         s_lastMsgFlags = 0;
224         return 0;
225     }
226     s_lastMsgFlags = pFR->Flags;
227 #endif // wxUSE_UNICODE_MSLU
228 
229     wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
230 
231     // map flags from Windows
232     wxEventType evtType;
233 
234     bool replace = false;
235     if ( pFR->Flags & FR_DIALOGTERM )
236     {
237         // we have to notify the dialog that it's being closed by user and
238         // not deleted programmatically as it behaves differently in these
239         // 2 cases
240         dialog->GetImpl()->SetClosedByUser();
241 
242         evtType = wxEVT_FIND_CLOSE;
243     }
244     else if ( pFR->Flags & FR_FINDNEXT )
245     {
246         evtType = wxEVT_FIND_NEXT;
247     }
248     else if ( pFR->Flags & FR_REPLACE )
249     {
250         evtType = wxEVT_FIND_REPLACE;
251 
252         replace = true;
253     }
254     else if ( pFR->Flags & FR_REPLACEALL )
255     {
256         evtType = wxEVT_FIND_REPLACE_ALL;
257 
258         replace = true;
259     }
260     else
261     {
262         wxFAIL_MSG( wxT("unknown find dialog event") );
263 
264         return 0;
265     }
266 
267     wxUint32 flags = 0;
268     if ( pFR->Flags & FR_DOWN )
269         flags |= wxFR_DOWN;
270     if ( pFR->Flags & FR_WHOLEWORD )
271         flags |= wxFR_WHOLEWORD;
272     if ( pFR->Flags & FR_MATCHCASE )
273         flags |= wxFR_MATCHCASE;
274 
275     wxFindDialogEvent event(evtType, dialog->GetId());
276     event.SetEventObject(dialog);
277     event.SetFlags(flags);
278     event.SetFindString(pFR->lpstrFindWhat);
279     if ( replace )
280     {
281         event.SetReplaceString(pFR->lpstrReplaceWith);
282     }
283 
284 #if wxUSE_UNICODE_MSLU
285     s_blockMsg = true;
286 #endif // wxUSE_UNICODE_MSLU
287 
288     dialog->Send(event);
289 
290 #if wxUSE_UNICODE_MSLU
291     s_blockMsg = false;
292 #endif // wxUSE_UNICODE_MSLU
293 
294     return true;
295 }
296 
297 // ----------------------------------------------------------------------------
298 // Find/replace dialog hook proc
299 // ----------------------------------------------------------------------------
300 
301 UINT_PTR CALLBACK
wxFindReplaceDialogHookProc(HWND hwnd,UINT uiMsg,WPARAM WXUNUSED (wParam),LPARAM lParam)302 wxFindReplaceDialogHookProc(HWND hwnd,
303                             UINT uiMsg,
304                             WPARAM WXUNUSED(wParam),
305                             LPARAM lParam)
306 {
307     if ( uiMsg == WM_INITDIALOG )
308     {
309         FINDREPLACE *pFR = (FINDREPLACE *)lParam;
310         wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
311 
312         ::SetWindowText(hwnd, dialog->GetTitle().t_str());
313 
314         // don't return FALSE from here or the dialog won't be shown
315         return TRUE;
316     }
317 
318     return 0;
319 }
320 
321 // ============================================================================
322 // wxFindReplaceDialog implementation
323 // ============================================================================
324 
325 // ----------------------------------------------------------------------------
326 // wxFindReplaceDialog ctors/dtor
327 // ----------------------------------------------------------------------------
328 
Init()329 void wxFindReplaceDialog::Init()
330 {
331     m_impl = NULL;
332     m_FindReplaceData = NULL;
333 
334     // as we're created in the hidden state, bring the internal flag in sync
335     m_isShown = false;
336 }
337 
wxFindReplaceDialog(wxWindow * parent,wxFindReplaceData * data,const wxString & title,int flags)338 wxFindReplaceDialog::wxFindReplaceDialog(wxWindow *parent,
339                                          wxFindReplaceData *data,
340                                          const wxString &title,
341                                          int flags)
342                    : wxFindReplaceDialogBase(parent, data, title, flags)
343 {
344     Init();
345 
346     (void)Create(parent, data, title, flags);
347 }
348 
~wxFindReplaceDialog()349 wxFindReplaceDialog::~wxFindReplaceDialog()
350 {
351     if ( m_impl )
352     {
353         // the dialog might have been already deleted if the user closed it
354         // manually but in this case we should have got a notification about it
355         // and the flag must have been set
356         if ( !m_impl->WasClosedByUser() )
357         {
358             // if it wasn't, delete the dialog ourselves
359             if ( !::DestroyWindow(GetHwnd()) )
360             {
361                 wxLogLastError(wxT("DestroyWindow(find dialog)"));
362             }
363         }
364 
365         // unsubclass the parent
366         delete m_impl;
367     }
368 
369     // prevent the base class dtor from trying to hide us!
370     m_isShown = false;
371 
372     // and from destroying our window [again]
373     m_hWnd = (WXHWND)NULL;
374 }
375 
Create(wxWindow * parent,wxFindReplaceData * data,const wxString & title,int flags)376 bool wxFindReplaceDialog::Create(wxWindow *parent,
377                                  wxFindReplaceData *data,
378                                  const wxString &title,
379                                  int flags)
380 {
381     m_windowStyle = flags;
382     m_FindReplaceData = data;
383     m_parent = parent;
384 
385     SetTitle(title);
386 
387     // we must have a parent as it will get the messages from us
388     return parent != NULL;
389 }
390 
391 // ----------------------------------------------------------------------------
392 // wxFindReplaceData show/hide
393 // ----------------------------------------------------------------------------
394 
Show(bool show)395 bool wxFindReplaceDialog::Show(bool show)
396 {
397     if ( !wxWindowBase::Show(show) )
398     {
399         // visibility status didn't change
400         return false;
401     }
402 
403     // do we already have the dialog window?
404     if ( m_hWnd )
405     {
406         // yes, just use it
407         (void)::ShowWindow(GetHwnd(), show ? SW_SHOW : SW_HIDE);
408 
409         return true;
410     }
411 
412     if ( !show )
413     {
414         // well, it doesn't exist which is as good as being hidden
415         return true;
416     }
417 
418     wxCHECK_MSG( m_FindReplaceData, false, wxT("call Create() first!") );
419 
420     wxASSERT_MSG( !m_impl, wxT("why don't we have the window then?") );
421 
422     m_impl = new wxFindReplaceDialogImpl(this, m_FindReplaceData->GetFlags());
423 
424     m_impl->InitFindWhat(m_FindReplaceData->GetFindString());
425 
426     bool replace = HasFlag(wxFR_REPLACEDIALOG);
427     if ( replace )
428     {
429         m_impl->InitReplaceWith(m_FindReplaceData->GetReplaceString());
430     }
431 
432     // call the right function to show the dialog which does what we want
433     FINDREPLACE *pFR = m_impl->GetPtrFindReplace();
434     HWND hwnd;
435     if ( replace )
436         hwnd = ::ReplaceText(pFR);
437     else
438         hwnd = ::FindText(pFR);
439 
440     if ( !hwnd )
441     {
442         wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
443                    ::CommDlgExtendedError());
444 
445         wxDELETE(m_impl);
446 
447         return false;
448     }
449 
450     if ( !::ShowWindow(hwnd, SW_SHOW) )
451     {
452         wxLogLastError(wxT("ShowWindow(find dialog)"));
453     }
454 
455     m_hWnd = (WXHWND)hwnd;
456 
457     return true;
458 }
459 
460 // ----------------------------------------------------------------------------
461 // wxFindReplaceDialog title handling
462 // ----------------------------------------------------------------------------
463 
464 // we set the title of this dialog in our jook proc but for now don't crash in
465 // the base class version because of m_hWnd == 0
466 
SetTitle(const wxString & title)467 void wxFindReplaceDialog::SetTitle( const wxString& title)
468 {
469     m_title = title;
470 }
471 
GetTitle() const472 wxString wxFindReplaceDialog::GetTitle() const
473 {
474     return m_title;
475 }
476 
477 // ----------------------------------------------------------------------------
478 // wxFindReplaceDialog position/size
479 // ----------------------------------------------------------------------------
480 
DoSetSize(int WXUNUSED (x),int WXUNUSED (y),int WXUNUSED (width),int WXUNUSED (height),int WXUNUSED (sizeFlags))481 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
482                                     int WXUNUSED(width), int WXUNUSED(height),
483                                     int WXUNUSED(sizeFlags))
484 {
485     // ignore - we can't change the size of this standard dialog
486     return;
487 }
488 
489 // NB: of course, both of these functions are completely bogus, but it's better
490 //     than nothing
DoGetSize(int * width,int * height) const491 void wxFindReplaceDialog::DoGetSize(int *width, int *height) const
492 {
493     // the standard dialog size
494     if ( width )
495         *width = 225;
496     if ( height )
497         *height = 324;
498 }
499 
DoGetClientSize(int * width,int * height) const500 void wxFindReplaceDialog::DoGetClientSize(int *width, int *height) const
501 {
502     // the standard dialog size
503     if ( width )
504         *width = 219;
505     if ( height )
506         *height = 299;
507 }
508 
509 #endif // wxUSE_FINDREPLDLG
510