]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextctrl.cpp
wxVariant support needs wx/icon.h earlier.
[wxWidgets.git] / src / richtext / richtextctrl.cpp
index c312aed560f796ba1f02dcdc067ad60e08dd6cf7..a795c052f79e83b89eaa62c5f690abb94a72ae83 100644 (file)
 #if wxUSE_RICHTEXT
 
 #include "wx/richtext/richtextctrl.h"
+#include "wx/richtext/richtextstyles.h"
 
 #ifndef WX_PRECOMP
+    #include "wx/wx.h"
     #include "wx/settings.h"
-    #include "wx/menu.h"
-    #include "wx/intl.h"
-    #include "wx/log.h"
-    #include "wx/stopwatch.h"
 #endif
 
 #include "wx/textfile.h"
@@ -144,10 +142,13 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va
     attributes.SetBackgroundColour(*wxWHITE);
     attributes.SetAlignment(wxTEXT_ALIGNMENT_LEFT);
     attributes.SetFlags(wxTEXT_ATTR_ALL);
-
-    SetDefaultStyle(attributes);
     SetBasicStyle(attributes);
 
+    // The default attributes will be merged with base attributes, so
+    // can be empty to begin with
+    wxTextAttrEx defaultAttributes;
+    SetDefaultStyle(defaultAttributes);
+
     SetBackgroundColour(*wxWHITE);
     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
 
@@ -186,6 +187,7 @@ void wxRichTextCtrl::Init()
     m_fullLayoutTime = 0;
     m_fullLayoutSavedPosition = 0;
     m_delayedLayoutThreshold = wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD;
+    m_caretPositionForDefaultStyle = -2;
 }
 
 /// Call Freeze to prevent refresh
@@ -212,6 +214,7 @@ void wxRichTextCtrl::Clear()
     m_buffer.Reset();
     m_buffer.SetDirty(true);
     m_caretPosition = -1;
+    m_caretPositionForDefaultStyle = -2;
     m_caretAtLineStart = false;
     m_selectionRange.SetRange(-2, -2);
 
@@ -256,7 +259,7 @@ void wxRichTextCtrl::OnPaint(wxPaintEvent& WXUNUSED(event))
             SetupScrollbars();
         }
 
-        GetBuffer().Draw(dc, GetBuffer().GetRange(), GetSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
+        GetBuffer().Draw(dc, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
     }
 
     if (GetCaret())
@@ -326,19 +329,6 @@ void wxRichTextCtrl::OnLeftClick(wxMouseEvent& event)
 
         MoveCaret(position, caretAtLineStart);
         SetDefaultStyleToCursorStyle();
-
-#if 0
-        wxWindow* p = GetParent();
-        while (p && !p->IsKindOf(CLASSINFO(wxFrame)))
-            p = p->GetParent();
-
-        wxFrame* frame = wxDynamicCast(p, wxFrame);
-        if (frame)
-        {
-            wxString msg = wxString::Format(wxT("Found position %ld"), position);
-            frame->SetStatusText(msg, 1);
-        }
-#endif
     }
 
     event.Skip();
@@ -414,6 +404,7 @@ void wxRichTextCtrl::OnRightClick(wxMouseEvent& event)
 /// Left-double-click
 void wxRichTextCtrl::OnLeftDClick(wxMouseEvent& event)
 {
+    SelectWord(GetCaretPosition()+1);
     event.Skip();
 }
 
@@ -463,7 +454,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
 
         DeleteSelectedContent(& newPos);
 
-        GetBuffer().InsertNewlineWithUndo(newPos+1, this);
+        GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
 
         wxRichTextEvent cmdEvent(
             wxEVT_COMMAND_RICHTEXT_RETURN,
@@ -542,7 +533,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
         DeleteSelectedContent(& newPos);
 
         wxString str = (wxChar) event.GetKeyCode();
-        GetBuffer().InsertTextWithUndo(newPos+1, str, this);
+        GetBuffer().InsertTextWithUndo(newPos+1, str, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
 
         EndBatchUndo();
 
@@ -1428,6 +1419,15 @@ void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
         ShowPosition(m_fullLayoutSavedPosition);
         Refresh(false);
     }
+
+    if (m_caretPositionForDefaultStyle != -2)
+    {
+        // If the caret position has changed, no longer reflect the default style
+        // in the UI.
+        if (GetCaretPosition() != m_caretPositionForDefaultStyle)
+            m_caretPositionForDefaultStyle = -2;
+    }
+
     event.Skip();
 }
 
@@ -1513,9 +1513,30 @@ bool wxRichTextCtrl::RecreateBuffer(const wxSize& size)
 // file IO functions
 // ----------------------------------------------------------------------------
 
-bool wxRichTextCtrl::LoadFile(const wxString& filename, int type)
+#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
+bool wxRichTextCtrl::LoadFile(const wxString& filename, int fileType)
+{
+    return DoLoadFile(filename, fileType);
+}
+
+bool wxRichTextCtrl::SaveFile(const wxString& filename, int fileType)
 {
-    bool success = GetBuffer().LoadFile(filename, type);
+    wxString filenameToUse = filename.empty() ? m_filename : filename;
+    if ( filenameToUse.empty() )
+    {
+        // what kind of message to give? is it an error or a program bug?
+        wxLogDebug(wxT("Can't save textctrl to file without filename."));
+
+        return false;
+    }
+
+    return DoSaveFile(filenameToUse, fileType);
+}
+#endif
+
+bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType)
+{
+    bool success = GetBuffer().LoadFile(filename, fileType);
     if (success)
         m_filename = filename;
 
@@ -1537,25 +1558,15 @@ bool wxRichTextCtrl::LoadFile(const wxString& filename, int type)
     }
 }
 
-bool wxRichTextCtrl::SaveFile(const wxString& filename, int type)
+bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType)
 {
-    wxString filenameToUse = filename.empty() ? m_filename : filename;
-    if ( filenameToUse.empty() )
-    {
-        // what kind of message to give? is it an error or a program bug?
-        wxLogDebug(wxT("Can't save textctrl to file without filename."));
-
-        return false;
-    }
-
-    if (GetBuffer().SaveFile(filenameToUse, type))
+    if (GetBuffer().SaveFile(filename, fileType))
     {
-        m_filename = filenameToUse;
+        m_filename = filename;
 
         DiscardEdits();
 
         return true;
-
     }
 
     wxLogError(_("The text couldn't be saved."));
@@ -1585,7 +1596,7 @@ wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image)
 
 void wxRichTextCtrl::SelectAll()
 {
-    SetSelection(0, GetLastPosition());
+    SetSelection(0, GetLastPosition()+1);
     m_selectionAnchor = -1;
 }
 
@@ -1597,6 +1608,60 @@ void wxRichTextCtrl::SelectNone()
     m_selectionAnchor = -2;
 }
 
+static bool wxIsWordDelimiter(const wxString& text)
+{
+    static wxString delimiters = wxT(" ,.:;!?-\"'~£$%^&*()_+-=`¬{}[]@#<>/\\|");
+    return !text.IsEmpty() && delimiters.Find(text) != wxNOT_FOUND;
+}
+
+/// Select the word at the given character position
+bool wxRichTextCtrl::SelectWord(long position)
+{
+    if (position < 0 || position > GetBuffer().GetRange().GetEnd())
+        return false;
+
+    wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(position);
+    if (!para)
+        return false;
+
+    long positionStart = position;
+    long positionEnd = position;
+
+    for (positionStart = position; positionStart >= para->GetRange().GetStart(); positionStart --)
+    {
+        wxString text = GetBuffer().GetTextForRange(wxRichTextRange(positionStart, positionStart));
+        if (wxIsWordDelimiter(text))
+        {
+            positionStart ++;
+            break;
+        }
+    }
+    if (positionStart < para->GetRange().GetStart())
+        positionStart = para->GetRange().GetStart();
+
+    for (positionEnd = position; positionEnd < para->GetRange().GetEnd(); positionEnd ++)
+    {
+        wxString text = GetBuffer().GetTextForRange(wxRichTextRange(positionEnd, positionEnd));
+        if (wxIsWordDelimiter(text))
+        {
+            positionEnd --;
+            break;
+        }
+    }
+    if (positionEnd >= para->GetRange().GetEnd())
+        positionEnd = para->GetRange().GetEnd();
+
+    SetSelection(positionStart, positionEnd+1);
+
+    if (positionStart >= 0)
+    {
+        MoveCaret(positionStart-1, true);
+        SetDefaultStyleToCursorStyle();
+    }
+
+    return true;
+}
+
 wxString wxRichTextCtrl::GetStringSelection() const
 {
     long from, to;
@@ -1681,7 +1746,8 @@ wxString wxRichTextCtrl::GetValue() const
 
 wxString wxRichTextCtrl::GetRange(long from, long to) const
 {
-    return GetBuffer().GetTextForRange(wxRichTextRange(from, to));
+    // Public API for range is different from internals
+    return GetBuffer().GetTextForRange(wxRichTextRange(from, to-1));
 }
 
 void wxRichTextCtrl::SetValue(const wxString& value)
@@ -1719,7 +1785,9 @@ void wxRichTextCtrl::WriteText(const wxString& value)
 
 void wxRichTextCtrl::DoWriteText(const wxString& value, bool WXUNUSED(selectionOnly))
 {
-    GetBuffer().InsertTextWithUndo(m_caretPosition+1, value, this);
+    wxString valueUnix = wxTextFile::Translate(value, wxTextFileType_Unix);
+
+    GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueUnix, this);
 }
 
 void wxRichTextCtrl::AppendText(const wxString& text)
@@ -1786,7 +1854,7 @@ void wxRichTextCtrl::Copy()
 {
     if (CanCopy())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         GetBuffer().CopyToClipboard(range);
     }
 }
@@ -1795,7 +1863,7 @@ void wxRichTextCtrl::Cut()
 {
     if (CanCut())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         GetBuffer().CopyToClipboard(range);
 
         DeleteSelectedContent();
@@ -1895,6 +1963,8 @@ void wxRichTextCtrl::GetSelection(long* from, long* to) const
 {
     *from = m_selectionRange.GetStart();
     *to = m_selectionRange.GetEnd();
+    if ((*to) != -1 && (*to) != -2)
+        (*to) ++;
 }
 
 bool wxRichTextCtrl::IsEditable() const
@@ -1913,7 +1983,7 @@ void wxRichTextCtrl::SetSelection(long from, long to)
     if ( (from == -1) && (to == -1) )
     {
         from = 0;
-        to = GetLastPosition();
+        to = GetLastPosition()+1;
     }
 
     DoSetSelection(from, to);
@@ -1922,7 +1992,8 @@ void wxRichTextCtrl::SetSelection(long from, long to)
 void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCaret))
 {
     m_selectionAnchor = from;
-    m_selectionRange.SetRange(from, to);
+    m_selectionRange.SetRange(from, to-1);
+
     Refresh(false);
     PositionCaret();
 }
@@ -1968,6 +2039,7 @@ void wxRichTextCtrl::MarkDirty()
 
 void wxRichTextCtrl::DiscardEdits()
 {
+    m_caretPositionForDefaultStyle = -2;
     m_buffer.Modify(false);
     m_buffer.GetCommandProcessor()->ClearCommands();
 }
@@ -2195,17 +2267,17 @@ void wxRichTextCtrl::OnContextMenu(wxContextMenuEvent& WXUNUSED(event))
 
 bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttrEx& style)
 {
-    return GetBuffer().SetStyle(wxRichTextRange(start, end), style);
+    return GetBuffer().SetStyle(wxRichTextRange(start, end-1), style);
 }
 
 bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
 {
-    return GetBuffer().SetStyle(wxRichTextRange(start, end), wxTextAttrEx(style));
+    return GetBuffer().SetStyle(wxRichTextRange(start, end-1), wxTextAttrEx(style));
 }
 
 bool wxRichTextCtrl::SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style)
 {
-    return GetBuffer().SetStyle(range, style);
+    return GetBuffer().SetStyle(range.ToInternal(), style);
 }
 
 bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttrEx& style)
@@ -2228,9 +2300,9 @@ const wxTextAttr& wxRichTextCtrl::GetDefaultStyle() const
     return GetBuffer().GetDefaultStyle();
 }
 
-bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style) const
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style)
 {
-    wxTextAttrEx attr;
+    wxTextAttrEx attr(style);
     if (GetBuffer().GetStyle(position, attr))
     {
         style = attr;
@@ -2240,16 +2312,40 @@ bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style) const
         return false;
 }
 
-bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style) const
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style)
 {
     return GetBuffer().GetStyle(position, style);
 }
 
-bool wxRichTextCtrl::GetStyle(long position, wxRichTextAttr& style) const
+bool wxRichTextCtrl::GetStyle(long position, wxRichTextAttr& style)
 {
     return GetBuffer().GetStyle(position, style);
 }
 
+/// Get the content (uncombined) attributes for this position.
+
+bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttr& style)
+{
+    wxTextAttrEx attr(style);
+    if (GetBuffer().GetUncombinedStyle(position, attr))
+    {
+        style = attr;
+        return true;
+    }
+    else
+        return false;
+}
+
+bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttrEx& style)
+{
+    return GetBuffer().GetUncombinedStyle(position, style);
+}
+
+bool wxRichTextCtrl::GetUncombinedStyle(long position, wxRichTextAttr& style)
+{
+    return GetBuffer().GetUncombinedStyle(position, style);
+}
+
 /// Set font, and also the buffer attributes
 bool wxRichTextCtrl::SetFont(const wxFont& font)
 {
@@ -2262,7 +2358,15 @@ bool wxRichTextCtrl::SetFont(const wxFont& font)
     wxTextAttrEx attr = GetBuffer().GetAttributes();
     attr.SetFont(font);
     GetBuffer().SetBasicStyle(attr);
+
+#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
+    // Don't set the default style, since it will be inherited from
+    // the basic style.
     GetBuffer().SetDefaultStyle(attr);
+#endif
+
+    GetBuffer().Invalidate(wxRICHTEXT_ALL);
+    Refresh(false);
 
     return true;
 }
@@ -2403,12 +2507,12 @@ bool wxRichTextCtrl::LayoutContent(bool onlyVisibleRect)
 }
 
 /// Is all of the selection bold?
-bool wxRichTextCtrl::IsSelectionBold() const
+bool wxRichTextCtrl::IsSelectionBold()
 {
     if (HasSelection())
     {
         wxRichTextAttr attr;
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
         attr.SetFontWeight(wxBOLD);
 
@@ -2420,9 +2524,12 @@ bool wxRichTextCtrl::IsSelectionBold() const
         // to see what the effect would be if we started typing.
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
-        if (GetStyle(GetCaretPosition()+1, attr))
+
+        long pos = GetAdjustedCaretPosition(GetCaretPosition());
+        if (GetStyle(pos, attr))
         {
-            wxRichTextApplyStyle(attr, GetDefaultStyleEx());
+            if (IsDefaultStyleShowing())
+                wxRichTextApplyStyle(attr, GetDefaultStyleEx());
             return attr.GetFontWeight() == wxBOLD;
         }
     }
@@ -2430,11 +2537,11 @@ bool wxRichTextCtrl::IsSelectionBold() const
 }
 
 /// Is all of the selection italics?
-bool wxRichTextCtrl::IsSelectionItalics() const
+bool wxRichTextCtrl::IsSelectionItalics()
 {
     if (HasSelection())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
         attr.SetFontStyle(wxITALIC);
@@ -2447,9 +2554,12 @@ bool wxRichTextCtrl::IsSelectionItalics() const
         // to see what the effect would be if we started typing.
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
-        if (GetStyle(GetCaretPosition()+1, attr))
+
+        long pos = GetAdjustedCaretPosition(GetCaretPosition());
+        if (GetStyle(pos, attr))
         {
-            wxRichTextApplyStyle(attr, GetDefaultStyleEx());
+            if (IsDefaultStyleShowing())
+                wxRichTextApplyStyle(attr, GetDefaultStyleEx());
             return attr.GetFontStyle() == wxITALIC;
         }
     }
@@ -2457,11 +2567,11 @@ bool wxRichTextCtrl::IsSelectionItalics() const
 }
 
 /// Is all of the selection underlined?
-bool wxRichTextCtrl::IsSelectionUnderlined() const
+bool wxRichTextCtrl::IsSelectionUnderlined()
 {
     if (HasSelection())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
         attr.SetFontUnderlined(true);
@@ -2474,9 +2584,12 @@ bool wxRichTextCtrl::IsSelectionUnderlined() const
         // to see what the effect would be if we started typing.
         wxRichTextAttr attr;
         attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
-        if (GetStyle(GetCaretPosition()+1, attr))
+        long pos = GetAdjustedCaretPosition(GetCaretPosition());
+
+        if (GetStyle(pos, attr))
         {
-            wxRichTextApplyStyle(attr, GetDefaultStyleEx());
+            if (IsDefaultStyleShowing())
+                wxRichTextApplyStyle(attr, GetDefaultStyleEx());
             return attr.GetFontUnderlined();
         }
     }
@@ -2493,7 +2606,7 @@ bool wxRichTextCtrl::ApplyBoldToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2507,7 +2620,7 @@ bool wxRichTextCtrl::ApplyItalicToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2521,29 +2634,23 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
 /// Is all of the selection aligned according to the specified flag?
-bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment) const
+bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment)
 {
+    wxRichTextRange range;
     if (HasSelection())
-    {
-        wxRichTextRange range = GetSelectionRange();
-        wxRichTextAttr attr;
-        attr.SetAlignment(alignment);
-
-        return HasParagraphAttributes(range, attr);
-    }
+        range = GetInternalSelectionRange();
     else
-    {
-        // If no selection, then we need to get information from the current paragraph.
-        wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(GetCaretPosition()+1);
-        if (para)
-            return para->GetAttributes().GetAlignment() == alignment;
-    }
-    return false;
+        range = wxRichTextRange(GetCaretPosition()+1, GetCaretPosition()+1);
+
+    wxRichTextAttr attr;
+    attr.SetAlignment(alignment);
+
+    return HasParagraphAttributes(range, attr);
 }
 
 /// Apply alignment to the selection
@@ -2557,18 +2664,62 @@ bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment)
     {
         wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(GetCaretPosition()+1);
         if (para)
-            return SetStyle(para->GetRange(), attr);
+            return SetStyle(para->GetRange().FromInternal(), attr);
     }
     return true;
 }
 
+/// Apply a named style to the selection
+void wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def)
+{
+    // Flags are defined within each definition, so only certain
+    // attributes are applied.
+    wxRichTextAttr attr(def->GetStyle());
+
+    // Make sure the attr has the style name
+    if (def->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition)))
+        attr.SetParagraphStyleName(def->GetName());
+    else
+        attr.SetCharacterStyleName(def->GetName());
+
+    if (HasSelection())
+        SetStyle(GetSelectionRange(), attr);
+    else
+        SetAndShowDefaultStyle(attr);
+}
+
+/// Apply the style sheet to the buffer, for example if the styles have changed.
+bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet* styleSheet)
+{
+    if (!styleSheet)
+        styleSheet = GetBuffer().GetStyleSheet();
+    if (!styleSheet)
+        return false;
+
+    if (GetBuffer().ApplyStyleSheet(styleSheet))
+    {
+        GetBuffer().Invalidate(wxRICHTEXT_ALL);
+        Refresh(false);
+        return true;
+    }
+    else
+        return false;
+}
+
 /// Sets the default style to the style under the cursor
 bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
 {
     wxTextAttrEx attr;
     attr.SetFlags(wxTEXT_ATTR_CHARACTER);
 
-    if (GetStyle(GetCaretPosition(), attr))
+    // If at the start of a paragraph, use the next position.
+    long pos = GetAdjustedCaretPosition(GetCaretPosition());
+
+#if wxRICHTEXT_USE_DYNAMIC_STYLES
+    if (GetUncombinedStyle(pos, attr))
+#else
+    if (GetStyle(pos, attr))
+#endif
     {
         SetDefaultStyle(attr);
         return true;
@@ -2587,5 +2738,39 @@ long wxRichTextCtrl::GetFirstVisiblePosition() const
         return 0;
 }
 
+/// The adjusted caret position is the character position adjusted to take
+/// into account whether we're at the start of a paragraph, in which case
+/// style information should be taken from the next position, not current one.
+long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos) const
+{
+    wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(caretPos+1);
+
+    if (para && (caretPos+1 == para->GetRange().GetStart()))
+        caretPos ++;
+    return caretPos;
+}
+
+/// Get/set the selection range in character positions. -1, -1 means no selection.
+/// The range is in API convention, i.e. a single character selection is denoted
+/// by (n, n+1)
+wxRichTextRange wxRichTextCtrl::GetSelectionRange() const
+{
+    wxRichTextRange range = GetInternalSelectionRange();
+    if (range != wxRichTextRange(-2,-2) && range != wxRichTextRange(-1,-1))
+        range.SetEnd(range.GetEnd() + 1);
+    return range;
+}
+
+void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange& range)
+{
+    wxRichTextRange range1(range);
+    if (range1 != wxRichTextRange(-2,-2) && range1 != wxRichTextRange(-1,-1) )
+        range1.SetEnd(range1.GetEnd() - 1);
+
+    wxASSERT( range1.GetStart() > range1.GetEnd() );
+
+    SetInternalSelectionRange(range1);
+}
+
 #endif
     // wxUSE_RICHTEXT