From kde-core-devel Mon Sep 22 09:28:22 2003 From: Andras Mantia Date: Mon, 22 Sep 2003 09:28:22 +0000 To: kde-core-devel Subject: [PATCH] Show the clipboard history when pressing the Paste button X-MARC-Message: https://marc.info/?l=kde-core-devel&m=106422310613039 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_2Csb/u8g+4yF85O" --Boundary-00=_2Csb/u8g+4yF85O Content-Type: Text/Plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline =2D----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, Here is an implementation of Datschge's idea: provide a list of the=20 clipboard history under the Paste button (similar to the history in=20 Konqueror). This is a generic implementation and by applying the patch ever= y=20 application will benefit of it without any change. It creates a new action= =20 class (KPasteAction) which communicates with Klipper via dcop. Of course=20 there is no guarantee that Klipper is running, in that case the button work= s=20 like before, and the only item in the menu is the current clipboard content= =2E=20 So the patch contains the KPasteAction class (the code could be simplified = in=20 KDE 4.0 if we inherit from KToolBarPopupAction and make the popupMenu()=20 method virtual) and a change in the KStdAction, so for Paste this class wil= l=20 be used.=20 I have only one problem with it that I couldn't solve cleanly: when a menu= =20 item is selected, I change the clipboard with a DCOP call, but the clipboar= d=20 isn't changed immediately (see the debug output) and I have to use a=20 singleShot timer to send the "activated" signal. Otherwise the selected tex= t=20 won't be pasted. I'm afraid a little about this issue as there may still be= =20 cases when the timer is elapsed before the clipboard is set. Any better ide= as=20 here? Setting the clipboard directly does not work and I get=20 "QClipboard::setData: Cannot set X11 selection owner for CLIPBOARD" in the= =20 debug output. Andras =2D --=20 Quanta Plus developer - http://quanta.sourceforge.net K Desktop Environment - http://www.kde.org =2D----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2-rc1-SuSE (GNU/Linux) iD8DBQE/bsC2TQdfac6L/08RAtqbAKCpC12OcWzWlsS0Muz5H7gdDwUEEwCdEIfW uxM6g4ZMANw4ZHsxQU6Zf8E=3D =3DCSCW =2D----END PGP SIGNATURE----- --Boundary-00=_2Csb/u8g+4yF85O Content-Type: text/x-diff; charset="us-ascii"; name="kactionclasses.cpp.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kactionclasses.cpp.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 +#include +#include +#include #include #include #include #include +#include #include #include #include @@ -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 ); } --Boundary-00=_2Csb/u8g+4yF85O Content-Type: text/x-diff; charset="us-ascii"; name="kstdaction.cpp.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kstdaction.cpp.patch" --- 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, --Boundary-00=_2Csb/u8g+4yF85O Content-Type: text/x-diff; charset="us-ascii"; name="kactionclasses.h.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kactionclasses.h.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 --Boundary-00=_2Csb/u8g+4yF85O--