You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/klipper/klipperpopup.cpp

305 lines
8.6 KiB

// -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*-
/* This file is part of the KDE project
Copyright (C) 2004 Esben Mose Hansen <kde@mosehansen.dk>
Copyright (C) by Andrew Stanley-Jones
Copyright (C) 2000 by Carsten Pfeiffer <pfeiffer@kde.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <kmessagebox.h>
#include <khelpmenu.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klocale.h>
#include <kaction.h>
#include <kglobalsettings.h>
#include <twin.h>
#include <kapplication.h>
#include <kglobalsettings.h>
#include <kdebug.h>
#include "klipperpopup.h"
#include "history.h"
#include "toplevel.h"
#include "popupproxy.h"
namespace {
static const int TOP_HISTORY_ITEM_INDEX = 2;
}
// #define DEBUG_EVENTS__
#ifdef DEBUG_EVENTS__
kdbgstream& operator<<( kdbgstream& stream, const TQKeyEvent& e ) {
stream << "(TQKeyEvent(text=" << e.text() << ",key=" << e.key() << ( e.isAccepted()?",accepted":",ignored)" ) << ",count=" << e.count();
if ( e.state() & Qt::AltButton ) {
stream << ",ALT";
}
if ( e.state() & Qt::ControlButton ) {
stream << ",CTRL";
}
if ( e.state() & Qt::MetaButton ) {
stream << ",META";
}
if ( e.state() & Qt::ShiftButton ) {
stream << ",SHIFT";
}
if ( e.isAutoRepeat() ) {
stream << ",AUTOREPEAT";
}
stream << ")";
return stream;
}
#endif
/**
* Exactly the same as KLineEdit, except that ALL key events are swallowed.
*
* We need this to avoid infinite loop when sending events to the search widget
*/
class KLineEditBlackKey : public KLineEdit {
public:
KLineEditBlackKey(const TQString& string, TQWidget* parent, const char* name )
: KLineEdit( string, parent, name )
{}
KLineEditBlackKey( TQWidget* parent, const char* name )
: KLineEdit( parent, name )
{}
~KLineEditBlackKey() {
}
protected:
virtual void keyPressEvent( TQKeyEvent* e ) {
KLineEdit::keyPressEvent( e );
e->accept();
}
};
KlipperPopup::KlipperPopup( History* history, TQWidget* parent, const char* name )
: KPopupMenu( parent, name ),
m_dirty( true ),
QSempty( i18n( "<empty clipboard>" ) ),
QSnomatch( i18n( "<no matches>" ) ),
m_history( history ),
helpmenu( new KHelpMenu( this, KlipperWidget::aboutData(), false ) ),
m_popupProxy( 0 ),
m_filterWidget( 0 ),
m_filterWidgetId( 10 ),
n_history_items( 0 )
{
KWin::WindowInfo i = KWin::windowInfo( winId(), NET::WMGeometry );
TQRect g = i.geometry();
TQRect screen = TDEGlobalSettings::desktopGeometry(g.center());
int menu_height = ( screen.height() ) * 3/4;
int menu_width = ( screen.width() ) * 1/3;
m_popupProxy = new PopupProxy( this, "popup_proxy", menu_height, menu_width );
connect( this, TQT_SIGNAL( aboutToShow() ), TQT_SLOT( slotAboutToShow() ) );
}
KlipperPopup::~KlipperPopup() {
}
void KlipperPopup::slotAboutToShow() {
if ( m_filterWidget ) {
if ( !m_filterWidget->text().isEmpty() ) {
m_dirty = true;
m_filterWidget->clear();
setItemVisible( m_filterWidgetId, false );
m_filterWidget->hide();
}
}
ensureClean();
}
void KlipperPopup::ensureClean() {
// If the history is unchanged since last menu build, the is no reason
// to rebuild it,
if ( m_dirty ) {
rebuild();
}
}
void KlipperPopup::buildFromScratch() {
m_filterWidget = new KLineEditBlackKey( this, "Klipper filter widget" );
insertTitle( SmallIcon( "klipper" ), i18n("Klipper - Clipboard Tool"));
m_filterWidgetId = insertItem( m_filterWidget, m_filterWidgetId, 1 );
m_filterWidget->setFocusPolicy( TQ_NoFocus );
setItemVisible( m_filterWidgetId, false );
m_filterWidget->hide();
TQString lastGroup;
// Bit of a hack here. It would be better of KHelpMenu could be an action.
// Insert Help-menu at the butttom of the "default" group.
TQString group;
TQString defaultGroup( "default" );
for ( KAction* action = m_actions.first(); action; action = m_actions.next() ) {
group = action->group();
if ( group != lastGroup ) {
if ( lastGroup == defaultGroup ) {
insertItem( SmallIconSet("help"), KStdGuiItem::help().text(), helpmenu->menu() );
}
insertSeparator();
}
lastGroup = group;
action->plug( this, -1 );
}
if ( TDEGlobalSettings::insertTearOffHandle() ) {
insertTearOffHandle();
}
}
void KlipperPopup::rebuild( const TQString& filter ) {
bool from_scratch = ( count() == 0 );
if ( from_scratch ) {
buildFromScratch();
} else {
for ( int i=0; i<n_history_items; i++ ) {
removeItemAt( TOP_HISTORY_ITEM_INDEX );
}
}
TQRegExp filterexp( filter );
if ( filterexp.isValid() ) {
m_filterWidget->setPaletteForegroundColor( paletteForegroundColor() );
} else {
m_filterWidget->setPaletteForegroundColor( TQColor( "red" ) );
}
n_history_items = m_popupProxy->buildParent( TOP_HISTORY_ITEM_INDEX, filterexp );
if ( n_history_items == 0 ) {
if ( m_history->empty() ) {
insertItem( QSempty, -1, TOP_HISTORY_ITEM_INDEX );
} else {
insertItem( QSnomatch, -1, TOP_HISTORY_ITEM_INDEX );
}
n_history_items++;
} else {
if ( history()->topIsUserSelected() ) {
int id = idAt( TOP_HISTORY_ITEM_INDEX );
if ( id != -1 ) {
setItemChecked( id,true );
}
}
}
m_dirty = false;
}
void KlipperPopup::plugAction( KAction* action ) {
m_actions.append( action );
}
/* virtual */
void KlipperPopup::keyPressEvent( TQKeyEvent* e ) {
// If alt-something is pressed, select a shortcut
// from the menu. Do this by sending a keyPress
// without the alt-modifier to the superobject.
if ( e->state() & AltButton ) {
TQKeyEvent ke( TQEvent::KeyPress,
e->key(),
e->ascii(),
e->state() ^ AltButton,
e->text(),
e->isAutoRepeat(),
e->count() );
KPopupMenu::keyPressEvent( &ke );
#ifdef DEBUG_EVENTS__
kdDebug() << "Passing this event to ancestor (KPopupMenu): " << e "->" << ke << endl;
#endif
if ( ke.isAccepted() ) {
e->accept();
return;
} else {
e->ignore();
}
}
// Otherwise, send most events to the search
// widget, except a few used for navigation:
// These go to the superobject.
switch( e->key() ) {
case Qt::Key_Up:
case Qt::Key_Down:
case Qt::Key_Right:
case Qt::Key_Left:
case Qt::Key_Tab:
case Qt::Key_Backtab:
case Qt::Key_Escape:
case Qt::Key_Return:
case Qt::Key_Enter:
{
#ifdef DEBUG_EVENTS__
kdDebug() << "Passing this event to ancestor (KPopupMenu): " << e << endl;
#endif
KPopupMenu::keyPressEvent( e );
if ( isItemActive( m_filterWidgetId ) ) {
setActiveItem( TOP_HISTORY_ITEM_INDEX );
}
break;
}
default:
{
#ifdef DEBUG_EVENTS__
kdDebug() << "Passing this event down to child (KLineEdit): " << e << endl;
#endif
TQString lastString = m_filterWidget->text();
TQApplication::sendEvent( m_filterWidget, e );
if ( m_filterWidget->text().isEmpty() ) {
if ( isItemVisible( m_filterWidgetId ) )
{
setItemVisible( m_filterWidgetId, false );
m_filterWidget->hide();
}
}
else if ( !isItemVisible( m_filterWidgetId ) )
{
setItemVisible( m_filterWidgetId, true );
m_filterWidget->show();
}
if ( m_filterWidget->text() != lastString) {
slotHistoryChanged();
rebuild( m_filterWidget->text() );
}
break;
} //default:
} //case
}
#include "klipperpopup.moc"