Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / klipper / klipperpopup.cpp
blob817d2f0e1f8a9c3baea164c1513a531da2729f95
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>
25 #include <klocale.h>
26 #include <kwindowsystem.h>
27 #include <kdebug.h>
29 #include "klipperpopup.h"
30 #include "history.h"
31 #include "klipper.h"
32 #include "popupproxy.h"
34 namespace {
35 static const int TOP_HISTORY_ITEM_INDEX = 2;
38 // #define DEBUG_EVENTS__
40 #ifdef 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 ) {
44 stream << ",ALT";
46 if ( e.modifiers() & Qt::ControlModifier ) {
47 stream << ",CTRL";
49 if ( e.modifiers() & Qt::MetaModifier ) {
50 stream << ",META";
52 if ( e.modifiers() & Qt::ShiftModifier ) {
53 stream << ",SHIFT";
55 if ( e.isAutoRepeat() ) {
56 stream << ",AUTOREPEAT";
58 stream << ")";
60 return stream;
62 #endif
64 /**
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 {
70 public:
71 KLineEditBlackKey( QWidget* parent )
72 : KLineEdit( parent )
75 ~KLineEditBlackKey() {
77 protected:
78 virtual void keyPressEvent( QKeyEvent* e ) {
79 KLineEdit::keyPressEvent( e );
80 e->accept();
86 KlipperPopup::KlipperPopup( History* history )
87 : m_dirty( true ),
88 QSempty( i18n( "<empty clipboard>" ) ),
89 QSnomatch( i18n( "<no matches>" ) ),
90 m_history( history ),
91 helpmenu( new KHelpMenu( this, Klipper::aboutData(), false ) ),
92 m_popupProxy( 0 ),
93 m_filterWidget( 0 ),
94 m_filterWidgetAction( 0 ),
95 n_history_items( 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() ) {
115 m_dirty = true;
116 m_filterWidget->clear();
117 m_filterWidgetAction->setVisible(false);
120 ensureClean();
124 void KlipperPopup::ensureClean() {
125 // If the history is unchanged since last menu build, the is no reason
126 // to rebuild it,
127 if ( m_dirty ) {
128 rebuild();
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++) {
146 if (i == 0)
147 addSeparator();
149 if (i + 1 == m_actions.count()) {
150 addMenu(helpmenu->menu())->setIcon(KIcon("help-contents"));
151 addSeparator();
154 addAction(m_actions.at(i));
157 if ( KGlobalSettings::insertTearOffHandle() ) {
158 setTearOffEnabled(true);
163 void KlipperPopup::rebuild( const QString& filter ) {
164 if (actions().isEmpty()) {
165 buildFromScratch();
166 } else {
167 for ( int i=0; i<n_history_items; i++ ) {
168 if (i < 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()) );
177 } else {
178 palette.setColor( m_filterWidget->foregroundRole(), Qt::red );
180 n_history_items = m_popupProxy->buildParent( TOP_HISTORY_ITEM_INDEX, filterexp );
181 if ( n_history_items == 0 ) {
182 if ( m_history->empty() ) {
183 insertAction(actions().at(TOP_HISTORY_ITEM_INDEX), new QAction(QSempty, this));
184 } else {
185 palette.setColor( m_filterWidget->foregroundRole(), Qt::red );
186 insertAction(actions().at(TOP_HISTORY_ITEM_INDEX), new QAction(QSnomatch, this));
188 n_history_items++;
189 } else {
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 );
196 m_dirty = false;
199 void KlipperPopup::plugAction( QAction* action ) {
200 m_actions.append(action);
204 /* virtual */
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,
211 e->key(),
212 e->modifiers() ^ Qt::AltModifier,
213 e->text(),
214 e->isAutoRepeat(),
215 e->count() );
216 KMenu::keyPressEvent( &ke );
217 #ifdef DEBUG_EVENTS__
218 kDebug() << "Passing this event to ancestor (KMenu): " << e << "->" << ke;
219 #endif
220 if (ke.isAccepted()) {
221 e->accept();
222 return;
223 } else {
224 e->ignore();
228 // Otherwise, send most events to the search
229 // widget, except a few used for navigation:
230 // These go to the superobject.
231 switch( e->key() ) {
232 case Qt::Key_Up:
233 case Qt::Key_Down:
234 case Qt::Key_Right:
235 case Qt::Key_Left:
236 case Qt::Key_Tab:
237 case Qt::Key_Backtab:
238 case Qt::Key_Escape:
239 case Qt::Key_Return:
240 case Qt::Key_Enter:
242 #ifdef DEBUG_EVENTS__
243 kDebug() << "Passing this event to ancestor (KMenu): " << e;
244 #endif
245 KMenu::keyPressEvent(e);
246 if (activeAction() == m_filterWidgetAction)
247 setActiveAction(actions().at(TOP_HISTORY_ITEM_INDEX));
249 break;
251 default:
253 #ifdef DEBUG_EVENTS__
254 kDebug() << "Passing this event down to child (KLineEdit): " << e;
255 #endif
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());
272 break;
273 } //default:
274 } //case
277 #include "klipperpopup.moc"