Merge branch 'osx-text-undo'
Implement undo/redo for (multiline) wxTextCtrl in wxOSX. See https://github.com/wxWidgets/wxWidgets/pull/2474
This commit is contained in:
commit
6689feb648
16 changed files with 220 additions and 25 deletions
|
|
@ -64,6 +64,9 @@ public:
|
|||
|
||||
virtual void Redo() wxOVERRIDE;
|
||||
virtual bool CanRedo() const wxOVERRIDE;
|
||||
#if wxUSE_RICHEDIT
|
||||
virtual void EmptyUndoBuffer() wxOVERRIDE;
|
||||
#endif // wxUSE_RICHEDIT
|
||||
|
||||
virtual void SetInsertionPointEnd() wxOVERRIDE;
|
||||
virtual long GetInsertionPoint() const wxOVERRIDE;
|
||||
|
|
|
|||
|
|
@ -436,6 +436,8 @@ public:
|
|||
- (void)textDidChange:(NSNotification *)aNotification;
|
||||
- (void)changeColor:(id)sender;
|
||||
|
||||
@property (retain) NSUndoManager* undoManager;
|
||||
|
||||
@end
|
||||
|
||||
@interface wxNSComboBox : NSComboBox
|
||||
|
|
|
|||
|
|
@ -136,12 +136,19 @@ public:
|
|||
|
||||
virtual void controlTextDidChange() wxOVERRIDE;
|
||||
|
||||
virtual bool CanUndo() const wxOVERRIDE;
|
||||
virtual void Undo() wxOVERRIDE;
|
||||
virtual bool CanRedo() const wxOVERRIDE;
|
||||
virtual void Redo() wxOVERRIDE;
|
||||
virtual void EmptyUndoBuffer() wxOVERRIDE;
|
||||
|
||||
protected:
|
||||
void DoUpdateTextStyle();
|
||||
|
||||
NSScrollView* m_scrollView;
|
||||
NSTextView* m_textView;
|
||||
bool m_useCharWrapping;
|
||||
NSUndoManager* m_undoManager;
|
||||
};
|
||||
|
||||
class wxNSComboBoxControl : public wxNSTextFieldControl, public wxComboWidgetImpl
|
||||
|
|
|
|||
|
|
@ -730,6 +730,7 @@ public :
|
|||
virtual void Undo() ;
|
||||
virtual bool CanRedo() const;
|
||||
virtual void Redo() ;
|
||||
virtual void EmptyUndoBuffer() ;
|
||||
virtual int GetNumberOfLines() const ;
|
||||
virtual long XYToPosition(long x, long y) const;
|
||||
virtual bool PositionToXY(long pos, long *x, long *y) const ;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ public:
|
|||
virtual void MarkDirty() wxOVERRIDE;
|
||||
virtual void DiscardEdits() wxOVERRIDE;
|
||||
|
||||
virtual void EmptyUndoBuffer() wxOVERRIDE;
|
||||
|
||||
// text control under some platforms supports the text styles: these
|
||||
// methods apply the given text style to the given selection or to
|
||||
// set/get the style which will be used for all appended text
|
||||
|
|
|
|||
|
|
@ -429,6 +429,11 @@ protected:
|
|||
wxString m_cpuArch;
|
||||
};
|
||||
|
||||
|
||||
// Returns true only for MSW programs running under Wine.
|
||||
#ifdef __WINDOWS__
|
||||
WXDLLIMPEXP_BASE bool wxIsRunningUnderWine();
|
||||
#else // !__WINDOWS__
|
||||
inline bool wxIsRunningUnderWine() { return false; }
|
||||
#endif // __WINDOWS__/!__WINDOWS__
|
||||
|
||||
#endif // _WX_PLATINFO_H_
|
||||
|
|
|
|||
|
|
@ -3642,7 +3642,7 @@ public:
|
|||
bool CanUndo() const wxOVERRIDE;
|
||||
|
||||
// Delete the undo history.
|
||||
void EmptyUndoBuffer();
|
||||
void EmptyUndoBuffer() wxOVERRIDE;
|
||||
|
||||
// Undo one action in the undo history.
|
||||
void Undo() wxOVERRIDE;
|
||||
|
|
|
|||
|
|
@ -574,6 +574,8 @@ public:
|
|||
DiscardEdits();
|
||||
}
|
||||
|
||||
virtual void EmptyUndoBuffer() { }
|
||||
|
||||
|
||||
// styles handling
|
||||
// ---------------
|
||||
|
|
|
|||
|
|
@ -629,3 +629,16 @@ public:
|
|||
|
||||
//@}
|
||||
};
|
||||
|
||||
/**
|
||||
Returns true only for MSW programs running under Wine.
|
||||
|
||||
This function can be used to check for some functionality not implemented
|
||||
when using Wine.
|
||||
|
||||
@since 3.1.6
|
||||
|
||||
@library{wxbase}
|
||||
@category{cfg}
|
||||
*/
|
||||
bool wxIsRunningUnderWine();
|
||||
|
|
|
|||
|
|
@ -1312,6 +1312,17 @@ public:
|
|||
*/
|
||||
virtual void DiscardEdits();
|
||||
|
||||
/**
|
||||
Delete the undo history.
|
||||
|
||||
Currently only implemented in wxMSW (for controls using wxTE_RICH2
|
||||
style only) and wxOSX (for multiline text controls only), does nothing
|
||||
in the other ports or for the controls not using the appropriate styles.
|
||||
|
||||
@since 3.1.6
|
||||
*/
|
||||
virtual void EmptyUndoBuffer();
|
||||
|
||||
/**
|
||||
This function inserts into the control the character which would have
|
||||
been inserted if the given key event had occurred in the text control.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@
|
|||
|
||||
#include "wx/apptrait.h"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include "wx/dynlib.h"
|
||||
#endif
|
||||
|
||||
// global object
|
||||
// VERY IMPORTANT: do not use the default constructor since it would
|
||||
// try to init the wxPlatformInfo instance using
|
||||
|
|
@ -373,3 +377,12 @@ wxEndianness wxPlatformInfo::GetEndianness(const wxString& end)
|
|||
|
||||
return wxENDIAN_INVALID;
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
bool wxIsRunningUnderWine()
|
||||
{
|
||||
return wxLoadedDLL("ntdll.dll").HasSymbol(wxS("wine_get_version"));
|
||||
}
|
||||
|
||||
#endif // __WINDOWS__
|
||||
|
|
|
|||
|
|
@ -690,33 +690,16 @@ bool wxTextCtrl::MSWCreateText(const wxString& value,
|
|||
::SendMessage(GetHwnd(), EM_SETMARGINS, wParam, lParam);
|
||||
}
|
||||
|
||||
#if wxUSE_RICHEDIT && wxUSE_OLE && defined(wxHAS_TOM_H)
|
||||
#if wxUSE_RICHEDIT
|
||||
// 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).
|
||||
// for a newly created control returns true, which is unexpected, so clear
|
||||
// the undo buffer.
|
||||
if ( GetRichVersion() >= 4 )
|
||||
{
|
||||
wxCOMPtr<IRichEditOle> pRichEditOle;
|
||||
if ( SendMessage(GetHwnd(), EM_GETOLEINTERFACE,
|
||||
0, (LPARAM)&pRichEditOle) && pRichEditOle )
|
||||
{
|
||||
wxCOMPtr<ITextDocument> 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);
|
||||
}
|
||||
}
|
||||
EmptyUndoBuffer();
|
||||
}
|
||||
#endif // wxUSE_RICHEDIT && wxHAS_TOM_H
|
||||
#endif // wxUSE_RICHEDIT
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2012,6 +1995,37 @@ bool wxTextCtrl::CanRedo() const
|
|||
return wxTextEntry::CanRedo();
|
||||
}
|
||||
|
||||
#if wxUSE_RICHEDIT
|
||||
|
||||
void wxTextCtrl::EmptyUndoBuffer()
|
||||
{
|
||||
#if wxUSE_OLE && defined(wxHAS_TOM_H)
|
||||
// We need to use Undo(tomFalse) to clear the undo buffer, but calling it
|
||||
// also disables the undo buffer, so we need to enable it again immediately
|
||||
// after clearing by calling Undo(tomTrue).
|
||||
if ( GetRichVersion() >= 4 )
|
||||
{
|
||||
wxCOMPtr<IRichEditOle> pRichEditOle;
|
||||
if ( SendMessage(GetHwnd(), EM_GETOLEINTERFACE,
|
||||
0, (LPARAM)&pRichEditOle) && pRichEditOle )
|
||||
{
|
||||
wxCOMPtr<ITextDocument> 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_OLE && wxHAS_TOM_H
|
||||
}
|
||||
#endif // wxUSE_RICHEDIT
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// caret handling (Windows only)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -426,6 +426,16 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
|
|||
}
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(NSRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
if ( self )
|
||||
{
|
||||
self.undoManager = [[[NSUndoManager alloc] init] autorelease];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)textDidChange:(NSNotification *)aNotification
|
||||
{
|
||||
wxUnusedVar(aNotification);
|
||||
|
|
@ -434,6 +444,11 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
|
|||
impl->controlTextDidChange();
|
||||
}
|
||||
|
||||
- (nullable NSUndoManager *)undoManagerForTextView:(NSTextView *)view
|
||||
{
|
||||
return self.undoManager;
|
||||
}
|
||||
|
||||
|
||||
- (void)changeColor:(id)sender
|
||||
{
|
||||
|
|
@ -773,6 +788,10 @@ wxNSTextViewControl::wxNSTextViewControl( wxTextCtrl *wxPeer, WXWidget w, long s
|
|||
|
||||
[tv setDelegate: tv];
|
||||
|
||||
m_undoManager = tv.undoManager;
|
||||
|
||||
[tv setAllowsUndo:YES];
|
||||
|
||||
InstallEventHandler(tv);
|
||||
}
|
||||
|
||||
|
|
@ -1019,6 +1038,46 @@ void wxNSTextViewControl::controlTextDidChange()
|
|||
DoUpdateTextStyle();
|
||||
}
|
||||
|
||||
bool wxNSTextViewControl::CanUndo() const
|
||||
{
|
||||
if ( !m_undoManager )
|
||||
return false;
|
||||
|
||||
return [m_undoManager canUndo];
|
||||
}
|
||||
|
||||
void wxNSTextViewControl::Undo()
|
||||
{
|
||||
if ( !m_undoManager )
|
||||
return;
|
||||
|
||||
[m_undoManager undo];
|
||||
}
|
||||
|
||||
bool wxNSTextViewControl::CanRedo() const
|
||||
{
|
||||
if ( !m_undoManager )
|
||||
return false;
|
||||
|
||||
return [m_undoManager canRedo];
|
||||
}
|
||||
|
||||
void wxNSTextViewControl::Redo()
|
||||
{
|
||||
if ( !m_undoManager )
|
||||
return;
|
||||
|
||||
[m_undoManager redo];
|
||||
}
|
||||
|
||||
void wxNSTextViewControl::EmptyUndoBuffer()
|
||||
{
|
||||
if ( !m_undoManager )
|
||||
return;
|
||||
|
||||
[m_undoManager removeAllActions];
|
||||
}
|
||||
|
||||
void wxNSTextViewControl::DoUpdateTextStyle()
|
||||
{
|
||||
if ( m_useCharWrapping )
|
||||
|
|
|
|||
|
|
@ -259,6 +259,13 @@ void wxTextCtrl::DiscardEdits()
|
|||
m_dirty = false;
|
||||
}
|
||||
|
||||
void wxTextCtrl::EmptyUndoBuffer()
|
||||
{
|
||||
wxCHECK_RET( GetTextPeer(), "Must create the control first" );
|
||||
|
||||
GetTextPeer()->EmptyUndoBuffer() ;
|
||||
}
|
||||
|
||||
int wxTextCtrl::GetNumberOfLines() const
|
||||
{
|
||||
return GetTextPeer()->GetNumberOfLines() ;
|
||||
|
|
@ -342,7 +349,7 @@ void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
|
|||
|
||||
void wxTextCtrl::OnKeyDown(wxKeyEvent& event)
|
||||
{
|
||||
if ( event.GetModifiers() == wxMOD_CONTROL )
|
||||
if ( event.ControlDown() )
|
||||
{
|
||||
switch( event.GetKeyCode() )
|
||||
{
|
||||
|
|
@ -361,6 +368,18 @@ void wxTextCtrl::OnKeyDown(wxKeyEvent& event)
|
|||
if ( CanCut() )
|
||||
Cut() ;
|
||||
return;
|
||||
case 'Z':
|
||||
if ( !event.ShiftDown() )
|
||||
{
|
||||
if ( CanUndo() )
|
||||
Undo() ;
|
||||
return;
|
||||
}
|
||||
// else fall through to Redo
|
||||
case 'Y':
|
||||
if ( CanRedo() )
|
||||
Redo() ;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -688,6 +707,10 @@ void wxTextWidgetImpl::Redo()
|
|||
{
|
||||
}
|
||||
|
||||
void wxTextWidgetImpl::EmptyUndoBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
long wxTextWidgetImpl::XYToPosition(long WXUNUSED(x), long WXUNUSED(y)) const
|
||||
{
|
||||
return 0 ;
|
||||
|
|
|
|||
|
|
@ -1094,6 +1094,7 @@ overrideNeeded = (
|
|||
'CanPaste',
|
||||
'CanRedo',
|
||||
'CanUndo',
|
||||
'EmptyUndoBuffer',
|
||||
'Clear',
|
||||
'AppendText',
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "wx/textctrl.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/platinfo.h"
|
||||
#include "wx/scopedptr.h"
|
||||
#include "wx/uiaction.h"
|
||||
|
||||
|
|
@ -1472,4 +1473,42 @@ TEST_CASE("wxTextCtrl::InitialCanUndo", "[wxTextCtrl][undo]")
|
|||
}
|
||||
}
|
||||
|
||||
// This test would always fail with MinGW-32 for the same reason as described
|
||||
// above.
|
||||
#ifndef __MINGW32_TOOLCHAIN__
|
||||
|
||||
TEST_CASE("wxTextCtrl::EmptyUndoBuffer", "[wxTextCtrl][undo]")
|
||||
{
|
||||
if ( wxIsRunningUnderWine() )
|
||||
{
|
||||
// Wine doesn't implement EM_GETOLEINTERFACE and related stuff currently
|
||||
WARN("Skipping test known to fail under Wine.");
|
||||
return;
|
||||
}
|
||||
|
||||
wxScopedPtr<wxTextCtrl> text(new wxTextCtrl(wxTheApp->GetTopWindow(),
|
||||
wxID_ANY, "",
|
||||
wxDefaultPosition,
|
||||
wxDefaultSize,
|
||||
wxTE_MULTILINE | wxTE_RICH2));
|
||||
|
||||
text->AppendText("foo");
|
||||
|
||||
if ( !text->CanUndo() )
|
||||
{
|
||||
WARN("Skipping test as Undo() is not supported on this platform.");
|
||||
return;
|
||||
}
|
||||
|
||||
text->EmptyUndoBuffer();
|
||||
|
||||
CHECK_FALSE( text->CanUndo() );
|
||||
|
||||
CHECK_NOTHROW( text->Undo() );
|
||||
|
||||
CHECK( text->GetValue() == "foo" );
|
||||
}
|
||||
|
||||
#endif // __MINGW32_TOOLCHAIN__
|
||||
|
||||
#endif //wxUSE_TEXTCTRL
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue