1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/fdrepdlg.cpp
3 // Purpose: wxFindReplaceDialog class
4 // Author: Markus Greither and Vadim Zeitlin
8 // Copyright: (c) Markus Greither
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
34 #include "wx/msw/wrapcdlg.h"
35 #include "wx/fdrepdlg.h"
37 // ----------------------------------------------------------------------------
38 // functions prototypes
39 // ----------------------------------------------------------------------------
41 LRESULT APIENTRY
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
,
42 WPARAM wParam
, LPARAM lParam
);
44 UINT_PTR CALLBACK
wxFindReplaceDialogHookProc(HWND hwnd
,
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 IMPLEMENT_DYNAMIC_CLASS(wxFindReplaceDialog
, wxDialog
)
55 // ----------------------------------------------------------------------------
56 // wxFindReplaceDialogImpl: the internals of wxFindReplaceDialog
57 // ----------------------------------------------------------------------------
59 class WXDLLEXPORT wxFindReplaceDialogImpl
62 wxFindReplaceDialogImpl(wxFindReplaceDialog
*dialog
, int flagsWX
);
63 ~wxFindReplaceDialogImpl();
65 void InitFindWhat(const wxString
& str
);
66 void InitReplaceWith(const wxString
& str
);
68 void SubclassDialog(HWND hwnd
);
70 static UINT
GetFindDialogMessage() { return ms_msgFindDialog
; }
72 // only for passing to ::FindText or ::ReplaceText
73 FINDREPLACE
*GetPtrFindReplace() { return &m_findReplace
; }
75 // set/query the "closed by user" flag
76 void SetClosedByUser() { m_wasClosedByUser
= true; }
77 bool WasClosedByUser() const { return m_wasClosedByUser
; }
80 void InitString(const wxString
& str
, LPTSTR
*ppStr
, WORD
*pLen
);
82 // the owner of the dialog
85 // the previous window proc of our owner
86 WNDPROC m_oldParentWndProc
;
88 // the find replace data used by the dialog
89 FINDREPLACE m_findReplace
;
91 // true if the user closed us, false otherwise
92 bool m_wasClosedByUser
;
94 // registered Message for Dialog
95 static UINT ms_msgFindDialog
;
97 DECLARE_NO_COPY_CLASS(wxFindReplaceDialogImpl
)
100 UINT
wxFindReplaceDialogImpl::ms_msgFindDialog
= 0;
102 // ============================================================================
104 // ============================================================================
106 // ----------------------------------------------------------------------------
107 // wxFindReplaceDialogImpl
108 // ----------------------------------------------------------------------------
110 wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog
*dialog
,
113 // get the identifier for the find dialog message if we don't have it yet
114 if ( !ms_msgFindDialog
)
116 ms_msgFindDialog
= ::RegisterWindowMessage(FINDMSGSTRING
);
118 if ( !ms_msgFindDialog
)
120 wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)"));
125 m_oldParentWndProc
= NULL
;
127 m_wasClosedByUser
= false;
129 wxZeroMemory(m_findReplace
);
131 // translate the flags: first the dialog creation flags
133 // always set this to be able to set the title
134 int flags
= FR_ENABLEHOOK
;
136 int flagsDialog
= dialog
->GetWindowStyle();
137 if ( flagsDialog
& wxFR_NOMATCHCASE
)
138 flags
|= FR_NOMATCHCASE
;
139 if ( flagsDialog
& wxFR_NOWHOLEWORD
)
140 flags
|= FR_NOWHOLEWORD
;
141 if ( flagsDialog
& wxFR_NOUPDOWN
)
142 flags
|= FR_NOUPDOWN
;
144 // and now the flags governing the initial values of the dialogs controls
145 if ( flagsWX
& wxFR_DOWN
)
147 if ( flagsWX
& wxFR_MATCHCASE
)
148 flags
|= FR_MATCHCASE
;
149 if ( flagsWX
& wxFR_WHOLEWORD
)
150 flags
|= FR_WHOLEWORD
;
152 m_findReplace
.lStructSize
= sizeof(FINDREPLACE
);
153 m_findReplace
.hwndOwner
= GetHwndOf(dialog
->GetParent());
154 m_findReplace
.Flags
= flags
;
156 m_findReplace
.lCustData
= (LPARAM
)dialog
;
157 m_findReplace
.lpfnHook
= wxFindReplaceDialogHookProc
;
160 void wxFindReplaceDialogImpl::InitString(const wxString
& str
,
161 LPTSTR
*ppStr
, WORD
*pLen
)
163 size_t len
= str
.length() + 1;
166 // MSDN docs say that the buffer must be at least 80 chars
170 *ppStr
= new wxChar
[len
];
171 wxStrcpy(*ppStr
, str
);
175 void wxFindReplaceDialogImpl::InitFindWhat(const wxString
& str
)
177 InitString(str
, &m_findReplace
.lpstrFindWhat
, &m_findReplace
.wFindWhatLen
);
180 void wxFindReplaceDialogImpl::InitReplaceWith(const wxString
& str
)
183 &m_findReplace
.lpstrReplaceWith
,
184 &m_findReplace
.wReplaceWithLen
);
187 void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd
)
191 // check that we don't subclass the parent twice: this would be a bad idea
192 // as then we'd have infinite recursion in wxFindReplaceWindowProc
193 wxCHECK_RET( wxGetWindowProc(hwnd
) !=
194 wx_reinterpret_cast(void *, wxFindReplaceWindowProc
),
195 _T("can't have more than one find dialog currently") );
197 // set the new one and save the old as user data to allow access to it
198 // from wxFindReplaceWindowProc
199 m_oldParentWndProc
= wxSetWindowProc(hwnd
, wxFindReplaceWindowProc
);
201 wxSetWindowUserData(hwnd
, (void *)m_oldParentWndProc
);
204 wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
206 delete [] m_findReplace
.lpstrFindWhat
;
207 delete [] m_findReplace
.lpstrReplaceWith
;
212 wxSetWindowProc(m_hwndOwner
, m_oldParentWndProc
);
216 // ----------------------------------------------------------------------------
217 // Window Proc for handling RegisterWindowMessage(FINDMSGSTRING)
218 // ----------------------------------------------------------------------------
220 LRESULT APIENTRY
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
,
221 WPARAM wParam
, LPARAM lParam
)
223 #if wxUSE_UNICODE_MSLU
224 static unsigned long s_lastMsgFlags
= 0;
226 // This flag helps us to identify the bogus ANSI message
227 // sent by UNICOWS.DLL (see below)
228 // while we're sending our message to the dialog
229 // we ignore possible messages sent in between
230 static bool s_blockMsg
= false;
231 #endif // wxUSE_UNICODE_MSLU
233 if ( nMsg
== wxFindReplaceDialogImpl::GetFindDialogMessage() )
235 FINDREPLACE
*pFR
= (FINDREPLACE
*)lParam
;
237 #if wxUSE_UNICODE_MSLU
238 // This is a hack for a MSLU problem: Versions up to 1.0.4011
239 // of UNICOWS.DLL send the correct UNICODE item after button press
240 // and a bogus ANSI mode item right after this, so lets ignore
241 // the second bogus message
242 if ( wxUsingUnicowsDll() && s_lastMsgFlags
== pFR
->Flags
)
247 s_lastMsgFlags
= pFR
->Flags
;
248 #endif // wxUSE_UNICODE_MSLU
250 wxFindReplaceDialog
*dialog
= (wxFindReplaceDialog
*)pFR
->lCustData
;
252 // map flags from Windows
255 bool replace
= false;
256 if ( pFR
->Flags
& FR_DIALOGTERM
)
258 // we have to notify the dialog that it's being closed by user and
259 // not deleted programmatically as it behaves differently in these
261 dialog
->GetImpl()->SetClosedByUser();
263 evtType
= wxEVT_COMMAND_FIND_CLOSE
;
265 else if ( pFR
->Flags
& FR_FINDNEXT
)
267 evtType
= wxEVT_COMMAND_FIND_NEXT
;
269 else if ( pFR
->Flags
& FR_REPLACE
)
271 evtType
= wxEVT_COMMAND_FIND_REPLACE
;
275 else if ( pFR
->Flags
& FR_REPLACEALL
)
277 evtType
= wxEVT_COMMAND_FIND_REPLACE_ALL
;
283 wxFAIL_MSG( _T("unknown find dialog event") );
289 if ( pFR
->Flags
& FR_DOWN
)
291 if ( pFR
->Flags
& FR_WHOLEWORD
)
292 flags
|= wxFR_WHOLEWORD
;
293 if ( pFR
->Flags
& FR_MATCHCASE
)
294 flags
|= wxFR_MATCHCASE
;
296 wxFindDialogEvent
event(evtType
, dialog
->GetId());
297 event
.SetEventObject(dialog
);
298 event
.SetFlags(flags
);
299 event
.SetFindString(pFR
->lpstrFindWhat
);
302 event
.SetReplaceString(pFR
->lpstrReplaceWith
);
305 #if wxUSE_UNICODE_MSLU
307 #endif // wxUSE_UNICODE_MSLU
311 #if wxUSE_UNICODE_MSLU
313 #endif // wxUSE_UNICODE_MSLU
315 #if wxUSE_UNICODE_MSLU
316 else if ( !s_blockMsg
)
318 #endif // wxUSE_UNICODE_MSLU
320 WNDPROC wndProc
= (WNDPROC
)wxGetWindowUserData(hwnd
);
323 wxASSERT_MSG( wndProc
!= wxFindReplaceWindowProc
,
324 _T("infinite recursion detected") );
326 return ::CallWindowProc(wndProc
, hwnd
, nMsg
, wParam
, lParam
);
329 // ----------------------------------------------------------------------------
330 // Find/replace dialog hook proc
331 // ----------------------------------------------------------------------------
334 wxFindReplaceDialogHookProc(HWND hwnd
,
336 WPARAM
WXUNUSED(wParam
),
339 if ( uiMsg
== WM_INITDIALOG
)
341 FINDREPLACE
*pFR
= (FINDREPLACE
*)lParam
;
342 wxFindReplaceDialog
*dialog
= (wxFindReplaceDialog
*)pFR
->lCustData
;
344 ::SetWindowText(hwnd
, dialog
->GetTitle());
346 // don't return FALSE from here or the dialog won't be shown
353 // ============================================================================
354 // wxFindReplaceDialog implementation
355 // ============================================================================
357 // ----------------------------------------------------------------------------
358 // wxFindReplaceDialog ctors/dtor
359 // ----------------------------------------------------------------------------
361 void wxFindReplaceDialog::Init()
364 m_FindReplaceData
= NULL
;
366 // as we're created in the hidden state, bring the internal flag in sync
370 wxFindReplaceDialog::wxFindReplaceDialog(wxWindow
*parent
,
371 wxFindReplaceData
*data
,
372 const wxString
&title
,
374 : wxFindReplaceDialogBase(parent
, data
, title
, flags
)
378 (void)Create(parent
, data
, title
, flags
);
381 wxFindReplaceDialog::~wxFindReplaceDialog()
383 // the dialog might have been already deleted if the user closed it
384 // manually but in this case we should have got a notification about it and
385 // the flagmust have been set
386 if ( !m_impl
->WasClosedByUser() )
388 // if it wasn't, delete the dialog ourselves
389 if ( !::DestroyWindow(GetHwnd()) )
391 wxLogLastError(_T("DestroyWindow(find dialog)"));
395 // unsubclass the parent
398 // prevent the base class dtor from trying to hide us!
401 // and from destroying our window [again]
402 m_hWnd
= (WXHWND
)NULL
;
405 bool wxFindReplaceDialog::Create(wxWindow
*parent
,
406 wxFindReplaceData
*data
,
407 const wxString
&title
,
410 m_windowStyle
= flags
;
411 m_FindReplaceData
= data
;
416 // we must have a parent as it will get the messages from us
417 return parent
!= NULL
;
420 // ----------------------------------------------------------------------------
421 // wxFindReplaceData show/hide
422 // ----------------------------------------------------------------------------
424 bool wxFindReplaceDialog::Show(bool show
)
426 if ( !wxWindowBase::Show(show
) )
428 // visibility status didn't change
432 // do we already have the dialog window?
436 (void)::ShowWindow(GetHwnd(), show
? SW_SHOW
: SW_HIDE
);
443 // well, it doesn't exist which is as good as being hidden
447 wxCHECK_MSG( m_FindReplaceData
, false, _T("call Create() first!") );
449 wxASSERT_MSG( !m_impl
, _T("why don't we have the window then?") );
451 m_impl
= new wxFindReplaceDialogImpl(this, m_FindReplaceData
->GetFlags());
453 m_impl
->InitFindWhat(m_FindReplaceData
->GetFindString());
455 bool replace
= HasFlag(wxFR_REPLACEDIALOG
);
458 m_impl
->InitReplaceWith(m_FindReplaceData
->GetReplaceString());
461 // call the right function to show the dialog which does what we want
462 FINDREPLACE
*pFR
= m_impl
->GetPtrFindReplace();
465 hwnd
= ::ReplaceText(pFR
);
467 hwnd
= ::FindText(pFR
);
471 wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
472 ::CommDlgExtendedError());
480 // subclass parent window in order to get FINDMSGSTRING message
481 m_impl
->SubclassDialog(GetHwndOf(m_parent
));
483 if ( !::ShowWindow(hwnd
, SW_SHOW
) )
485 wxLogLastError(_T("ShowWindow(find dialog)"));
488 m_hWnd
= (WXHWND
)hwnd
;
493 // ----------------------------------------------------------------------------
494 // wxFindReplaceDialog title handling
495 // ----------------------------------------------------------------------------
497 // we set the title of this dialog in our jook proc but for now don't crash in
498 // the base class version because of m_hWnd == 0
500 void wxFindReplaceDialog::SetTitle( const wxString
& title
)
505 wxString
wxFindReplaceDialog::GetTitle() const
510 // ----------------------------------------------------------------------------
511 // wxFindReplaceDialog position/size
512 // ----------------------------------------------------------------------------
514 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
),
515 int WXUNUSED(width
), int WXUNUSED(height
),
516 int WXUNUSED(sizeFlags
))
518 // ignore - we can't change the size of this standard dialog
522 // NB: of course, both of these functions are completely bogus, but it's better
524 void wxFindReplaceDialog::DoGetSize(int *width
, int *height
) const
526 // the standard dialog size
533 void wxFindReplaceDialog::DoGetClientSize(int *width
, int *height
) const
535 // the standard dialog size
542 #endif // wxUSE_FINDREPLDLG