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