]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/textctrl.cpp
added trivial wxLaunchDefaultApplication() implementation for wxMac; added a test...
[wxWidgets.git] / src / msw / textctrl.cpp
index 974fa7a30d37309c3ef3fe47f7de7f0f0b84b8a4..47ec9ab448782dc8a4f276af61be3b953e95e6ae 100644 (file)
 
 #include "wx/msw/missing.h"
 
 
 #include "wx/msw/missing.h"
 
+#if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT
+
+// dummy value used for m_dropTarget, different from any valid pointer value
+// (which are all even under Windows) and NULL
+static wxDropTarget *
+    wxRICHTEXT_DEFAULT_DROPTARGET = wx_reinterpret_cast(wxDropTarget *, 1);
+
+#endif // wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT
+
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // private classes
 // ----------------------------------------------------------------------------
@@ -239,6 +248,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxTextCtrlBase)
 
 BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
     EVT_CHAR(wxTextCtrl::OnChar)
 
 BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
     EVT_CHAR(wxTextCtrl::OnChar)
+    EVT_KEY_DOWN(wxTextCtrl::OnKeyDown)
     EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
 
 #if wxUSE_RICHEDIT
     EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
 
 #if wxUSE_RICHEDIT
@@ -289,6 +299,14 @@ void wxTextCtrl::Init()
 
 wxTextCtrl::~wxTextCtrl()
 {
 
 wxTextCtrl::~wxTextCtrl()
 {
+#if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT
+    if ( m_dropTarget == wxRICHTEXT_DEFAULT_DROPTARGET )
+    {
+        // don't try to destroy this dummy pointer in the base class dtor
+        m_dropTarget = NULL;
+    }
+#endif // wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT
+
     delete m_privateContextMenu;
 }
 
     delete m_privateContextMenu;
 }
 
@@ -308,6 +326,20 @@ bool wxTextCtrl::Create(wxWindow *parent,
     if ( !MSWCreateText(value, pos, size) )
         return false;
 
     if ( !MSWCreateText(value, pos, size) )
         return false;
 
+#if wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT
+    if ( IsRich() )
+    {
+        // rich text controls have a default associated drop target which
+        // allows them to receive (rich) text dropped on them, which is nice,
+        // but prevents us from associating a user-defined drop target with
+        // them as we need to unregister the old one first
+        //
+        // to make it work, we set m_dropTarget to this special value initially
+        // and check for it in our SetDropTarget()
+        m_dropTarget = wxRICHTEXT_DEFAULT_DROPTARGET;
+    }
+#endif // wxUSE_DRAG_AND_DROP && wxUSE_RICHEDIT
+
     return true;
 }
 
     return true;
 }
 
@@ -452,9 +484,19 @@ bool wxTextCtrl::MSWCreateText(const wxString& value,
         valueWin = value;
     }
 
         valueWin = value;
     }
 
+    // suppress events sent during control creation: we're called either from
+    // the ctor and then we shouldn't generate any events for compatibility
+    // with the other ports, or from SetWindowStyleFlag() and then we shouldn't
+    // generate the events because our text doesn't really change, the fact
+    // that we (sometimes) need to recreate the control is just an
+    // implementation detail
+    m_updatesCount = -2;
+
     if ( !MSWCreateControl(windowClass.wx_str(), msStyle, pos, size, valueWin) )
         return false;
 
     if ( !MSWCreateControl(windowClass.wx_str(), msStyle, pos, size, valueWin) )
         return false;
 
+    m_updatesCount = -1;
+
 #if wxUSE_RICHEDIT
     if (IsRich())
     {
 #if wxUSE_RICHEDIT
     if (IsRich())
     {
@@ -502,6 +544,14 @@ bool wxTextCtrl::MSWCreateText(const wxString& value,
     }
 #endif // wxUSE_RICHEDIT
 
     }
 #endif // wxUSE_RICHEDIT
 
+#ifndef __WXWINCE__
+    // Without this, if we pass the size in the constructor and then don't change it,
+    // the themed borders will be drawn incorrectly.
+    SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0,
+                SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
+                SWP_FRAMECHANGED);
+#endif
+
     return true;
 }
 
     return true;
 }
 
@@ -551,7 +601,7 @@ WXDWORD wxTextCtrl::MSWGetStyle(long style, WXDWORD *exstyle) const
 {
     long msStyle = wxControl::MSWGetStyle(style, exstyle);
 
 {
     long msStyle = wxControl::MSWGetStyle(style, exstyle);
 
-    // styles which we alaways add by default
+    // styles which we always add by default
     if ( style & wxTE_MULTILINE )
     {
         msStyle |= ES_MULTILINE | ES_WANTRETURN;
     if ( style & wxTE_MULTILINE )
     {
         msStyle |= ES_MULTILINE | ES_WANTRETURN;
@@ -745,10 +795,12 @@ wxString wxTextCtrl::GetRange(long from, long to) const
                    encoding = font.GetEncoding();
                 }
 
                    encoding = font.GetEncoding();
                 }
 
+#if wxUSE_INTL
                 if ( encoding == wxFONTENCODING_SYSTEM )
                 {
                     encoding = wxLocale::GetSystemEncoding();
                 }
                 if ( encoding == wxFONTENCODING_SYSTEM )
                 {
                     encoding = wxLocale::GetSystemEncoding();
                 }
+#endif // wxUSE_INTL
 
                 if ( encoding == wxFONTENCODING_SYSTEM )
                 {
 
                 if ( encoding == wxFONTENCODING_SYSTEM )
                 {
@@ -935,6 +987,9 @@ wxTextCtrl::StreamIn(const wxString& value,
 
     const size_t len = conv.MB2WC(NULL, value.mb_str(), value.length());
 
 
     const size_t len = conv.MB2WC(NULL, value.mb_str(), value.length());
 
+    if (len == wxCONV_FAILED)
+        return false;
+
 #if wxUSE_WCHAR_T
     wxWCharBuffer wchBuf(len);
     wchar_t *wpc = wchBuf.data();
 #if wxUSE_WCHAR_T
     wxWCharBuffer wchBuf(len);
     wchar_t *wpc = wchBuf.data();
@@ -1027,7 +1082,8 @@ wxTextCtrl::StreamOut(wxFontEncoding encoding, bool selectionOnly) const
         // conversion but what else can we do)
         wxCSConv conv(encoding);
         size_t lenNeeded = conv.WC2MB(NULL, wchBuf, 0);
         // conversion but what else can we do)
         wxCSConv conv(encoding);
         size_t lenNeeded = conv.WC2MB(NULL, wchBuf, 0);
-        if ( lenNeeded++ )
+
+        if ( lenNeeded != wxCONV_FAILED && lenNeeded++ )
         {
             conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, lenNeeded);
         }
         {
             conv.WC2MB(wxStringBuffer(out, lenNeeded), wchBuf, lenNeeded);
         }
@@ -1133,9 +1189,7 @@ void wxTextCtrl::DoWriteText(const wxString& value, int flags)
 
 void wxTextCtrl::AppendText(const wxString& text)
 {
 
 void wxTextCtrl::AppendText(const wxString& text)
 {
-    SetInsertionPointEnd();
-
-    WriteText(text);
+    wxTextEntry::AppendText(text);
 
 #if wxUSE_RICHEDIT
     // don't do this if we're frozen, saves some time
 
 #if wxUSE_RICHEDIT
     // don't do this if we're frozen, saves some time
@@ -1152,18 +1206,12 @@ void wxTextCtrl::Clear()
 {
     ::SetWindowText(GetHwnd(), wxEmptyString);
 
 {
     ::SetWindowText(GetHwnd(), wxEmptyString);
 
-#if wxUSE_RICHEDIT
-    if ( !IsRich() )
-#endif // wxUSE_RICHEDIT
+    if ( IsMultiLine() && !IsRich() )
     {
         // rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves
         // but the normal ones don't -- make Clear() behaviour consistent by
         // always sending this event
     {
         // rich edit controls send EN_UPDATE from WM_SETTEXT handler themselves
         // but the normal ones don't -- make Clear() behaviour consistent by
         // always sending this event
-
-        // Windows already sends an update event for single-line
-        // controls.
-        if ( m_windowStyle & wxTE_MULTILINE )
-            SendUpdateEvent();
+        SendUpdateEvent();
     }
 }
 
     }
 }
 
@@ -1186,91 +1234,10 @@ bool wxTextCtrl::EmulateKeyPress(const wxKeyEvent& event)
 
 #endif // __WIN32__
 
 
 #endif // __WIN32__
 
-// ----------------------------------------------------------------------------
-// Clipboard operations
-// ----------------------------------------------------------------------------
-
-void wxTextCtrl::Copy()
-{
-    if (CanCopy())
-    {
-        ::SendMessage(GetHwnd(), WM_COPY, 0, 0L);
-    }
-}
-
-void wxTextCtrl::Cut()
-{
-    if (CanCut())
-    {
-        ::SendMessage(GetHwnd(), WM_CUT, 0, 0L);
-    }
-}
-
-void wxTextCtrl::Paste()
-{
-    if (CanPaste())
-    {
-        ::SendMessage(GetHwnd(), WM_PASTE, 0, 0L);
-    }
-}
-
-bool wxTextCtrl::HasSelection() const
-{
-    long from, to;
-    GetSelection(&from, &to);
-    return from != to;
-}
-
-bool wxTextCtrl::CanCopy() const
-{
-    // Can copy if there's a selection
-    return HasSelection();
-}
-
-bool wxTextCtrl::CanCut() const
-{
-    return CanCopy() && IsEditable();
-}
-
-bool wxTextCtrl::CanPaste() const
-{
-    if ( !IsEditable() )
-        return false;
-
-#if wxUSE_RICHEDIT
-    if ( IsRich() )
-    {
-        UINT cf = 0; // 0 == any format
-
-        return ::SendMessage(GetHwnd(), EM_CANPASTE, cf, 0) != 0;
-    }
-#endif // wxUSE_RICHEDIT
-
-    // Standard edit control: check for straight text on clipboard
-    if ( !::OpenClipboard(GetHwndOf(wxTheApp->GetTopWindow())) )
-        return false;
-
-    bool isTextAvailable = ::IsClipboardFormatAvailable(CF_TEXT) != 0;
-    ::CloseClipboard();
-
-    return isTextAvailable;
-}
-
 // ----------------------------------------------------------------------------
 // Accessors
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 // Accessors
 // ----------------------------------------------------------------------------
 
-void wxTextCtrl::SetEditable(bool editable)
-{
-    HWND hWnd = GetHwnd();
-    ::SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L);
-}
-
-void wxTextCtrl::SetInsertionPoint(long pos)
-{
-    DoSetSelection(pos, pos);
-}
-
 void wxTextCtrl::SetInsertionPointEnd()
 {
     // we must not do anything if the caret is already there because calling
 void wxTextCtrl::SetInsertionPointEnd()
 {
     // we must not do anything if the caret is already there because calling
@@ -1284,21 +1251,7 @@ void wxTextCtrl::SetInsertionPointEnd()
         return;
     }
 
         return;
     }
 
-    long pos;
-
-#if wxUSE_RICHEDIT
-    if ( m_verRichEdit == 1 )
-    {
-        // we don't have to waste time calling GetLastPosition() in this case
-        pos = -1;
-    }
-    else // !RichEdit 1.0
-#endif // wxUSE_RICHEDIT
-    {
-        pos = lastPosition;
-    }
-
-    SetInsertionPoint(pos);
+    SetInsertionPoint(lastPosition);
 }
 
 long wxTextCtrl::GetInsertionPoint() const
 }
 
 long wxTextCtrl::GetInsertionPoint() const
@@ -1314,23 +1267,27 @@ long wxTextCtrl::GetInsertionPoint() const
     }
 #endif // wxUSE_RICHEDIT
 
     }
 #endif // wxUSE_RICHEDIT
 
-    DWORD Pos = (DWORD)::SendMessage(GetHwnd(), EM_GETSEL, 0, 0L);
-    return Pos & 0xFFFF;
+    return wxTextEntry::GetInsertionPoint();
 }
 
 wxTextPos wxTextCtrl::GetLastPosition() const
 {
 }
 
 wxTextPos wxTextCtrl::GetLastPosition() const
 {
-    int numLines = GetNumberOfLines();
-    long posStartLastLine = XYToPosition(0, numLines - 1);
+    if ( IsMultiLine() )
+    {
+        int numLines = GetNumberOfLines();
+        long posStartLastLine = XYToPosition(0, numLines - 1);
+
+        long lenLastLine = GetLengthOfLineContainingPos(posStartLastLine);
 
 
-    long lenLastLine = GetLengthOfLineContainingPos(posStartLastLine);
+        return posStartLastLine + lenLastLine;
+    }
 
 
-    return posStartLastLine + lenLastLine;
+    return wxTextEntry::GetLastPosition();
 }
 
 // If the return values from and to are the same, there is no
 // selection.
 }
 
 // If the return values from and to are the same, there is no
 // selection.
-void wxTextCtrl::GetSelection(long* from, long* to) const
+void wxTextCtrl::GetSelection(long *from, long *to) const
 {
 #if wxUSE_RICHEDIT
     if ( IsRich() )
 {
 #if wxUSE_RICHEDIT
     if ( IsRich() )
@@ -1344,63 +1301,40 @@ void wxTextCtrl::GetSelection(long* from, long* to) const
     else
 #endif // !wxUSE_RICHEDIT
     {
     else
 #endif // !wxUSE_RICHEDIT
     {
-        DWORD dwStart, dwEnd;
-        ::SendMessage(GetHwnd(), EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
-
-        *from = dwStart;
-        *to = dwEnd;
+        wxTextEntry::GetSelection(from, to);
     }
 }
 
     }
 }
 
-bool wxTextCtrl::IsEditable() const
-{
-    // strangely enough, we may be called before the control is created: our
-    // own Create() calls MSWGetStyle() which calls AcceptsFocus() which calls
-    // us
-    if ( !m_hWnd )
-        return true;
-
-    long style = ::GetWindowLong(GetHwnd(), GWL_STYLE);
-
-    return (style & ES_READONLY) == 0;
-}
-
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 // selection
 // ----------------------------------------------------------------------------
 
-void wxTextCtrl::SetSelection(long from, long to)
-{
-    // if from and to are both -1, it means (in wxWidgets) that all text should
-    // be selected - translate into Windows convention
-    if ( (from == -1) && (to == -1) )
-    {
-        from = 0;
-        to = -1;
-    }
-
-    DoSetSelection(from, to);
-}
-
-void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret)
+void wxTextCtrl::DoSetSelection(long from, long to, int flags)
 {
     HWND hWnd = GetHwnd();
 
 #if wxUSE_RICHEDIT
     if ( IsRich() )
     {
 {
     HWND hWnd = GetHwnd();
 
 #if wxUSE_RICHEDIT
     if ( IsRich() )
     {
+        // if from and to are both -1, it means (in wxWidgets) that all text
+        // should be selected, translate this into Windows convention
+        if ( (from == -1) && (to == -1) )
+        {
+            from = 0;
+        }
+
         CHARRANGE range;
         range.cpMin = from;
         range.cpMax = to;
         CHARRANGE range;
         range.cpMin = from;
         range.cpMax = to;
-        ::SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM) &range);
+        ::SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM)&range);
     }
     else
 #endif // wxUSE_RICHEDIT
     {
     }
     else
 #endif // wxUSE_RICHEDIT
     {
-        ::SendMessage(hWnd, EM_SETSEL, (WPARAM)from, (LPARAM)to);
+        wxTextEntry::DoSetSelection(from, to, flags);
     }
 
     }
 
-    if ( scrollCaret && !IsFrozen() )
+    if ( (flags & SetSel_Scroll) && !IsFrozen() )
     {
 #if wxUSE_RICHEDIT
         // richedit 3.0 (i.e. the version living in riched20.dll distributed
     {
 #if wxUSE_RICHEDIT
         // richedit 3.0 (i.e. the version living in riched20.dll distributed
@@ -1434,7 +1368,7 @@ void wxTextCtrl::DoSetSelection(long from, long to, bool scrollCaret)
         }
 #endif // wxUSE_RICHEDIT
 
         }
 #endif // wxUSE_RICHEDIT
 
-        ::SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
+        ::SendMessage(hWnd, EM_SCROLLCARET, 0, (LPARAM)0);
 
 #if wxUSE_RICHEDIT
         // restore ECO_NOHIDESEL if we changed it
 
 #if wxUSE_RICHEDIT
         // restore ECO_NOHIDESEL if we changed it
@@ -1467,22 +1401,9 @@ bool wxTextCtrl::DoLoadFile(const wxString& file, int fileType)
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// Editing
+// dirty status
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-void wxTextCtrl::Replace(long from, long to, const wxString& value)
-{
-    // Set selection and remove it
-    DoSetSelection(from, to, false /* don't scroll caret into view */);
-
-    DoWriteText(value);
-}
-
-void wxTextCtrl::Remove(long from, long to)
-{
-    Replace(from, to, wxEmptyString);
-}
-
 bool wxTextCtrl::IsModified() const
 {
     return ::SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
 bool wxTextCtrl::IsModified() const
 {
     return ::SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0;
@@ -1490,27 +1411,27 @@ bool wxTextCtrl::IsModified() const
 
 void wxTextCtrl::MarkDirty()
 {
 
 void wxTextCtrl::MarkDirty()
 {
-    ::SendMessage(GetHwnd(), EM_SETMODIFY, TRUE, 0L);
+    ::SendMessage(GetHwnd(), EM_SETMODIFY, TRUE, 0);
 }
 
 void wxTextCtrl::DiscardEdits()
 {
 }
 
 void wxTextCtrl::DiscardEdits()
 {
-    ::SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
-}
-
-int wxTextCtrl::GetNumberOfLines() const
-{
-    return (int)::SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
+    ::SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0);
 }
 
 // ----------------------------------------------------------------------------
 // Positions <-> coords
 // ----------------------------------------------------------------------------
 
 }
 
 // ----------------------------------------------------------------------------
 // Positions <-> coords
 // ----------------------------------------------------------------------------
 
+int wxTextCtrl::GetNumberOfLines() const
+{
+    return (int)::SendMessage(GetHwnd(), EM_GETLINECOUNT, 0, 0);
+}
+
 long wxTextCtrl::XYToPosition(long x, long y) const
 {
     // This gets the char index for the _beginning_ of this line
 long wxTextCtrl::XYToPosition(long x, long y) const
 {
     // This gets the char index for the _beginning_ of this line
-    long charIndex = ::SendMessage(GetHwnd(), EM_LINEINDEX, (WPARAM)y, (LPARAM)0);
+    long charIndex = ::SendMessage(GetHwnd(), EM_LINEINDEX, y, 0);
 
     return charIndex + x;
 }
 
     return charIndex + x;
 }
@@ -1524,12 +1445,12 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
 #if wxUSE_RICHEDIT
     if ( IsRich() )
     {
 #if wxUSE_RICHEDIT
     if ( IsRich() )
     {
-        lineNo = ::SendMessage(hWnd, EM_EXLINEFROMCHAR, 0, (LPARAM)pos);
+        lineNo = ::SendMessage(hWnd, EM_EXLINEFROMCHAR, 0, pos);
     }
     else
 #endif // wxUSE_RICHEDIT
     {
     }
     else
 #endif // wxUSE_RICHEDIT
     {
-        lineNo = ::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, 0);
+        lineNo = ::SendMessage(hWnd, EM_LINEFROMCHAR, pos, 0);
     }
 
     if ( lineNo == -1 )
     }
 
     if ( lineNo == -1 )
@@ -1539,7 +1460,7 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
     }
 
     // This gets the char index for the _beginning_ of this line
     }
 
     // This gets the char index for the _beginning_ of this line
-    long charIndex = ::SendMessage(hWnd, EM_LINEINDEX, (WPARAM)lineNo, (LPARAM)0);
+    long charIndex = ::SendMessage(hWnd, EM_LINEINDEX, lineNo, 0);
     if ( charIndex == -1 )
     {
         return false;
     if ( charIndex == -1 )
     {
         return false;
@@ -1657,21 +1578,21 @@ void wxTextCtrl::ShowPosition(long pos)
 
     // Is this where scrolling is relative to - the line containing the caret?
     // Or is the first visible line??? Try first visible line.
 
     // Is this where scrolling is relative to - the line containing the caret?
     // Or is the first visible line??? Try first visible line.
-//    int currentLineLineNo1 = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L);
+//    int currentLineLineNo1 = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, -1, 0L);
 
 
-    int currentLineLineNo = (int)::SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, (WPARAM)0, (LPARAM)0L);
+    int currentLineLineNo = (int)::SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, 0, 0);
 
 
-    int specifiedLineLineNo = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
+    int specifiedLineLineNo = (int)::SendMessage(hWnd, EM_LINEFROMCHAR, pos, 0);
 
     int linesToScroll = specifiedLineLineNo - currentLineLineNo;
 
     if (linesToScroll != 0)
 
     int linesToScroll = specifiedLineLineNo - currentLineLineNo;
 
     if (linesToScroll != 0)
-      (void)::SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
+      ::SendMessage(hWnd, EM_LINESCROLL, 0, linesToScroll);
 }
 
 long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const
 {
 }
 
 long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const
 {
-    return ::SendMessage(GetHwnd(), EM_LINELENGTH, (WPARAM)pos, 0);
+    return ::SendMessage(GetHwnd(), EM_LINELENGTH, pos, 0);
 }
 
 int wxTextCtrl::GetLineLength(long lineNo) const
 }
 
 int wxTextCtrl::GetLineLength(long lineNo) const
@@ -1704,9 +1625,16 @@ wxString wxTextCtrl::GetLineText(long lineNo) const
             // should never see it
             if ( buf[len - 2] == _T('\r') && buf[len - 1] == _T('\n') )
             {
             // should never see it
             if ( buf[len - 2] == _T('\r') && buf[len - 1] == _T('\n') )
             {
+                // richedit 1.0 uses "\r\n" as line terminator, so remove "\r"
+                // here and "\n" below
                 buf[len - 2] = _T('\n');
                 len--;
             }
                 buf[len - 2] = _T('\n');
                 len--;
             }
+            else if ( buf[len - 1] == _T('\r') )
+            {
+                // richedit 2.0+ uses only "\r", replace it with "\n"
+                buf[len - 1] = _T('\n');
+            }
         }
 #endif // wxUSE_RICHEDIT
 
         }
 #endif // wxUSE_RICHEDIT
 
@@ -1734,14 +1662,7 @@ void wxTextCtrl::SetMaxLength(unsigned long len)
     else
 #endif // wxUSE_RICHEDIT
     {
     else
 #endif // wxUSE_RICHEDIT
     {
-        if ( len >= 0xffff )
-        {
-            // this will set it to a platform-dependent maximum (much more
-            // than 64Kb under NT)
-            len = 0;
-        }
-
-        ::SendMessage(GetHwnd(), EM_LIMITTEXT, len, 0);
+        wxTextEntry::SetMaxLength(len);
     }
 }
 
     }
 }
 
@@ -1749,41 +1670,27 @@ void wxTextCtrl::SetMaxLength(unsigned long len)
 // Undo/redo
 // ----------------------------------------------------------------------------
 
 // Undo/redo
 // ----------------------------------------------------------------------------
 
-void wxTextCtrl::Undo()
-{
-    if (CanUndo())
-    {
-        ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
-    }
-}
-
 void wxTextCtrl::Redo()
 {
 void wxTextCtrl::Redo()
 {
-    if (CanRedo())
-    {
 #if wxUSE_RICHEDIT
 #if wxUSE_RICHEDIT
-        if (GetRichVersion() > 1)
-            ::SendMessage(GetHwnd(), EM_REDO, 0, 0);
-        else
-#endif
-        // Same as Undo, since Undo undoes the undo, i.e. a redo.
-        ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
+    if ( GetRichVersion() > 1 )
+    {
+        ::SendMessage(GetHwnd(), EM_REDO, 0, 0);
+        return;
     }
     }
-}
+#endif // wxUSE_RICHEDIT
 
 
-bool wxTextCtrl::CanUndo() const
-{
-    return ::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0;
+    wxTextEntry::Redo();
 }
 
 bool wxTextCtrl::CanRedo() const
 {
 #if wxUSE_RICHEDIT
 }
 
 bool wxTextCtrl::CanRedo() const
 {
 #if wxUSE_RICHEDIT
-    if (GetRichVersion() > 1)
+    if ( GetRichVersion() > 1 )
         return ::SendMessage(GetHwnd(), EM_CANREDO, 0, 0) != 0;
         return ::SendMessage(GetHwnd(), EM_CANREDO, 0, 0) != 0;
-    else
-#endif
-    return ::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0;
+#endif // wxUSE_RICHEDIT
+
+    return wxTextEntry::CanRedo();
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -1797,7 +1704,7 @@ bool wxTextCtrl::ShowNativeCaret(bool show)
         if ( !(show ? ::ShowCaret(GetHwnd()) : ::HideCaret(GetHwnd())) )
         {
             // not an error, may simply indicate that it's not shown/hidden
         if ( !(show ? ::ShowCaret(GetHwnd()) : ::HideCaret(GetHwnd())) )
         {
             // not an error, may simply indicate that it's not shown/hidden
-            // yet (i.e. it had been hidden/showh 2 times before)
+            // yet (i.e. it had been hidden/shown 2 times before)
             return false;
         }
 
             return false;
         }
 
@@ -1808,7 +1715,7 @@ bool wxTextCtrl::ShowNativeCaret(bool show)
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// implemenation details
+// implementation details
 // ----------------------------------------------------------------------------
 
 void wxTextCtrl::Command(wxCommandEvent & event)
 // ----------------------------------------------------------------------------
 
 void wxTextCtrl::Command(wxCommandEvent & event)
@@ -1901,7 +1808,7 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
                 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
                 InitCommandEvent(event);
                 event.SetString(GetValue());
                 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
                 InitCommandEvent(event);
                 event.SetString(GetValue());
-                if ( GetEventHandler()->ProcessEvent(event) )
+                if ( HandleWindowEvent(event) )
                 if ( !HasFlag(wxTE_MULTILINE) )
                     return;
                 //else: multiline controls need Enter for themselves
                 if ( !HasFlag(wxTE_MULTILINE) )
                     return;
                 //else: multiline controls need Enter for themselves
@@ -1950,6 +1857,35 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
     event.Skip();
 }
 
     event.Skip();
 }
 
+void wxTextCtrl::OnKeyDown(wxKeyEvent& event)
+{
+    // richedit control doesn't send WM_PASTE, WM_CUT and WM_COPY messages
+    // when Ctrl-V, X or C is pressed and this prevents wxClipboardTextEvent
+    // from working. So we work around it by intercepting these shortcuts
+    // ourselves and emitting clipboard events (which richedit will handle,
+    // so everything works as before, including pasting of rich text):
+    if ( event.GetModifiers() == wxMOD_CONTROL && IsRich() )
+    {
+        switch ( event.GetKeyCode() )
+        {
+            case 'C':
+                Copy();
+                return;
+            case 'X':
+                Cut();
+                return;
+            case 'V':
+                Paste();
+                return;
+            default:
+                break;
+        }
+    }
+
+    // no, we didn't process it
+    event.Skip();
+}
+
 WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 {
     WXLRESULT lRc = wxTextCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
 WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 {
     WXLRESULT lRc = wxTextCtrlBase::MSWWindowProc(nMsg, wParam, lParam);
@@ -1994,13 +1930,6 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
                 }
             }
             break;
                 }
             }
             break;
-
-        case WM_CUT:
-        case WM_COPY:
-        case WM_PASTE:
-            if ( HandleClipboardEvent(nMsg) )
-                lRc = 0;
-            break;
     }
 
     return lRc;
     }
 
     return lRc;
@@ -2038,27 +1967,13 @@ bool wxTextCtrl::SendUpdateEvent()
             return false;
     }
 
             return false;
     }
 
-    wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
-    InitCommandEvent(event);
-
-    return ProcessCommand(event);
+    return SendTextUpdatedEvent();
 }
 
 bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
 {
     switch ( param )
     {
 }
 
 bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
 {
     switch ( param )
     {
-        case EN_SETFOCUS:
-        case EN_KILLFOCUS:
-            {
-                wxFocusEvent event(param == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
-                                                         : wxEVT_SET_FOCUS,
-                                   m_windowId);
-                event.SetEventObject(this);
-                GetEventHandler()->ProcessEvent(event);
-            }
-            break;
-
         case EN_CHANGE:
             SendUpdateEvent();
             break;
         case EN_CHANGE:
             SendUpdateEvent();
             break;
@@ -2074,7 +1989,9 @@ bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
             }
             break;
 
             }
             break;
 
-            // the other edit notification messages are not processed
+            // the other edit notification messages are not processed (or, in
+            // the case of EN_{SET/KILL}FOCUS were already handled at WM_SET/
+            // KILLFOCUS level)
         default:
             return false;
     }
         default:
             return false;
     }
@@ -2127,7 +2044,7 @@ bool wxTextCtrl::AdjustSpaceLimit()
     return true;
 }
 
     return true;
 }
 
-bool wxTextCtrl::AcceptsFocus() const
+bool wxTextCtrl::AcceptsFocusFromKeyboard() const
 {
     // we don't want focus if we can't be edited unless we're a multiline
     // control because then it might be still nice to get focus from keyboard
 {
     // we don't want focus if we can't be edited unless we're a multiline
     // control because then it might be still nice to get focus from keyboard
@@ -2187,15 +2104,12 @@ void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
 
 void wxTextCtrl::OnDelete(wxCommandEvent& WXUNUSED(event))
 {
 
 void wxTextCtrl::OnDelete(wxCommandEvent& WXUNUSED(event))
 {
-    long from, to;
-    GetSelection(& from, & to);
-    if (from != -1 && to != -1)
-        Remove(from, to);
+    RemoveSelection();
 }
 
 void wxTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event))
 {
 }
 
 void wxTextCtrl::OnSelectAll(wxCommandEvent& WXUNUSED(event))
 {
-    SetSelection(-1, -1);
+    SelectAll();
 }
 
 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
 }
 
 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
@@ -2225,14 +2139,12 @@ void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
 
 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent& event)
 {
 
 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent& event)
 {
-    long from, to;
-    GetSelection(& from, & to);
-    event.Enable(from != -1 && to != -1 && from != to && IsEditable()) ;
+    event.Enable( HasSelection() && IsEditable() );
 }
 
 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
 {
 }
 
 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent& event)
 {
-    event.Enable(GetLastPosition() > 0);
+    event.Enable( !IsEmpty() );
 }
 
 void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
 }
 
 void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
@@ -2261,13 +2173,15 @@ void wxTextCtrl::OnContextMenu(wxContextMenuEvent& event)
     event.Skip();
 }
 
     event.Skip();
 }
 
-void wxTextCtrl::OnSetFocus(wxFocusEvent& WXUNUSED(event))
+void wxTextCtrl::OnSetFocus(wxFocusEvent& event)
 {
     // be sure the caret remains invisible if the user had hidden it
     if ( !m_isNativeCaretShown )
     {
         ::HideCaret(GetHwnd());
     }
 {
     // be sure the caret remains invisible if the user had hidden it
     if ( !m_isNativeCaretShown )
     {
         ::HideCaret(GetHwnd());
     }
+
+    event.Skip();
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -2390,6 +2304,22 @@ bool wxTextCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
     return wxTextCtrlBase::MSWOnNotify(idCtrl, lParam, result);
 }
 
     return wxTextCtrlBase::MSWOnNotify(idCtrl, lParam, result);
 }
 
+#if wxUSE_DRAG_AND_DROP
+
+void wxTextCtrl::SetDropTarget(wxDropTarget *dropTarget)
+{
+    if ( m_dropTarget == wxRICHTEXT_DEFAULT_DROPTARGET )
+    {
+        // get rid of the built-in drop target
+        ::RevokeDragDrop(GetHwnd());
+        m_dropTarget = NULL;
+    }
+
+    wxTextCtrlBase::SetDropTarget(dropTarget);
+}
+
+#endif // wxUSE_DRAG_AND_DROP
+
 // ----------------------------------------------------------------------------
 // colour setting for the rich edit controls
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // colour setting for the rich edit controls
 // ----------------------------------------------------------------------------
@@ -2438,8 +2368,6 @@ bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
 // styling support for rich edit controls
 // ----------------------------------------------------------------------------
 
 // styling support for rich edit controls
 // ----------------------------------------------------------------------------
 
-#if wxUSE_RICHEDIT
-
 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
 {
     if ( !IsRich() )
 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
 {
     if ( !IsRich() )
@@ -2477,7 +2405,7 @@ bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
 
     if ( changeSel )
     {
 
     if ( changeSel )
     {
-        DoSetSelection(start, end, false /* don't scroll caret into view */);
+        DoSetSelection(start, end, SetSel_NoScroll);
     }
 
     // initialize CHARFORMAT struct
     }
 
     // initialize CHARFORMAT struct
@@ -2516,9 +2444,12 @@ bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
         // the real height in twips and not the negative number which
         // wxFillLogFont() returns (this is correct in general and works with
         // the Windows font mapper, but not here)
         // the real height in twips and not the negative number which
         // wxFillLogFont() returns (this is correct in general and works with
         // the Windows font mapper, but not here)
+
+        wxFont font(style.GetFont());
+
         LOGFONT lf;
         LOGFONT lf;
-        wxFillLogFont(&lf, &style.GetFont());
-        cf.yHeight = 20*style.GetFont().GetPointSize(); // 1 pt = 20 twips
+        wxFillLogFont(&lf, &font);
+        cf.yHeight = 20*font.GetPointSize(); // 1 pt = 20 twips
         cf.bCharSet = lf.lfCharSet;
         cf.bPitchAndFamily = lf.lfPitchAndFamily;
         wxStrncpy( cf.szFaceName, lf.lfFaceName, WXSIZEOF(cf.szFaceName) );
         cf.bCharSet = lf.lfCharSet;
         cf.bPitchAndFamily = lf.lfPitchAndFamily;
         wxStrncpy( cf.szFaceName, lf.lfFaceName, WXSIZEOF(cf.szFaceName) );
@@ -2655,7 +2586,7 @@ bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
     if ( changeSel )
     {
         // restore the original selection
     if ( changeSel )
     {
         // restore the original selection
-        DoSetSelection(startOld, endOld, false);
+        DoSetSelection(startOld, endOld, SetSel_NoScroll);
     }
 
     return ok;
     }
 
     return ok;
@@ -2718,7 +2649,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
 
     if ( changeSel )
     {
 
     if ( changeSel )
     {
-        DoSetSelection(position, position+1, false /* don't scroll caret into view */);
+        DoSetSelection(position, position + 1, SetSel_NoScroll);
     }
 
     // get the selection formatting
     }
 
     // get the selection formatting
@@ -2818,14 +2749,12 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style)
     if ( changeSel )
     {
         // restore the original selection
     if ( changeSel )
     {
         // restore the original selection
-        DoSetSelection(startOld, endOld, false);
+        DoSetSelection(startOld, endOld, SetSel_NoScroll);
     }
 
     return true;
 }
 
     }
 
     return true;
 }
 
-#endif
-
 // ----------------------------------------------------------------------------
 // wxRichEditModule
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // wxRichEditModule
 // ----------------------------------------------------------------------------
@@ -2905,7 +2834,7 @@ bool wxRichEditModule::LoadInkEdit()
     wxLogNull logNull;
     return ms_inkEditLib.Load(wxT("inked"));
 }
     wxLogNull logNull;
     return ms_inkEditLib.Load(wxT("inked"));
 }
-#endif
+#endif // wxUSE_INKEDIT
 
 
 #endif // wxUSE_RICHEDIT
 
 
 #endif // wxUSE_RICHEDIT