Use IRichEditOleCallback for wxTextCtrl's context menu.

In wxMSW, use IRichEditOleCallback::GetContextMenu() to provide our
default context menu for rich text controls, instead of using
EVT_CONTEXT_MENU.

The latter completely overrides native control's handling and in
particular breaks Windows 8's builtin spellchecking support.

Fall back to the previous non-OLE code for older richtext versions.

Also make the new MSWCreateContextMenu() method virtual so that the
context menu can be customized.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76723 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2014-06-18 12:51:49 +00:00
parent 2cf91e5c7c
commit bd650ec3d9
3 changed files with 114 additions and 30 deletions

View File

@@ -170,6 +170,11 @@ public:
// EDIT control has one already)
void OnContextMenu(wxContextMenuEvent& event);
// Create context menu for RICHEDIT controls. This may be called once during
// the control's lifetime or every time the menu is shown, depending on
// implementation.
virtual wxMenu *MSWCreateContextMenu();
// be sure the caret remains invisible if the user
// called HideNativeCaret() before
void OnSetFocus(wxFocusEvent& event);

View File

@@ -40,6 +40,7 @@
#include "wx/wxcrtvararg.h"
#endif
#include "wx/scopedptr.h"
#include "wx/stack.h"
#include "wx/sysopt.h"
@@ -63,6 +64,8 @@
#if wxUSE_RICHEDIT
#include <richedit.h>
#include <richole.h>
#include "wx/msw/ole/oleutils.h"
#endif // wxUSE_RICHEDIT
#include "wx/msw/missing.h"
@@ -126,6 +129,71 @@ bool wxRichEditModule::ms_inkEditLibLoadAttemped = false;
IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
#if wxUSE_OLE
extern wxMenu *wxCurrentPopupMenu;
class wxTextCtrlOleCallback : public IRichEditOleCallback
{
public:
wxTextCtrlOleCallback(wxTextCtrl *text) : m_textCtrl(text), m_menu(NULL) {}
~wxTextCtrlOleCallback() { DeleteContextMenuObject(); }
STDMETHODIMP ContextSensitiveHelp(BOOL WXUNUSED(enterMode)) { return E_NOTIMPL; }
STDMETHODIMP DeleteObject(LPOLEOBJECT WXUNUSED(oleobj)) { return E_NOTIMPL; }
STDMETHODIMP GetClipboardData(CHARRANGE* WXUNUSED(chrg), DWORD WXUNUSED(reco), LPDATAOBJECT* WXUNUSED(dataobj)) { return E_NOTIMPL; }
STDMETHODIMP GetDragDropEffect(BOOL WXUNUSED(drag), DWORD WXUNUSED(grfKeyState), LPDWORD WXUNUSED(effect)) { return E_NOTIMPL; }
STDMETHODIMP GetInPlaceContext(LPOLEINPLACEFRAME* WXUNUSED(frame), LPOLEINPLACEUIWINDOW* WXUNUSED(doc), LPOLEINPLACEFRAMEINFO WXUNUSED(frameInfo)) { return E_NOTIMPL; }
STDMETHODIMP GetNewStorage(LPSTORAGE *WXUNUSED(stg)) { return E_NOTIMPL; }
STDMETHODIMP QueryAcceptData(LPDATAOBJECT WXUNUSED(dataobj), CLIPFORMAT* WXUNUSED(format), DWORD WXUNUSED(reco), BOOL WXUNUSED(really), HGLOBAL WXUNUSED(hMetaPict)) { return E_NOTIMPL; }
STDMETHODIMP QueryInsertObject(LPCLSID WXUNUSED(clsid), LPSTORAGE WXUNUSED(stg), LONG WXUNUSED(cp)) { return E_NOTIMPL; }
STDMETHODIMP ShowContainerUI(BOOL WXUNUSED(show)) { return E_NOTIMPL; }
STDMETHODIMP GetContextMenu(WORD WXUNUSED(seltype), LPOLEOBJECT WXUNUSED(oleobj), CHARRANGE* WXUNUSED(chrg), HMENU *menu)
{
// 'menu' will be shown and destroyed by the caller. We need to keep
// its wx counterpart, the wxMenu instance, around until it is
// dismissed, though, so store it in m_menu and destroy sometime later.
DeleteContextMenuObject();
m_menu = m_textCtrl->MSWCreateContextMenu();
*menu = m_menu->GetHMenu();
// Make wx handle events from the popup menu correctly:
m_menu->SetInvokingWindow(m_textCtrl);
wxCurrentPopupMenu = m_menu;
return S_OK;
}
DECLARE_IUNKNOWN_METHODS;
private:
void DeleteContextMenuObject()
{
if ( m_menu )
{
m_menu->MSWDetachHMENU();
if ( wxCurrentPopupMenu == m_menu )
wxCurrentPopupMenu = NULL;
wxDELETE(m_menu);
}
}
wxTextCtrl *m_textCtrl;
wxMenu *m_menu;
wxDECLARE_NO_COPY_CLASS(wxTextCtrlOleCallback);
};
BEGIN_IID_TABLE(wxTextCtrlOleCallback)
ADD_IID(Unknown)
ADD_IID(RichEditOleCallback)
END_IID_TABLE;
IMPLEMENT_IUNKNOWN_METHODS(wxTextCtrlOleCallback)
#endif // wxUSE_OLE
#endif // wxUSE_RICHEDIT
// a small class used to set m_updatesCount to 0 (to filter duplicate events if
@@ -186,10 +254,6 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
EVT_KEY_DOWN(wxTextCtrl::OnKeyDown)
EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
#if wxUSE_RICHEDIT
EVT_CONTEXT_MENU(wxTextCtrl::OnContextMenu)
#endif
EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
@@ -480,6 +544,17 @@ bool wxTextCtrl::MSWCreateText(const wxString& value,
}
::SendMessage(GetHwnd(), EM_SETEVENTMASK, 0, mask);
bool contextMenuConnected = false;
#if wxUSE_OLE
if ( m_verRichEdit >= 4 )
{
wxTextCtrlOleCallback *cb = new wxTextCtrlOleCallback(this);
contextMenuConnected = ::SendMessage(GetHwnd(), EM_SETOLECALLBACK, 0, (LPARAM)cb) != 0;
}
#endif
if ( !contextMenuConnected )
Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(wxTextCtrl::OnContextMenu));
}
else
#endif // wxUSE_RICHEDIT
@@ -2278,32 +2353,6 @@ void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
event.Enable( !IsEmpty() );
}
void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
{
#if wxUSE_RICHEDIT
if (IsRich())
{
if (!m_privateContextMenu)
{
m_privateContextMenu = new wxMenu;
m_privateContextMenu->Append(wxID_UNDO, _("&Undo"));
m_privateContextMenu->Append(wxID_REDO, _("&Redo"));
m_privateContextMenu->AppendSeparator();
m_privateContextMenu->Append(wxID_CUT, _("Cu&t"));
m_privateContextMenu->Append(wxID_COPY, _("&Copy"));
m_privateContextMenu->Append(wxID_PASTE, _("&Paste"));
m_privateContextMenu->Append(wxID_CLEAR, _("&Delete"));
m_privateContextMenu->AppendSeparator();
m_privateContextMenu->Append(wxID_SELECTALL, _("Select &All"));
}
PopupMenu(m_privateContextMenu);
return;
}
else
#endif
event.Skip();
}
void wxTextCtrl::OnSetFocus(wxFocusEvent& event)
{
// be sure the caret remains invisible if the user had hidden it
@@ -2318,6 +2367,34 @@ void wxTextCtrl::OnSetFocus(wxFocusEvent& event)
// the rest of the file only deals with the rich edit controls
#if wxUSE_RICHEDIT
void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
{
if (IsRich())
{
if (!m_privateContextMenu)
m_privateContextMenu = MSWCreateContextMenu();
PopupMenu(m_privateContextMenu);
return;
}
else
event.Skip();
}
wxMenu *wxTextCtrl::MSWCreateContextMenu()
{
wxMenu *m = new wxMenu;
m->Append(wxID_UNDO, _("&Undo"));
m->Append(wxID_REDO, _("&Redo"));
m->AppendSeparator();
m->Append(wxID_CUT, _("Cu&t"));
m->Append(wxID_COPY, _("&Copy"));
m->Append(wxID_PASTE, _("&Paste"));
m->Append(wxID_CLEAR, _("&Delete"));
m->AppendSeparator();
m->Append(wxID_SELECTALL, _("Select &All"));
return m;
}
// ----------------------------------------------------------------------------
// EN_LINK processing
// ----------------------------------------------------------------------------

View File

@@ -2335,6 +2335,8 @@ bool wxWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu)
{
menu = wxCurrentPopupMenu;
isPopup = true;
if ( evtType == wxEVT_MENU_CLOSE )
wxCurrentPopupMenu = NULL;
}
else
{