]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
GetSocketManager() has no GUI-specific version under Darwin finally
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 9a96b42105532bb88c76685e8dd820d6194d6979..7d61b5e8a6e8085561f77b7b422b63faadd5745c 100644 (file)
@@ -309,7 +309,8 @@ int wxRichTextCompositeObject::HitTest(wxDC& dc, const wxPoint& pt, long& textPo
         node = node->GetNext();
     }
 
-    return wxRICHTEXT_HITTEST_NONE;
+    textPosition = GetRange().GetEnd()-1;
+    return wxRICHTEXT_HITTEST_AFTER|wxRICHTEXT_HITTEST_OUTSIDE;
 }
 
 /// Finds the absolute position and row height for the given character position
@@ -959,7 +960,17 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraph(const wxString& text,
     wxTextAttr defaultCharStyle;
     wxTextAttr defaultParaStyle;
 
-    wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+    // If the default style is a named paragraph style, don't apply any character formatting
+    // to the initial text string.
+    if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+    {
+        wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+        if (def)
+            defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+    }
+    else
+        wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
     wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
     wxTextAttr* cStyle = & defaultCharStyle;
 
@@ -982,7 +993,17 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
 
     wxTextAttr defaultCharStyle;
     wxTextAttr defaultParaStyle;
-    wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
+    // If the default style is a named paragraph style, don't apply any character formatting
+    // to the initial text string.
+    if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+    {
+        wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+        if (def)
+            defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+    }
+    else
+        wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
 
     wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
     wxTextAttr* cStyle = & defaultCharStyle;
@@ -1048,7 +1069,17 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddImage(const wxImage& image, wxT
 
     wxTextAttr defaultCharStyle;
     wxTextAttr defaultParaStyle;
-    wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
+    // If the default style is a named paragraph style, don't apply any character formatting
+    // to the initial text string.
+    if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+    {
+        wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+        if (def)
+            defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+    }
+    else
+        wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
 
     wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
     wxTextAttr* cStyle = & defaultCharStyle;
@@ -1145,7 +1176,8 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextParag
             wxRichTextParagraph* firstPara = wxDynamicCast(firstParaNode->GetData(), wxRichTextParagraph);
             wxASSERT(firstPara != NULL);
 
-            para->SetAttributes(firstPara->GetAttributes());
+            if (!(fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE))
+                para->SetAttributes(firstPara->GetAttributes());
 
             // Save empty paragraph attributes for appending later
             // These are character attributes deliberately set for a new paragraph. Without this,
@@ -1159,13 +1191,10 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextParag
 
             while (objectNode)
             {
-                if (!objectNode->GetData()->IsEmpty())
-                {
-                    wxRichTextObject* newObj = objectNode->GetData()->Clone();
+                wxRichTextObject* newObj = objectNode->GetData()->Clone();
 
-                    // Append
-                    para->AppendChild(newObj);
-                }
+                // Append
+                para->AppendChild(newObj);
 
                 objectNode = objectNode->GetNext();
             }
@@ -1212,7 +1241,8 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextParag
             // 4. Add back the remaining content.
             if (finalPara)
             {
-                finalPara->MoveFromList(savedObjects);
+                if (nextObject)
+                    finalPara->MoveFromList(savedObjects);
 
                 // Ensure there's at least one object
                 if (finalPara->GetChildCount() == 0)
@@ -1224,7 +1254,9 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextParag
                 }
             }
 
-            if (finalPara && finalPara != para)
+            if ((fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE) && firstPara)
+                finalPara->SetAttributes(firstPara->GetAttributes());
+            else if (finalPara && finalPara != para)
                 finalPara->SetAttributes(originalAttr);
 
             return true;
@@ -1426,6 +1458,7 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
             obj->DeleteRange(range);
 
             wxRichTextRange thisRange = obj->GetRange();
+            wxTextAttrEx thisAttr = obj->GetAttributes();
 
             // If the whole paragraph is within the range to delete,
             // delete the whole thing.
@@ -1459,7 +1492,14 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
 
                 wxTextAttrEx nextParaAttr;
                 if (applyFinalParagraphStyle)
-                    nextParaAttr = nextParagraph->GetAttributes();
+                {
+                    // Special case when deleting the end of a paragraph - use _this_ paragraph's style,
+                    // not the next one.
+                    if (range.GetStart() == range.GetEnd() && range.GetStart() == thisRange.GetEnd())
+                        nextParaAttr = thisAttr;
+                    else
+                        nextParaAttr = nextParagraph->GetAttributes();
+                }
 
                 if (firstPara && nextParagraph && firstPara != nextParagraph)
                 {
@@ -1470,15 +1510,7 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
                     {
                         wxRichTextObject* obj1 = node1->GetData();
 
-                        // If the object is empty, optimise it out
-                        if (obj1->IsEmpty())
-                        {
-                            delete obj1;
-                        }
-                        else
-                        {
-                            firstPara->AppendChild(obj1);
-                        }
+                        firstPara->AppendChild(obj1);
 
                         wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext();
                         nextParagraph->GetChildren().Erase(node1);
@@ -1490,6 +1522,13 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
                     RemoveChild(nextParagraph, true);
                 }
 
+                // Avoid empty paragraphs
+                if (firstPara && firstPara->GetChildren().GetCount() == 0)
+                {
+                    wxRichTextPlainText* text = new wxRichTextPlainText(wxEmptyString);
+                    firstPara->AppendChild(text);
+                }
+
                 if (applyFinalParagraphStyle)
                     firstPara->SetAttributes(nextParaAttr);
 
@@ -1769,7 +1808,7 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
                         splitPoint ++;
 
                     // Find last object
-                    if (splitPoint == newPara->GetRange().GetEnd() || splitPoint == (newPara->GetRange().GetEnd() - 1))
+                    if (splitPoint == newPara->GetRange().GetEnd())
                         lastObject = newPara->GetChildren().GetLast()->GetData();
                     else
                         // lastObject is set as a side-effect of splitting. It's
@@ -3727,7 +3766,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
         wxSize lineSize = line->GetSize();
         wxRichTextRange lineRange = line->GetAbsoluteRange();
 
-        if (pt.y >= linePos.y && pt.y <= linePos.y + lineSize.y)
+        if (pt.y <= linePos.y + lineSize.y)
         {
             if (pt.x < linePos.x)
             {
@@ -4272,22 +4311,50 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
     wxString str = m_text;
     wxString toRemove = wxRichTextLineBreakChar;
     str.Replace(toRemove, wxT(" "));
+    if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
+        str.MakeUpper();
 
     long len = range.GetLength();
     wxString stringChunk = str.Mid(range.GetStart() - offset, (size_t) len);
-    if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
-        stringChunk.MakeUpper();
-
-    int charHeight = dc.GetCharHeight();
-
-    int x = rect.x;
-    int y = rect.y + (rect.height - charHeight - (descent - m_descent));
 
     // Test for the optimized situations where all is selected, or none
     // is selected.
 
-    wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
-    wxCheckSetFont(dc, font);
+    wxFont textFont(GetBuffer()->GetFontTable().FindFont(textAttr));
+    wxCheckSetFont(dc, textFont);
+    int charHeight = dc.GetCharHeight();
+
+    int x, y;
+    if ( textFont.Ok() )
+    {
+        if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT) )
+        {
+            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+            textFont.SetPointSize( static_cast<int>(size) );
+            x = rect.x;
+            y = rect.y;
+            wxCheckSetFont(dc, textFont);
+        }
+        else if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) )
+        {
+            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+            textFont.SetPointSize( static_cast<int>(size) );
+            x = rect.x;
+            int sub_height = static_cast<int>( static_cast<double>(charHeight) / wxSCRIPT_MUL_FACTOR);
+            y = rect.y + (rect.height - sub_height + (descent - m_descent));
+            wxCheckSetFont(dc, textFont);
+        }
+        else
+        {
+            x = rect.x;
+            y = rect.y + (rect.height - charHeight - (descent - m_descent));
+        }
+    }
+    else
+    {
+        x = rect.x;
+        y = rect.y + (rect.height - charHeight - (descent - m_descent));
+    }
 
     // (a) All selected.
     if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
@@ -4305,7 +4372,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
         // (c) Part selected, part not
         // Let's draw unselected chunk, selected chunk, then unselected chunk.
 
-        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
 
         // 1. Initial unselected chunk, if any, up until start of selection.
         if (selectionRange.GetStart() > range.GetStart() && selectionRange.GetStart() <= range.GetEnd())
@@ -4422,7 +4489,7 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttr& attr, con
         wxCheckSetBrush(dc, wxBrush(highlightColour));
         wxCheckSetPen(dc, wxPen(highlightColour));
         dc.SetTextForeground(highlightTextColour);
-        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
     }
     else
     {
@@ -4430,11 +4497,11 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttr& attr, con
 
         if (attr.HasFlag(wxTEXT_ATTR_BACKGROUND_COLOUR) && attr.GetBackgroundColour().IsOk())
         {
-            dc.SetBackgroundMode(wxSOLID);
+            dc.SetBackgroundMode(wxBRUSHSTYLE_SOLID);
             dc.SetTextBackground(attr.GetBackgroundColour());
         }
         else
-            dc.SetBackgroundMode(wxTRANSPARENT);
+            dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
     }
 
     while (hasTabs)
@@ -4542,8 +4609,24 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
     // of line breaks - and we don't need it, since we'll calculate size within
     // formatted text by doing it in chunks according to the line ranges
 
+    bool bScript(false);
     wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
-    wxCheckSetFont(dc, font);
+    if (font.Ok())
+    {
+        if ( textAttr.HasTextEffects() && ( (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT)
+            || (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) ) )
+        {
+            wxFont textFont = font;
+            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+            textFont.SetPointSize( static_cast<int>(size) );
+            wxCheckSetFont(dc, textFont);
+            bScript = true;
+        }
+        else
+        {
+            wxCheckSetFont(dc, font);
+        }
+    }
 
     int startPos = range.GetStart() - GetRange().GetStart();
     long len = range.GetLength();
@@ -4611,8 +4694,13 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
             }
         }
     }
+
     dc.GetTextExtent(stringChunk, & w, & h, & descent);
     width += w;
+
+    if ( bScript )
+        dc.SetFont(font);
+
     size = wxSize(width, dc.GetCharHeight());
 
     return true;
@@ -4903,17 +4991,47 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl, int
     action->GetNewParagraphs().AppendChild(newPara);
     action->GetNewParagraphs().UpdateRanges();
     action->GetNewParagraphs().SetPartialParagraph(false);
-    action->SetPosition(pos);
+    wxRichTextParagraph* para = GetParagraphAtPosition(pos, false);
+    long pos1 = pos;
 
     if (p)
         newPara->SetAttributes(*p);
 
+    if (flags & wxRICHTEXT_INSERT_INTERACTIVE)
+    {
+        if (para && para->GetRange().GetEnd() == pos)
+            pos1 ++;
+        if (newPara->GetAttributes().HasBulletNumber())
+            newPara->GetAttributes().SetBulletNumber(newPara->GetAttributes().GetBulletNumber()+1);
+    }
+
+    action->SetPosition(pos);
+
+    // Use the default character style
     // Use the default character style
     if (!GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
-        newPara->GetChildren().GetFirst()->GetData()->SetAttributes(GetDefaultStyle());
+    {
+        // Check whether the default style merely reflects the paragraph/basic style,
+        // in which case don't apply it.
+        wxTextAttrEx defaultStyle(GetDefaultStyle());
+        wxTextAttrEx toApply;
+        if (para)
+        {
+            wxRichTextAttr combinedAttr = para->GetCombinedAttributes();
+            wxTextAttrEx newAttr;
+            // This filters out attributes that are accounted for by the current
+            // paragraph/basic style
+            wxRichTextApplyStyle(toApply, defaultStyle, & combinedAttr);
+        }
+        else
+            toApply = defaultStyle;
+
+        if (!toApply.IsDefault())
+            newPara->GetChildren().GetFirst()->GetData()->SetAttributes(toApply);
+    }
 
     // Set the range we'll need to delete in Undo
-    action->SetRange(wxRichTextRange(pos, pos));
+    action->SetRange(wxRichTextRange(pos1, pos1));
 
     SubmitAction(action);
 
@@ -5032,22 +5150,18 @@ bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange& range, wxRichT
     // Copy the fragment that we'll need to restore in Undo
     CopyFragment(range, action->GetOldParagraphs());
 
-    // Special case: if there is only one (non-partial) paragraph,
-    // we must save the *next* paragraph's style, because that
-    // is the style we must apply when inserting the content back
-    // when undoing the delete. (This is because we're merging the
-    // paragraph with the previous paragraph and throwing away
-    // the style, and we need to restore it.)
-    if (!action->GetOldParagraphs().GetPartialParagraph() && action->GetOldParagraphs().GetChildCount() == 1)
+    // See if we're deleting a paragraph marker, in which case we need to
+    // make a note not to copy the attributes from the 2nd paragraph to the 1st.
+    if (range.GetStart() == range.GetEnd())
     {
-        wxRichTextParagraph* lastPara = GetParagraphAtPosition(range.GetStart());
-        if (lastPara)
+        wxRichTextParagraph* para = GetParagraphAtPosition(range.GetStart());
+        if (para && para->GetRange().GetEnd() == range.GetEnd())
         {
-            wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetEnd()+1);
-            if (nextPara)
+            wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetStart()+1);
+            if (nextPara && nextPara != para)
             {
-                wxRichTextParagraph* para = (wxRichTextParagraph*) action->GetOldParagraphs().GetChild(0);
-                para->SetAttributes(nextPara->GetAttributes());
+                action->GetOldParagraphs().GetChildren().GetFirst()->GetData()->SetAttributes(nextPara->GetAttributes());
+                action->GetOldParagraphs().GetAttributes().SetFlags(action->GetOldParagraphs().GetAttributes().GetFlags() | wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE);
             }
         }
     }
@@ -5065,7 +5179,7 @@ bool wxRichTextBuffer::BeginBatchUndo(const wxString& cmdName)
         wxASSERT(m_batchedCommand == NULL);
         if (m_batchedCommand)
         {
-            GetCommandProcessor()->Submit(m_batchedCommand);
+            GetCommandProcessor()->Store(m_batchedCommand);
         }
         m_batchedCommand = new wxRichTextCommand(cmdName);
     }
@@ -5085,7 +5199,7 @@ bool wxRichTextBuffer::EndBatchUndo()
 
     if (m_batchedCommandDepth == 0)
     {
-        GetCommandProcessor()->Submit(m_batchedCommand);
+        GetCommandProcessor()->Store(m_batchedCommand);
         m_batchedCommand = NULL;
     }
 
@@ -5096,7 +5210,15 @@ bool wxRichTextBuffer::EndBatchUndo()
 bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
 {
     if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
+    {
+        wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
+        cmd->AddAction(action);
+        cmd->Do();
+        cmd->GetActions().Clear();
+        delete cmd;
+
         m_batchedCommand->AddAction(action);
+    }
     else
     {
         wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
@@ -5662,6 +5784,8 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
                 if (richTextBuffer)
                 {
                     InsertParagraphsWithUndo(position+1, *richTextBuffer, GetRichTextCtrl(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+                    if (GetRichTextCtrl())
+                        GetRichTextCtrl()->ShowPosition(position + richTextBuffer->GetRange().GetEnd());
                     delete richTextBuffer;
                 }
             }
@@ -5685,6 +5809,9 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
 #endif
                 InsertTextWithUndo(position+1, text2, GetRichTextCtrl());
 
+                if (GetRichTextCtrl())
+                    GetRichTextCtrl()->ShowPosition(position + text2.Length());
+
                 success = true;
             }
             else if (wxTheClipboard->IsSupported(wxDF_BITMAP))
@@ -5941,7 +6068,7 @@ bool wxRichTextStdRenderer::DrawTextBullet(wxRichTextParagraph* paragraph, wxDC&
         if (attr.GetTextColour().Ok())
             dc.SetTextForeground(attr.GetTextColour());
 
-        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
 
         int charHeight = dc.GetCharHeight();
         wxCoord tw, th;
@@ -6129,7 +6256,7 @@ bool wxRichTextAction::Do()
                 wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
                 int lastY = firstVisiblePt.y + clientSize.y;
 
-                wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetPosition());
+                wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetRange().GetStart());
                 wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
                 while (node)
                 {
@@ -6162,9 +6289,9 @@ bool wxRichTextAction::Do()
             }
 #endif
 
-            m_buffer->InsertFragment(GetPosition(), m_newParagraphs);
+            m_buffer->InsertFragment(GetRange().GetStart(), m_newParagraphs);
             m_buffer->UpdateRanges();
-            m_buffer->Invalidate(GetRange());
+            m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart()-1, GetRange().GetEnd()));
 
             long newCaretPosition = GetPosition() + m_newParagraphs.GetRange().GetLength();
 
@@ -6206,7 +6333,11 @@ bool wxRichTextAction::Do()
             m_buffer->UpdateRanges();
             m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
 
-            UpdateAppearance(GetRange().GetStart()-1, true /* send update event */);
+            long caretPos = GetRange().GetStart()-1;
+            if (caretPos >= m_buffer->GetRange().GetEnd())
+                caretPos --;
+
+            UpdateAppearance(caretPos, true /* send update event */);
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,