From 78c91815008ef5888231c6c7f3678872e9e35ff6 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Fri, 12 May 2006 15:21:41 +0000
Subject: [PATCH] added clipboard events (wxEVT_COMMAND_TEXT_COPY/CUT/PASTE)
 and implemented them for wxMSW

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39141 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/category.tex  |  1 +
 docs/latex/wx/classes.tex   |  1 +
 docs/latex/wx/clipevent.tex | 84 +++++++++++++++++++++++++++++++++++++
 include/wx/event.h          | 41 ++++++++++++++++++
 include/wx/msw/window.h     |  2 +
 samples/text/text.cpp       | 59 +++++++++++++++++++++++++-
 src/common/event.cpp        |  6 +++
 src/msw/combobox.cpp        |  7 ++++
 src/msw/textctrl.cpp        | 42 +++++++++++++++++++
 src/msw/window.cpp          | 12 ++++++
 10 files changed, 253 insertions(+), 2 deletions(-)
 create mode 100644 docs/latex/wx/clipevent.tex

diff --git a/docs/latex/wx/category.tex b/docs/latex/wx/category.tex
index f1ae1587ba..3c5d54fba5 100644
--- a/docs/latex/wx/category.tex
+++ b/docs/latex/wx/category.tex
@@ -218,6 +218,7 @@ An event object contains information about a specific event. Event handlers
 \twocolitem{\helpref{wxActivateEvent}{wxactivateevent}}{A window or application activation event}
 \twocolitem{\helpref{wxCalendarEvent}{wxcalendarevent}}{Used with \helpref{wxCalendarCtrl}{wxcalendarctrl}}
 \twocolitem{\helpref{wxCalculateLayoutEvent}{wxcalculatelayoutevent}}{Used to calculate window layout}
+\twocolitem{\helpref{wxClipboardTextEvent}{wxclipboardtextevent}}{A clipboard copy/cut/paste treebook event event}
 \twocolitem{\helpref{wxCloseEvent}{wxcloseevent}}{A close window or end session event}
 \twocolitem{\helpref{wxCommandEvent}{wxcommandevent}}{An event from a variety of standard controls}
 \twocolitem{\helpref{wxContextMenuEvent}{wxcontextmenuevent}}{An event generated when the user issues a context menu command}
diff --git a/docs/latex/wx/classes.tex b/docs/latex/wx/classes.tex
index 7dc6aff273..93257fe33a 100644
--- a/docs/latex/wx/classes.tex
+++ b/docs/latex/wx/classes.tex
@@ -39,6 +39,7 @@
 \input clientdc.tex
 \input clientdat.tex
 \input clipbrd.tex
+\input clipevent.tex
 \input closeevt.tex
 \input cmdlpars.tex
 \input colour.tex
diff --git a/docs/latex/wx/clipevent.tex b/docs/latex/wx/clipevent.tex
new file mode 100644
index 0000000000..de6e3ba0eb
--- /dev/null
+++ b/docs/latex/wx/clipevent.tex
@@ -0,0 +1,84 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Name:        clipevent.tex
+%% Purpose:     wxClipboardTextEvent documentation
+%% Author:      Evgeniy Tarassov, Vadim Zeitlin
+%% Modified by:
+%% Created:     2005-10-04
+%% RCS-ID:      $Id$
+%% Copyright:   (c) 2006 Vadim Zeitlin <vadim@wxwindows.org>
+%% License:     wxWindows license
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{\class{wxClipboardTextEvent}}\label{wxclipboardtextevent}
+
+This class represents the events generated by a control (typically a 
+\helpref{wxTextCtrl}{wxtextctrl} but other windows can generate these events as
+well) when its content gets copied or cut to, or pasted from the clipboard.
+There are three types of corresponding events wxEVT\_COMMAND\_TEXT\_COPY,
+wxEVT\_COMMAND\_TEXT\_CUT and wxEVT\_COMMAND\_TEXT\_PASTE.
+
+If any of these events is processed (without being skipped) by an event
+handler, the corresponding operation doesn't take place which allows to prevent
+the text from being copied from or pasted to a control. It is also possible to
+examine the clipboard contents in the PASTE event handler and transform it in
+some way before inserting in a control -- for example, changing its case or
+removing invalid characters.
+
+Finally notice that a CUT event is always preceded by the COPY event which
+makes it possible to only process the latter if it doesn't matter if the text
+was copied or cut.
+
+\wxheading{Remarks}
+
+These events are currently only generated by \helpref{wxComboBox}{wxcombobox} and
+under Windows and \helpref{wxTextCtrl}{wxtextctrl} under Windows and GTK and
+are not generated for the text controls with \texttt{wxTE\_RICH} style under
+Windows.
+
+
+\wxheading{Derived from}
+
+\helpref{wxCommandEvent}{wxcommandevent}\\
+\helpref{wxEvent}{wxevent}\\
+\helpref{wxObject}{wxobject}
+
+
+
+\wxheading{Include files}
+
+<wx/event.h>
+
+
+
+\wxheading{Event handling}
+
+To process this type of events use the following event handling macros. The
+\arg{func} parameter must be a member functions that takes an argument of type
+\texttt{wxClipboardTextEvent \&}.
+
+\twocolwidtha{10cm}
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf EVT\_TEXT\_COPY(id, func)}}{Some or all of the controls
+content was copied to the clipboard.}
+\twocolitem{{\bf EVT\_TEXT\_CUT(id, func)}}{Some or all of the controls content
+was cut (i.e. copied and deleted).}
+\twocolitem{{\bf EVT\_TEXT\_PASTE(id, func)}}{Clipboard content was pasted into
+the control.}
+\end{twocollist}
+
+
+
+\wxheading{See also}
+
+\helpref{wxClipboard}{wxclipboard}
+
+
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxClipboardTextEvent::wxClipboardTextEvent}\label{wxclipboardtexteventwxclipboardtextevent}
+
+\func{}{wxClipboardTextEvent}{\param{wxEventType }{commandType = wxEVT\_NULL}, \param{int }{id = 0}}
+
+
diff --git a/include/wx/event.h b/include/wx/event.h
index 909ffbc405..acdf448c41 100644
--- a/include/wx/event.h
+++ b/include/wx/event.h
@@ -267,6 +267,11 @@ BEGIN_DECLARE_EVENT_TYPES()
     DECLARE_EVENT_TYPE(wxEVT_MOVING, 442)
     DECLARE_EVENT_TYPE(wxEVT_HIBERNATE, 443)
 
+        // Clipboard events
+    DECLARE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY, 444)
+    DECLARE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT, 445)
+    DECLARE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE, 446)
+
         // Generic command events
         // Note: a click is a higher-level event than button down/up
     DECLARE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK, 500)
@@ -2014,6 +2019,34 @@ private:
     DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxHelpEvent)
 };
 
+// A Clipboard Text event is sent when a window intercepts text copy/cut/paste
+// message, i.e. the user has cut/copied/pasted data from/into a text control
+// via ctrl-C/X/V, ctrl/shift-del/insert, a popup menu command, etc.
+// NOTE : under windows these events are *NOT* generated automatically
+// for a Rich Edit text control.
+/*
+wxEVT_COMMAND_TEXT_COPY
+wxEVT_COMMAND_TEXT_CUT
+wxEVT_COMMAND_TEXT_PASTE
+*/
+
+class WXDLLIMPEXP_CORE wxClipboardTextEvent : public wxCommandEvent
+{
+public:
+    wxClipboardTextEvent(wxEventType type = wxEVT_NULL,
+                     wxWindowID winid = 0)
+        : wxCommandEvent(type, winid)
+    { }
+    wxClipboardTextEvent(const wxClipboardTextEvent & event)
+        : wxCommandEvent(event)
+    { }
+
+    virtual wxEvent *Clone() const { return new wxClipboardTextEvent(*this); }
+
+private:
+    DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxClipboardTextEvent)
+};
+
 // A Context event is sent when the user right clicks on a window or
 // presses Shift-F10
 // NOTE : Under windows this is a repackaged WM_CONTETXMENU message
@@ -2531,6 +2564,7 @@ typedef void (wxEvtHandler::*wxNotifyEventFunction)(wxNotifyEvent&);
 typedef void (wxEvtHandler::*wxHelpEventFunction)(wxHelpEvent&);
 typedef void (wxEvtHandler::*wxContextMenuEventFunction)(wxContextMenuEvent&);
 typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureChangedEvent&);
+typedef void (wxEvtHandler::*wxClipboardTextEventFunction)(wxClipboardTextEvent&);
 
 // these typedefs don't have the same name structure as the others, keep for
 // backwards compatibility only
@@ -2611,6 +2645,8 @@ typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureC
     (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxContextMenuEventFunction, &func)
 #define wxMouseCaptureChangedEventHandler(func) \
     (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxMouseCaptureChangedEventFunction, &func)
+#define wxClipboardTextEventHandler(func) \
+    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxClipboardTextEventFunction, &func)
 
 #endif // wxUSE_GUI
 
@@ -3002,6 +3038,11 @@ typedef void (wxEvtHandler::*wxMouseCaptureChangedEventFunction)(wxMouseCaptureC
 #define EVT_CONTEXT_MENU(func) wx__DECLARE_EVT0(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(func))
 #define EVT_COMMAND_CONTEXT_MENU(winid, func) wx__DECLARE_EVT1(wxEVT_CONTEXT_MENU, winid, wxContextMenuEventHandler(func))
 
+// Clipboard text Events
+#define EVT_TEXT_CUT(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_CUT, winid, wxClipboardTextEventHandler(func))
+#define EVT_TEXT_COPY(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_COPY, winid, wxClipboardTextEventHandler(func))
+#define EVT_TEXT_PASTE(winid, func) wx__DECLARE_EVT1(wxEVT_COMMAND_TEXT_PASTE, winid, wxClipboardTextEventHandler(func))
+
 // ----------------------------------------------------------------------------
 // Global data
 // ----------------------------------------------------------------------------
diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h
index b69eecbabc..d9c3e215ad 100644
--- a/include/wx/msw/window.h
+++ b/include/wx/msw/window.h
@@ -332,6 +332,8 @@ public:
 #ifdef __WIN32__
     int HandleMenuChar(int chAccel, WXLPARAM lParam);
 #endif
+    // Create and process a clipboard event specified by type.
+    bool HandleClipboardEvent( WXUINT nMsg );
 
     bool HandleQueryDragIcon(WXHICON *hIcon);
 
diff --git a/samples/text/text.cpp b/samples/text/text.cpp
index 9fda9d9c2d..fe76bd993f 100644
--- a/samples/text/text.cpp
+++ b/samples/text/text.cpp
@@ -75,6 +75,10 @@ public:
     void OnTextURL(wxTextUrlEvent& event);
     void OnTextMaxLen(wxCommandEvent& event);
 
+    void OnTextCut(wxClipboardTextEvent & event);
+    void OnTextCopy(wxClipboardTextEvent & event);
+    void OnTextPaste(wxClipboardTextEvent & event);
+
     void OnMouseEvent(wxMouseEvent& event);
 
     void OnSetFocus(wxFocusEvent& event);
@@ -85,10 +89,13 @@ public:
     static bool ms_logMouse;
     static bool ms_logText;
     static bool ms_logFocus;
+    static bool ms_logClip;
 
 private:
     static inline wxChar GetChar(bool on, wxChar c) { return on ? c : _T('-'); }
+
     void LogKeyEvent(const wxChar *name, wxKeyEvent& event) const;
+    void LogClipEvent(const wxChar *what, wxClipboardTextEvent& event);
 
     bool m_hasCapture;
 
@@ -282,6 +289,11 @@ public:
         MyTextCtrl::ms_logFocus = event.IsChecked();
     }
 
+    void OnLogClip(wxCommandEvent& event)
+    {
+        MyTextCtrl::ms_logClip = event.IsChecked();
+    }
+
     void OnSetText(wxCommandEvent& WXUNUSED(event))
     {
         m_panel->m_text->SetValue(_T("Hello, world (what else did you expect)?"));
@@ -366,6 +378,7 @@ enum
     // clipboard menu
     TEXT_CLIPBOARD_COPY = 200,
     TEXT_CLIPBOARD_PASTE,
+    TEXT_CLIPBOARD_VETO,
 
     // tooltip menu
     TEXT_TOOLTIPS_SETDELAY = 300,
@@ -397,6 +410,7 @@ enum
     TEXT_LOG_MOUSE,
     TEXT_LOG_TEXT,
     TEXT_LOG_FOCUS,
+    TEXT_LOG_CLIP,
 
     TEXT_END
 };
@@ -441,6 +455,9 @@ bool MyApp::OnInit()
                           _T("Copy the selection to the clipboard"));
     menuClipboard->Append(TEXT_CLIPBOARD_PASTE, _T("&Paste\tCtrl-Shift-V"),
                           _T("Paste from clipboard to the text control"));
+    menuClipboard->AppendSeparator();
+    menuClipboard->AppendCheckItem(TEXT_CLIPBOARD_VETO, _T("Vet&o\tCtrl-Shift-O"),
+                                   _T("Veto all clipboard operations"));
     menu_bar->Append(menuClipboard, _T("&Clipboard"));
 #endif // wxUSE_CLIPBOARD
 
@@ -475,13 +492,13 @@ bool MyApp::OnInit()
     menuLog->AppendCheckItem(TEXT_LOG_MOUSE, _T("Log &mouse events"));
     menuLog->AppendCheckItem(TEXT_LOG_TEXT, _T("Log &text events"));
     menuLog->AppendCheckItem(TEXT_LOG_FOCUS, _T("Log &focus events"));
+    menuLog->AppendCheckItem(TEXT_LOG_CLIP, _T("Log clip&board events"));
     menuLog->AppendSeparator();
     menuLog->Append(TEXT_CLEAR, _T("&Clear the log\tCtrl-L"),
                     _T("Clear the log window contents"));
 
     // select only the interesting events by default
-    MyTextCtrl::ms_logKey =
-    MyTextCtrl::ms_logChar = false;
+    MyTextCtrl::ms_logClip =
     MyTextCtrl::ms_logText = true;
 
     menuLog->Check(TEXT_LOG_KEY, MyTextCtrl::ms_logKey);
@@ -514,6 +531,9 @@ BEGIN_EVENT_TABLE(MyTextCtrl, wxTextCtrl)
     EVT_TEXT_ENTER(wxID_ANY, MyTextCtrl::OnTextEnter)
     EVT_TEXT_URL(wxID_ANY, MyTextCtrl::OnTextURL)
     EVT_TEXT_MAXLEN(wxID_ANY, MyTextCtrl::OnTextMaxLen)
+    EVT_TEXT_CUT(wxID_ANY,   MyTextCtrl::OnTextCut)
+    EVT_TEXT_COPY(wxID_ANY,  MyTextCtrl::OnTextCopy)
+    EVT_TEXT_PASTE(wxID_ANY, MyTextCtrl::OnTextPaste)
 
     EVT_MOUSE_EVENTS(MyTextCtrl::OnMouseEvent)
 
@@ -526,6 +546,7 @@ bool MyTextCtrl::ms_logChar = false;
 bool MyTextCtrl::ms_logMouse = false;
 bool MyTextCtrl::ms_logText = false;
 bool MyTextCtrl::ms_logFocus = false;
+bool MyTextCtrl::ms_logClip = false;
 
 void MyTextCtrl::LogKeyEvent(const wxChar *name, wxKeyEvent& event) const
 {
@@ -795,6 +816,39 @@ void MyTextCtrl::OnTextMaxLen(wxCommandEvent& WXUNUSED(event))
     wxLogMessage(_T("You can't enter more characters into this control."));
 }
 
+
+void MyTextCtrl::OnTextCut(wxClipboardTextEvent& event)
+{
+    LogClipEvent(_T("cut to"), event);
+}
+
+void MyTextCtrl::OnTextCopy(wxClipboardTextEvent& event)
+{
+    LogClipEvent(_T("copied to"), event);
+}
+
+void MyTextCtrl::OnTextPaste(wxClipboardTextEvent& event)
+{
+    LogClipEvent(_T("pasted from"), event);
+}
+
+void MyTextCtrl::LogClipEvent(const wxChar *what, wxClipboardTextEvent& event)
+{
+    wxFrame *frame = wxDynamicCast(wxGetTopLevelParent(this), wxFrame);
+    wxCHECK_RET( frame, _T("no parent frame?") );
+
+    const bool veto = frame->GetMenuBar()->IsChecked(TEXT_CLIPBOARD_VETO);
+    if ( !veto )
+        event.Skip();
+
+    if ( ms_logClip )
+    {
+        wxLogMessage(_T("Text %s%s the clipboard."),
+                     veto ? _T("not ") : _T(""), what);
+    }
+}
+
+
 void MyTextCtrl::OnTextURL(wxTextUrlEvent& event)
 {
     const wxMouseEvent& ev = event.GetMouseEvent();
@@ -1237,6 +1291,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
     EVT_MENU(TEXT_LOG_MOUSE,MyFrame::OnLogMouse)
     EVT_MENU(TEXT_LOG_TEXT, MyFrame::OnLogText)
     EVT_MENU(TEXT_LOG_FOCUS,MyFrame::OnLogFocus)
+    EVT_MENU(TEXT_LOG_CLIP, MyFrame::OnLogClip)
 #if wxUSE_LOG
     EVT_MENU(TEXT_CLEAR,    MyFrame::OnLogClear)
 #endif // wxUSE_LOG
diff --git a/src/common/event.cpp b/src/common/event.cpp
index 9debc5b90a..f200ea664c 100644
--- a/src/common/event.cpp
+++ b/src/common/event.cpp
@@ -92,6 +92,7 @@
     IMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent)
     IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent)
+    IMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent)
 #endif // wxUSE_GUI
 
 #if wxUSE_BASE
@@ -288,6 +289,11 @@ DEFINE_EVENT_TYPE(wxEVT_COMPARE_ITEM)
 DEFINE_EVENT_TYPE(wxEVT_INIT_DIALOG)
 DEFINE_EVENT_TYPE(wxEVT_UPDATE_UI)
 
+// Clipboard events
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE)
+
 // Generic command events
 // Note: a click is a higher-level event than button down/up
 DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK)
diff --git a/src/msw/combobox.cpp b/src/msw/combobox.cpp
index 61908d5fdc..18c6b0da34 100644
--- a/src/msw/combobox.cpp
+++ b/src/msw/combobox.cpp
@@ -207,6 +207,13 @@ LRESULT APIENTRY _EXPORT wxComboEditWndProc(HWND hWnd,
                 }
             }
             break;
+
+        case WM_CUT:
+        case WM_COPY:
+        case WM_PASTE:
+            if( win->HandleClipboardEvent( message ) )
+                return 0;
+            break;
     }
 
     return ::CallWindowProc(CASTWNDPROC gs_wndprocEdit, hWnd, message, wParam, lParam);
diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp
index c2c88e5525..4230d68033 100644
--- a/src/msw/textctrl.cpp
+++ b/src/msw/textctrl.cpp
@@ -258,10 +258,49 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus)
 END_EVENT_TABLE()
 
+// ----------------------------------------------------------------------------
+// function prototypes
+// ----------------------------------------------------------------------------
+
+LRESULT APIENTRY _EXPORT wxTextCtrlWndProc(HWND hWnd,
+                                           UINT message,
+                                           WPARAM wParam,
+                                           LPARAM lParam);
+
+// ---------------------------------------------------------------------------
+// global vars
+// ---------------------------------------------------------------------------
+
+// the pointer to standard text control wnd proc
+static WNDPROC gs_wndprocEdit = (WNDPROC)NULL;
+
 // ============================================================================
 // implementation
 // ============================================================================
 
+// ----------------------------------------------------------------------------
+// wnd proc for subclassed edit control
+// ----------------------------------------------------------------------------
+
+LRESULT APIENTRY _EXPORT wxTextCtrlWndProc(HWND hWnd,
+                                           UINT message,
+                                           WPARAM wParam,
+                                           LPARAM lParam)
+{
+    wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
+
+    switch ( message )
+    {
+        case WM_CUT:
+        case WM_COPY:
+        case WM_PASTE:
+            if( win->HandleClipboardEvent( message ) )
+                return 0;
+            break;
+    }
+    return ::CallWindowProc(CASTWNDPROC gs_wndprocEdit, hWnd, message, wParam, lParam);
+}
+
 // ----------------------------------------------------------------------------
 // creation
 // ----------------------------------------------------------------------------
@@ -479,6 +518,9 @@ bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
     }
 #endif // wxUSE_RICHEDIT
 
+    gs_wndprocEdit = wxSetWindowProc((HWND)GetHwnd(),
+                                     wxTextCtrlWndProc);
+
     return true;
 }
 
diff --git a/src/msw/window.cpp b/src/msw/window.cpp
index 7e6640eb42..28985957c0 100644
--- a/src/msw/window.cpp
+++ b/src/msw/window.cpp
@@ -5053,6 +5053,18 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
     return wxNOT_FOUND;
 }
 
+bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg )
+{
+    const wxEventType type = ( nMsg == WM_CUT ) ? wxEVT_COMMAND_TEXT_CUT :
+                             ( nMsg == WM_COPY ) ? wxEVT_COMMAND_TEXT_COPY :
+                           /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE;
+    wxClipboardTextEvent evt(type, GetId());
+
+    evt.SetEventObject(this);
+
+    return GetEventHandler()->ProcessEvent(evt);
+}
+
 // ---------------------------------------------------------------------------
 // joystick
 // ---------------------------------------------------------------------------
-- 
2.50.0

