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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "mswfdrepdlg.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  38 #include "wx/msw/private.h" 
  40 #if !defined(__WIN32__) || defined(__WXWINCE__) 
  44 #include "wx/fdrepdlg.h" 
  46 // ---------------------------------------------------------------------------- 
  47 // functions prototypes 
  48 // ---------------------------------------------------------------------------- 
  50 LRESULT APIENTRY 
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
, 
  51                                        WPARAM wParam
, LPARAM lParam
); 
  53 UINT_PTR CALLBACK 
wxFindReplaceDialogHookProc(HWND hwnd
, 
  58 // ---------------------------------------------------------------------------- 
  60 // ---------------------------------------------------------------------------- 
  62 IMPLEMENT_DYNAMIC_CLASS(wxFindReplaceDialog
, wxDialog
) 
  64 // ---------------------------------------------------------------------------- 
  65 // wxFindReplaceDialogImpl: the internals of wxFindReplaceDialog 
  66 // ---------------------------------------------------------------------------- 
  68 class WXDLLEXPORT wxFindReplaceDialogImpl
 
  71     wxFindReplaceDialogImpl(wxFindReplaceDialog 
*dialog
, int flagsWX
); 
  72     ~wxFindReplaceDialogImpl(); 
  74     void InitFindWhat(const wxString
& str
); 
  75     void InitReplaceWith(const wxString
& str
); 
  77     void SubclassDialog(HWND hwnd
); 
  79     static UINT 
GetFindDialogMessage() { return ms_msgFindDialog
; } 
  81     // only for passing to ::FindText or ::ReplaceText 
  82     FINDREPLACE 
*GetPtrFindReplace() { return &m_findReplace
; } 
  84     // set/query the "closed by user" flag 
  85     void SetClosedByUser() { m_wasClosedByUser 
= TRUE
; } 
  86     bool WasClosedByUser() const { return m_wasClosedByUser
; } 
  89     void InitString(const wxString
& str
, LPTSTR 
*ppStr
, WORD 
*pLen
); 
  91     // the owner of the dialog 
  94     // the previous window proc of our owner 
  95     WNDPROC m_oldParentWndProc
; 
  97     // the find replace data used by the dialog 
  98     FINDREPLACE m_findReplace
; 
 100     // TRUE if the user closed us, FALSE otherwise 
 101     bool m_wasClosedByUser
; 
 103     // registered Message for Dialog 
 104     static UINT ms_msgFindDialog
; 
 106     DECLARE_NO_COPY_CLASS(wxFindReplaceDialogImpl
) 
 109 UINT 
wxFindReplaceDialogImpl::ms_msgFindDialog 
= 0; 
 111 // ============================================================================ 
 113 // ============================================================================ 
 115 // ---------------------------------------------------------------------------- 
 116 // wxFindReplaceDialogImpl 
 117 // ---------------------------------------------------------------------------- 
 119 wxFindReplaceDialogImpl::wxFindReplaceDialogImpl(wxFindReplaceDialog 
*dialog
, 
 122     // get the identifier for the find dialog message if we don't have it yet 
 123     if ( !ms_msgFindDialog 
) 
 125         ms_msgFindDialog 
= ::RegisterWindowMessage(FINDMSGSTRING
); 
 127         if ( !ms_msgFindDialog 
) 
 129             wxLogLastError(_T("RegisterWindowMessage(FINDMSGSTRING)")); 
 134     m_oldParentWndProc 
= NULL
; 
 136     m_wasClosedByUser 
= FALSE
; 
 138     wxZeroMemory(m_findReplace
); 
 140     // translate the flags: first the dialog creation flags 
 142     // always set this to be able to set the title 
 143     int flags 
= FR_ENABLEHOOK
; 
 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
; 
 153     // and now the flags governing the initial values of the dialogs controls 
 154     if ( flagsWX 
& wxFR_DOWN
) 
 156     if ( flagsWX 
& wxFR_MATCHCASE
) 
 157         flags 
|= FR_MATCHCASE
; 
 158     if ( flagsWX 
& wxFR_WHOLEWORD 
) 
 159         flags 
|= FR_WHOLEWORD
; 
 161     m_findReplace
.lStructSize 
= sizeof(FINDREPLACE
); 
 162     m_findReplace
.hwndOwner 
= GetHwndOf(dialog
->GetParent()); 
 163     m_findReplace
.Flags 
= flags
; 
 165     m_findReplace
.lCustData 
= (LPARAM
)dialog
; 
 166     m_findReplace
.lpfnHook 
= wxFindReplaceDialogHookProc
; 
 169 void wxFindReplaceDialogImpl::InitString(const wxString
& str
, 
 170                                          LPTSTR 
*ppStr
, WORD 
*pLen
) 
 172     size_t len 
= str
.length() + 1; 
 175         // MSDN docs say that the buffer must be at least 80 chars 
 179     *ppStr 
= new wxChar
[len
]; 
 180     wxStrcpy(*ppStr
, str
); 
 184 void wxFindReplaceDialogImpl::InitFindWhat(const wxString
& str
) 
 186     InitString(str
, &m_findReplace
.lpstrFindWhat
, &m_findReplace
.wFindWhatLen
); 
 189 void wxFindReplaceDialogImpl::InitReplaceWith(const wxString
& str
) 
 192                &m_findReplace
.lpstrReplaceWith
, 
 193                &m_findReplace
.wReplaceWithLen
); 
 196 void wxFindReplaceDialogImpl::SubclassDialog(HWND hwnd
) 
 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
) ) 
 204         // set the new one and save the old as user data to allow access to it 
 205         // from wxFindReplaceWindowProc 
 206         m_oldParentWndProc 
= wxSetWindowProc(hwnd
, wxFindReplaceWindowProc
); 
 208         wxSetWindowUserData(hwnd
, (void *)m_oldParentWndProc
); 
 212 wxFindReplaceDialogImpl::~wxFindReplaceDialogImpl() 
 214     delete [] m_findReplace
.lpstrFindWhat
; 
 215     delete [] m_findReplace
.lpstrReplaceWith
; 
 220         wxSetWindowProc(m_hwndOwner
, m_oldParentWndProc
); 
 224 // ---------------------------------------------------------------------------- 
 225 // Window Proc for handling RegisterWindowMessage(FINDMSGSTRING) 
 226 // ---------------------------------------------------------------------------- 
 228 LRESULT APIENTRY 
wxFindReplaceWindowProc(HWND hwnd
, WXUINT nMsg
, 
 229                                          WPARAM wParam
, LPARAM lParam
) 
 231 #if wxUSE_UNICODE_MSLU 
 232     static unsigned long s_lastMsgFlags 
= 0; 
 234     // This flag helps us to identify the bogus ANSI message 
 235     // sent by UNICOWS.DLL (see below) 
 236     // while we're sending our message to the dialog 
 237     // we ignore possible messages sent in between 
 238     static bool s_blockMsg 
= false; 
 239 #endif // wxUSE_UNICODE_MSLU 
 241     if ( nMsg 
== wxFindReplaceDialogImpl::GetFindDialogMessage() ) 
 243         FINDREPLACE 
*pFR 
= (FINDREPLACE 
*)lParam
; 
 245 #if wxUSE_UNICODE_MSLU 
 246         // This is a hack for a MSLU problem: Versions up to 1.0.4011 
 247         // of UNICOWS.DLL send the correct UNICODE item after button press 
 248         // and a bogus ANSI mode item right after this, so lets ignore 
 249         // the second bogus message 
 250         if ( s_lastMsgFlags 
== pFR
->Flags 
) 
 255         s_lastMsgFlags 
= pFR
->Flags
; 
 256 #endif // wxUSE_UNICODE_MSLU 
 258         wxFindReplaceDialog 
*dialog 
= (wxFindReplaceDialog 
*)pFR
->lCustData
; 
 260         // map flags from Windows 
 263         bool replace 
= FALSE
; 
 264         if ( pFR
->Flags 
& FR_DIALOGTERM 
) 
 266             // we have to notify the dialog that it's being closed by user and 
 267             // not deleted programmatically as it behaves differently in these 
 269             dialog
->GetImpl()->SetClosedByUser(); 
 271             evtType 
= wxEVT_COMMAND_FIND_CLOSE
; 
 273         else if ( pFR
->Flags 
& FR_FINDNEXT 
) 
 275             evtType 
= wxEVT_COMMAND_FIND_NEXT
; 
 277         else if ( pFR
->Flags 
& FR_REPLACE 
) 
 279             evtType 
= wxEVT_COMMAND_FIND_REPLACE
; 
 283         else if ( pFR
->Flags 
& FR_REPLACEALL 
) 
 285             evtType 
= wxEVT_COMMAND_FIND_REPLACE_ALL
; 
 291             wxFAIL_MSG( _T("unknown find dialog event") ); 
 297         if ( pFR
->Flags 
& FR_DOWN 
) 
 299         if ( pFR
->Flags 
& FR_WHOLEWORD 
) 
 300             flags 
|= wxFR_WHOLEWORD
; 
 301         if ( pFR
->Flags 
& FR_MATCHCASE 
) 
 302             flags 
|= wxFR_MATCHCASE
; 
 304         wxFindDialogEvent 
event(evtType
, dialog
->GetId()); 
 305         event
.SetEventObject(dialog
); 
 306         event
.SetFlags(flags
); 
 307         event
.SetFindString(pFR
->lpstrFindWhat
); 
 310             event
.SetReplaceString(pFR
->lpstrReplaceWith
); 
 313 #if wxUSE_UNICODE_MSLU 
 315 #endif // wxUSE_UNICODE_MSLU 
 319 #if wxUSE_UNICODE_MSLU 
 321 #endif // wxUSE_UNICODE_MSLU 
 323 #if wxUSE_UNICODE_MSLU 
 324     else if ( !s_blockMsg 
) 
 326 #endif // wxUSE_UNICODE_MSLU 
 328     WNDPROC wndProc 
= (WNDPROC
)wxGetWindowUserData(hwnd
); 
 331     wxASSERT_MSG( wndProc 
!= wxFindReplaceWindowProc
, 
 332                   _T("infinite recursion detected") ); 
 334     return ::CallWindowProc(wndProc
, hwnd
, nMsg
, wParam
, lParam
); 
 337 // ---------------------------------------------------------------------------- 
 338 // Find/replace dialog hook proc 
 339 // ---------------------------------------------------------------------------- 
 342 wxFindReplaceDialogHookProc(HWND hwnd
, 
 344                             WPARAM 
WXUNUSED(wParam
), 
 347     if ( uiMsg 
== WM_INITDIALOG 
) 
 349         FINDREPLACE 
*pFR 
= (FINDREPLACE 
*)lParam
; 
 350         wxFindReplaceDialog 
*dialog 
= (wxFindReplaceDialog 
*)pFR
->lCustData
; 
 352         ::SetWindowText(hwnd
, dialog
->GetTitle()); 
 354         // don't return FALSE from here or the dialog won't be shown 
 361 // ============================================================================ 
 362 // wxFindReplaceDialog implementation 
 363 // ============================================================================ 
 365 // ---------------------------------------------------------------------------- 
 366 // wxFindReplaceDialog ctors/dtor 
 367 // ---------------------------------------------------------------------------- 
 369 void wxFindReplaceDialog::Init() 
 372     m_FindReplaceData 
= NULL
; 
 374     // as we're created in the hidden state, bring the internal flag in sync 
 378 wxFindReplaceDialog::wxFindReplaceDialog(wxWindow 
*parent
, 
 379                                          wxFindReplaceData 
*data
, 
 380                                          const wxString 
&title
, 
 382                    : wxFindReplaceDialogBase(parent
, data
, title
, flags
) 
 386     (void)Create(parent
, data
, title
, flags
); 
 389 wxFindReplaceDialog::~wxFindReplaceDialog() 
 391     // the dialog might have been already deleted if the user closed it 
 392     // manually but in this case we should have got a notification about it and 
 393     // the flagmust have been set 
 394     if ( !m_impl
->WasClosedByUser() ) 
 396         // if it wasn't, delete the dialog ourselves 
 397         if ( !::DestroyWindow(GetHwnd()) ) 
 399             wxLogLastError(_T("DestroyWindow(find dialog)")); 
 403     // unsubclass the parent 
 406     // prevent the base class dtor from trying to hide us! 
 409     // and from destroying our window [again] 
 410     m_hWnd 
= (WXHWND
)NULL
; 
 413 bool wxFindReplaceDialog::Create(wxWindow 
*parent
, 
 414                                  wxFindReplaceData 
*data
, 
 415                                  const wxString 
&title
, 
 418     m_windowStyle 
= flags
; 
 419     m_FindReplaceData 
= data
; 
 424     // we must have a parent as it will get the messages from us 
 425     return parent 
!= NULL
; 
 428 // ---------------------------------------------------------------------------- 
 429 // wxFindReplaceData show/hide 
 430 // ---------------------------------------------------------------------------- 
 432 bool wxFindReplaceDialog::Show(bool show
) 
 434     if ( !wxWindowBase::Show(show
) ) 
 436         // visibility status didn't change 
 440     // do we already have the dialog window? 
 444         (void)::ShowWindow(GetHwnd(), show 
? SW_SHOW 
: SW_HIDE
); 
 451         // well, it doesn't exist which is as good as being hidden 
 455     wxCHECK_MSG( m_FindReplaceData
, FALSE
, _T("call Create() first!") ); 
 457     wxASSERT_MSG( !m_impl
, _T("why don't we have the window then?") ); 
 459     m_impl 
= new wxFindReplaceDialogImpl(this, m_FindReplaceData
->GetFlags()); 
 461     m_impl
->InitFindWhat(m_FindReplaceData
->GetFindString()); 
 463     bool replace 
= HasFlag(wxFR_REPLACEDIALOG
); 
 466         m_impl
->InitReplaceWith(m_FindReplaceData
->GetReplaceString()); 
 469     // call the right function to show the dialog which does what we want 
 470     FINDREPLACE 
*pFR 
= m_impl
->GetPtrFindReplace(); 
 473         hwnd 
= ::ReplaceText(pFR
); 
 475         hwnd 
= ::FindText(pFR
); 
 479         wxLogError(_("Failed to create the standard find/replace dialog (error code %d)"), 
 480                    ::CommDlgExtendedError()); 
 488     // subclass parent window in order to get FINDMSGSTRING message 
 489     m_impl
->SubclassDialog(GetHwndOf(m_parent
)); 
 491     if ( !::ShowWindow(hwnd
, SW_SHOW
) ) 
 493         wxLogLastError(_T("ShowWindow(find dialog)")); 
 496     m_hWnd 
= (WXHWND
)hwnd
; 
 501 // ---------------------------------------------------------------------------- 
 502 // wxFindReplaceDialog title handling 
 503 // ---------------------------------------------------------------------------- 
 505 // we set the title of this dialog in our jook proc but for now don't crash in 
 506 // the base class version because of m_hWnd == 0 
 508 void wxFindReplaceDialog::SetTitle( const wxString
& title
) 
 513 wxString 
wxFindReplaceDialog::GetTitle() const 
 518 // ---------------------------------------------------------------------------- 
 519 // wxFindReplaceDialog position/size 
 520 // ---------------------------------------------------------------------------- 
 522 void wxFindReplaceDialog::DoSetSize(int WXUNUSED(x
), int WXUNUSED(y
), 
 523                                     int WXUNUSED(width
), int WXUNUSED(height
), 
 524                                     int WXUNUSED(sizeFlags
)) 
 526     // ignore - we can't change the size of this standard dialog 
 530 // NB: of course, both of these functions are completely bogus, but it's better 
 532 void wxFindReplaceDialog::DoGetSize(int *width
, int *height
) const 
 534     // the standard dialog size 
 541 void wxFindReplaceDialog::DoGetClientSize(int *width
, int *height
) const 
 543     // the standard dialog size 
 550 #endif // wxUSE_FINDREPLDLG