]> git.saurik.com Git - wxWidgets.git/blob - src/msw/fdrepdlg.cpp
another segfault fix
[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 // set/query the "closed by user" flag
85 void SetClosedByUser() { m_wasClosedByUser = TRUE; }
86 bool WasClosedByUser() const { return m_wasClosedByUser; }
87
88 private:
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
100 // TRUE if the user closed us, FALSE otherwise
101 bool m_wasClosedByUser;
102
103 // registered Message for Dialog
104 static UINT ms_msgFindDialog;
105 };
106
107 UINT wxFindReplaceDialogImpl::ms_msgFindDialog = 0;
108
109 // ============================================================================
110 // implementation
111 // ============================================================================
112
113 // ----------------------------------------------------------------------------
114 // wxFindReplaceDialogImpl
115 // ----------------------------------------------------------------------------
116
117 wxFindReplaceDialogImpl::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
134 m_wasClosedByUser = FALSE;
135
136 wxZeroMemory(m_findReplace);
137
138 // translate the flags: first the dialog creation flags
139
140 // always set this to be able to set the title
141 int flags = FR_ENABLEHOOK;
142
143 int flagsDialog = dialog->GetWindowStyle();
144 if ( flagsDialog & wxFR_NOMATCHCASE)
145 flags |= FR_NOMATCHCASE;
146 if ( flagsDialog & wxFR_NOWHOLEWORD)
147 flags |= FR_NOWHOLEWORD;
148 if ( flagsDialog & wxFR_NOUPDOWN)
149 flags |= FR_NOUPDOWN;
150
151 // and now the flags governing the initial values of the dialogs controls
152 if ( flagsWX & wxFR_DOWN)
153 flags |= FR_DOWN;
154 if ( flagsWX & wxFR_MATCHCASE)
155 flags |= FR_MATCHCASE;
156 if ( flagsWX & wxFR_WHOLEWORD )
157 flags |= FR_WHOLEWORD;
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
167 void 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
182 void wxFindReplaceDialogImpl::InitFindWhat(const wxString& str)
183 {
184 InitString(str, &m_findReplace.lpstrFindWhat, &m_findReplace.wFindWhatLen);
185 }
186
187 void wxFindReplaceDialogImpl::InitReplaceWith(const wxString& str)
188 {
189 InitString(str,
190 &m_findReplace.lpstrReplaceWith,
191 &m_findReplace.wReplaceWithLen);
192 }
193
194 void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd)
195 {
196 m_hwndOwner = hwnd;
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
200 WNDPROC oldParentWndProc = (WNDPROC)::GetWindowLong(hwnd, GWL_WNDPROC);
201
202 if ( oldParentWndProc != wxFindReplaceWindowProc )
203 {
204 // save old wnd proc elsewhere to access it from
205 // wxFindReplaceWindowProc
206 m_oldParentWndProc = oldParentWndProc;
207 (void)::SetWindowLong(hwnd, GWL_USERDATA, (LONG)oldParentWndProc);
208
209 // and set the new one
210 (void)::SetWindowLong(hwnd, GWL_WNDPROC, (LONG)wxFindReplaceWindowProc);
211 }
212 }
213
214 wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
215 {
216 delete [] m_findReplace.lpstrFindWhat;
217 delete [] m_findReplace.lpstrReplaceWith;
218
219 if ( m_hwndOwner )
220 {
221 ::SetWindowLong(m_hwndOwner, GWL_WNDPROC, (LONG)m_oldParentWndProc);
222 }
223 }
224
225 // ----------------------------------------------------------------------------
226 // Window Proc for handling RegisterWindowMessage(FINDMSGSTRING)
227 // ----------------------------------------------------------------------------
228
229 LRESULT APIENTRY wxFindReplaceWindowProc(HWND hwnd, WXUINT nMsg,
230 WPARAM wParam, LPARAM lParam)
231 {
232 if ( nMsg == wxFindReplaceDialogImpl::GetFindDialogMessage() )
233 {
234 FINDREPLACE *pFR = (FINDREPLACE *)lParam;
235 wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
236
237 // map flags from Windows
238 wxEventType evtType;
239
240 bool replace = FALSE;
241 if ( pFR->Flags & FR_DIALOGTERM )
242 {
243 // we have to notify the dialog that it's being closed by user and
244 // not deleted programmatically as it behaves differently in these
245 // 2 cases
246 dialog->GetImpl()->SetClosedByUser();
247
248 evtType = wxEVT_COMMAND_FIND_CLOSE;
249 }
250 else if ( pFR->Flags & FR_FINDNEXT )
251 {
252 evtType = wxEVT_COMMAND_FIND_NEXT;
253 }
254 else if ( pFR->Flags & FR_REPLACE )
255 {
256 evtType = wxEVT_COMMAND_FIND_REPLACE;
257
258 replace = TRUE;
259 }
260 else if ( pFR->Flags & FR_REPLACEALL )
261 {
262 evtType = wxEVT_COMMAND_FIND_REPLACE_ALL;
263
264 replace = TRUE;
265 }
266 else
267 {
268 wxFAIL_MSG( _T("unknown find dialog event") );
269
270 return 0;
271 }
272
273 wxUint32 flags = 0;
274 if ( pFR->Flags & FR_DOWN )
275 flags |= wxFR_DOWN;
276 if ( pFR->Flags & FR_WHOLEWORD )
277 flags |= wxFR_WHOLEWORD;
278 if ( pFR->Flags & FR_MATCHCASE )
279 flags |= wxFR_MATCHCASE;
280
281 wxFindDialogEvent event(evtType, dialog->GetId());
282 event.SetEventObject(dialog);
283 event.SetFlags(flags);
284 event.SetFindString(pFR->lpstrFindWhat);
285 if ( replace )
286 {
287 event.SetReplaceString(pFR->lpstrReplaceWith);
288 }
289
290 dialog->Send(event);
291 }
292
293 WNDPROC wndProc = (WNDPROC)::GetWindowLong(hwnd, GWL_USERDATA);
294
295 // sanity check
296 wxASSERT_MSG( wndProc != wxFindReplaceWindowProc,
297 _T("infinite recursion detected") );
298
299 return ::CallWindowProc(wndProc, hwnd, nMsg, wParam, lParam);
300 }
301
302 // ----------------------------------------------------------------------------
303 // Find/replace dialog hook proc
304 // ----------------------------------------------------------------------------
305
306 UINT CALLBACK wxFindReplaceDialogHookProc(HWND hwnd,
307 UINT uiMsg,
308 WPARAM WXUNUSED(wParam),
309 LPARAM lParam)
310 {
311 if ( uiMsg == WM_INITDIALOG )
312 {
313 FINDREPLACE *pFR = (FINDREPLACE *)lParam;
314 wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
315
316 ::SetWindowText(hwnd, dialog->GetTitle());
317
318 // don't return FALSE from here or the dialog won't be shown
319 return TRUE;
320 }
321
322 return 0;
323 }
324
325 // ============================================================================
326 // wxFindReplaceDialog implementation
327 // ============================================================================
328
329 // ----------------------------------------------------------------------------
330 // wxFindReplaceDialog ctors/dtor
331 // ----------------------------------------------------------------------------
332
333 void wxFindReplaceDialog::Init()
334 {
335 m_impl = NULL;
336 m_FindReplaceData = NULL;
337
338 // as we're created in the hidden state, bring the internal flag in sync
339 m_isShown = FALSE;
340 }
341
342 wxFindReplaceDialog::wxFindReplaceDialog(wxWindow *parent,
343 wxFindReplaceData *data,
344 const wxString &title,
345 int flags)
346 : wxFindReplaceDialogBase(parent, data, title, flags)
347 {
348 Init();
349
350 (void)Create(parent, data, title, flags);
351 }
352
353 wxFindReplaceDialog::~wxFindReplaceDialog()
354 {
355 // the dialog might have been already deleted if the user closed it
356 // manually but in this case we should have got a notification about it and
357 // the flagmust have been set
358 if ( !m_impl->WasClosedByUser() )
359 {
360 // if it wasn't, delete the dialog ourselves
361 if ( !::DestroyWindow(GetHwnd()) )
362 {
363 wxLogLastError(_T("DestroyWindow(find dialog)"));
364 }
365 }
366
367 // unsubclass the parent
368 delete m_impl;
369
370 // prevent the base class dtor from trying to hide us!
371 m_isShown = FALSE;
372
373 // and from destroying our window [again]
374 m_hWnd = (WXHWND)NULL;
375 }
376
377 bool wxFindReplaceDialog::Create(wxWindow *parent,
378 wxFindReplaceData *data,
379 const wxString &title,
380 int flags)
381 {
382 m_windowStyle = flags;
383 m_FindReplaceData = data;
384 m_parent = parent;
385
386 SetTitle(title);
387
388 // we must have a parent as it will get the messages from us
389 return parent != NULL;
390 }
391
392 // ----------------------------------------------------------------------------
393 // wxFindReplaceData show/hide
394 // ----------------------------------------------------------------------------
395
396 bool wxFindReplaceDialog::Show(bool show)
397 {
398 if ( !wxWindowBase::Show(show) )
399 {
400 // visibility status didn't change
401 return FALSE;
402 }
403
404 // do we already have the dialog window?
405 if ( m_hWnd )
406 {
407 // yes, just use it
408 (void)::ShowWindow(GetHwnd(), show ? SW_SHOW : SW_HIDE);
409
410 return TRUE;
411 }
412
413 if ( !show )
414 {
415 // well, it doesn't exist which is as good as being hidden
416 return TRUE;
417 }
418
419 wxCHECK_MSG( m_FindReplaceData, FALSE, _T("call Create() first!") );
420
421 wxASSERT_MSG( !m_impl, _T("why don't we have the window then?") );
422
423 m_impl = new wxFindReplaceDialogImpl(this, m_FindReplaceData->GetFlags());
424
425 m_impl->InitFindWhat(m_FindReplaceData->GetFindString());
426
427 bool replace = HasFlag(wxFR_REPLACEDIALOG);
428 if ( replace )
429 {
430 m_impl->InitReplaceWith(m_FindReplaceData->GetReplaceString());
431 }
432
433 // call the right function to show the dialog which does what we want
434 FINDREPLACE *pFR = m_impl->GetPtrFindReplace();
435 HWND hwnd;
436 if ( replace )
437 hwnd = ::ReplaceText(pFR);
438 else
439 hwnd = ::FindText(pFR);
440
441 if ( !hwnd )
442 {
443 wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
444 ::CommDlgExtendedError());
445
446 delete m_impl;
447 m_impl = NULL;
448
449 return FALSE;
450 }
451
452 // subclass parent window in order to get FINDMSGSTRING message
453 m_impl->SubclassDialog(GetHwndOf(m_parent));
454
455 if ( !::ShowWindow(hwnd, SW_SHOW) )
456 {
457 wxLogLastError(_T("ShowWindow(find dialog)"));
458 }
459
460 m_hWnd = (WXHWND)hwnd;
461
462 return TRUE;
463 }
464
465 // ----------------------------------------------------------------------------
466 // wxFindReplaceDialog title handling
467 // ----------------------------------------------------------------------------
468
469 // we set the title of this dialog in our jook proc but for now don't crash in
470 // the base class version because of m_hWnd == 0
471
472 void wxFindReplaceDialog::SetTitle( const wxString& title)
473 {
474 m_title = title;
475 }
476
477 wxString wxFindReplaceDialog::GetTitle() const
478 {
479 return m_title;
480 }
481
482 // ----------------------------------------------------------------------------
483 // wxFindReplaceDialog position/size
484 // ----------------------------------------------------------------------------
485
486 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
487 int WXUNUSED(width), int WXUNUSED(height),
488 int WXUNUSED(sizeFlags))
489 {
490 // ignore - we can't change the size of this standard dialog
491 return;
492 }
493
494 // NB: of course, both of these functions are completely bogus, but it's better
495 // than nothing
496 void wxFindReplaceDialog::DoGetSize(int *width, int *height) const
497 {
498 // the standard dialog size
499 if ( width )
500 *width = 225;
501 if ( height )
502 *height = 324;
503 }
504
505 void wxFindReplaceDialog::DoGetClientSize(int *width, int *height) const
506 {
507 // the standard dialog size
508 if ( width )
509 *width = 219;
510 if ( height )
511 *height = 299;
512 }
513
514 #endif // wxUSE_FINDREPLDLG
515