]> git.saurik.com Git - wxWidgets.git/blame - src/msw/fdrepdlg.cpp
fix for [ 950550 ] wxChoice - wxEmptyString (wxChoice::FindString doesn't work with...
[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
65571936 9// Licence: wxWindows licence
c41b00c9
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
4676948b 40#if !defined(__WIN32__) || defined(__WXWINCE__)
c41b00c9
VZ
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
975b6bcf
VZ
53UINT_PTR CALLBACK wxFindReplaceDialogHookProc(HWND hwnd,
54 UINT uiMsg,
55 WPARAM wParam,
56 LPARAM lParam);
c41b00c9
VZ
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 84 // set/query the "closed by user" flag
cbe874bd 85 void SetClosedByUser() { m_wasClosedByUser = true; }
14fca738
VZ
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
cbe874bd 100 // true if the user closed us, false otherwise
14fca738
VZ
101 bool m_wasClosedByUser;
102
c41b00c9
VZ
103 // registered Message for Dialog
104 static UINT ms_msgFindDialog;
22f3361e
VZ
105
106 DECLARE_NO_COPY_CLASS(wxFindReplaceDialogImpl)
c41b00c9
VZ
107};
108
109UINT wxFindReplaceDialogImpl::ms_msgFindDialog = 0;
110
111// ============================================================================
112// implementation
113// ============================================================================
114
115// ----------------------------------------------------------------------------
116// wxFindReplaceDialogImpl
117// ----------------------------------------------------------------------------
118
119wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog *dialog,
120 int flagsWX)
121{
122 // get the identifier for the find dialog message if we don't have it yet
123 if ( !ms_msgFindDialog )
124 {
125 ms_msgFindDialog = ::RegisterWindowMessage(FINDMSGSTRING);
126
127 if ( !ms_msgFindDialog )
128 {
129 wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)"));
130 }
131 }
132
133 m_hwndOwner = NULL;
134 m_oldParentWndProc = NULL;
135
cbe874bd 136 m_wasClosedByUser = false;
14fca738 137
c41b00c9
VZ
138 wxZeroMemory(m_findReplace);
139
761989ff 140 // translate the flags: first the dialog creation flags
c41b00c9
VZ
141
142 // always set this to be able to set the title
143 int flags = FR_ENABLEHOOK;
144
761989ff
VZ
145 int flagsDialog = dialog->GetWindowStyle();
146 if ( flagsDialog & wxFR_NOMATCHCASE)
c41b00c9 147 flags |= FR_NOMATCHCASE;
761989ff 148 if ( flagsDialog & wxFR_NOWHOLEWORD)
c41b00c9 149 flags |= FR_NOWHOLEWORD;
761989ff 150 if ( flagsDialog & wxFR_NOUPDOWN)
c41b00c9 151 flags |= FR_NOUPDOWN;
761989ff
VZ
152
153 // and now the flags governing the initial values of the dialogs controls
c41b00c9
VZ
154 if ( flagsWX & wxFR_DOWN)
155 flags |= FR_DOWN;
761989ff
VZ
156 if ( flagsWX & wxFR_MATCHCASE)
157 flags |= FR_MATCHCASE;
158 if ( flagsWX & wxFR_WHOLEWORD )
159 flags |= FR_WHOLEWORD;
c41b00c9
VZ
160
161 m_findReplace.lStructSize = sizeof(FINDREPLACE);
162 m_findReplace.hwndOwner = GetHwndOf(dialog->GetParent());
163 m_findReplace.Flags = flags;
164
165 m_findReplace.lCustData = (LPARAM)dialog;
166 m_findReplace.lpfnHook = wxFindReplaceDialogHookProc;
167}
168
169void wxFindReplaceDialogImpl::InitString(const wxString& str,
170 LPTSTR *ppStr, WORD *pLen)
171{
172 size_t len = str.length() + 1;
173 if ( len < 80 )
174 {
175 // MSDN docs say that the buffer must be at least 80 chars
176 len = 80;
177 }
178
179 *ppStr = new wxChar[len];
180 wxStrcpy(*ppStr, str);
5c519b6c 181 *pLen = (WORD)len;
c41b00c9
VZ
182}
183
184void wxFindReplaceDialogImpl::InitFindWhat(const wxString& str)
185{
186 InitString(str, &m_findReplace.lpstrFindWhat, &m_findReplace.wFindWhatLen);
187}
188
189void wxFindReplaceDialogImpl::InitReplaceWith(const wxString& str)
190{
191 InitString(str,
192 &m_findReplace.lpstrReplaceWith,
193 &m_findReplace.wReplaceWithLen);
194}
195
196void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd)
197{
198 m_hwndOwner = hwnd;
761989ff
VZ
199
200 // check that we don't subclass the parent twice: this would be a bad idea
201 // as then we'd have infinite recursion in wxFindReplaceWindowProc
eb5e4d9a 202 if ( !wxCheckWindowWndProc((WXHWND)hwnd, (WXFARPROC)wxFindReplaceWindowProc) )
761989ff 203 {
975b6bcf
VZ
204 // set the new one and save the old as user data to allow access to it
205 // from wxFindReplaceWindowProc
206 m_oldParentWndProc = wxSetWindowProc(hwnd, wxFindReplaceWindowProc);
207
7330bb53 208 wxSetWindowUserData(hwnd, (void *)m_oldParentWndProc);
761989ff 209 }
c41b00c9
VZ
210}
211
212wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
213{
214 delete [] m_findReplace.lpstrFindWhat;
215 delete [] m_findReplace.lpstrReplaceWith;
216
217 if ( m_hwndOwner )
218 {
975b6bcf
VZ
219 // undo subclassing
220 wxSetWindowProc(m_hwndOwner, m_oldParentWndProc);
c41b00c9
VZ
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 230{
ea392212
VZ
231#if wxUSE_UNICODE_MSLU
232 static unsigned long s_lastMsgFlags = 0;
233
234 // This flag helps us to identify the bogus ANSI message
235 // sent by UNICOWS.DLL (see below)
236 // while we're sending our message to the dialog
237 // we ignore possible messages sent in between
238 static bool s_blockMsg = false;
239#endif // wxUSE_UNICODE_MSLU
240
c41b00c9
VZ
241 if ( nMsg == wxFindReplaceDialogImpl::GetFindDialogMessage() )
242 {
243 FINDREPLACE *pFR = (FINDREPLACE *)lParam;
ea392212
VZ
244
245#if wxUSE_UNICODE_MSLU
246 // This is a hack for a MSLU problem: Versions up to 1.0.4011
247 // of UNICOWS.DLL send the correct UNICODE item after button press
248 // and a bogus ANSI mode item right after this, so lets ignore
249 // the second bogus message
250 if ( s_lastMsgFlags == pFR->Flags )
251 {
252 s_lastMsgFlags = 0;
253 return 0;
254 }
255 s_lastMsgFlags = pFR->Flags;
256#endif // wxUSE_UNICODE_MSLU
257
c41b00c9
VZ
258 wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
259
260 // map flags from Windows
261 wxEventType evtType;
262
cbe874bd 263 bool replace = false;
c41b00c9
VZ
264 if ( pFR->Flags & FR_DIALOGTERM )
265 {
14fca738
VZ
266 // we have to notify the dialog that it's being closed by user and
267 // not deleted programmatically as it behaves differently in these
268 // 2 cases
269 dialog->GetImpl()->SetClosedByUser();
270
c41b00c9
VZ
271 evtType = wxEVT_COMMAND_FIND_CLOSE;
272 }
273 else if ( pFR->Flags & FR_FINDNEXT )
274 {
275 evtType = wxEVT_COMMAND_FIND_NEXT;
276 }
277 else if ( pFR->Flags & FR_REPLACE )
278 {
761989ff 279 evtType = wxEVT_COMMAND_FIND_REPLACE;
c41b00c9 280
cbe874bd 281 replace = true;
c41b00c9
VZ
282 }
283 else if ( pFR->Flags & FR_REPLACEALL )
284 {
761989ff 285 evtType = wxEVT_COMMAND_FIND_REPLACE_ALL;
c41b00c9 286
cbe874bd 287 replace = true;
c41b00c9
VZ
288 }
289 else
290 {
291 wxFAIL_MSG( _T("unknown find dialog event") );
292
293 return 0;
294 }
295
296 wxUint32 flags = 0;
297 if ( pFR->Flags & FR_DOWN )
298 flags |= wxFR_DOWN;
299 if ( pFR->Flags & FR_WHOLEWORD )
300 flags |= wxFR_WHOLEWORD;
301 if ( pFR->Flags & FR_MATCHCASE )
302 flags |= wxFR_MATCHCASE;
303
304 wxFindDialogEvent event(evtType, dialog->GetId());
761989ff 305 event.SetEventObject(dialog);
c41b00c9
VZ
306 event.SetFlags(flags);
307 event.SetFindString(pFR->lpstrFindWhat);
308 if ( replace )
309 {
310 event.SetReplaceString(pFR->lpstrReplaceWith);
311 }
312
ea392212
VZ
313#if wxUSE_UNICODE_MSLU
314 s_blockMsg = true;
315#endif // wxUSE_UNICODE_MSLU
316
8db37e06 317 dialog->Send(event);
ea392212
VZ
318
319#if wxUSE_UNICODE_MSLU
320 s_blockMsg = false;
321#endif // wxUSE_UNICODE_MSLU
c41b00c9 322 }
ea392212
VZ
323#if wxUSE_UNICODE_MSLU
324 else if ( !s_blockMsg )
325 s_lastMsgFlags = 0;
326#endif // wxUSE_UNICODE_MSLU
c41b00c9 327
975b6bcf 328 WNDPROC wndProc = (WNDPROC)wxGetWindowUserData(hwnd);
c41b00c9 329
761989ff
VZ
330 // sanity check
331 wxASSERT_MSG( wndProc != wxFindReplaceWindowProc,
332 _T("infinite recursion detected") );
333
c41b00c9 334 return ::CallWindowProc(wndProc, hwnd, nMsg, wParam, lParam);
761989ff 335}
c41b00c9
VZ
336
337// ----------------------------------------------------------------------------
338// Find/replace dialog hook proc
339// ----------------------------------------------------------------------------
340
975b6bcf
VZ
341UINT_PTR CALLBACK
342wxFindReplaceDialogHookProc(HWND hwnd,
343 UINT uiMsg,
344 WPARAM WXUNUSED(wParam),
345 LPARAM lParam)
c41b00c9
VZ
346{
347 if ( uiMsg == WM_INITDIALOG )
348 {
349 FINDREPLACE *pFR = (FINDREPLACE *)lParam;
350 wxFindReplaceDialog *dialog = (wxFindReplaceDialog *)pFR->lCustData;
351
352 ::SetWindowText(hwnd, dialog->GetTitle());
353
354 // don't return FALSE from here or the dialog won't be shown
355 return TRUE;
356 }
357
358 return 0;
359}
360
361// ============================================================================
362// wxFindReplaceDialog implementation
363// ============================================================================
364
365// ----------------------------------------------------------------------------
366// wxFindReplaceDialog ctors/dtor
367// ----------------------------------------------------------------------------
368
369void wxFindReplaceDialog::Init()
370{
371 m_impl = NULL;
372 m_FindReplaceData = NULL;
373
374 // as we're created in the hidden state, bring the internal flag in sync
cbe874bd 375 m_isShown = false;
c41b00c9
VZ
376}
377
378wxFindReplaceDialog::wxFindReplaceDialog(wxWindow *parent,
379 wxFindReplaceData *data,
761989ff
VZ
380 const wxString &title,
381 int flags)
208c5141 382 : wxFindReplaceDialogBase(parent, data, title, flags)
c41b00c9
VZ
383{
384 Init();
385
761989ff 386 (void)Create(parent, data, title, flags);
c41b00c9
VZ
387}
388
389wxFindReplaceDialog::~wxFindReplaceDialog()
390{
14fca738
VZ
391 // the dialog might have been already deleted if the user closed it
392 // manually but in this case we should have got a notification about it and
393 // the flagmust have been set
394 if ( !m_impl->WasClosedByUser() )
395 {
396 // if it wasn't, delete the dialog ourselves
397 if ( !::DestroyWindow(GetHwnd()) )
398 {
399 wxLogLastError(_T("DestroyWindow(find dialog)"));
400 }
401 }
402
761989ff 403 // unsubclass the parent
c41b00c9 404 delete m_impl;
761989ff
VZ
405
406 // prevent the base class dtor from trying to hide us!
cbe874bd 407 m_isShown = false;
761989ff 408
14fca738 409 // and from destroying our window [again]
44d5b352 410 m_hWnd = (WXHWND)NULL;
c41b00c9
VZ
411}
412
413bool wxFindReplaceDialog::Create(wxWindow *parent,
414 wxFindReplaceData *data,
761989ff
VZ
415 const wxString &title,
416 int flags)
c41b00c9 417{
761989ff 418 m_windowStyle = flags;
c41b00c9
VZ
419 m_FindReplaceData = data;
420 m_parent = parent;
421
422 SetTitle(title);
423
424 // we must have a parent as it will get the messages from us
425 return parent != NULL;
426}
427
c41b00c9
VZ
428// ----------------------------------------------------------------------------
429// wxFindReplaceData show/hide
430// ----------------------------------------------------------------------------
431
432bool wxFindReplaceDialog::Show(bool show)
433{
434 if ( !wxWindowBase::Show(show) )
435 {
436 // visibility status didn't change
cbe874bd 437 return false;
c41b00c9
VZ
438 }
439
440 // do we already have the dialog window?
441 if ( m_hWnd )
442 {
443 // yes, just use it
761989ff
VZ
444 (void)::ShowWindow(GetHwnd(), show ? SW_SHOW : SW_HIDE);
445
cbe874bd 446 return true;
c41b00c9
VZ
447 }
448
449 if ( !show )
450 {
451 // well, it doesn't exist which is as good as being hidden
cbe874bd 452 return true;
c41b00c9
VZ
453 }
454
cbe874bd 455 wxCHECK_MSG( m_FindReplaceData, false, _T("call Create() first!") );
c41b00c9
VZ
456
457 wxASSERT_MSG( !m_impl, _T("why don't we have the window then?") );
458
761989ff 459 m_impl = new wxFindReplaceDialogImpl(this, m_FindReplaceData->GetFlags());
c41b00c9
VZ
460
461 m_impl->InitFindWhat(m_FindReplaceData->GetFindString());
462
761989ff
VZ
463 bool replace = HasFlag(wxFR_REPLACEDIALOG);
464 if ( replace )
c41b00c9 465 {
761989ff 466 m_impl->InitReplaceWith(m_FindReplaceData->GetReplaceString());
c41b00c9
VZ
467 }
468
469 // call the right function to show the dialog which does what we want
761989ff
VZ
470 FINDREPLACE *pFR = m_impl->GetPtrFindReplace();
471 HWND hwnd;
472 if ( replace )
473 hwnd = ::ReplaceText(pFR);
474 else
475 hwnd = ::FindText(pFR);
476
477 if ( !hwnd )
c41b00c9
VZ
478 {
479 wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
480 ::CommDlgExtendedError());
481
482 delete m_impl;
483 m_impl = NULL;
484
cbe874bd 485 return false;
c41b00c9
VZ
486 }
487
488 // subclass parent window in order to get FINDMSGSTRING message
489 m_impl->SubclassDialog(GetHwndOf(m_parent));
490
761989ff 491 if ( !::ShowWindow(hwnd, SW_SHOW) )
c41b00c9
VZ
492 {
493 wxLogLastError(_T("ShowWindow(find dialog)"));
494 }
495
761989ff
VZ
496 m_hWnd = (WXHWND)hwnd;
497
cbe874bd 498 return true;
c41b00c9
VZ
499}
500
501// ----------------------------------------------------------------------------
502// wxFindReplaceDialog title handling
503// ----------------------------------------------------------------------------
504
505// we set the title of this dialog in our jook proc but for now don't crash in
506// the base class version because of m_hWnd == 0
507
508void wxFindReplaceDialog::SetTitle( const wxString& title)
509{
510 m_title = title;
511}
512
513wxString wxFindReplaceDialog::GetTitle() const
514{
515 return m_title;
516}
517
518// ----------------------------------------------------------------------------
519// wxFindReplaceDialog position/size
520// ----------------------------------------------------------------------------
521
522void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
523 int WXUNUSED(width), int WXUNUSED(height),
524 int WXUNUSED(sizeFlags))
525{
526 // ignore - we can't change the size of this standard dialog
527 return;
528}
529
530// NB: of course, both of these functions are completely bogus, but it's better
531// than nothing
532void wxFindReplaceDialog::DoGetSize(int *width, int *height) const
533{
534 // the standard dialog size
535 if ( width )
536 *width = 225;
537 if ( height )
538 *height = 324;
539}
540
541void wxFindReplaceDialog::DoGetClientSize(int *width, int *height) const
542{
543 // the standard dialog size
544 if ( width )
545 *width = 219;
546 if ( height )
547 *height = 299;
548}
549
550#endif // wxUSE_FINDREPLDLG
551