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