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 // ----------------------------------------------------------------------------
21 #pragma implementation "mswfdrepdlg.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
38 #include "wx/msw/private.h"
40 #if !defined(__WIN32__) || defined(__WXWINCE__)
44 #include "wx/fdrepdlg.h"
46 // ----------------------------------------------------------------------------
47 // functions prototypes
48 // ----------------------------------------------------------------------------
50 LRESULT APIENTRY
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
,
51 WPARAM wParam
, LPARAM lParam
);
53 UINT CALLBACK
wxFindReplaceDialogHookProc(HWND hwnd
,
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 IMPLEMENT_DYNAMIC_CLASS(wxFindReplaceDialog
, wxDialog
)
64 // ----------------------------------------------------------------------------
65 // wxFindReplaceDialogImpl: the internals of wxFindReplaceDialog
66 // ----------------------------------------------------------------------------
68 class WXDLLEXPORT wxFindReplaceDialogImpl
71 wxFindReplaceDialogImpl(wxFindReplaceDialog
*dialog
, int flagsWX
);
72 ~wxFindReplaceDialogImpl();
74 void InitFindWhat(const wxString
& str
);
75 void InitReplaceWith(const wxString
& str
);
77 void SubclassDialog(HWND hwnd
);
79 static UINT
GetFindDialogMessage() { return ms_msgFindDialog
; }
81 // only for passing to ::FindText or ::ReplaceText
82 FINDREPLACE
*GetPtrFindReplace() { return &m_findReplace
; }
84 // set/query the "closed by user" flag
85 void SetClosedByUser() { m_wasClosedByUser
= TRUE
; }
86 bool WasClosedByUser() const { return m_wasClosedByUser
; }
89 void InitString(const wxString
& str
, LPTSTR
*ppStr
, WORD
*pLen
);
91 // the owner of the dialog
94 // the previous window proc of our owner
95 WNDPROC m_oldParentWndProc
;
97 // the find replace data used by the dialog
98 FINDREPLACE m_findReplace
;
100 // TRUE if the user closed us, FALSE otherwise
101 bool m_wasClosedByUser
;
103 // registered Message for Dialog
104 static UINT ms_msgFindDialog
;
106 DECLARE_NO_COPY_CLASS(wxFindReplaceDialogImpl
)
109 UINT
wxFindReplaceDialogImpl::ms_msgFindDialog
= 0;
111 // ============================================================================
113 // ============================================================================
115 // ----------------------------------------------------------------------------
116 // wxFindReplaceDialogImpl
117 // ----------------------------------------------------------------------------
119 wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog
*dialog
,
122 // get the identifier for the find dialog message if we don't have it yet
123 if ( !ms_msgFindDialog
)
125 ms_msgFindDialog
= ::RegisterWindowMessage(FINDMSGSTRING
);
127 if ( !ms_msgFindDialog
)
129 wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)"));
134 m_oldParentWndProc
= NULL
;
136 m_wasClosedByUser
= FALSE
;
138 wxZeroMemory(m_findReplace
);
140 // translate the flags: first the dialog creation flags
142 // always set this to be able to set the title
143 int flags
= FR_ENABLEHOOK
;
145 int flagsDialog
= dialog
->GetWindowStyle();
146 if ( flagsDialog
& wxFR_NOMATCHCASE
)
147 flags
|= FR_NOMATCHCASE
;
148 if ( flagsDialog
& wxFR_NOWHOLEWORD
)
149 flags
|= FR_NOWHOLEWORD
;
150 if ( flagsDialog
& wxFR_NOUPDOWN
)
151 flags
|= FR_NOUPDOWN
;
153 // and now the flags governing the initial values of the dialogs controls
154 if ( flagsWX
& wxFR_DOWN
)
156 if ( flagsWX
& wxFR_MATCHCASE
)
157 flags
|= FR_MATCHCASE
;
158 if ( flagsWX
& wxFR_WHOLEWORD
)
159 flags
|= FR_WHOLEWORD
;
161 m_findReplace
.lStructSize
= sizeof(FINDREPLACE
);
162 m_findReplace
.hwndOwner
= GetHwndOf(dialog
->GetParent());
163 m_findReplace
.Flags
= flags
;
165 m_findReplace
.lCustData
= (LPARAM
)dialog
;
166 m_findReplace
.lpfnHook
= wxFindReplaceDialogHookProc
;
169 void wxFindReplaceDialogImpl::InitString(const wxString
& str
,
170 LPTSTR
*ppStr
, WORD
*pLen
)
172 size_t len
= str
.length() + 1;
175 // MSDN docs say that the buffer must be at least 80 chars
179 *ppStr
= new wxChar
[len
];
180 wxStrcpy(*ppStr
, str
);
184 void wxFindReplaceDialogImpl::InitFindWhat(const wxString
& str
)
186 InitString(str
, &m_findReplace
.lpstrFindWhat
, &m_findReplace
.wFindWhatLen
);
189 void wxFindReplaceDialogImpl::InitReplaceWith(const wxString
& str
)
192 &m_findReplace
.lpstrReplaceWith
,
193 &m_findReplace
.wReplaceWithLen
);
196 void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd
)
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
202 if ( !wxCheckWindowWndProc((WXHWND
)hwnd
, (WXFARPROC
)wxFindReplaceWindowProc
) )
204 WNDPROC oldParentWndProc
= (WNDPROC
)::GetWindowLong(hwnd
, GWL_WNDPROC
);
205 // save old wnd proc elsewhere to access it from
206 // wxFindReplaceWindowProc
207 m_oldParentWndProc
= oldParentWndProc
;
208 (void)::SetWindowLong(hwnd
, GWL_USERDATA
, (LONG
)oldParentWndProc
);
210 // and set the new one
211 (void)::SetWindowLong(hwnd
, GWL_WNDPROC
, (LONG
)wxFindReplaceWindowProc
);
215 wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl()
217 delete [] m_findReplace
.lpstrFindWhat
;
218 delete [] m_findReplace
.lpstrReplaceWith
;
222 ::SetWindowLong(m_hwndOwner
, GWL_WNDPROC
, (LONG
)m_oldParentWndProc
);
226 // ----------------------------------------------------------------------------
227 // Window Proc for handling RegisterWindowMessage(FINDMSGSTRING)
228 // ----------------------------------------------------------------------------
230 LRESULT APIENTRY
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
,
231 WPARAM wParam
, LPARAM lParam
)
233 #if wxUSE_UNICODE_MSLU
234 static unsigned long s_lastMsgFlags
= 0;
236 // This flag helps us to identify the bogus ANSI message
237 // sent by UNICOWS.DLL (see below)
238 // while we're sending our message to the dialog
239 // we ignore possible messages sent in between
240 static bool s_blockMsg
= false;
241 #endif // wxUSE_UNICODE_MSLU
243 if ( nMsg
== wxFindReplaceDialogImpl::GetFindDialogMessage() )
245 FINDREPLACE
*pFR
= (FINDREPLACE
*)lParam
;
247 #if wxUSE_UNICODE_MSLU
248 // This is a hack for a MSLU problem: Versions up to 1.0.4011
249 // of UNICOWS.DLL send the correct UNICODE item after button press
250 // and a bogus ANSI mode item right after this, so lets ignore
251 // the second bogus message
252 if ( s_lastMsgFlags
== pFR
->Flags
)
257 s_lastMsgFlags
= pFR
->Flags
;
258 #endif // wxUSE_UNICODE_MSLU
260 wxFindReplaceDialog
*dialog
= (wxFindReplaceDialog
*)pFR
->lCustData
;
262 // map flags from Windows
265 bool replace
= FALSE
;
266 if ( pFR
->Flags
& FR_DIALOGTERM
)
268 // we have to notify the dialog that it's being closed by user and
269 // not deleted programmatically as it behaves differently in these
271 dialog
->GetImpl()->SetClosedByUser();
273 evtType
= wxEVT_COMMAND_FIND_CLOSE
;
275 else if ( pFR
->Flags
& FR_FINDNEXT
)
277 evtType
= wxEVT_COMMAND_FIND_NEXT
;
279 else if ( pFR
->Flags
& FR_REPLACE
)
281 evtType
= wxEVT_COMMAND_FIND_REPLACE
;
285 else if ( pFR
->Flags
& FR_REPLACEALL
)
287 evtType
= wxEVT_COMMAND_FIND_REPLACE_ALL
;
293 wxFAIL_MSG( _T("unknown find dialog event") );
299 if ( pFR
->Flags
& FR_DOWN
)
301 if ( pFR
->Flags
& FR_WHOLEWORD
)
302 flags
|= wxFR_WHOLEWORD
;
303 if ( pFR
->Flags
& FR_MATCHCASE
)
304 flags
|= wxFR_MATCHCASE
;
306 wxFindDialogEvent
event(evtType
, dialog
->GetId());
307 event
.SetEventObject(dialog
);
308 event
.SetFlags(flags
);
309 event
.SetFindString(pFR
->lpstrFindWhat
);
312 event
.SetReplaceString(pFR
->lpstrReplaceWith
);
315 #if wxUSE_UNICODE_MSLU
317 #endif // wxUSE_UNICODE_MSLU
321 #if wxUSE_UNICODE_MSLU
323 #endif // wxUSE_UNICODE_MSLU
325 #if wxUSE_UNICODE_MSLU
326 else if ( !s_blockMsg
)
328 #endif // wxUSE_UNICODE_MSLU
330 WNDPROC wndProc
= (WNDPROC
)::GetWindowLong(hwnd
, GWL_USERDATA
);
333 wxASSERT_MSG( wndProc
!= wxFindReplaceWindowProc
,
334 _T("infinite recursion detected") );
336 return ::CallWindowProc(wndProc
, hwnd
, nMsg
, wParam
, lParam
);
339 // ----------------------------------------------------------------------------
340 // Find/replace dialog hook proc
341 // ----------------------------------------------------------------------------
343 UINT CALLBACK
wxFindReplaceDialogHookProc(HWND hwnd
,
345 WPARAM
WXUNUSED(wParam
),
348 if ( uiMsg
== WM_INITDIALOG
)
350 FINDREPLACE
*pFR
= (FINDREPLACE
*)lParam
;
351 wxFindReplaceDialog
*dialog
= (wxFindReplaceDialog
*)pFR
->lCustData
;
353 ::SetWindowText(hwnd
, dialog
->GetTitle());
355 // don't return FALSE from here or the dialog won't be shown
362 // ============================================================================
363 // wxFindReplaceDialog implementation
364 // ============================================================================
366 // ----------------------------------------------------------------------------
367 // wxFindReplaceDialog ctors/dtor
368 // ----------------------------------------------------------------------------
370 void wxFindReplaceDialog::Init()
373 m_FindReplaceData
= NULL
;
375 // as we're created in the hidden state, bring the internal flag in sync
379 wxFindReplaceDialog::wxFindReplaceDialog(wxWindow
*parent
,
380 wxFindReplaceData
*data
,
381 const wxString
&title
,
383 : wxFindReplaceDialogBase(parent
, data
, title
, flags
)
387 (void)Create(parent
, data
, title
, flags
);
390 wxFindReplaceDialog::~wxFindReplaceDialog()
392 // the dialog might have been already deleted if the user closed it
393 // manually but in this case we should have got a notification about it and
394 // the flagmust have been set
395 if ( !m_impl
->WasClosedByUser() )
397 // if it wasn't, delete the dialog ourselves
398 if ( !::DestroyWindow(GetHwnd()) )
400 wxLogLastError(_T("DestroyWindow(find dialog)"));
404 // unsubclass the parent
407 // prevent the base class dtor from trying to hide us!
410 // and from destroying our window [again]
411 m_hWnd
= (WXHWND
)NULL
;
414 bool wxFindReplaceDialog::Create(wxWindow
*parent
,
415 wxFindReplaceData
*data
,
416 const wxString
&title
,
419 m_windowStyle
= flags
;
420 m_FindReplaceData
= data
;
425 // we must have a parent as it will get the messages from us
426 return parent
!= NULL
;
429 // ----------------------------------------------------------------------------
430 // wxFindReplaceData show/hide
431 // ----------------------------------------------------------------------------
433 bool wxFindReplaceDialog::Show(bool show
)
435 if ( !wxWindowBase::Show(show
) )
437 // visibility status didn't change
441 // do we already have the dialog window?
445 (void)::ShowWindow(GetHwnd(), show
? SW_SHOW
: SW_HIDE
);
452 // well, it doesn't exist which is as good as being hidden
456 wxCHECK_MSG( m_FindReplaceData
, FALSE
, _T("call Create() first!") );
458 wxASSERT_MSG( !m_impl
, _T("why don't we have the window then?") );
460 m_impl
= new wxFindReplaceDialogImpl(this, m_FindReplaceData
->GetFlags());
462 m_impl
->InitFindWhat(m_FindReplaceData
->GetFindString());
464 bool replace
= HasFlag(wxFR_REPLACEDIALOG
);
467 m_impl
->InitReplaceWith(m_FindReplaceData
->GetReplaceString());
470 // call the right function to show the dialog which does what we want
471 FINDREPLACE
*pFR
= m_impl
->GetPtrFindReplace();
474 hwnd
= ::ReplaceText(pFR
);
476 hwnd
= ::FindText(pFR
);
480 wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"),
481 ::CommDlgExtendedError());
489 // subclass parent window in order to get FINDMSGSTRING message
490 m_impl
->SubclassDialog(GetHwndOf(m_parent
));
492 if ( !::ShowWindow(hwnd
, SW_SHOW
) )
494 wxLogLastError(_T("ShowWindow(find dialog)"));
497 m_hWnd
= (WXHWND
)hwnd
;
502 // ----------------------------------------------------------------------------
503 // wxFindReplaceDialog title handling
504 // ----------------------------------------------------------------------------
506 // we set the title of this dialog in our jook proc but for now don't crash in
507 // the base class version because of m_hWnd == 0
509 void wxFindReplaceDialog::SetTitle( const wxString
& title
)
514 wxString
wxFindReplaceDialog::GetTitle() const
519 // ----------------------------------------------------------------------------
520 // wxFindReplaceDialog position/size
521 // ----------------------------------------------------------------------------
523 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
),
524 int WXUNUSED(width
), int WXUNUSED(height
),
525 int WXUNUSED(sizeFlags
))
527 // ignore - we can't change the size of this standard dialog
531 // NB: of course, both of these functions are completely bogus, but it's better
533 void wxFindReplaceDialog::DoGetSize(int *width
, int *height
) const
535 // the standard dialog size
542 void wxFindReplaceDialog::DoGetClientSize(int *width
, int *height
) const
544 // the standard dialog size
551 #endif // wxUSE_FINDREPLDLG