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