]> git.saurik.com Git - wxWidgets.git/blob - src/msw/fdrepdlg.cpp
fixes for Raise() to work correctly with both top level and child windows
[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 : wxFindReplaceDialogBase(parent, data, title, flags)
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 // wxFindReplaceData show/hide
368 // ----------------------------------------------------------------------------
369
370 bool wxFindReplaceDialog::Show(bool show)
371 {
372 if ( !wxWindowBase::Show(show) )
373 {
374 // visibility status didn't change
375 return FALSE;
376 }
377
378 // do we already have the dialog window?
379 if ( m_hWnd )
380 {
381 // yes, just use it
382 (void)::ShowWindow(GetHwnd(), show ? SW_SHOW : SW_HIDE);
383
384 return TRUE;
385 }
386
387 if ( !show )
388 {
389 // well, it doesn't exist which is as good as being hidden
390 return TRUE;
391 }
392
393 wxCHECK_MSG( m_FindReplaceData, FALSE, _T("call Create() first!") );
394
395 wxASSERT_MSG( !m_impl, _T("why don't we have the window then?") );
396
397 m_impl = new wxFindReplaceDialogImpl(this, m_FindReplaceData->GetFlags());
398
399 m_impl->InitFindWhat(m_FindReplaceData->GetFindString());
400
401 bool replace = HasFlag(wxFR_REPLACEDIALOG);
402 if ( replace )
403 {
404 m_impl->InitReplaceWith(m_FindReplaceData->GetReplaceString());
405 }
406
407 // call the right function to show the dialog which does what we want
408 FINDREPLACE *pFR = m_impl->GetPtrFindReplace();
409 HWND hwnd;
410 if ( replace )
411 hwnd = ::ReplaceText(pFR);
412 else
413 hwnd = ::FindText(pFR);
414
415 if ( !hwnd )
416 {
417 wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
418 ::CommDlgExtendedError());
419
420 delete m_impl;
421 m_impl = NULL;
422
423 return FALSE;
424 }
425
426 // subclass parent window in order to get FINDMSGSTRING message
427 m_impl->SubclassDialog(GetHwndOf(m_parent));
428
429 if ( !::ShowWindow(hwnd, SW_SHOW) )
430 {
431 wxLogLastError(_T("ShowWindow(find dialog)"));
432 }
433
434 m_hWnd = (WXHWND)hwnd;
435
436 return TRUE;
437 }
438
439 // ----------------------------------------------------------------------------
440 // wxFindReplaceDialog title handling
441 // ----------------------------------------------------------------------------
442
443 // we set the title of this dialog in our jook proc but for now don't crash in
444 // the base class version because of m_hWnd == 0
445
446 void wxFindReplaceDialog::SetTitle( const wxString& title)
447 {
448 m_title = title;
449 }
450
451 wxString wxFindReplaceDialog::GetTitle() const
452 {
453 return m_title;
454 }
455
456 // ----------------------------------------------------------------------------
457 // wxFindReplaceDialog position/size
458 // ----------------------------------------------------------------------------
459
460 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
461 int WXUNUSED(width), int WXUNUSED(height),
462 int WXUNUSED(sizeFlags))
463 {
464 // ignore - we can't change the size of this standard dialog
465 return;
466 }
467
468 // NB: of course, both of these functions are completely bogus, but it's better
469 // than nothing
470 void wxFindReplaceDialog::DoGetSize(int *width, int *height) const
471 {
472 // the standard dialog size
473 if ( width )
474 *width = 225;
475 if ( height )
476 *height = 324;
477 }
478
479 void wxFindReplaceDialog::DoGetClientSize(int *width, int *height) const
480 {
481 // the standard dialog size
482 if ( width )
483 *width = 219;
484 if ( height )
485 *height = 299;
486 }
487
488 #endif // wxUSE_FINDREPLDLG
489