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