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