1 // -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
2 /* This file is part of the KDE project
3 Copyright (C) 2004 Esben Mose Hansen <kde@mosehansen.dk>
4 Copyright (C) by Andrew Stanley-Jones
5 Copyright (C) 2000 by Carsten Pfeiffer <pfeiffer@kde.org>
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
23 #include <khelpmenu.h>
24 #include <klineedit.h>
26 #include <kwindowsystem.h>
29 #include "klipperpopup.h"
32 #include "popupproxy.h"
35 static const int TOP_HISTORY_ITEM_INDEX
= 2;
38 // #define DEBUG_EVENTS__
41 kdbgstream
& operator<<( kdbgstream
& stream
, const QKeyEvent
& e
) {
42 stream
<< "(QKeyEvent(text=" << e
.text() << ",key=" << e
.key() << ( e
.isAccepted()?",accepted":",ignored)" ) << ",count=" << e
.count();
43 if ( e
.modifiers() & Qt::AltModifier
) {
46 if ( e
.modifiers() & Qt::ControlModifier
) {
49 if ( e
.modifiers() & Qt::MetaModifier
) {
52 if ( e
.modifiers() & Qt::ShiftModifier
) {
55 if ( e
.isAutoRepeat() ) {
56 stream
<< ",AUTOREPEAT";
65 * Exactly the same as KLineEdit, except that ALL key events are swallowed.
67 * We need this to avoid infinite loop when sending events to the search widget
69 class KLineEditBlackKey
: public KLineEdit
{
71 KLineEditBlackKey( QWidget
* parent
)
75 ~KLineEditBlackKey() {
78 virtual void keyPressEvent( QKeyEvent
* e
) {
79 KLineEdit::keyPressEvent( e
);
86 KlipperPopup::KlipperPopup( History
* history
)
88 m_qsEmpty( i18n( "<empty clipboard>" ) ),
89 m_qsNoMatch( i18n( "<no matches>" ) ),
91 m_helpmenu( new KHelpMenu( this, Klipper::aboutData(), false ) ),
94 m_filterWidgetAction( 0 ),
97 KWindowInfo i
= KWindowSystem::windowInfo( winId(), NET::WMGeometry
);
98 QRect g
= i
.geometry();
99 QRect screen
= KGlobalSettings::desktopGeometry(g
.center());
100 int menu_height
= ( screen
.height() ) * 3/4;
101 int menu_width
= ( screen
.width() ) * 1/3;
103 m_popupProxy
= new PopupProxy( this, menu_height
, menu_width
);
105 connect( this, SIGNAL( aboutToShow() ), SLOT( slotAboutToShow() ) );
108 KlipperPopup::~KlipperPopup() {
112 void KlipperPopup::slotAboutToShow() {
113 if ( m_filterWidget
) {
114 if ( !m_filterWidget
->text().isEmpty() ) {
116 m_filterWidget
->clear();
117 m_filterWidgetAction
->setVisible(false);
124 void KlipperPopup::ensureClean() {
125 // If the history is unchanged since last menu build, the is no reason
133 void KlipperPopup::buildFromScratch() {
134 addTitle(KIcon("klipper"), i18n("Klipper - Clipboard Tool"));
136 m_filterWidget
= new KLineEditBlackKey(this);
137 m_filterWidgetAction
= new QWidgetAction(this);
138 m_filterWidgetAction
->setDefaultWidget(m_filterWidget
);
140 addAction(m_filterWidgetAction
);
141 m_filterWidget
->setFocusPolicy( Qt::NoFocus
);
142 m_filterWidgetAction
->setVisible(false);
144 QListIterator
<QAction
*> i(m_actions
);
145 for (int i
= 0; i
< m_actions
.count(); i
++) {
149 if (i
+ 1 == m_actions
.count()) {
150 addMenu(m_helpmenu
->menu())->setIcon(KIcon("help-contents"));
154 addAction(m_actions
.at(i
));
157 if ( KGlobalSettings::insertTearOffHandle() ) {
158 setTearOffEnabled(true);
163 void KlipperPopup::rebuild( const QString
& filter
) {
164 if (actions().isEmpty()) {
167 for ( int i
=0; i
<m_nHistoryItems
; i
++ ) {
168 Q_ASSERT(TOP_HISTORY_ITEM_INDEX
< actions().count());
169 removeAction(actions().at(TOP_HISTORY_ITEM_INDEX
));
173 QRegExp
filterexp( filter
);
174 QPalette palette
= m_filterWidget
->palette();
175 if ( filterexp
.isValid() ) {
176 palette
.setColor( m_filterWidget
->foregroundRole(), palette
.color(foregroundRole()) );
178 palette
.setColor( m_filterWidget
->foregroundRole(), Qt::red
);
180 m_nHistoryItems
= m_popupProxy
->buildParent( TOP_HISTORY_ITEM_INDEX
, filterexp
);
181 if ( m_nHistoryItems
== 0 ) {
182 if ( m_history
->empty() ) {
183 insertAction(actions().at(TOP_HISTORY_ITEM_INDEX
), new QAction(m_qsEmpty
, this));
185 palette
.setColor( m_filterWidget
->foregroundRole(), Qt::red
);
186 insertAction(actions().at(TOP_HISTORY_ITEM_INDEX
), new QAction(m_qsNoMatch
, this));
190 if ( history()->topIsUserSelected() ) {
191 actions().at(TOP_HISTORY_ITEM_INDEX
)->setCheckable(true);
192 actions().at(TOP_HISTORY_ITEM_INDEX
)->setChecked(true);
195 m_filterWidget
->setPalette( palette
);
199 void KlipperPopup::plugAction( QAction
* action
) {
200 m_actions
.append(action
);
205 void KlipperPopup::keyPressEvent( QKeyEvent
* e
) {
206 // If alt-something is pressed, select a shortcut
207 // from the menu. Do this by sending a keyPress
208 // without the alt-modifier to the superobject.
209 if ( e
->modifiers() & Qt::AltModifier
) {
210 QKeyEvent
ke( QEvent::KeyPress
,
212 e
->modifiers() ^ Qt::AltModifier
,
216 KMenu::keyPressEvent( &ke
);
217 #ifdef DEBUG_EVENTS__
218 kDebug() << "Passing this event to ancestor (KMenu): " << e
<< "->" << ke
;
220 if (ke
.isAccepted()) {
228 // Otherwise, send most events to the search
229 // widget, except a few used for navigation:
230 // These go to the superobject.
237 case Qt::Key_Backtab
:
242 #ifdef DEBUG_EVENTS__
243 kDebug() << "Passing this event to ancestor (KMenu): " << e
;
245 KMenu::keyPressEvent(e
);
246 if (activeAction() == m_filterWidgetAction
)
247 setActiveAction(actions().at(TOP_HISTORY_ITEM_INDEX
));
253 #ifdef DEBUG_EVENTS__
254 kDebug() << "Passing this event down to child (KLineEdit): " << e
;
256 setActiveAction(actions().at(actions().indexOf(m_filterWidgetAction
)));
257 QString lastString
= m_filterWidget
->text();
258 QApplication::sendEvent(m_filterWidget
, e
);
260 if (m_filterWidget
->text().isEmpty()) {
261 if (m_filterWidgetAction
->isVisible())
262 m_filterWidgetAction
->setVisible(false);
264 else if (!m_filterWidgetAction
->isVisible() )
265 m_filterWidgetAction
->setVisible(true);
267 if (m_filterWidget
->text() != lastString
) {
268 slotHistoryChanged();
269 rebuild(m_filterWidget
->text());
277 #include "klipperpopup.moc"