]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextctrl.cpp
Typo.
[wxWidgets.git] / src / richtext / richtextctrl.cpp
index 1c06c5137d203b3257de7e06dd0195398c5dc6a4..b77d1a2fc1866ee7d813af565a9293caa93ebbbd 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/stopwatch.h"
 #endif
 
 #include "wx/textfile.h"
@@ -143,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);
 
@@ -185,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
@@ -211,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);
 
@@ -255,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())
@@ -462,7 +466,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,
@@ -541,7 +545,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();
 
@@ -1427,6 +1431,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();
 }
 
@@ -1512,9 +1525,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)
 {
-    bool success = GetBuffer().LoadFile(filename, type);
+    return DoLoadFile(filename, fileType);
+}
+
+bool wxRichTextCtrl::SaveFile(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;
+    }
+
+    return DoSaveFile(filenameToUse, fileType);
+}
+#endif
+
+bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType)
+{
+    bool success = GetBuffer().LoadFile(filename, fileType);
     if (success)
         m_filename = filename;
 
@@ -1536,25 +1570,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() )
+    if (GetBuffer().SaveFile(filename, fileType))
     {
-        // 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))
-    {
-        m_filename = filenameToUse;
+        m_filename = filename;
 
         DiscardEdits();
 
         return true;
-
     }
 
     wxLogError(_("The text couldn't be saved."));
@@ -1584,7 +1608,7 @@ wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image)
 
 void wxRichTextCtrl::SelectAll()
 {
-    SetSelection(0, GetLastPosition());
+    SetSelection(0, GetLastPosition()+1);
     m_selectionAnchor = -1;
 }
 
@@ -1680,7 +1704,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)
@@ -1718,7 +1743,9 @@ void wxRichTextCtrl::WriteText(const wxString& value)
 
 void wxRichTextCtrl::DoWriteText(const wxString& value, bool WXUNUSED(selectionOnly))
 {
-    GetBuffer().InsertTextWithUndo(m_caretPosition+1, value, this);
+    wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Unix);
+
+    GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueDos, this);
 }
 
 void wxRichTextCtrl::AppendText(const wxString& text)
@@ -1785,7 +1812,7 @@ void wxRichTextCtrl::Copy()
 {
     if (CanCopy())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         GetBuffer().CopyToClipboard(range);
     }
 }
@@ -1794,7 +1821,7 @@ void wxRichTextCtrl::Cut()
 {
     if (CanCut())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         GetBuffer().CopyToClipboard(range);
 
         DeleteSelectedContent();
@@ -1894,6 +1921,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
@@ -1912,7 +1941,7 @@ void wxRichTextCtrl::SetSelection(long from, long to)
     if ( (from == -1) && (to == -1) )
     {
         from = 0;
-        to = GetLastPosition();
+        to = GetLastPosition()+1;
     }
 
     DoSetSelection(from, to);
@@ -1921,7 +1950,7 @@ 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();
 }
@@ -1967,6 +1996,7 @@ void wxRichTextCtrl::MarkDirty()
 
 void wxRichTextCtrl::DiscardEdits()
 {
+    m_caretPositionForDefaultStyle = -2;
     m_buffer.Modify(false);
     m_buffer.GetCommandProcessor()->ClearCommands();
 }
@@ -2194,17 +2224,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)
@@ -2227,9 +2257,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;
@@ -2239,16 +2269,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)
 {
@@ -2261,7 +2315,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;
 }
@@ -2402,12 +2464,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);
 
@@ -2419,9 +2481,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;
         }
     }
@@ -2429,11 +2494,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);
@@ -2446,9 +2511,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;
         }
     }
@@ -2456,11 +2524,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);
@@ -2473,9 +2541,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();
         }
     }
@@ -2492,7 +2563,7 @@ bool wxRichTextCtrl::ApplyBoldToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2506,7 +2577,7 @@ bool wxRichTextCtrl::ApplyItalicToSelection()
     if (HasSelection())
         return SetStyle(GetSelectionRange(), attr);
     else
-        SetDefaultStyle(attr);
+        SetAndShowDefaultStyle(attr);
     return true;
 }
 
@@ -2520,16 +2591,16 @@ 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)
 {
     if (HasSelection())
     {
-        wxRichTextRange range = GetSelectionRange();
+        wxRichTextRange range = GetInternalSelectionRange();
         wxRichTextAttr attr;
         attr.SetAlignment(alignment);
 
@@ -2556,18 +2627,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;
@@ -2586,5 +2701,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