+ else
+ GetBuffer().Invalidate(wxRICHTEXT_ALL);
+
+#if wxRICHTEXT_BUFFERED_PAINTING
+ RecreateBuffer();
+#endif
+
+ event.Skip();
+}
+
+// Force any pending layout due to large buffer
+void wxRichTextCtrl::ForceDelayedLayout()
+{
+ if (m_fullLayoutRequired)
+ {
+ m_fullLayoutRequired = false;
+ m_fullLayoutTime = 0;
+ GetBuffer().Invalidate(wxRICHTEXT_ALL);
+ ShowPosition(m_fullLayoutSavedPosition);
+ Refresh(false);
+ Update();
+ }
+}
+
+/// Idle-time processing
+void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
+{
+#if wxRICHTEXT_USE_OWN_CARET
+ if (((wxRichTextCaret*) GetCaret())->GetNeedsUpdate())
+ {
+ ((wxRichTextCaret*) GetCaret())->SetNeedsUpdate(false);
+ PositionCaret();
+ GetCaret()->Show();
+ }
+#endif
+
+ const int layoutInterval = wxRICHTEXT_DEFAULT_LAYOUT_INTERVAL;
+
+ if (m_fullLayoutRequired && (wxGetLocalTimeMillis() > (m_fullLayoutTime + layoutInterval)))
+ {
+ m_fullLayoutRequired = false;
+ m_fullLayoutTime = 0;
+ GetBuffer().Invalidate(wxRICHTEXT_ALL);
+ 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();
+}
+
+/// Scrolling
+void wxRichTextCtrl::OnScroll(wxScrollWinEvent& event)
+{
+#if wxRICHTEXT_USE_OWN_CARET
+ if (!((wxRichTextCaret*) GetCaret())->GetNeedsUpdate())
+ {
+ GetCaret()->Hide();
+ ((wxRichTextCaret*) GetCaret())->SetNeedsUpdate();
+ }
+#endif
+
+ event.Skip();
+}
+
+/// Set up scrollbars, e.g. after a resize
+void wxRichTextCtrl::SetupScrollbars(bool atTop)
+{
+ if (IsFrozen())
+ return;
+
+ if (GetBuffer().IsEmpty() || !m_verticalScrollbarEnabled)
+ {
+ SetScrollbars(0, 0, 0, 0, 0, 0);
+ return;
+ }
+
+ // TODO: reimplement scrolling so we scroll by line, not by fixed number
+ // of pixels. See e.g. wxVScrolledWindow for ideas.
+ int pixelsPerUnit = 5;
+ wxSize clientSize = GetClientSize();
+
+ int maxHeight = (int) (0.5 + GetScale() * (GetBuffer().GetCachedSize().y + GetBuffer().GetTopMargin()));
+
+ // Round up so we have at least maxHeight pixels
+ int unitsY = (int) (((float)maxHeight/(float)pixelsPerUnit) + 0.5);
+
+ int startX = 0, startY = 0;
+ if (!atTop)
+ GetViewStart(& startX, & startY);
+
+ int maxPositionX = 0;
+ int maxPositionY = (int) ((((float)(wxMax((unitsY*pixelsPerUnit) - clientSize.y, 0)))/((float)pixelsPerUnit)) + 0.5);
+
+ int newStartX = wxMin(maxPositionX, startX);
+ int newStartY = wxMin(maxPositionY, startY);
+
+ int oldPPUX, oldPPUY;
+ int oldStartX, oldStartY;
+ int oldVirtualSizeX = 0, oldVirtualSizeY = 0;
+ GetScrollPixelsPerUnit(& oldPPUX, & oldPPUY);
+ GetViewStart(& oldStartX, & oldStartY);
+ GetVirtualSize(& oldVirtualSizeX, & oldVirtualSizeY);
+ if (oldPPUY > 0)
+ oldVirtualSizeY /= oldPPUY;
+
+ if (oldPPUX == 0 && oldPPUY == pixelsPerUnit && oldVirtualSizeY == unitsY && oldStartX == newStartX && oldStartY == newStartY)
+ return;
+
+ // Don't set scrollbars if there were none before, and there will be none now.
+ if (oldPPUY != 0 && (oldVirtualSizeY*oldPPUY < clientSize.y) && (unitsY*pixelsPerUnit < clientSize.y))
+ return;
+
+ // Move to previous scroll position if
+ // possible
+ SetScrollbars(0, pixelsPerUnit, 0, unitsY, newStartX, newStartY);
+}
+
+/// Paint the background
+void wxRichTextCtrl::PaintBackground(wxDC& dc)
+{
+ wxColour backgroundColour = GetBackgroundColour();
+ if (!backgroundColour.IsOk())
+ backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
+
+ // Clear the background
+ dc.SetBrush(wxBrush(backgroundColour));
+ dc.SetPen(*wxTRANSPARENT_PEN);
+ wxRect windowRect(GetClientSize());
+ windowRect.x -= 2; windowRect.y -= 2;
+ windowRect.width += 4; windowRect.height += 4;
+
+ // We need to shift the rectangle to take into account
+ // scrolling. Converting device to logical coordinates.
+ CalcUnscrolledPosition(windowRect.x, windowRect.y, & windowRect.x, & windowRect.y);
+ dc.DrawRectangle(windowRect);
+}
+
+#if wxRICHTEXT_BUFFERED_PAINTING
+/// Recreate buffer bitmap if necessary
+bool wxRichTextCtrl::RecreateBuffer(const wxSize& size)
+{
+ wxSize sz = size;
+ if (sz == wxDefaultSize)
+ sz = GetClientSize();
+
+ if (sz.x < 1 || sz.y < 1)
+ return false;
+
+ if (!m_bufferBitmap.IsOk() || m_bufferBitmap.GetWidth() < sz.x || m_bufferBitmap.GetHeight() < sz.y)
+ m_bufferBitmap = wxBitmap(sz.x, sz.y);
+ return m_bufferBitmap.IsOk();
+}
+#endif
+
+// ----------------------------------------------------------------------------
+// file IO functions
+// ----------------------------------------------------------------------------
+#if wxUSE_FFILE && wxUSE_STREAMS
+bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType)
+{
+ SetFocusObject(& GetBuffer(), true);
+
+ bool success = GetBuffer().LoadFile(filename, (wxRichTextFileType)fileType);
+ if (success)
+ m_filename = filename;
+
+ DiscardEdits();
+ SetInsertionPoint(0);
+ LayoutContent();
+ PositionCaret();
+ SetupScrollbars(true);
+ Refresh(false);
+ wxTextCtrl::SendTextUpdatedEvent(this);
+
+ if (success)
+ return true;
+ else
+ {
+ wxLogError(_("File couldn't be loaded."));
+
+ return false;
+ }
+}
+
+bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType)
+{
+ if (GetBuffer().SaveFile(filename, (wxRichTextFileType)fileType))
+ {
+ m_filename = filename;
+
+ DiscardEdits();
+
+ return true;
+ }
+
+ wxLogError(_("The text couldn't be saved."));
+
+ return false;
+}
+#endif // wxUSE_FFILE && wxUSE_STREAMS
+
+// ----------------------------------------------------------------------------
+// wxRichTextCtrl specific functionality
+// ----------------------------------------------------------------------------
+
+/// Add a new paragraph of text to the end of the buffer
+wxRichTextRange wxRichTextCtrl::AddParagraph(const wxString& text)
+{
+ wxRichTextRange range = GetFocusObject()->AddParagraph(text);
+ GetBuffer().Invalidate();
+ LayoutContent();
+ return range;
+}
+
+/// Add an image
+wxRichTextRange wxRichTextCtrl::AddImage(const wxImage& image)
+{
+ wxRichTextRange range = GetFocusObject()->AddImage(image);
+ GetBuffer().Invalidate();
+ LayoutContent();
+ return range;
+}
+
+// ----------------------------------------------------------------------------
+// selection and ranges
+// ----------------------------------------------------------------------------
+
+/// Select none
+void wxRichTextCtrl::SelectNone()
+{
+ if (m_selection.IsValid())
+ {
+ wxRichTextSelection oldSelection = m_selection;
+
+ m_selection.Reset();
+
+ RefreshForSelectionChange(oldSelection, m_selection);
+ }
+ m_selectionAnchor = -2;
+ m_selectionAnchorObject = NULL;
+ m_selectionState = wxRichTextCtrlSelectionState_Normal;
+}
+
+static bool wxIsWordDelimiter(const wxString& text)
+{
+ return !text.IsEmpty() && !wxIsalnum(text[0]);
+}
+
+/// Select the word at the given character position
+bool wxRichTextCtrl::SelectWord(long position)
+{
+ if (position < 0 || position > GetFocusObject()->GetOwnRange().GetEnd())
+ return false;
+
+ wxRichTextParagraph* para = GetFocusObject()->GetParagraphAtPosition(position);
+ if (!para)
+ return false;
+
+ if (position == para->GetRange().GetEnd())
+ position --;
+
+ long positionStart = position;
+ long positionEnd = position;
+
+ for (positionStart = position; positionStart >= para->GetRange().GetStart(); positionStart --)
+ {
+ wxString text = GetFocusObject()->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 = GetFocusObject()->GetTextForRange(wxRichTextRange(positionEnd, positionEnd));
+ if (wxIsWordDelimiter(text))
+ {
+ positionEnd --;
+ break;
+ }
+ }
+ if (positionEnd >= para->GetRange().GetEnd())
+ positionEnd = para->GetRange().GetEnd();
+
+ if (positionEnd < positionStart)
+ return false;
+
+ SetSelection(positionStart, positionEnd+1);
+
+ if (positionStart >= 0)
+ {
+ MoveCaret(positionStart-1, true);
+ SetDefaultStyleToCursorStyle();
+ }
+
+ return true;
+}
+
+wxString wxRichTextCtrl::GetStringSelection() const
+{
+ long from, to;
+ GetSelection(&from, &to);
+
+ return GetRange(from, to);
+}
+
+// ----------------------------------------------------------------------------
+// hit testing
+// ----------------------------------------------------------------------------
+
+wxTextCtrlHitTestResult
+wxRichTextCtrl::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const
+{
+ // implement in terms of the other overload as the native ports typically
+ // can get the position and not (x, y) pair directly (although wxUniv
+ // directly gets x and y -- and so overrides this method as well)
+ long pos;
+ wxTextCtrlHitTestResult rc = HitTest(pt, &pos);
+
+ if ( rc != wxTE_HT_UNKNOWN )
+ {
+ PositionToXY(pos, x, y);
+ }
+
+ return rc;
+}
+
+wxTextCtrlHitTestResult
+wxRichTextCtrl::HitTest(const wxPoint& pt,
+ long * pos) const
+{
+ wxClientDC dc((wxRichTextCtrl*) this);
+ ((wxRichTextCtrl*)this)->PrepareDC(dc);
+
+ // Buffer uses logical position (relative to start of buffer)
+ // so convert
+ wxPoint pt2 = GetLogicalPoint(pt);
+
+ wxRichTextObject* hitObj = NULL;
+ wxRichTextObject* contextObj = NULL;
+ wxRichTextDrawingContext context((wxRichTextBuffer*) & GetBuffer());
+ int hit = ((wxRichTextCtrl*)this)->GetFocusObject()->HitTest(dc, context, pt2, *pos, & hitObj, & contextObj, wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS);
+
+ if ((hit & wxRICHTEXT_HITTEST_BEFORE) && (hit & wxRICHTEXT_HITTEST_OUTSIDE))
+ return wxTE_HT_BEFORE;
+ else if ((hit & wxRICHTEXT_HITTEST_AFTER) && (hit & wxRICHTEXT_HITTEST_OUTSIDE))
+ return wxTE_HT_BEYOND;
+ else if (hit & (wxRICHTEXT_HITTEST_BEFORE|wxRICHTEXT_HITTEST_AFTER))
+ return wxTE_HT_ON_TEXT;
+
+ return wxTE_HT_UNKNOWN;
+}
+
+wxRichTextParagraphLayoutBox*
+wxRichTextCtrl::FindContainerAtPoint(const wxPoint pt, long& position, int& hit, wxRichTextObject* hitObj, int flags/* = 0*/)
+{
+ wxClientDC dc(this);
+ PrepareDC(dc);
+ dc.SetFont(GetFont());
+
+ wxPoint logicalPt = GetLogicalPoint(pt);
+
+ wxRichTextObject* contextObj = NULL;
+ wxRichTextDrawingContext context(& GetBuffer());
+ hit = GetBuffer().HitTest(dc, context, GetUnscaledPoint(logicalPt), position, &hitObj, &contextObj, flags);
+ wxRichTextParagraphLayoutBox* container = wxDynamicCast(contextObj, wxRichTextParagraphLayoutBox);
+
+ return container;
+}
+
+
+// ----------------------------------------------------------------------------
+// set/get the controls text
+// ----------------------------------------------------------------------------
+
+wxString wxRichTextCtrl::DoGetValue() const
+{
+ return GetBuffer().GetText();
+}
+
+wxString wxRichTextCtrl::GetRange(long from, long to) const
+{
+ // Public API for range is different from internals
+ return GetFocusObject()->GetTextForRange(wxRichTextRange(from, to-1));
+}
+
+void wxRichTextCtrl::DoSetValue(const wxString& value, int flags)
+{
+ // Don't call Clear here, since it always sends a text updated event
+ m_buffer.ResetAndClearCommands();
+ m_buffer.Invalidate(wxRICHTEXT_ALL);
+ m_caretPosition = -1;
+ m_caretPositionForDefaultStyle = -2;
+ m_caretAtLineStart = false;
+ m_selection.Reset();
+ m_selectionState = wxRichTextCtrlSelectionState_Normal;
+
+ Scroll(0,0);
+
+ if (!IsFrozen())
+ {
+ LayoutContent();
+ Refresh(false);
+ }
+
+ if (!value.IsEmpty())
+ {
+ // Remove empty paragraph
+ GetBuffer().Clear();
+ DoWriteText(value, flags);
+
+ // for compatibility, don't move the cursor when doing SetValue()
+ SetInsertionPoint(0);
+ }
+ else
+ {
+ // still send an event for consistency
+ if (flags & SetValue_SendEvent)
+ wxTextCtrl::SendTextUpdatedEvent(this);
+ }
+ DiscardEdits();
+}
+
+void wxRichTextCtrl::WriteText(const wxString& value)
+{
+ DoWriteText(value);
+}
+
+void wxRichTextCtrl::DoWriteText(const wxString& value, int flags)
+{
+ wxString valueUnix = wxTextFile::Translate(value, wxTextFileType_Unix);
+
+ GetFocusObject()->InsertTextWithUndo(& GetBuffer(), m_caretPosition+1, valueUnix, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+ wxRichTextDrawingContext context(& GetBuffer());
+ GetBuffer().Defragment(context);
+
+ if ( flags & SetValue_SendEvent )
+ wxTextCtrl::SendTextUpdatedEvent(this);
+}
+
+void wxRichTextCtrl::AppendText(const wxString& text)
+{
+ SetInsertionPointEnd();
+
+ WriteText(text);
+}
+
+/// Write an image at the current insertion point
+bool wxRichTextCtrl::WriteImage(const wxImage& image, wxBitmapType bitmapType, const wxRichTextAttr& textAttr)
+{
+ wxRichTextImageBlock imageBlock;
+
+ wxImage image2 = image;
+ if (imageBlock.MakeImageBlock(image2, bitmapType))
+ return WriteImage(imageBlock, textAttr);
+
+ return false;
+}
+
+bool wxRichTextCtrl::WriteImage(const wxString& filename, wxBitmapType bitmapType, const wxRichTextAttr& textAttr)
+{
+ wxRichTextImageBlock imageBlock;
+
+ wxImage image;
+ if (imageBlock.MakeImageBlock(filename, bitmapType, image, false))
+ return WriteImage(imageBlock, textAttr);
+
+ return false;
+}
+
+bool wxRichTextCtrl::WriteImage(const wxRichTextImageBlock& imageBlock, const wxRichTextAttr& textAttr)
+{
+ return GetFocusObject()->InsertImageWithUndo(& GetBuffer(), m_caretPosition+1, imageBlock, this, 0, textAttr);
+}
+
+bool wxRichTextCtrl::WriteImage(const wxBitmap& bitmap, wxBitmapType bitmapType, const wxRichTextAttr& textAttr)
+{
+ if (bitmap.IsOk())
+ {
+ wxRichTextImageBlock imageBlock;
+
+ wxImage image = bitmap.ConvertToImage();
+ if (image.IsOk() && imageBlock.MakeImageBlock(image, bitmapType))
+ return WriteImage(imageBlock, textAttr);
+ }
+
+ return false;
+}
+
+// Write a text box at the current insertion point.
+wxRichTextBox* wxRichTextCtrl::WriteTextBox(const wxRichTextAttr& textAttr)
+{
+ wxRichTextBox* textBox = new wxRichTextBox;
+ textBox->SetAttributes(textAttr);
+ textBox->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style
+ textBox->AddParagraph(wxEmptyString);
+ textBox->SetParent(NULL);
+
+ // The object returned is the one actually inserted into the buffer,
+ // while the original one is deleted.
+ wxRichTextObject* obj = GetFocusObject()->InsertObjectWithUndo(& GetBuffer(), m_caretPosition+1, textBox, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+ wxRichTextBox* box = wxDynamicCast(obj, wxRichTextBox);
+ return box;
+}
+
+wxRichTextField* wxRichTextCtrl::WriteField(const wxString& fieldType, const wxRichTextProperties& properties,
+ const wxRichTextAttr& textAttr)
+{
+ return GetFocusObject()->InsertFieldWithUndo(& GetBuffer(), m_caretPosition+1, fieldType, properties,
+ this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE, textAttr);
+}
+
+// Write a table at the current insertion point, returning the table.
+wxRichTextTable* wxRichTextCtrl::WriteTable(int rows, int cols, const wxRichTextAttr& tableAttr, const wxRichTextAttr& cellAttr)
+{
+ wxASSERT(rows > 0 && cols > 0);
+
+ if (rows <= 0 || cols <= 0)
+ return NULL;
+
+ wxRichTextTable* table = new wxRichTextTable;
+ table->SetAttributes(tableAttr);
+ table->SetParent(& GetBuffer()); // set parent temporarily for AddParagraph to use correct style
+
+ table->CreateTable(rows, cols);
+
+ table->SetParent(NULL);
+
+ int i, j;
+ for (j = 0; j < rows; j++)
+ {
+ for (i = 0; i < cols; i++)
+ {
+ table->GetCell(j, i)->GetAttributes() = cellAttr;
+ }
+ }
+
+ // The object returned is the one actually inserted into the buffer,
+ // while the original one is deleted.
+ wxRichTextObject* obj = GetFocusObject()->InsertObjectWithUndo(& GetBuffer(), m_caretPosition+1, table, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+ wxRichTextTable* tableResult = wxDynamicCast(obj, wxRichTextTable);
+ return tableResult;
+}
+
+
+/// Insert a newline (actually paragraph) at the current insertion point.
+bool wxRichTextCtrl::Newline()
+{
+ return GetFocusObject()->InsertNewlineWithUndo(& GetBuffer(), m_caretPosition+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+}
+
+/// Insert a line break at the current insertion point.
+bool wxRichTextCtrl::LineBreak()
+{
+ wxString text;
+ text = wxRichTextLineBreakChar;
+ return GetFocusObject()->InsertTextWithUndo(& GetBuffer(), m_caretPosition+1, text, this);
+}
+
+// ----------------------------------------------------------------------------
+// Clipboard operations
+// ----------------------------------------------------------------------------
+
+void wxRichTextCtrl::Copy()
+{
+ if (CanCopy())
+ {
+ wxRichTextRange range = GetInternalSelectionRange();
+ GetBuffer().CopyToClipboard(range);
+ }
+}
+
+void wxRichTextCtrl::Cut()
+{
+ if (CanCut())
+ {
+ wxRichTextRange range = GetInternalSelectionRange();
+ GetBuffer().CopyToClipboard(range);
+
+ DeleteSelectedContent();
+ LayoutContent();
+ Refresh(false);
+ }
+}
+
+void wxRichTextCtrl::Paste()
+{
+ if (CanPaste())
+ {
+ BeginBatchUndo(_("Paste"));
+
+ long newPos = m_caretPosition;
+ DeleteSelectedContent(& newPos);
+
+ GetBuffer().PasteFromClipboard(newPos);
+
+ EndBatchUndo();
+ }
+}
+
+void wxRichTextCtrl::DeleteSelection()
+{
+ if (CanDeleteSelection())
+ {
+ DeleteSelectedContent();
+ }
+}
+
+bool wxRichTextCtrl::HasSelection() const
+{
+ return (m_selection.IsValid() && m_selection.GetContainer() == GetFocusObject());
+}
+
+bool wxRichTextCtrl::HasUnfocusedSelection() const
+{
+ return m_selection.IsValid();
+}
+
+bool wxRichTextCtrl::CanCopy() const
+{
+ // Can copy if there's a selection
+ return HasSelection();
+}
+
+bool wxRichTextCtrl::CanCut() const
+{
+ return CanDeleteSelection();
+}
+
+bool wxRichTextCtrl::CanPaste() const
+{
+ if ( !IsEditable() || !GetFocusObject() || !CanInsertContent(* GetFocusObject(), m_caretPosition+1))
+ return false;
+
+ return GetBuffer().CanPasteFromClipboard();
+}
+
+bool wxRichTextCtrl::CanDeleteSelection() const
+{
+ return HasSelection() && IsEditable() && CanDeleteRange(* GetFocusObject(), GetSelectionRange());
+}
+
+
+// ----------------------------------------------------------------------------
+// Accessors
+// ----------------------------------------------------------------------------
+
+void wxRichTextCtrl::SetContextMenu(wxMenu* menu)
+{
+ if (m_contextMenu && m_contextMenu != menu)
+ delete m_contextMenu;
+ m_contextMenu = menu;
+}
+
+void wxRichTextCtrl::SetEditable(bool editable)
+{
+ m_editable = editable;
+}
+
+void wxRichTextCtrl::SetInsertionPoint(long pos)
+{
+ SelectNone();
+
+ m_caretPosition = pos - 1;
+ m_caretAtLineStart = true;
+
+ PositionCaret();
+
+ SetDefaultStyleToCursorStyle();
+}
+
+void wxRichTextCtrl::SetInsertionPointEnd()
+{
+ long pos = GetLastPosition();
+ SetInsertionPoint(pos);
+}
+
+long wxRichTextCtrl::GetInsertionPoint() const
+{
+ return m_caretPosition+1;
+}
+
+wxTextPos wxRichTextCtrl::GetLastPosition() const
+{
+ return GetFocusObject()->GetOwnRange().GetEnd();
+}
+
+// If the return values from and to are the same, there is no
+// selection.
+void wxRichTextCtrl::GetSelection(long* from, long* to) const
+{
+ if (m_selection.IsValid())
+ {
+ *from = m_selection.GetRange().GetStart();
+ *to = m_selection.GetRange().GetEnd();
+ (*to) ++;
+ }
+ else
+ {
+ *from = -2;
+ *to = -2;
+ }
+}
+
+bool wxRichTextCtrl::IsEditable() const
+{
+ return m_editable;
+}
+
+// ----------------------------------------------------------------------------
+// selection
+// ----------------------------------------------------------------------------
+
+void wxRichTextCtrl::SetSelection(long from, long to)
+{
+ // if from and to are both -1, it means (in wxWidgets) that all text should
+ // be selected.
+ if ( (from == -1) && (to == -1) )
+ {
+ from = 0;
+ to = GetLastPosition()+1;
+ }
+
+ if (from == to)
+ {
+ SelectNone();
+ }
+ else
+ {
+ wxRichTextSelection oldSelection = m_selection;
+
+ m_selectionAnchor = from-1;
+ m_selectionAnchorObject = NULL;
+ m_selection.Set(wxRichTextRange(from, to-1), GetFocusObject());
+
+ m_caretPosition = wxMax(-1, to-1);
+
+ RefreshForSelectionChange(oldSelection, m_selection);
+ PositionCaret();
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Editing
+// ----------------------------------------------------------------------------
+
+void wxRichTextCtrl::Replace(long from, long to,
+ const wxString& value)
+{
+ BeginBatchUndo(_("Replace"));
+
+ SetSelection(from, to);
+
+ wxRichTextAttr attr(GetDefaultStyle());
+
+ DeleteSelectedContent();
+
+ SetDefaultStyle(attr);
+
+ if (!value.IsEmpty())
+ DoWriteText(value, SetValue_SelectionOnly);
+
+ EndBatchUndo();
+}
+
+void wxRichTextCtrl::Remove(long from, long to)
+{
+ SelectNone();
+
+ GetFocusObject()->DeleteRangeWithUndo(wxRichTextRange(from, to-1), this, & GetBuffer());
+
+ LayoutContent();
+ if (!IsFrozen())
+ Refresh(false);
+}
+
+bool wxRichTextCtrl::IsModified() const
+{
+ return m_buffer.IsModified();
+}
+
+void wxRichTextCtrl::MarkDirty()
+{
+ m_buffer.Modify(true);
+}
+
+void wxRichTextCtrl::DiscardEdits()
+{
+ m_caretPositionForDefaultStyle = -2;
+ m_buffer.Modify(false);
+ m_buffer.GetCommandProcessor()->ClearCommands();
+}
+
+int wxRichTextCtrl::GetNumberOfLines() const
+{
+ return GetFocusObject()->GetParagraphCount();
+}
+
+// ----------------------------------------------------------------------------
+// Positions <-> coords
+// ----------------------------------------------------------------------------
+
+long wxRichTextCtrl::XYToPosition(long x, long y) const
+{
+ return GetFocusObject()->XYToPosition(x, y);
+}
+
+bool wxRichTextCtrl::PositionToXY(long pos, long *x, long *y) const
+{
+ return GetFocusObject()->PositionToXY(pos, x, y);
+}
+
+// ----------------------------------------------------------------------------
+//
+// ----------------------------------------------------------------------------
+
+void wxRichTextCtrl::ShowPosition(long pos)
+{
+ if (!IsPositionVisible(pos))
+ ScrollIntoView(pos-1, WXK_DOWN);
+}
+
+int wxRichTextCtrl::GetLineLength(long lineNo) const
+{
+ return GetFocusObject()->GetParagraphLength(lineNo);
+}
+
+wxString wxRichTextCtrl::GetLineText(long lineNo) const
+{
+ return GetFocusObject()->GetParagraphText(lineNo);
+}
+
+// ----------------------------------------------------------------------------
+// Undo/redo
+// ----------------------------------------------------------------------------
+
+void wxRichTextCtrl::Undo()
+{
+ if (CanUndo())
+ {
+ GetCommandProcessor()->Undo();
+ }
+}