[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-core-devel
Subject:    [PATCH] Show the clipboard history when pressing the Paste button
From:       Andras Mantia <amantia () kde ! org>
Date:       2003-09-22 9:28:22
[Download RAW message or body]

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

  Here is an implementation of Datschge's idea: provide a list of the 
clipboard history under the Paste button (similar to the history in 
Konqueror). This is a generic implementation and by applying the patch every 
application will benefit of it without any change. It creates a new action 
class (KPasteAction) which communicates with Klipper via dcop. Of course 
there is no guarantee that Klipper is running, in that case the button works 
like before, and the only item in the menu is the current clipboard content. 
So the patch contains the KPasteAction class (the code could be simplified in 
KDE 4.0 if we inherit from KToolBarPopupAction and make the popupMenu() 
method virtual) and a change in the KStdAction, so for Paste this class will 
be used. 
 I have only one problem with it that I couldn't solve cleanly: when a menu 
item is selected, I change the clipboard with a DCOP call, but the clipboard 
isn't changed immediately (see the debug output) and I have to use a 
singleShot timer to send the "activated" signal. Otherwise the selected text 
won't be pasted. I'm afraid a little about this issue as there may still be 
cases when the timer is elapsed before the clipboard is set. Any better ideas 
here? Setting the clipboard directly does not work and I get 
"QClipboard::setData: Cannot set X11 selection owner for CLIPBOARD" in the 
debug output.

Andras


- -- 
Quanta Plus developer - http://quanta.sourceforge.net
K Desktop Environment - http://www.kde.org
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2-rc1-SuSE (GNU/Linux)

iD8DBQE/bsC2TQdfac6L/08RAtqbAKCpC12OcWzWlsS0Muz5H7gdDwUEEwCdEIfW
uxM6g4ZMANw4ZHsxQU6Zf8E=
=CSCW
-----END PGP SIGNATURE-----

["kactionclasses.cpp.diff" (text/x-diff)]

--- kactionclasses.cpp.orig	2003-09-21 13:14:40.000000000 +0300
+++ kactionclasses.cpp	2003-09-22 12:14:40.000000000 +0300
@@ -27,11 +27,15 @@
 
 #include <assert.h>
 
+#include <qcstring.h>
+#include <qclipboard.h>
+#include <qdatastream.h>
 #include <qfontdatabase.h>
 #include <qobjectlist.h>
 #include <qwhatsthis.h>
 #include <qtimer.h>
 
+#include <dcopclient.h>
 #include <kaccel.h>
 #include <kapplication.h>
 #include <kconfig.h>
@@ -1976,6 +2052,116 @@
   return -1;
 }
 
+KPasteAction::KPasteAction( const QString& text,
+                            const QString& icon,
+                            const KShortcut& cut,
+                            const QObject* receiver,
+                            const char* slot, QObject* parent,
+                            const char* name)
+  : KAction( text, icon, cut, receiver, slot, parent, name )
+{  
+  m_popup = new KPopupMenu;
+  connect(m_popup, SIGNAL(aboutToShow()), this, SLOT(menuAboutToShow()));
+  connect(m_popup, SIGNAL(activated(int)), this, SLOT(menuItemActivated(int)));  
+  m_popup->setCheckable(true);
+}            
+
+KPasteAction::~KPasteAction()
+{
+}    
+
+int KPasteAction::plug( QWidget *widget, int index )
+{
+  if (kapp && !kapp->authorizeKAction(name()))
+    return -1;
+  // This is very related to KActionMenu::plug.
+  // In fact this class could be an interesting base class for KActionMenu
+  if ( widget->inherits( "KToolBar" ) )
+  {
+    KToolBar *bar = (KToolBar *)widget;
+
+    int id_ = KAction::getToolButtonID();
+
+    KInstance * instance;
+    if ( m_parentCollection )
+        instance = m_parentCollection->instance();
+    else
+        instance = KGlobal::instance();
+
+    bar->insertButton( icon(), id_, SIGNAL( clicked() ), this,
+                       SLOT( slotActivated() ), isEnabled(), plainText(),
+                       index, instance );
+
+    addContainer( bar, id_ );
+
+    connect( bar, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
+
+    bar->setDelayedPopup( id_, m_popup, true );
+
+    if ( !whatsThis().isEmpty() )
+        QWhatsThis::add( bar->getButton( id_ ), whatsThisWithIcon() );
+
+    return containerCount() - 1;
+  }
+
+  return KAction::plug( widget, index );
+}
+     
+void KPasteAction::menuAboutToShow()
+{
+    m_popup->clear();
+    QStringList list;
+    DCOPClient *client = kapp->dcopClient();
+    if (!client->isAttached()) {    
+      (client->attach());
+    }  
+    if (client->isAttached()){
+        if (client->isApplicationRegistered("klipper")) {
+          QByteArray data;
+          QCString replyType;
+          QByteArray replyData;
+          if (client->call("klipper", "klipper", "getClipboardHistoryMenu()", data, \
replyType, replyData, false, 100)) { +            QDataStream replyStream(replyData, \
IO_ReadOnly); +            replyStream >> list;
+          }
+        }
+    }
+    QString clipboardText = qApp->clipboard()->text(QClipboard::Clipboard);
+    if (list.isEmpty())
+        list << clipboardText;
+    bool found = false;        
+    for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) 
+    {
+      int id = m_popup->insertItem(*it);
+      if (!found && *it == clipboardText)
+      {
+        m_popup->setItemChecked(id, true);
+        found = true;
+      }
+    }
+}
+
+void KPasteAction::menuItemActivated( int id)
+{
+    DCOPClient *client = kapp->dcopClient();
+    if (!client->isAttached()) {    
+      (client->attach());
+    }  
+    if (client->isAttached()){
+         if (client->isApplicationRegistered("klipper")) {
+           QByteArray data;
+           QDataStream arg(data, IO_WriteOnly);
+           arg << m_popup->text(id);
+           QCString replyType;
+           QByteArray replyData;
+           if (client->send("klipper", "klipper", "setClipboardContents(QString)", \
data)) { +             kdDebug(129) << "Clipboard: " << \
qApp->clipboard()->text(QClipboard::Clipboard) << endl; +           }
+         }
+      }
+    QTimer::singleShot(20, this, SLOT(slotActivated())); 
+}
+
 void KToggleAction::virtual_hook( int id, void* data )
 { KAction::virtual_hook( id, data ); }
 


["kstdaction.cpp.patch" (text/x-diff)]

--- kstdaction.cpp.orig	2003-09-22 10:00:26.000000000 +0300
+++ kstdaction.cpp	2003-09-22 10:41:43.000000000 +0300
@@ -105,6 +105,15 @@
 			pAction = ret;
 			break;
 		 }
+         case Paste:
+         {
+            KPasteAction *ret;
+            ret = new KPasteAction(sLabel, iconName, cut,
+					recvr, slot,
+					parent, (name) ? name : pInfo->psName );
+            pAction = ret;
+            break;        
+         }
 		 default:
 			pAction = new KAction( sLabel, iconName, cut,
 					recvr, slot,

["kactionclasses.h.diff" (text/x-diff)]

--- kactionclasses.h.orig	2003-09-07 23:47:30.000000000 +0300
+++ kactionclasses.h	2003-09-22 11:10:38.000000000 +0300
@@ -1241,4 +1253,39 @@
     KActionSeparatorPrivate *d;
 };
 
+class KPasteAction: public KAction
+{
+    Q_OBJECT
+public:
+    /**
+     * Create a KPasteAction, with a text, an icon, an accelerator,
+     * a slot connected to the action, parent and name.
+     *
+     * If you do not want or have a keyboard accelerator, set the
+     * @p cut param to 0.
+     *
+     * @param text The text that will be displayed.
+     * @param icon The icon to display.
+     * @param cut The corresponding keyboard accelerator (shortcut).
+     * @param receiver The SLOT's owner.
+     * @param slot The SLOT to invoke to execute this action.
+     * @param parent This action's parent.
+     * @param name An internal name for this action.
+     */
+    KPasteAction( const QString& text, const QString& icon, const KShortcut& cut,
+                  const QObject* receiver, const char* slot,
+                  QObject* parent = 0, const char* name = 0 );
+    
+    virtual ~KPasteAction();
+    virtual int plug( QWidget *widget, int index = -1 );
+    
+protected slots:
+    void menuAboutToShow();
+    void menuItemActivated( int id);
+
+private:
+    KPopupMenu *m_popup;
+    class KPasteActionPrivate;
+    KPasteActionPrivate *d;
+};
 #endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic