]> git.saurik.com Git - wxWidgets.git/blobdiff - samples/richtext/richtext.cpp
Don't return NULL widget from wxFileCtrl page of widgets sample.
[wxWidgets.git] / samples / richtext / richtext.cpp
index ff29361e165ac200824c6dd3bf127be639138e55..d50ec7b575f176bdc75c7b9fda724cc504389ddc 100644 (file)
@@ -34,6 +34,8 @@
 #include "wx/splitter.h"
 #include "wx/sstream.h"
 #include "wx/html/htmlwin.h"
+#include "wx/stopwatch.h"
+#include "wx/sysopt.h"
 
 #if wxUSE_FILESYSTEM
 #include "wx/filesys.h"
@@ -44,7 +46,7 @@
 #include "wx/cshelp.h"
 #endif
 
-#ifndef __WXMSW__
+#ifndef wxHAS_IMAGES_IN_RESOURCES
     #include "../sample.xpm"
 #endif
 
 // 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
 {
@@ -130,9 +175,16 @@ public:
     void OnItalic(wxCommandEvent& event);
     void OnUnderline(wxCommandEvent& event);
 
+    void OnStrikethrough(wxCommandEvent& event);
+    void OnSuperscript(wxCommandEvent& event);
+    void OnSubscript(wxCommandEvent& event);
+
     void OnUpdateBold(wxUpdateUIEvent& event);
     void OnUpdateItalic(wxUpdateUIEvent& event);
     void OnUpdateUnderline(wxUpdateUIEvent& event);
+    void OnUpdateStrikethrough(wxUpdateUIEvent& event);
+    void OnUpdateSuperscript(wxUpdateUIEvent& event);
+    void OnUpdateSubscript(wxUpdateUIEvent& event);
 
     void OnAlignLeft(wxCommandEvent& event);
     void OnAlignCentre(wxCommandEvent& event);
@@ -197,7 +249,7 @@ private:
     // any class wishing to process wxWidgets events must use this macro
     DECLARE_EVENT_TABLE()
 
-    wxRichTextCtrl*         m_richTextCtrl;
+    MyRichTextCtrl*         m_richTextCtrl;
 };
 
 // ----------------------------------------------------------------------------
@@ -214,6 +266,9 @@ enum
     ID_FORMAT_BOLD = 100,
     ID_FORMAT_ITALIC,
     ID_FORMAT_UNDERLINE,
+    ID_FORMAT_STRIKETHROUGH,
+    ID_FORMAT_SUPERSCRIPT,
+    ID_FORMAT_SUBSCRIPT,
     ID_FORMAT_FONT,
     ID_FORMAT_IMAGE,
     ID_FORMAT_PARAGRAPH,
@@ -279,10 +334,18 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(ID_FORMAT_ITALIC,  MyFrame::OnItalic)
     EVT_MENU(ID_FORMAT_UNDERLINE,  MyFrame::OnUnderline)
 
+    EVT_MENU(ID_FORMAT_STRIKETHROUGH,  MyFrame::OnStrikethrough)
+    EVT_MENU(ID_FORMAT_SUPERSCRIPT,  MyFrame::OnSuperscript)
+    EVT_MENU(ID_FORMAT_SUBSCRIPT,  MyFrame::OnSubscript)
+
     EVT_UPDATE_UI(ID_FORMAT_BOLD,  MyFrame::OnUpdateBold)
     EVT_UPDATE_UI(ID_FORMAT_ITALIC,  MyFrame::OnUpdateItalic)
     EVT_UPDATE_UI(ID_FORMAT_UNDERLINE,  MyFrame::OnUpdateUnderline)
 
+    EVT_UPDATE_UI(ID_FORMAT_STRIKETHROUGH,  MyFrame::OnUpdateStrikethrough)
+    EVT_UPDATE_UI(ID_FORMAT_SUPERSCRIPT,  MyFrame::OnUpdateSuperscript)
+    EVT_UPDATE_UI(ID_FORMAT_SUBSCRIPT,  MyFrame::OnUpdateSubscript)
+
     EVT_MENU(ID_FORMAT_ALIGN_LEFT,  MyFrame::OnAlignLeft)
     EVT_MENU(ID_FORMAT_ALIGN_CENTRE,  MyFrame::OnAlignCentre)
     EVT_MENU(ID_FORMAT_ALIGN_RIGHT,  MyFrame::OnAlignRight)
@@ -368,6 +431,8 @@ bool MyApp::OnInit()
 
     CreateStyles();
 
+    MyRichTextCtrl::SetEnhancedDrawingHandler();
+
     // Add extra handlers (plain text is automatically added)
     wxRichTextBuffer::AddHandler(new wxRichTextXMLHandler);
     wxRichTextBuffer::AddHandler(new wxRichTextHTMLHandler);
@@ -570,6 +635,10 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
         const wxSize& size, long style)
        : wxFrame(NULL, id, title, pos, size, style)
 {
+#ifdef __WXMAC__
+    SetWindowVariant(wxWINDOW_VARIANT_SMALL);
+#endif
+    
     // set the frame icon
     SetIcon(wxICON(sample));
 
@@ -578,7 +647,7 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
 
     // the "About" item should be in the help menu
     wxMenu *helpMenu = new wxMenu;
-    helpMenu->Append(ID_About, wxT("&About...\tF1"), wxT("Show about dialog"));
+    helpMenu->Append(ID_About, wxT("&About\tF1"), wxT("Show about dialog"));
 
     fileMenu->Append(wxID_OPEN, wxT("&Open\tCtrl+O"), wxT("Open a file"));
     fileMenu->Append(wxID_SAVE, wxT("&Save\tCtrl+S"), wxT("Save a file"));
@@ -615,6 +684,10 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
     formatMenu->AppendCheckItem(ID_FORMAT_ITALIC, _("&Italic\tCtrl+I"));
     formatMenu->AppendCheckItem(ID_FORMAT_UNDERLINE, _("&Underline\tCtrl+U"));
     formatMenu->AppendSeparator();
+    formatMenu->AppendCheckItem(ID_FORMAT_STRIKETHROUGH, _("Stri&kethrough"));
+    formatMenu->AppendCheckItem(ID_FORMAT_SUPERSCRIPT, _("Superscrip&t"));
+    formatMenu->AppendCheckItem(ID_FORMAT_SUBSCRIPT, _("Subscrip&t"));
+    formatMenu->AppendSeparator();
     formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_LEFT, _("L&eft Align"));
     formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_RIGHT, _("&Right Align"));
     formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_CENTRE, _("&Centre"));
@@ -676,7 +749,21 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
     }
 #endif
 
-    wxToolBar* toolBar = CreateToolBar();
+    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
+    SetSizer(sizer);
+
+    // On Mac, don't create a 'native' wxToolBar because small bitmaps are not supported by native
+    // toolbars. On Mac, a non-native, small-bitmap toolbar doesn't show unless it is explicitly
+    // managed, hence the use of sizers. In a real application, use larger icons for the main
+    // toolbar to avoid the need for this workaround. Or, use the toolbar in a container window
+    // as part of a more complex hierarchy, and the toolbar will automatically be non-native.
+
+    wxSystemOptions::SetOption(wxT("mac.toolbar.no-native"), 1);
+
+    wxToolBar* toolBar = new wxToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
+                                       wxNO_BORDER|wxTB_FLAT|wxTB_NODIVIDER|wxTB_NOALIGN);
+
+    sizer->Add(toolBar, 0, wxEXPAND);
 
     toolBar->AddTool(wxID_OPEN, wxEmptyString, wxBitmap(open_xpm), _("Open"));
     toolBar->AddTool(wxID_SAVEAS, wxEmptyString, wxBitmap(save_xpm), _("Save"));
@@ -700,24 +787,27 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
     toolBar->AddTool(ID_FORMAT_INDENT_MORE, wxEmptyString, wxBitmap(indentmore_xpm), _("Indent More"));
     toolBar->AddSeparator();
     toolBar->AddTool(ID_FORMAT_FONT, wxEmptyString, wxBitmap(font_xpm), _("Font"));
-    toolBar->AddTool(ID_FORMAT_IMAGE, wxString("Im"), wxBitmap(font_xpm), _("Image Property"));
+    toolBar->AddSeparator();
 
-    wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, ID_RICHTEXT_STYLE_COMBO, wxDefaultPosition, wxSize(200, -1));
+    wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, ID_RICHTEXT_STYLE_COMBO, wxDefaultPosition, wxSize(160, -1), wxCB_READONLY);
     toolBar->AddControl(combo);
 
     toolBar->Realize();
 
-    wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(), wxSP_LIVE_UPDATE);
+    wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxSize(100,100), wxSP_LIVE_UPDATE);
+    sizer->Add(splitter, 1, wxEXPAND);
 
     wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
     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);
 
+    m_richTextCtrl->SetMargins(10, 10);
+
     m_richTextCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
 
     combo->SetStyleSheet(wxGetApp().GetStyleSheet());
@@ -736,6 +826,8 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
         splitter->SplitVertically(m_richTextCtrl, styleListCtrl, 500);
     }
 
+    Layout();
+
     splitter->UpdateSize();
 
     styleListCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
@@ -748,14 +840,14 @@ 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());
 
-    r.BeginSuppressUndo();
-
     r.Freeze();
 
+    r.BeginSuppressUndo();
+
     r.BeginParagraphSpacing(0, 20);
 
     r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
@@ -787,11 +879,12 @@ void MyFrame::WriteInitialText()
     imageAttr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_LEFT);
     r.WriteText(wxString(wxT("This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side. This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side. This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side.")));
     r.WriteImage(wxBitmap(zebra_xpm), wxBITMAP_TYPE_PNG, imageAttr);
+
     imageAttr.GetTextBoxAttr().GetTop().SetValue(200);
     imageAttr.GetTextBoxAttr().GetTop().SetUnits(wxTEXT_ATTR_UNITS_PIXELS);
     imageAttr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_RIGHT);
     r.WriteImage(wxBitmap(zebra_xpm), wxBITMAP_TYPE_PNG, imageAttr);
-    r.WriteText(wxString(wxT("This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side. This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side. This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side.")));
+    r.WriteText(wxString(wxT("This is a simple test for a floating right image test. The zebra image should be placed at the right side of the current buffer and all the text should flow around it at the left side. This is a simple test for a floating left image test. The zebra image should be placed at the right side of the current buffer and all the text should flow around it at the left side. This is a simple test for a floating left image test. The zebra image should be placed at the right side of the current buffer and all the text should flow around it at the left side.")));
     r.EndAlignment();
     r.Newline();
 
@@ -949,10 +1042,89 @@ void MyFrame::WriteInitialText()
     r.WriteText(wxT("Note: this sample content was generated programmatically from within the MyFrame constructor in the demo. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!\n"));
 
     r.EndParagraphSpacing();
+#if 1
 
-    r.Thaw();
+    {
+        // Add a text box
+
+        r.Newline();
+
+        wxRichTextAttr attr;
+        attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
+
+        attr.GetTextBoxAttr().GetBorder().SetColour(*wxBLACK);
+        attr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
+
+        wxRichTextBox* textBox = r.WriteTextBox(attr);
+        r.SetFocusObject(textBox);
+
+        r.WriteText(wxT("This is a text box. Just testing! Once more unto the breach, dear friends, once more..."));
+
+        r.SetFocusObject(NULL); // Set the focus back to the main buffer
+        r.SetInsertionPointEnd();
+    }
+#endif
+#if 1
+    {
+        // Add a table
+
+        r.Newline();
+
+        wxRichTextAttr attr;
+        attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetPadding() = attr.GetTextBoxAttr().GetMargins();
+
+        attr.GetTextBoxAttr().GetBorder().SetColour(*wxBLACK);
+        attr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
+        attr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
+
+        wxRichTextAttr cellAttr = attr;
+        cellAttr.GetTextBoxAttr().GetWidth().SetValue(200, wxTEXT_ATTR_UNITS_PIXELS);
+        cellAttr.GetTextBoxAttr().GetHeight().SetValue(150, wxTEXT_ATTR_UNITS_PIXELS);
+
+        wxRichTextTable* table = r.WriteTable(3, 2, attr, cellAttr);
+        int i, j;
+        for (j = 0; j < table->GetRowCount(); j++)
+        {
+            for (i = 0; i < table->GetColumnCount(); i++)
+            {
+                wxString msg = wxString::Format(wxT("This is cell %d, %d"), (j+1), (i+1));
+                r.SetFocusObject(table->GetCell(j, i));
+                r.WriteText(msg);
+            }
+        }
+        r.SetFocusObject(NULL); // Set the focus back to the main buffer
+        r.SetInsertionPointEnd();
+    }
+#endif
 
     r.EndSuppressUndo();
+
+    // 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.Thaw();
 }
 
 // event handlers
@@ -1071,7 +1243,14 @@ void MyFrame::OnSaveAs(wxCommandEvent& WXUNUSED(event))
 
         if (!path.empty())
         {
+            wxBusyCursor busy;
+            wxStopWatch stopwatch;
+
             m_richTextCtrl->SaveFile(path);
+
+            long t = stopwatch.Time();
+            wxLogDebug(wxT("Saving took %ldms"), t);
+            wxMessageBox(wxString::Format(wxT("Saving took %ldms"), t));
         }
     }
 }
@@ -1091,6 +1270,21 @@ void MyFrame::OnUnderline(wxCommandEvent& WXUNUSED(event))
     m_richTextCtrl->ApplyUnderlineToSelection();
 }
 
+void MyFrame::OnStrikethrough(wxCommandEvent& WXUNUSED(event))
+{
+    m_richTextCtrl->ApplyTextEffectToSelection(wxTEXT_ATTR_EFFECT_STRIKETHROUGH);
+}
+
+void MyFrame::OnSuperscript(wxCommandEvent& WXUNUSED(event))
+{
+    m_richTextCtrl->ApplyTextEffectToSelection(wxTEXT_ATTR_EFFECT_SUPERSCRIPT);
+}
+
+void MyFrame::OnSubscript(wxCommandEvent& WXUNUSED(event))
+{
+    m_richTextCtrl->ApplyTextEffectToSelection(wxTEXT_ATTR_EFFECT_SUBSCRIPT);
+}
+
 
 void MyFrame::OnUpdateBold(wxUpdateUIEvent& event)
 {
@@ -1107,6 +1301,21 @@ void MyFrame::OnUpdateUnderline(wxUpdateUIEvent& event)
     event.Check(m_richTextCtrl->IsSelectionUnderlined());
 }
 
+void MyFrame::OnUpdateStrikethrough(wxUpdateUIEvent& event)
+{
+    event.Check(m_richTextCtrl->DoesSelectionHaveTextEffectFlag(wxTEXT_ATTR_EFFECT_STRIKETHROUGH));
+}
+
+void MyFrame::OnUpdateSuperscript(wxUpdateUIEvent& event)
+{
+    event.Check(m_richTextCtrl->DoesSelectionHaveTextEffectFlag(wxTEXT_ATTR_EFFECT_SUPERSCRIPT));
+}
+
+void MyFrame::OnUpdateSubscript(wxUpdateUIEvent& event)
+{
+    event.Check(m_richTextCtrl->DoesSelectionHaveTextEffectFlag(wxTEXT_ATTR_EFFECT_SUBSCRIPT));
+}
+
 void MyFrame::OnAlignLeft(wxCommandEvent& WXUNUSED(event))
 {
     m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_LEFT);
@@ -1175,7 +1384,7 @@ void MyFrame::OnFont(wxCommandEvent& WXUNUSED(event))
         fontData = dialog.GetFontData();
         attr.SetFlags(wxTEXT_ATTR_FONT);
         attr.SetFont(fontData.GetChosenFont());
-        if (attr.GetFont().Ok())
+        if (attr.GetFont().IsOk())
         {
             m_richTextCtrl->SetStyle(range, attr);
         }
@@ -1191,15 +1400,14 @@ void MyFrame::OnImage(wxCommandEvent& WXUNUSED(event))
     range = m_richTextCtrl->GetSelectionRange();
     wxASSERT(range.ToInternal().GetLength() == 1);
 
-    wxRichTextImage* image = wxDynamicCast(m_richTextCtrl->GetBuffer().GetLeafObjectAtPosition(range.GetStart()), wxRichTextImage);
+    wxRichTextImage* image = wxDynamicCast(m_richTextCtrl->GetFocusObject()->GetLeafObjectAtPosition(range.GetStart()), wxRichTextImage);
     if (image)
     {
-        wxRichTextImageDialog imageDlg(this);
-        imageDlg.SetImageObject(image, &m_richTextCtrl->GetBuffer());
+        wxRichTextObjectPropertiesDialog imageDlg(image, this);
 
         if (imageDlg.ShowModal() == wxID_OK)
         {
-            image = imageDlg.ApplyImageAttr();
+            imageDlg.ApplyStyle(m_richTextCtrl);
         }
     }
 }
@@ -1255,7 +1463,7 @@ void MyFrame::OnUpdateImage(wxUpdateUIEvent& event)
     range = m_richTextCtrl->GetSelectionRange();
     if (range.ToInternal().GetLength() == 1)
     {
-        obj = m_richTextCtrl->GetBuffer().GetLeafObjectAtPosition(range.GetStart());
+        obj = m_richTextCtrl->GetFocusObject()->GetLeafObjectAtPosition(range.GetStart());
         if (obj && obj->IsKindOf(CLASSINFO(wxRichTextImage)))
         {
             event.Enable(true);
@@ -1517,7 +1725,7 @@ void MyFrame::OnInsertSymbol(wxCommandEvent& WXUNUSED(event))
     m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr);
 
     wxString currentFontName;
-    if (attr.HasFont() && attr.GetFont().Ok())
+    if (attr.HasFont() && attr.GetFont().IsOk())
         currentFontName = attr.GetFont().GetFaceName();
 
     // Don't set the initial font in the dialog (so the user is choosing
@@ -1671,15 +1879,119 @@ void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
     wxPanel* panel = new wxPanel(nb, wxID_ANY, wxDefaultPosition, wxDefaultSize);
     wxPanel* panel2 = new wxPanel(nb, wxID_ANY, wxDefaultPosition, wxDefaultSize);
 
-    wxRichTextCtrl* richTextCtrl = new wxRichTextCtrl(panel, wxID_ANY, wxEmptyString, wxPoint(5, 5), wxSize(200, 150), wxVSCROLL|wxTE_READONLY);
+    new wxRichTextCtrl(panel, wxID_ANY, wxEmptyString, wxPoint(5, 5), wxSize(200, 150), wxVSCROLL|wxTE_READONLY);
     nb->AddPage(panel, wxT("Page 1"));
 
-    wxRichTextCtrl* richTextCtrl2 = new wxRichTextCtrl(panel2, wxID_ANY, wxEmptyString, wxPoint(5, 5), wxSize(200, 150), wxVSCROLL|wxTE_READONLY);
+    new wxRichTextCtrl(panel2, wxID_ANY, wxEmptyString, wxPoint(5, 5), wxSize(200, 150), wxVSCROLL|wxTE_READONLY);
     nb->AddPage(panel2, wxT("Page 2"));
 
-    wxButton* button = new wxButton(& dialog, wxID_OK, wxT("OK"), wxPoint(5, 180));
+    new wxButton(& dialog, wxID_OK, wxT("OK"), wxPoint(5, 180));
 
     dialog.ShowModal();
 
 //    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);
+}