]> git.saurik.com Git - wxWidgets.git/commitdiff
Added further API for intercepting deletion and content insertion
authorJulian Smart <julian@anthemion.co.uk>
Wed, 25 Jan 2012 15:10:09 +0000 (15:10 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Wed, 25 Jan 2012 15:10:09 +0000 (15:10 +0000)
Added simple implementation of locked objects to sample

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70465 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/richtext/richtextbuffer.h
include/wx/richtext/richtextctrl.h
interface/wx/richtext/richtextbuffer.h
interface/wx/richtext/richtextctrl.h
samples/richtext/richtext.cpp
src/richtext/richtextbuffer.cpp
src/richtext/richtextctrl.cpp

index 87c39441ecf4b88c2e2a1e9442f87465b33c8c7a..cdcd75b83785435267312f446ff342ab8cdda1a8 100644 (file)
@@ -3231,6 +3231,12 @@ public:
 
     virtual wxRichTextObject* Clone() const { return new wxRichTextParagraphLayoutBox(*this); }
 
+    /**
+        Prepares the content just before insertion (or after buffer reset).
+        Currently is only called if undo mode is on.
+    */
+    virtual void PrepareContent(wxRichTextParagraphLayoutBox& container);
+
     /**
         Insert fragment into this box at the given position. If partialParagraph is true,
         it is assumed that the last (or only) paragraph is just a piece of data with no paragraph
index 20072812450b392a8eaccd62c1d9a7d08bb316bb..87f085122c481f4b08a800b2bd168d9c15a88bdc 100644 (file)
@@ -1658,6 +1658,24 @@ public:
     */
     virtual wxString GetPropertiesMenuLabel(wxRichTextObject* obj) { return obj->GetPropertiesMenuLabel(); }
 
+    /**
+        Prepares the content just before insertion (or after buffer reset). Called by the same function in wxRichTextBuffer.
+        Currently is only called if undo mode is on.
+    */
+    virtual void PrepareContent(wxRichTextParagraphLayoutBox& WXUNUSED(container)) {}
+
+    /**
+        Can we delete this range?
+        Sends an event to the control.
+    */
+    virtual bool CanDeleteRange(wxRichTextParagraphLayoutBox& container, const wxRichTextRange& range) const;
+
+    /**
+        Can we insert content at this position?
+        Sends an event to the control.
+    */
+    virtual bool CanInsertContent(wxRichTextParagraphLayoutBox& container, long pos) const;
+
 // Command handlers
 
     /**
index 86a7baf5ef0b76f24e7ed87bd4cb0fe272d44a71..4d10e415747f3a5dd68c9dfe485d4bd7bf6965fd 100644 (file)
@@ -3111,6 +3111,12 @@ public:
 
     virtual wxRichTextObject* Clone() const { return new wxRichTextParagraphLayoutBox(*this); }
 
+    /**
+        Prepares the content just before insertion (or after buffer reset).
+        Currently is only called if undo mode is on.
+    */
+    virtual void PrepareContent(wxRichTextParagraphLayoutBox& container);
+
     /**
         Insert fragment into this box at the given position. If partialParagraph is true,
         it is assumed that the last (or only) paragraph is just a piece of data with no paragraph
index 4252ca8e23550ecaf4e54bafe659a3c5e542c4d5..7cbe45a4d1d22ba054eda6e95a38dfa484b5a75e 100644 (file)
@@ -1617,6 +1617,24 @@ public:
     */
     virtual wxString GetPropertiesMenuLabel(wxRichTextObject* obj);
 
+    /**
+        Prepares the content just before insertion (or after buffer reset). Called by the same function in wxRichTextBuffer.
+        Currently is only called if undo mode is on.
+    */
+    virtual void PrepareContent(wxRichTextParagraphLayoutBox& WXUNUSED(container)) {}
+
+    /**
+        Can we delete this range?
+        Sends an event to the control.
+    */
+    virtual bool CanDeleteRange(wxRichTextParagraphLayoutBox& container, const wxRichTextRange& range) const;
+
+    /**
+        Can we insert content at this position?
+        Sends an event to the control.
+    */
+    virtual bool CanInsertContent(wxRichTextParagraphLayoutBox& container, long pos) const;
+
 // Command handlers
 
     /**
index 860e15d022c067cf0e6b64f3361886951e2cd701..6198a574987ea95774c4126eda53702c7747b018 100644 (file)
 // private classes
 // ----------------------------------------------------------------------------
 
+// Define a new application type, each program should derive a class from wxApp
+class MyRichTextCtrl: public wxRichTextCtrl
+{
+public:
+    MyRichTextCtrl( wxWindow* parent, wxWindowID id = -1, const wxString& value = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+        long style = wxRE_MULTILINE, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxTextCtrlNameStr):
+      wxRichTextCtrl(parent, id, value, pos, size, style, validator, name)
+    {
+        m_lockId = 0;
+        m_locked = false;
+    }
+
+    void SetLockId(long id) { m_lockId = id; }
+    long GetLockId() const { return m_lockId; }
+
+    void BeginLock() { m_lockId ++; m_locked = true; }
+    void EndLock() { m_locked = false; }
+    bool IsLocked() const { return m_locked; }
+
+    static void SetEnhancedDrawingHandler();
+
+    /**
+        Prepares the content just before insertion (or after buffer reset). Called by the same function in wxRichTextBuffer.
+        Currently is only called if undo mode is on.
+    */
+    virtual void PrepareContent(wxRichTextParagraphLayoutBox& container);
+
+    /**
+        Can we delete this range?
+        Sends an event to the control.
+    */
+    virtual bool CanDeleteRange(wxRichTextParagraphLayoutBox& container, const wxRichTextRange& range) const;
+
+    /**
+        Can we insert content at this position?
+        Sends an event to the control.
+    */
+    virtual bool CanInsertContent(wxRichTextParagraphLayoutBox& container, long pos) const;
+
+    long    m_lockId;
+    bool    m_locked;
+};
+
 // Define a new application type, each program should derive a class from wxApp
 class MyApp : public wxApp
 {
@@ -205,7 +248,7 @@ private:
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
 
-    wxRichTextCtrl*         m_richTextCtrl;
+    MyRichTextCtrl*         m_richTextCtrl;
 };
 
 // ----------------------------------------------------------------------------
@@ -387,6 +430,8 @@ bool MyApp::OnInit()
 
     CreateStyles();
 
+    MyRichTextCtrl::SetEnhancedDrawingHandler();
+
     // Add extra handlers (plain text is automatically added)
     wxRichTextBuffer::AddHandler(new wxRichTextXMLHandler);
     wxRichTextBuffer::AddHandler(new wxRichTextHTMLHandler);
@@ -736,7 +781,7 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
     wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD);
     wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
 
-    m_richTextCtrl = new wxRichTextCtrl(splitter, ID_RICHTEXT_CTRL, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxWANTS_CHARS);
+    m_richTextCtrl = new MyRichTextCtrl(splitter, ID_RICHTEXT_CTRL, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxWANTS_CHARS);
     wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL);
 
     m_richTextCtrl->SetFont(font);
@@ -773,10 +818,27 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
 // Write text
 void MyFrame::WriteInitialText()
 {
-    wxRichTextCtrl& r = *m_richTextCtrl;
+    MyRichTextCtrl& r = *m_richTextCtrl;
 
     r.SetDefaultStyle(wxRichTextAttr());
 
+    // Add some locked content first - needs Undo to be enabled
+    {
+        r.BeginLock();
+        r.WriteText(wxString(wxT("This is a locked object.")));
+        r.EndLock();
+
+        r.WriteText(wxString(wxT(" This is unlocked text. ")));
+
+        r.BeginLock();
+        r.WriteText(wxString(wxT("More locked content.")));
+        r.EndLock();
+        r.Newline();
+
+        // Flush the Undo buffer
+        r.GetCommandProcessor()->ClearCommands();
+    }
+
     r.BeginSuppressUndo();
 
     r.Freeze();
@@ -1807,3 +1869,107 @@ void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
 
 //    wxGetApp().GetPrinting()->PageSetup();
 }
+
+void MyRichTextCtrl::PrepareContent(wxRichTextParagraphLayoutBox& container)
+{
+    if (IsLocked())
+    {
+        // Lock all content that's about to be added to the control
+        wxRichTextObjectList::compatibility_iterator node = container.GetChildren().GetFirst();
+        while (node)
+        {
+            wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
+            if (para)
+            {
+                wxRichTextObjectList::compatibility_iterator childNode = para->GetChildren().GetFirst();
+                while (childNode)
+                {
+                    wxRichTextObject* obj = childNode->GetData();
+                    obj->GetProperties().SetProperty(wxT("Lock"), m_lockId);
+
+                    childNode = childNode->GetNext();
+                }
+            }
+            node = node->GetNext();
+        }
+    }
+}
+
+bool MyRichTextCtrl::CanDeleteRange(wxRichTextParagraphLayoutBox& container, const wxRichTextRange& range) const
+{
+    long i;
+    for (i = range.GetStart(); i < range.GetEnd(); i++)
+    {
+        wxRichTextObject* obj = container.GetLeafObjectAtPosition(i);
+        if (obj && obj->GetProperties().HasProperty(wxT("Lock")))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool MyRichTextCtrl::CanInsertContent(wxRichTextParagraphLayoutBox& container, long pos) const
+{
+    wxRichTextObject* child1 = container.GetLeafObjectAtPosition(pos);
+    wxRichTextObject* child2 = container.GetLeafObjectAtPosition(pos-1);
+
+    long lock1 = -1, lock2 = -1;
+
+    if (child1 && child1->GetProperties().HasProperty(wxT("Lock")))
+        lock1 = child1->GetProperties().GetPropertyLong(wxT("Lock"));
+    if (child2 && child2->GetProperties().HasProperty(wxT("Lock")))
+        lock2 = child2->GetProperties().GetPropertyLong(wxT("Lock"));
+
+    if (lock1 != -1 && lock1 == lock2)
+        return false;
+
+    // Don't allow insertion before a locked object if it's at the beginning of the buffer.
+    if (pos == 0 && lock1 != -1)
+        return false;
+
+    return true;
+}
+
+
+class wxRichTextEnhancedDrawingHandler: public wxRichTextDrawingHandler
+{
+public:
+    wxRichTextEnhancedDrawingHandler()
+    {
+        SetName(wxT("enhanceddrawing"));
+        m_lockBackgroundColour = wxColour(220, 220, 220);
+    }
+
+    /**
+        Returns @true if this object has virtual attributes that we can provide.
+    */
+    virtual bool HasVirtualAttributes(wxRichTextObject* obj) const;
+
+    /**
+        Provides virtual attributes that we can provide.
+    */
+    virtual bool GetVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const;
+
+    wxColour    m_lockBackgroundColour;
+};
+
+bool wxRichTextEnhancedDrawingHandler::HasVirtualAttributes(wxRichTextObject* obj) const
+{
+    return obj->GetProperties().HasProperty(wxT("Lock"));
+}
+
+bool wxRichTextEnhancedDrawingHandler::GetVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const
+{
+    if (obj->GetProperties().HasProperty(wxT("Lock")))
+    {
+        attr.SetBackgroundColour(m_lockBackgroundColour);
+        return true;
+    }
+    return false;
+}
+
+void MyRichTextCtrl::SetEnhancedDrawingHandler()
+{
+    wxRichTextBuffer::AddDrawingHandler(new wxRichTextEnhancedDrawingHandler);
+}
index 1303fe8379a8db020a75c316ea53376c2a07304b..e8aee909545a9032a12c07bee6777951aac240bf 100644 (file)
@@ -3524,6 +3524,14 @@ bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange&
     return foundCount == matchingCount && foundCount != 0;
 }
 
+void wxRichTextParagraphLayoutBox::PrepareContent(wxRichTextParagraphLayoutBox& container)
+{
+    wxRichTextBuffer* buffer = GetBuffer();
+    if (buffer && buffer->GetRichTextCtrl())
+        buffer->GetRichTextCtrl()->PrepareContent(container);
+}
+
+
 /// Set character or paragraph properties
 bool wxRichTextParagraphLayoutBox::SetProperties(const wxRichTextRange& range, const wxRichTextProperties& properties, int flags)
 {
@@ -3697,6 +3705,8 @@ void wxRichTextParagraphLayoutBox::Reset()
 
     AddParagraph(wxEmptyString);
 
+    PrepareContent(*this);
+
     InvalidateHierarchy(wxRICHTEXT_ALL);
 }
 
@@ -7201,6 +7211,9 @@ bool wxRichTextBuffer::EndBatchUndo()
 /// Submit immediately, or delay according to whether collapsing is on
 bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
 {
+    if (action && !action->GetNewParagraphs().IsEmpty())
+        PrepareContent(action->GetNewParagraphs());
+
     if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
     {
         wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
index 9395714d2dd95a6360029076ed092ee2b81cb643..f5302ee6ca34e1110ae8874126d44063d910243d 100644 (file)
@@ -1113,12 +1113,26 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         // Must process this before translation, otherwise it's translated into a WXK_DELETE event.
         if (event.CmdDown() && event.GetKeyCode() == WXK_BACK)
         {
+            if (!IsEditable())
+            {
+                return;
+            }
+
+            if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange()))
+            {
+                return;
+            }
+
             BeginBatchUndo(_("Delete Text"));
 
             long newPos = m_caretPosition;
 
             bool processed = DeleteSelectedContent(& newPos);
 
+            int deletions = 0;
+            if (processed)
+                deletions ++;
+
             // Submit range in character positions, which are greater than caret positions,
             // so subtract 1 for deleted character and add 1 for conversion to character position.
             if (newPos > -1)
@@ -1128,13 +1142,25 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
                     long pos = wxRichTextCtrl::FindNextWordPosition(-1);
                     if (pos < newPos)
                     {
-                        GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this, & GetBuffer());
+                        wxRichTextRange range(pos+1, newPos);
+                        if (CanDeleteRange(* GetFocusObject(), range.FromInternal()))
+                        {
+                            GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer());
+                            deletions ++;
+                        }
                         processed = true;
                     }
                 }
 
                 if (!processed)
-                    GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this, & GetBuffer());
+                {
+                    wxRichTextRange range(newPos, newPos);
+                    if (CanDeleteRange(* GetFocusObject(), range.FromInternal()))
+                    {
+                        GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer());
+                        deletions ++;
+                    }
+                }
             }
 
             EndBatchUndo();
@@ -1150,14 +1176,17 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
             ScrollIntoView(m_caretPosition, WXK_LEFT);
 
-            wxRichTextEvent cmdEvent(
-                wxEVT_COMMAND_RICHTEXT_DELETE,
-                GetId());
-            cmdEvent.SetEventObject(this);
-            cmdEvent.SetFlags(flags);
-            cmdEvent.SetPosition(m_caretPosition+1);
-            cmdEvent.SetContainer(GetFocusObject());
-            GetEventHandler()->ProcessEvent(cmdEvent);
+            if (deletions > 0)
+            {
+                wxRichTextEvent cmdEvent(
+                    wxEVT_COMMAND_RICHTEXT_DELETE,
+                    GetId());
+                cmdEvent.SetEventObject(this);
+                cmdEvent.SetFlags(flags);
+                cmdEvent.SetPosition(m_caretPosition+1);
+                cmdEvent.SetContainer(GetFocusObject());
+                GetEventHandler()->ProcessEvent(cmdEvent);
+            }
 
             Update();
         }
@@ -1177,10 +1206,18 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
     if (event.GetKeyCode() == WXK_RETURN)
     {
-        BeginBatchUndo(_("Insert Text"));
+        if (!CanInsertContent(* GetFocusObject(), m_caretPosition+1))
+            return;
 
         long newPos = m_caretPosition;
 
+        if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange()))
+        {
+            return;
+        }
+
+        BeginBatchUndo(_("Insert Text"));
+
         DeleteSelectedContent(& newPos);
 
         if (event.ShiftDown())
@@ -1219,12 +1256,21 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
     }
     else if (event.GetKeyCode() == WXK_BACK)
     {
-        BeginBatchUndo(_("Delete Text"));
-
         long newPos = m_caretPosition;
 
+        if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange()))
+        {
+            return;
+        }
+
+        BeginBatchUndo(_("Delete Text"));
+
         bool processed = DeleteSelectedContent(& newPos);
 
+        int deletions = 0;
+        if (processed)
+            deletions ++;
+
         // Submit range in character positions, which are greater than caret positions,
         // so subtract 1 for deleted character and add 1 for conversion to character position.
         if (newPos > -1)
@@ -1234,13 +1280,25 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
                 long pos = wxRichTextCtrl::FindNextWordPosition(-1);
                 if (pos < newPos)
                 {
-                    GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(pos+1, newPos), this, & GetBuffer());
+                    wxRichTextRange range(pos+1, newPos);
+                    if (CanDeleteRange(* GetFocusObject(), range.FromInternal()))
+                    {
+                        GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer());
+                        deletions ++;
+                    }
                     processed = true;
                 }
             }
 
             if (!processed)
-                GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos, newPos), this, & GetBuffer());
+            {
+                wxRichTextRange range(newPos, newPos);
+                if (CanDeleteRange(* GetFocusObject(), range.FromInternal()))
+                {
+                    GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer());
+                    deletions ++;
+                }
+            }
         }
 
         EndBatchUndo();
@@ -1256,25 +1314,37 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
         ScrollIntoView(m_caretPosition, WXK_LEFT);
 
-        wxRichTextEvent cmdEvent(
-            wxEVT_COMMAND_RICHTEXT_DELETE,
-            GetId());
-        cmdEvent.SetEventObject(this);
-        cmdEvent.SetFlags(flags);
-        cmdEvent.SetPosition(m_caretPosition+1);
-        cmdEvent.SetContainer(GetFocusObject());
-        GetEventHandler()->ProcessEvent(cmdEvent);
+        if (deletions > 0)
+        {
+            wxRichTextEvent cmdEvent(
+                wxEVT_COMMAND_RICHTEXT_DELETE,
+                GetId());
+            cmdEvent.SetEventObject(this);
+            cmdEvent.SetFlags(flags);
+            cmdEvent.SetPosition(m_caretPosition+1);
+            cmdEvent.SetContainer(GetFocusObject());
+            GetEventHandler()->ProcessEvent(cmdEvent);
+        }
 
         Update();
     }
     else if (event.GetKeyCode() == WXK_DELETE)
     {
-        BeginBatchUndo(_("Delete Text"));
-
         long newPos = m_caretPosition;
 
+        if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange()))
+        {
+            return;
+        }
+
+        BeginBatchUndo(_("Delete Text"));
+
         bool processed = DeleteSelectedContent(& newPos);
 
+        int deletions = 0;
+        if (processed)
+            deletions ++;
+
         // Submit range in character positions, which are greater than caret positions,
         if (newPos < GetFocusObject()->GetOwnRange().GetEnd()+1)
         {
@@ -1283,13 +1353,25 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
                 long pos = wxRichTextCtrl::FindNextWordPosition(1);
                 if (pos != -1 && (pos > newPos))
                 {
-                    GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos+1, pos), this, & GetBuffer());
+                    wxRichTextRange range(newPos+1, pos);
+                    if (CanDeleteRange(* GetFocusObject(), range.FromInternal()))
+                    {
+                        GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer());
+                        deletions ++;
+                    }
                     processed = true;
                 }
             }
 
             if (!processed && newPos < (GetLastPosition()-1))
-                GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(newPos+1, newPos+1), this, & GetBuffer());
+            {
+                wxRichTextRange range(newPos+1, newPos+1);
+                if (CanDeleteRange(* GetFocusObject(), range.FromInternal()))
+                {
+                    GetFocusObject()->DeleteRangeWithUndo(range, this, & GetBuffer());
+                    deletions ++;
+                }
+            }
         }
 
         EndBatchUndo();
@@ -1305,14 +1387,17 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
         ScrollIntoView(m_caretPosition, WXK_LEFT);
 
-        wxRichTextEvent cmdEvent(
-            wxEVT_COMMAND_RICHTEXT_DELETE,
-            GetId());
-        cmdEvent.SetEventObject(this);
-        cmdEvent.SetFlags(flags);
-        cmdEvent.SetPosition(m_caretPosition+1);
-        cmdEvent.SetContainer(GetFocusObject());
-        GetEventHandler()->ProcessEvent(cmdEvent);
+        if (deletions > 0)
+        {
+            wxRichTextEvent cmdEvent(
+                wxEVT_COMMAND_RICHTEXT_DELETE,
+                GetId());
+            cmdEvent.SetEventObject(this);
+            cmdEvent.SetFlags(flags);
+            cmdEvent.SetPosition(m_caretPosition+1);
+            cmdEvent.SetContainer(GetFocusObject());
+            GetEventHandler()->ProcessEvent(cmdEvent);
+        }
 
         Update();
     }
@@ -1377,6 +1462,12 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
                     }
                 }
 
+                if (!CanInsertContent(* GetFocusObject(), m_caretPosition+1))
+                    return;
+
+                if (HasSelection() && !CanDeleteRange(* GetFocusObject(), GetSelectionRange()))
+                    return;
+
                 BeginBatchUndo(_("Insert Text"));
 
                 long newPos = m_caretPosition;
@@ -3018,12 +3109,12 @@ bool wxRichTextCtrl::CanCopy() const
 
 bool wxRichTextCtrl::CanCut() const
 {
-    return HasSelection() && IsEditable();
+    return CanDeleteSelection();
 }
 
 bool wxRichTextCtrl::CanPaste() const
 {
-    if ( !IsEditable() )
+    if ( !IsEditable() || !GetFocusObject() || !CanInsertContent(* GetFocusObject(), m_caretPosition+1))
         return false;
 
     return GetBuffer().CanPasteFromClipboard();
@@ -3031,7 +3122,7 @@ bool wxRichTextCtrl::CanPaste() const
 
 bool wxRichTextCtrl::CanDeleteSelection() const
 {
-    return HasSelection() && IsEditable();
+    return HasSelection() && IsEditable() && CanDeleteRange(* GetFocusObject(), GetSelectionRange());
 }
 
 
@@ -4460,6 +4551,16 @@ bool wxRichTextDropSource::GiveFeedback(wxDragResult WXUNUSED(effect))
 }
 #endif // wxUSE_DRAG_AND_DROP
 
+bool wxRichTextCtrl::CanDeleteRange(wxRichTextParagraphLayoutBox& WXUNUSED(container), const wxRichTextRange& WXUNUSED(range)) const
+{
+    return true;
+}
+
+bool wxRichTextCtrl::CanInsertContent(wxRichTextParagraphLayoutBox& WXUNUSED(container), long WXUNUSED(pos)) const
+{
+    return true;
+}
+
 
 #if wxRICHTEXT_USE_OWN_CARET