diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index 985664755c..16bb3cceff 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -65,7 +65,21 @@ #if wxUSE_RICHEDIT #include #include + + // MinGW32 doesn't have tom.h and doesn't define the interfaces and the + // constants we need, so we can't use ITextDocument::Undo() with it. All + // the other compilers do have this header. + #ifndef __MINGW32_TOOLCHAIN__ + #define wxHAS_TOM_H + #endif + + #ifdef wxHAS_TOM_H + #include + #endif + #include "wx/msw/ole/oleutils.h" + + #include "wx/msw/private/comptr.h" #endif // wxUSE_RICHEDIT #if wxUSE_INKEDIT @@ -129,6 +143,17 @@ DEFINE_GUID(wxIID_IRichEditOleCallback, 0x00020d03, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); } // anonymous namespace + +#ifdef wxHAS_TOM_H + +// This one is not defined in the standard libraries at all and MSDN just says +// to define it explicitly, so we do it for IID_XXX constant itself and not our +// own wxIID_XXX. +DEFINE_GUID(IID_ITextDocument, + 0x8cc497c0, 0xa1df, 0x11ce, 0x80, 0x98, 0x00, 0xaa, 0x00, 0x47, 0xbe, 0x5d); + +#endif // wxHAS_TOM_H + #endif // wxUSE_OLE // ---------------------------------------------------------------------------- @@ -668,6 +693,34 @@ bool wxTextCtrl::MSWCreateText(const wxString& value, ::SendMessage(GetHwnd(), EM_SETMARGINS, wParam, lParam); } +#if wxUSE_RICHEDIT && defined(wxHAS_TOM_H) + // For RichEdit >= 4, SetFont(), called above from MSWCreateControl(), uses + // EM_SETCHARFORMAT which affects the undo buffer, meaning that CanUndo() + // for a newly created control returns true, which is unexpected. To avoid + // this, we explicitly use Undo(tomFalse) here to clear the undo buffer. + // And since Undo(tomFalse) also disables the undo buffer, we need to + // enable it again immediately after clearing by calling Undo(tomTrue). + if ( GetRichVersion() >= 4 ) + { + wxCOMPtr pRichEditOle; + if ( SendMessage(GetHwnd(), EM_GETOLEINTERFACE, + 0, (LPARAM)&pRichEditOle) && pRichEditOle ) + { + wxCOMPtr pDoc; + HRESULT hr = pRichEditOle->QueryInterface + ( + wxIID_PPV_ARGS(ITextDocument, &pDoc) + ); + if ( SUCCEEDED(hr) ) + { + hr = pDoc->Undo(tomFalse, NULL); + if ( SUCCEEDED(hr) ) + pDoc->Undo(tomTrue, NULL); + } + } + } +#endif // wxUSE_RICHEDIT && wxHAS_TOM_H + return true; } diff --git a/tests/controls/textctrltest.cpp b/tests/controls/textctrltest.cpp index e07c218d67..d30c620d0a 100644 --- a/tests/controls/textctrltest.cpp +++ b/tests/controls/textctrltest.cpp @@ -1432,4 +1432,35 @@ TEST_CASE("wxTextCtrl::EventsOnCreate", "[wxTextCtrl][event]") CHECK( updated.GetCount() == 1 ); } +TEST_CASE("wxTextCtrl::InitialCanUndo", "[wxTextCtrl][undo]") +{ + wxWindow* const parent = wxTheApp->GetTopWindow(); + + const long styles[] = { 0, wxTE_RICH, wxTE_RICH2 }; + + for ( size_t n = 0; n < WXSIZEOF(styles); n++ ) + { + const long style = styles[n]; + +#ifdef __MINGW32_TOOLCHAIN__ + if ( style == wxTE_RICH2 ) + { + // We can't call ITextDocument::Undo() in wxMSW code when using + // MinGW32, so this test would always fail with it. + WARN("Skipping test known to fail with MinGW-32."); + } + continue; +#endif // __MINGW32_TOOLCHAIN__ + + INFO("wxTextCtrl with style " << style); + + wxScopedPtr text(new wxTextCtrl(parent, wxID_ANY, "", + wxDefaultPosition, + wxDefaultSize, + style)); + + CHECK( !text->CanUndo() ); + } +} + #endif //wxUSE_TEXTCTRL