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