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 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  30     #include "wx/msw/wrapcdlg.h" 
  35 #include "wx/fdrepdlg.h" 
  37 #include "wx/msw/mslu.h" 
  39 // ---------------------------------------------------------------------------- 
  40 // functions prototypes 
  41 // ---------------------------------------------------------------------------- 
  43 LRESULT CALLBACK 
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
, 
  44                                          WPARAM wParam
, LPARAM lParam
); 
  46 UINT_PTR CALLBACK 
wxFindReplaceDialogHookProc(HWND hwnd
, 
  51 // ---------------------------------------------------------------------------- 
  53 // ---------------------------------------------------------------------------- 
  55 IMPLEMENT_DYNAMIC_CLASS(wxFindReplaceDialog
, wxDialog
) 
  57 // ---------------------------------------------------------------------------- 
  58 // wxFindReplaceDialogImpl: the internals of wxFindReplaceDialog 
  59 // ---------------------------------------------------------------------------- 
  61 class WXDLLEXPORT wxFindReplaceDialogImpl
 
  64     wxFindReplaceDialogImpl(wxFindReplaceDialog 
*dialog
, int flagsWX
); 
  65     ~wxFindReplaceDialogImpl(); 
  67     void InitFindWhat(const wxString
& str
); 
  68     void InitReplaceWith(const wxString
& str
); 
  70     void SubclassDialog(HWND hwnd
); 
  72     static UINT 
GetFindDialogMessage() { return ms_msgFindDialog
; } 
  74     // only for passing to ::FindText or ::ReplaceText 
  75     FINDREPLACE 
*GetPtrFindReplace() { return &m_findReplace
; } 
  77     // set/query the "closed by user" flag 
  78     void SetClosedByUser() { m_wasClosedByUser 
= true; } 
  79     bool WasClosedByUser() const { return m_wasClosedByUser
; } 
  82     void InitString(const wxString
& str
, LPTSTR 
*ppStr
, WORD 
*pLen
); 
  84     // the owner of the dialog 
  87     // the previous window proc of our owner 
  88     WNDPROC m_oldParentWndProc
; 
  90     // the find replace data used by the dialog 
  91     FINDREPLACE m_findReplace
; 
  93     // true if the user closed us, false otherwise 
  94     bool m_wasClosedByUser
; 
  96     // registered Message for Dialog 
  97     static UINT ms_msgFindDialog
; 
  99     DECLARE_NO_COPY_CLASS(wxFindReplaceDialogImpl
) 
 102 UINT 
wxFindReplaceDialogImpl::ms_msgFindDialog 
= 0; 
 104 // ============================================================================ 
 106 // ============================================================================ 
 108 // ---------------------------------------------------------------------------- 
 109 // wxFindReplaceDialogImpl 
 110 // ---------------------------------------------------------------------------- 
 112 wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog 
*dialog
, 
 115     // get the identifier for the find dialog message if we don't have it yet 
 116     if ( !ms_msgFindDialog 
) 
 118         ms_msgFindDialog 
= ::RegisterWindowMessage(FINDMSGSTRING
); 
 120         if ( !ms_msgFindDialog 
) 
 122             wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)")); 
 127     m_oldParentWndProc 
= NULL
; 
 129     m_wasClosedByUser 
= false; 
 131     wxZeroMemory(m_findReplace
); 
 133     // translate the flags: first the dialog creation flags 
 135     // always set this to be able to set the title 
 136     int flags 
= FR_ENABLEHOOK
; 
 138     int flagsDialog 
= dialog
->GetWindowStyle(); 
 139     if ( flagsDialog 
& wxFR_NOMATCHCASE
) 
 140         flags 
|= FR_NOMATCHCASE
; 
 141     if ( flagsDialog 
& wxFR_NOWHOLEWORD
) 
 142         flags 
|= FR_NOWHOLEWORD
; 
 143     if ( flagsDialog 
& wxFR_NOUPDOWN
) 
 144         flags 
|= FR_NOUPDOWN
; 
 146     // and now the flags governing the initial values of the dialogs controls 
 147     if ( flagsWX 
& wxFR_DOWN
) 
 149     if ( flagsWX 
& wxFR_MATCHCASE
) 
 150         flags 
|= FR_MATCHCASE
; 
 151     if ( flagsWX 
& wxFR_WHOLEWORD 
) 
 152         flags 
|= FR_WHOLEWORD
; 
 154     m_findReplace
.lStructSize 
= sizeof(FINDREPLACE
); 
 155     m_findReplace
.hwndOwner 
= GetHwndOf(dialog
->GetParent()); 
 156     m_findReplace
.Flags 
= flags
; 
 158     m_findReplace
.lCustData 
= (LPARAM
)dialog
; 
 159     m_findReplace
.lpfnHook 
= wxFindReplaceDialogHookProc
; 
 162 void wxFindReplaceDialogImpl::InitString(const wxString
& str
, 
 163                                          LPTSTR 
*ppStr
, WORD 
*pLen
) 
 165     size_t len 
= str
.length() + 1; 
 168         // MSDN docs say that the buffer must be at least 80 chars 
 172     *ppStr 
= new wxChar
[len
]; 
 173     wxStrcpy(*ppStr
, str
); 
 177 void wxFindReplaceDialogImpl::InitFindWhat(const wxString
& str
) 
 179     InitString(str
, &m_findReplace
.lpstrFindWhat
, &m_findReplace
.wFindWhatLen
); 
 182 void wxFindReplaceDialogImpl::InitReplaceWith(const wxString
& str
) 
 185                &m_findReplace
.lpstrReplaceWith
, 
 186                &m_findReplace
.wReplaceWithLen
); 
 189 void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd
) 
 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 
 195     wxCHECK_RET( wxGetWindowProc(hwnd
) != &wxFindReplaceWindowProc
, 
 196                  _T("can't have more than one find dialog currently") ); 
 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
); 
 202     wxSetWindowUserData(hwnd
, (void *)m_oldParentWndProc
); 
 205 wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl() 
 207     delete [] m_findReplace
.lpstrFindWhat
; 
 208     delete [] m_findReplace
.lpstrReplaceWith
; 
 213         wxSetWindowProc(m_hwndOwner
, m_oldParentWndProc
); 
 217 // ---------------------------------------------------------------------------- 
 218 // Window Proc for handling RegisterWindowMessage(FINDMSGSTRING) 
 219 // ---------------------------------------------------------------------------- 
 221 LRESULT CALLBACK 
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
, 
 222                                          WPARAM wParam
, LPARAM lParam
) 
 224 #if wxUSE_UNICODE_MSLU 
 225     static unsigned long s_lastMsgFlags 
= 0; 
 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 
 234     if ( nMsg 
== wxFindReplaceDialogImpl::GetFindDialogMessage() ) 
 236         FINDREPLACE 
*pFR 
= (FINDREPLACE 
*)lParam
; 
 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 
 243         if ( wxUsingUnicowsDll() && s_lastMsgFlags 
== pFR
->Flags 
) 
 248         s_lastMsgFlags 
= pFR
->Flags
; 
 249 #endif // wxUSE_UNICODE_MSLU 
 251         wxFindReplaceDialog 
*dialog 
= (wxFindReplaceDialog 
*)pFR
->lCustData
; 
 253         // map flags from Windows 
 256         bool replace 
= false; 
 257         if ( pFR
->Flags 
& FR_DIALOGTERM 
) 
 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 
 262             dialog
->GetImpl()->SetClosedByUser(); 
 264             evtType 
= wxEVT_COMMAND_FIND_CLOSE
; 
 266         else if ( pFR
->Flags 
& FR_FINDNEXT 
) 
 268             evtType 
= wxEVT_COMMAND_FIND_NEXT
; 
 270         else if ( pFR
->Flags 
& FR_REPLACE 
) 
 272             evtType 
= wxEVT_COMMAND_FIND_REPLACE
; 
 276         else if ( pFR
->Flags 
& FR_REPLACEALL 
) 
 278             evtType 
= wxEVT_COMMAND_FIND_REPLACE_ALL
; 
 284             wxFAIL_MSG( _T("unknown find dialog event") ); 
 290         if ( pFR
->Flags 
& FR_DOWN 
) 
 292         if ( pFR
->Flags 
& FR_WHOLEWORD 
) 
 293             flags 
|= wxFR_WHOLEWORD
; 
 294         if ( pFR
->Flags 
& FR_MATCHCASE 
) 
 295             flags 
|= wxFR_MATCHCASE
; 
 297         wxFindDialogEvent 
event(evtType
, dialog
->GetId()); 
 298         event
.SetEventObject(dialog
); 
 299         event
.SetFlags(flags
); 
 300         event
.SetFindString(pFR
->lpstrFindWhat
); 
 303             event
.SetReplaceString(pFR
->lpstrReplaceWith
); 
 306 #if wxUSE_UNICODE_MSLU 
 308 #endif // wxUSE_UNICODE_MSLU 
 312 #if wxUSE_UNICODE_MSLU 
 314 #endif // wxUSE_UNICODE_MSLU 
 316 #if wxUSE_UNICODE_MSLU 
 317     else if ( !s_blockMsg 
) 
 319 #endif // wxUSE_UNICODE_MSLU 
 321     WNDPROC wndProc 
= (WNDPROC
)wxGetWindowUserData(hwnd
); 
 324     wxASSERT_MSG( wndProc 
!= wxFindReplaceWindowProc
, 
 325                   _T("infinite recursion detected") ); 
 327     return ::CallWindowProc(wndProc
, hwnd
, nMsg
, wParam
, lParam
); 
 330 // ---------------------------------------------------------------------------- 
 331 // Find/replace dialog hook proc 
 332 // ---------------------------------------------------------------------------- 
 335 wxFindReplaceDialogHookProc(HWND hwnd
, 
 337                             WPARAM 
WXUNUSED(wParam
), 
 340     if ( uiMsg 
== WM_INITDIALOG 
) 
 342         FINDREPLACE 
*pFR 
= (FINDREPLACE 
*)lParam
; 
 343         wxFindReplaceDialog 
*dialog 
= (wxFindReplaceDialog 
*)pFR
->lCustData
; 
 345         ::SetWindowText(hwnd
, dialog
->GetTitle()); 
 347         // don't return FALSE from here or the dialog won't be shown 
 354 // ============================================================================ 
 355 // wxFindReplaceDialog implementation 
 356 // ============================================================================ 
 358 // ---------------------------------------------------------------------------- 
 359 // wxFindReplaceDialog ctors/dtor 
 360 // ---------------------------------------------------------------------------- 
 362 void wxFindReplaceDialog::Init() 
 365     m_FindReplaceData 
= NULL
; 
 367     // as we're created in the hidden state, bring the internal flag in sync 
 371 wxFindReplaceDialog::wxFindReplaceDialog(wxWindow 
*parent
, 
 372                                          wxFindReplaceData 
*data
, 
 373                                          const wxString 
&title
, 
 375                    : wxFindReplaceDialogBase(parent
, data
, title
, flags
) 
 379     (void)Create(parent
, data
, title
, flags
); 
 382 wxFindReplaceDialog::~wxFindReplaceDialog() 
 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() ) 
 389         // if it wasn't, delete the dialog ourselves 
 390         if ( !::DestroyWindow(GetHwnd()) ) 
 392             wxLogLastError(_T("DestroyWindow(find dialog)")); 
 396     // unsubclass the parent 
 399     // prevent the base class dtor from trying to hide us! 
 402     // and from destroying our window [again] 
 403     m_hWnd 
= (WXHWND
)NULL
; 
 406 bool wxFindReplaceDialog::Create(wxWindow 
*parent
, 
 407                                  wxFindReplaceData 
*data
, 
 408                                  const wxString 
&title
, 
 411     m_windowStyle 
= flags
; 
 412     m_FindReplaceData 
= data
; 
 417     // we must have a parent as it will get the messages from us 
 418     return parent 
!= NULL
; 
 421 // ---------------------------------------------------------------------------- 
 422 // wxFindReplaceData show/hide 
 423 // ---------------------------------------------------------------------------- 
 425 bool wxFindReplaceDialog::Show(bool show
) 
 427     if ( !wxWindowBase::Show(show
) ) 
 429         // visibility status didn't change 
 433     // do we already have the dialog window? 
 437         (void)::ShowWindow(GetHwnd(), show 
? SW_SHOW 
: SW_HIDE
); 
 444         // well, it doesn't exist which is as good as being hidden 
 448     wxCHECK_MSG( m_FindReplaceData
, false, _T("call Create() first!") ); 
 450     wxASSERT_MSG( !m_impl
, _T("why don't we have the window then?") ); 
 452     m_impl 
= new wxFindReplaceDialogImpl(this, m_FindReplaceData
->GetFlags()); 
 454     m_impl
->InitFindWhat(m_FindReplaceData
->GetFindString()); 
 456     bool replace 
= HasFlag(wxFR_REPLACEDIALOG
); 
 459         m_impl
->InitReplaceWith(m_FindReplaceData
->GetReplaceString()); 
 462     // call the right function to show the dialog which does what we want 
 463     FINDREPLACE 
*pFR 
= m_impl
->GetPtrFindReplace(); 
 466         hwnd 
= ::ReplaceText(pFR
); 
 468         hwnd 
= ::FindText(pFR
); 
 472         wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"), 
 473                    ::CommDlgExtendedError()); 
 481     // subclass parent window in order to get FINDMSGSTRING message 
 482     m_impl
->SubclassDialog(GetHwndOf(m_parent
)); 
 484     if ( !::ShowWindow(hwnd
, SW_SHOW
) ) 
 486         wxLogLastError(_T("ShowWindow(find dialog)")); 
 489     m_hWnd 
= (WXHWND
)hwnd
; 
 494 // ---------------------------------------------------------------------------- 
 495 // wxFindReplaceDialog title handling 
 496 // ---------------------------------------------------------------------------- 
 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 
 501 void wxFindReplaceDialog::SetTitle( const wxString
& title
) 
 506 wxString 
wxFindReplaceDialog::GetTitle() const 
 511 // ---------------------------------------------------------------------------- 
 512 // wxFindReplaceDialog position/size 
 513 // ---------------------------------------------------------------------------- 
 515 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
), 
 516                                     int WXUNUSED(width
), int WXUNUSED(height
), 
 517                                     int WXUNUSED(sizeFlags
)) 
 519     // ignore - we can't change the size of this standard dialog 
 523 // NB: of course, both of these functions are completely bogus, but it's better 
 525 void wxFindReplaceDialog::DoGetSize(int *width
, int *height
) const 
 527     // the standard dialog size 
 534 void wxFindReplaceDialog::DoGetClientSize(int *width
, int *height
) const 
 536     // the standard dialog size 
 543 #endif // wxUSE_FINDREPLDLG