]> git.saurik.com Git - wxWidgets.git/blame - src/msw/fdrepdlg.cpp
make sure we are removing ourselves from the focus of the toplevel frame when deletin...
[wxWidgets.git] / src / msw / fdrepdlg.cpp
CommitLineData
c41b00c9
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/fdrepdlg.cpp
3// Purpose: wxFindReplaceDialog class
8db37e06
VZ
4// Author: Markus Greither and Vadim Zeitlin
5// Modified by:
c41b00c9
VZ
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__
8db37e06 21 #pragma implementation "mswfdrepdlg.h"
c41b00c9
VZ
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
761989ff 50LRESULT APIENTRY wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg,
c41b00c9
VZ
51 WPARAM wParam, LPARAM lParam);
52
53UINT CALLBACK wxFindReplaceDialogHookProc(HWND hwnd,
54 UINT uiMsg,
55 WPARAM wParam,
56 LPARAM lParam);
57
58// ----------------------------------------------------------------------------
59// wxWin macros
60// ----------------------------------------------------------------------------
61
62IMPLEMENT_DYNAMIC_CLASS(wxFindReplaceDialog, wxDialog)
63
c41b00c9
VZ
64// ----------------------------------------------------------------------------
65// wxFindReplaceDialogImpl: the internals of wxFindReplaceDialog
66// ----------------------------------------------------------------------------
67
68class WXDLLEXPORT wxFindReplaceDialogImpl
69{
70public:
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
14fca738
VZ
84 // set/query the "closed by user" flag
85 void SetClosedByUser() { m_wasClosedByUser = TRUE; }
86 bool WasClosedByUser() const { return m_wasClosedByUser; }
87
c41b00c9
VZ
88private:
89 void InitString(const wxString& str, LPTSTR *ppStr, WORD *pLen);
90
91 // the owner of the dialog
92 HWND m_hwndOwner;
93
94 // the previous window proc of our owner
95 WNDPROC m_oldParentWndProc;
96
97 // the find replace data used by the dialog
98 FINDREPLACE m_findReplace;
99
14fca738
VZ
100 // TRUE if the user closed us, FALSE otherwise
101 bool m_wasClosedByUser;
102
c41b00c9
VZ
103 // registered Message for Dialog
104 static UINT ms_msgFindDialog;
105};
106
107UINT wxFindReplaceDialogImpl::ms_msgFindDialog = 0;
108
109// ============================================================================
110// implementation
111// ============================================================================
112
113// ----------------------------------------------------------------------------
114// wxFindReplaceDialogImpl
115// ----------------------------------------------------------------------------
116
117wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog *dialog,
118 int flagsWX)
119{
120 // get the identifier for the find dialog message if we don't have it yet
121 if ( !ms_msgFindDialog )
122 {
123 ms_msgFindDialog = ::RegisterWindowMessage(FINDMSGSTRING);
124
125 if ( !ms_msgFindDialog )
126 {
127 wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)"));
128 }
129 }
130
131 m_hwndOwner = NULL;
132 m_oldParentWndProc = NULL;
133
14fca738
VZ
134 m_wasClosedByUser = FALSE;
135
c41b00c9
VZ
136 wxZeroMemory(m_findReplace);
137
761989ff 138 // translate the flags: first the dialog creation flags
c41b00c9
VZ
139
140 // always set this to be able to set the title
141 int flags = FR_ENABLEHOOK;
142
761989ff
VZ
143 int flagsDialog = dialog->GetWindowStyle();
144 if ( flagsDialog & wxFR_NOMATCHCASE)
c41b00c9 145 flags |= FR_NOMATCHCASE;
761989ff 146 if ( flagsDialog & wxFR_NOWHOLEWORD)
c41b00c9 147 flags |= FR_NOWHOLEWORD;
761989ff 148 if ( flagsDialog & wxFR_NOUPDOWN)
c41b00c9 149 flags |= FR_NOUPDOWN;
761989ff
VZ
150
151 // and now the flags governing the initial values of the dialogs controls
c41b00c9
VZ
152 if ( flagsWX & wxFR_DOWN)
153 flags |= FR_DOWN;
761989ff
VZ
154 if ( flagsWX & wxFR_MATCHCASE)
155 flags |= FR_MATCHCASE;
156 if ( flagsWX & wxFR_WHOLEWORD )
157 flags |= FR_WHOLEWORD;
c41b00c9
VZ
158
159 m_findReplace.lStructSize = sizeof(FINDREPLACE);
160 m_findReplace.hwndOwner = GetHwndOf(dialog->GetParent());
161 m_findReplace.Flags = flags;
162
163 m_findReplace.lCustData = (LPARAM)dialog;
164 m_findReplace.lpfnHook = wxFindReplaceDialogHookProc;
165}
166
167void wxFindReplaceDialogImpl::InitString(const wxString& str,
168 LPTSTR *ppStr, WORD *pLen)
169{
170 size_t len = str.length() + 1;
171 if ( len < 80 )
172 {
173 // MSDN docs say that the buffer must be at least 80 chars
174 len = 80;
175 }
176
177 *ppStr = new wxChar[len];
178 wxStrcpy(*ppStr, str);
179 *pLen = len;
180}
181
182void wxFindReplaceDialogImpl::InitFindWhat(const wxString& str)
183{
184 InitString(str, &m_findReplace.lpstrFindWhat, &m_findReplace.wFindWhatLen);
185}
186
187void wxFindReplaceDialogImpl::InitReplaceWith(const wxString& str)
188{
189 InitString(str,
190 &m_findReplace.lpstrReplaceWith,
191 &m_findReplace.wReplaceWithLen);
192}
193
194void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd)
195{
196 m_hwndOwner = hwnd;
761989ff
VZ
197
198 // check that we don't subclass the parent twice: this would be a bad idea
199 // as then we'd have infinite recursion in wxFindReplaceWindowProc
eb5e4d9a 200 if ( !wxCheckWindowWndProc((WXHWND)hwnd, (WXFARPROC)wxFindReplaceWindowProc) )
761989ff 201 {
eb5e4d9a 202 WNDPROC oldParentWndProc = (WNDPROC)::GetWindowLong(hwnd, GWL_WNDPROC);
761989ff
VZ
203 // save old wnd proc elsewhere to access it from
204 // wxFindReplaceWindowProc
205 m_oldParentWndProc = oldParentWndProc;
206 (void)::SetWindowLong(hwnd, GWL_USERDATA, (LONG)oldParentWndProc);
207
208 // and set the new one
209 (void)::SetWindowLong(hwnd, GWL_WNDPROC, (LONG)wxFindReplaceWindowProc);
210 }
c41b00c9
VZ
211}
212
213wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
214{
215 delete [] m_findReplace.lpstrFindWhat;
216 delete [] m_findReplace.lpstrReplaceWith;
217
218 if ( m_hwndOwner )
219 {
220 ::SetWindowLong(m_hwndOwner, GWL_WNDPROC, (LONG)m_oldParentWndProc);
221 }
222}
223
224// ----------------------------------------------------------------------------
225// Window Proc for handling RegisterWindowMessage(FINDMSGSTRING)
226// ----------------------------------------------------------------------------
227
761989ff
VZ
228LRESULT APIENTRY wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg,
229 WPARAM wParam, LPARAM lParam)
c41b00c9
VZ
230{
231 if ( nMsg == wxFindReplaceDialogImpl::GetFindDialogMessage() )
232 {
233 FINDREPLACE *pFR = (FINDREPLACE *)lParam;
234 wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
235
236 // map flags from Windows
237 wxEventType evtType;
238
239 bool replace = FALSE;
240 if ( pFR->Flags & FR_DIALOGTERM )
241 {
14fca738
VZ
242 // we have to notify the dialog that it's being closed by user and
243 // not deleted programmatically as it behaves differently in these
244 // 2 cases
245 dialog->GetImpl()->SetClosedByUser();
246
c41b00c9
VZ
247 evtType = wxEVT_COMMAND_FIND_CLOSE;
248 }
249 else if ( pFR->Flags & FR_FINDNEXT )
250 {
251 evtType = wxEVT_COMMAND_FIND_NEXT;
252 }
253 else if ( pFR->Flags & FR_REPLACE )
254 {
761989ff 255 evtType = wxEVT_COMMAND_FIND_REPLACE;
c41b00c9
VZ
256
257 replace = TRUE;
258 }
259 else if ( pFR->Flags & FR_REPLACEALL )
260 {
761989ff 261 evtType = wxEVT_COMMAND_FIND_REPLACE_ALL;
c41b00c9
VZ
262
263 replace = TRUE;
264 }
265 else
266 {
267 wxFAIL_MSG( _T("unknown find dialog event") );
268
269 return 0;
270 }
271
272 wxUint32 flags = 0;
273 if ( pFR->Flags & FR_DOWN )
274 flags |= wxFR_DOWN;
275 if ( pFR->Flags & FR_WHOLEWORD )
276 flags |= wxFR_WHOLEWORD;
277 if ( pFR->Flags & FR_MATCHCASE )
278 flags |= wxFR_MATCHCASE;
279
280 wxFindDialogEvent event(evtType, dialog->GetId());
761989ff 281 event.SetEventObject(dialog);
c41b00c9
VZ
282 event.SetFlags(flags);
283 event.SetFindString(pFR->lpstrFindWhat);
284 if ( replace )
285 {
286 event.SetReplaceString(pFR->lpstrReplaceWith);
287 }
288
8db37e06 289 dialog->Send(event);
c41b00c9
VZ
290 }
291
292 WNDPROC wndProc = (WNDPROC)::GetWindowLong(hwnd, GWL_USERDATA);
293
761989ff
VZ
294 // sanity check
295 wxASSERT_MSG( wndProc != wxFindReplaceWindowProc,
296 _T("infinite recursion detected") );
297
c41b00c9 298 return ::CallWindowProc(wndProc, hwnd, nMsg, wParam, lParam);
761989ff 299}
c41b00c9
VZ
300
301// ----------------------------------------------------------------------------
302// Find/replace dialog hook proc
303// ----------------------------------------------------------------------------
304
305UINT CALLBACK wxFindReplaceDialogHookProc(HWND hwnd,
306 UINT uiMsg,
307 WPARAM WXUNUSED(wParam),
308 LPARAM lParam)
309{
310 if ( uiMsg == WM_INITDIALOG )
311 {
312 FINDREPLACE *pFR = (FINDREPLACE *)lParam;
313 wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
314
315 ::SetWindowText(hwnd, dialog->GetTitle());
316
317 // don't return FALSE from here or the dialog won't be shown
318 return TRUE;
319 }
320
321 return 0;
322}
323
324// ============================================================================
325// wxFindReplaceDialog implementation
326// ============================================================================
327
328// ----------------------------------------------------------------------------
329// wxFindReplaceDialog ctors/dtor
330// ----------------------------------------------------------------------------
331
332void wxFindReplaceDialog::Init()
333{
334 m_impl = NULL;
335 m_FindReplaceData = NULL;
336
337 // as we're created in the hidden state, bring the internal flag in sync
338 m_isShown = FALSE;
339}
340
341wxFindReplaceDialog::wxFindReplaceDialog(wxWindow *parent,
342 wxFindReplaceData *data,
761989ff
VZ
343 const wxString &title,
344 int flags)
208c5141 345 : wxFindReplaceDialogBase(parent, data, title, flags)
c41b00c9
VZ
346{
347 Init();
348
761989ff 349 (void)Create(parent, data, title, flags);
c41b00c9
VZ
350}
351
352wxFindReplaceDialog::~wxFindReplaceDialog()
353{
14fca738
VZ
354 // the dialog might have been already deleted if the user closed it
355 // manually but in this case we should have got a notification about it and
356 // the flagmust have been set
357 if ( !m_impl->WasClosedByUser() )
358 {
359 // if it wasn't, delete the dialog ourselves
360 if ( !::DestroyWindow(GetHwnd()) )
361 {
362 wxLogLastError(_T("DestroyWindow(find dialog)"));
363 }
364 }
365
761989ff 366 // unsubclass the parent
c41b00c9 367 delete m_impl;
761989ff
VZ
368
369 // prevent the base class dtor from trying to hide us!
370 m_isShown = FALSE;
371
14fca738 372 // and from destroying our window [again]
44d5b352 373 m_hWnd = (WXHWND)NULL;
c41b00c9
VZ
374}
375
376bool wxFindReplaceDialog::Create(wxWindow *parent,
377 wxFindReplaceData *data,
761989ff
VZ
378 const wxString &title,
379 int flags)
c41b00c9 380{
761989ff 381 m_windowStyle = flags;
c41b00c9
VZ
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
c41b00c9
VZ
391// ----------------------------------------------------------------------------
392// wxFindReplaceData show/hide
393// ----------------------------------------------------------------------------
394
395bool 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
761989ff
VZ
407 (void)::ShowWindow(GetHwnd(), show ? SW_SHOW : SW_HIDE);
408
409 return TRUE;
c41b00c9
VZ
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, _T("call Create() first!") );
419
420 wxASSERT_MSG( !m_impl, _T("why don't we have the window then?") );
421
761989ff 422 m_impl = new wxFindReplaceDialogImpl(this, m_FindReplaceData->GetFlags());
c41b00c9
VZ
423
424 m_impl->InitFindWhat(m_FindReplaceData->GetFindString());
425
761989ff
VZ
426 bool replace = HasFlag(wxFR_REPLACEDIALOG);
427 if ( replace )
c41b00c9 428 {
761989ff 429 m_impl->InitReplaceWith(m_FindReplaceData->GetReplaceString());
c41b00c9
VZ
430 }
431
432 // call the right function to show the dialog which does what we want
761989ff
VZ
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 )
c41b00c9
VZ
441 {
442 wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
443 ::CommDlgExtendedError());
444
445 delete m_impl;
446 m_impl = NULL;
447
448 return FALSE;
449 }
450
451 // subclass parent window in order to get FINDMSGSTRING message
452 m_impl->SubclassDialog(GetHwndOf(m_parent));
453
761989ff 454 if ( !::ShowWindow(hwnd, SW_SHOW) )
c41b00c9
VZ
455 {
456 wxLogLastError(_T("ShowWindow(find dialog)"));
457 }
458
761989ff
VZ
459 m_hWnd = (WXHWND)hwnd;
460
c41b00c9
VZ
461 return TRUE;
462}
463
464// ----------------------------------------------------------------------------
465// wxFindReplaceDialog title handling
466// ----------------------------------------------------------------------------
467
468// we set the title of this dialog in our jook proc but for now don't crash in
469// the base class version because of m_hWnd == 0
470
471void wxFindReplaceDialog::SetTitle( const wxString& title)
472{
473 m_title = title;
474}
475
476wxString wxFindReplaceDialog::GetTitle() const
477{
478 return m_title;
479}
480
481// ----------------------------------------------------------------------------
482// wxFindReplaceDialog position/size
483// ----------------------------------------------------------------------------
484
485void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
486 int WXUNUSED(width), int WXUNUSED(height),
487 int WXUNUSED(sizeFlags))
488{
489 // ignore - we can't change the size of this standard dialog
490 return;
491}
492
493// NB: of course, both of these functions are completely bogus, but it's better
494// than nothing
495void wxFindReplaceDialog::DoGetSize(int *width, int *height) const
496{
497 // the standard dialog size
498 if ( width )
499 *width = 225;
500 if ( height )
501 *height = 324;
502}
503
504void wxFindReplaceDialog::DoGetClientSize(int *width, int *height) const
505{
506 // the standard dialog size
507 if ( width )
508 *width = 219;
509 if ( height )
510 *height = 299;
511}
512
513#endif // wxUSE_FINDREPLDLG
514