diff --git a/kicker/kicker/ui/Makefile.am b/kicker/kicker/ui/Makefile.am index e60e99bfd..1bd54777e 100644 --- a/kicker/kicker/ui/Makefile.am +++ b/kicker/kicker/ui/Makefile.am @@ -13,7 +13,7 @@ libkicker_ui_la_SOURCES = addbutton_mnu.cpp appletitem.ui appletview.ui addapple recentapps.cpp browser_dlg.cpp \ removeapplet_mnu.cpp removeextension_mnu.cpp removecontainer_mnu.cpp \ removebutton_mnu.cpp popupmenutitle.cpp hidebutton.cpp \ - addappletvisualfeedback.cpp + addappletvisualfeedback.cpp clicklineedit.cpp libkicker_ui_la_LIBADD = $(top_builddir)/libkonq/libkonq.la $(top_builddir)/kdmlib/libdmctl.la @@ -25,7 +25,8 @@ noinst_HEADERS = addapplet.h appletwidget.h addbutton_mnu.h addapplet_mnu.h appl addextension_mnu.h extensionop_mnu.h \ recentapps.h browser_dlg.h \ removeapplet_mnu.h removeextension_mnu.h removecontainer_mnu.h \ - removebutton_mnu.h popupmenutitle.h hidebutton.h addappletvisualfeedback.h + removebutton_mnu.h popupmenutitle.h hidebutton.h \ + addappletvisualfeedback.h clicklineedit.h removecontainer_mnu.lo: ../../libkicker/kickerSettings.h removeextension_mnu.lo: ../../libkicker/kickerSettings.h diff --git a/kicker/kicker/ui/clicklineedit.cpp b/kicker/kicker/ui/clicklineedit.cpp new file mode 100644 index 000000000..52cb8776d --- /dev/null +++ b/kicker/kicker/ui/clicklineedit.cpp @@ -0,0 +1,85 @@ +/* + This file is part of libkdepim. + Copyright (c) 2004 Daniel Molkentin + based on code by Cornelius Schumacher + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + + +#include "clicklineedit.h" + +#include "qpainter.h" + +using namespace KPIM; + +ClickLineEdit::ClickLineEdit(TQWidget *parent, const TQString &msg, const char* name) : + KLineEdit(parent, name) +{ + mDrawClickMsg = true; + setClickMessage( msg ); +} + +ClickLineEdit::~ClickLineEdit() {} + + +void ClickLineEdit::setClickMessage( const TQString &msg ) +{ + mClickMessage = msg; + repaint(); +} + +void ClickLineEdit::setText( const TQString &txt ) +{ + mDrawClickMsg = txt.isEmpty(); + repaint(); + KLineEdit::setText( txt ); +} + +void ClickLineEdit::drawContents( TQPainter *p ) +{ + KLineEdit::drawContents( p ); + + if ( mDrawClickMsg == true && !hasFocus() ) { + TQPen tmp = p->pen(); + p->setPen( gray ); + TQRect cr = contentsRect(); + p->drawText( cr, AlignAuto|AlignVCenter, mClickMessage ); + p->setPen( tmp ); + } +} + +void ClickLineEdit::focusInEvent( TQFocusEvent *ev ) +{ + if ( mDrawClickMsg == true ) + { + mDrawClickMsg = false; + repaint(); + } + TQLineEdit::focusInEvent( ev ); +} + +void ClickLineEdit::focusOutEvent( TQFocusEvent *ev ) +{ + if ( text().isEmpty() ) + { + mDrawClickMsg = true; + repaint(); + } + TQLineEdit::focusOutEvent( ev ); +} + +#include "clicklineedit.moc" diff --git a/kicker/kicker/ui/clicklineedit.h b/kicker/kicker/ui/clicklineedit.h new file mode 100644 index 000000000..cadafae4c --- /dev/null +++ b/kicker/kicker/ui/clicklineedit.h @@ -0,0 +1,63 @@ +/* + This file is part of libkdepim. + Copyright (c) 2004 Daniel Molkentin + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef CLICKLINEEDIT_H +#define CLICKLINEEDIT_H + +#include + + +namespace KPIM { + +/** + This class provides a KLineEdit which contains a greyed-out hinting + text as long as the user didn't enter any text + + @short LineEdit with customizable "Click here" text + @author Daniel Molkentin +*/ +class KDE_EXPORT ClickLineEdit : public KLineEdit +{ + Q_OBJECT + public: + ClickLineEdit( TQWidget *parent, const TQString &msg = TQString::null, const char* name = 0 ); + ~ClickLineEdit(); + + void setClickMessage( const TQString &msg ); + TQString clickMessage() const { return mClickMessage; } + + virtual void setText( const TQString& txt ); + + protected: + virtual void drawContents( TQPainter *p ); + virtual void focusInEvent( TQFocusEvent *ev ); + virtual void focusOutEvent( TQFocusEvent *ev ); + + private: + TQString mClickMessage; + bool mDrawClickMsg; + +}; + +} + +#endif // CLICKLINEEDIT_H + + diff --git a/kicker/kicker/ui/k_mnu.cpp b/kicker/kicker/ui/k_mnu.cpp index b2e3d59bb..589ed74e8 100644 --- a/kicker/kicker/ui/k_mnu.cpp +++ b/kicker/kicker/ui/k_mnu.cpp @@ -26,9 +26,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #include +#include #include #include +#include +#include #include #include @@ -40,9 +44,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #include #include #include +#include #include #include "client_mnu.h" @@ -57,10 +63,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "popupmenutitle.h" #include "quickbrowser_mnu.h" #include "recentapps.h" +#include "clicklineedit.h" #include "k_mnu.h" #include "k_mnu.moc" +const int PanelKMenu::searchLineID(23140 /*whatever*/); + PanelKMenu::PanelKMenu() : PanelServiceMenu(TQString::null, TQString::null, 0, "KMenu") , bookmarkMenu(0) @@ -165,6 +174,25 @@ void PanelKMenu::paletteChanged() } } +/* A MenuHBox is supposed to be inserted into a menu. + * You can set a special widget in the hbox which will + * get the focus if the user moves up or down with the + * cursor keys + */ +class MenuHBox : public TQHBox { +public: + MenuHBox(PanelKMenu* parent) : TQHBox(parent) + { + } + + virtual void keyPressEvent(TQKeyEvent *e) + { + + } +private: + PanelKMenu *parent; +}; + void PanelKMenu::initialize() { // kdDebug(1210) << "PanelKMenu::initialize()" << endl; @@ -191,6 +219,22 @@ void PanelKMenu::initialize() // add services PanelServiceMenu::initialize(); + // Insert search field + TQHBox* hbox = new TQHBox( this ); + KToolBarButton *clearButton = new KToolBarButton( "locationbar_erase", 0, hbox ); + searchEdit = new KPIM::ClickLineEdit(hbox, " "+i18n("Press '/' to search...")); + hbox->setFocusPolicy(TQWidget::StrongFocus); + hbox->setFocusProxy(searchEdit); + hbox->setSpacing( 3 ); + connect(clearButton, TQT_SIGNAL(clicked()), searchEdit, TQT_SLOT(clear())); + connect(this, TQT_SIGNAL(aboutToHide()), this, TQT_SLOT(slotClearSearch())); + connect(searchEdit, TQT_SIGNAL(textChanged(const TQString&)), + this, TQT_SLOT( slotUpdateSearch( const TQString&))); + insertItem(hbox, searchLineID, 0); + + //TQToolTip::add(clearButton, i18n("Clear Search")); + //TQToolTip::add(searchEdit, i18n("Enter the name of an application")); + if (KickerSettings::showMenuTitles()) { int id; @@ -581,6 +625,47 @@ void PanelKMenu::mouseMoveEvent(TQMouseEvent *e) PanelServiceMenu::mouseMoveEvent( &newEvent ); } +void PanelKMenu::slotUpdateSearch(const TQString& searchString) +{ + kdDebug() << "Searching for " << searchString << endl; + setSearchString(searchString); +} + +void PanelKMenu::slotClearSearch() +{ + if (searchEdit && searchEdit->text().isEmpty() == false) { + TQTimer::singleShot(0, searchEdit, TQT_SLOT(clear())); + } +} + +void PanelKMenu::keyPressEvent(TQKeyEvent* e) +{ + // We move the focus to the search field if the + // user presses '/'. This is the same shortcut as + // konqueror is using, and afaik it's hardcoded both + // here and there. This sucks badly for many non-us + // keyboard layouts, but for the sake of consistency + // we follow konqueror. + if (!searchEdit) return KPanelMenu::keyPressEvent(e); + + if (e->key() == TQt::Key_Slash && !searchEdit->hasFocus()) { + if (indexOf(searchLineID) >=0 ) { + setActiveItem(indexOf(searchLineID)); + } + } + else if (e->key() == TQt::Key_Escape && searchEdit->text().isEmpty() == false) { + searchEdit->clear(); + } + else if (e->key() == TQt::Key_Delete && !searchEdit->hasFocus() && + searchEdit->text().isEmpty() == false) + { + searchEdit->clear(); + } + else { + KPanelMenu::keyPressEvent(e); + } +} + void PanelKMenu::configChanged() { RecentlyLaunchedApps::the().m_bNeedToUpdate = false; diff --git a/kicker/kicker/ui/k_mnu.h b/kicker/kicker/ui/k_mnu.h index 412648f1b..91904e0d0 100644 --- a/kicker/kicker/ui/k_mnu.h +++ b/kicker/kicker/ui/k_mnu.h @@ -30,6 +30,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "service_mnu.h" +namespace KPIM { + // Yes, ClickLineEdit was copied from libkdepim. + // Can we have it in kdelibs please? + class ClickLineEdit; +} + class KickerClientMenu; class KBookmarkMenu; class KActionCollection; @@ -73,6 +79,8 @@ protected slots: void slotSaveSession(); void slotRunCommand(); void slotEditUserContact(); + void slotUpdateSearch(const TQString &searchtext); + void slotClearSearch(); void paletteChanged(); virtual void configChanged(); void updateRecent(); @@ -87,6 +95,8 @@ protected: void mouseMoveEvent(TQMouseEvent *); bool loadSidePixmap(); void doNewSession(bool lock); + void filterMenu(PanelServiceMenu* menu, const TQString &searchString); + void keyPressEvent(TQKeyEvent* e); void createRecentMenuItems(); virtual void clearSubmenus(); @@ -101,6 +111,8 @@ private: KActionCollection *actionCollection; KBookmarkOwner *bookmarkOwner; PopupMenuList dynamicSubMenus; + KPIM::ClickLineEdit *searchEdit; + static const int searchLineID; }; #endif diff --git a/kicker/kicker/ui/service_mnu.cpp b/kicker/kicker/ui/service_mnu.cpp index 9b46b2396..fa18a7038 100644 --- a/kicker/kicker/ui/service_mnu.cpp +++ b/kicker/kicker/ui/service_mnu.cpp @@ -26,6 +26,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include #include #include @@ -100,6 +101,8 @@ void PanelServiceMenu::initialize() clear(); clearSubmenus(); + searchSubMenuIDs.clear(); + searchMenuItems.clear(); doInitialize(); } @@ -202,6 +205,10 @@ void PanelServiceMenu::fillMenu(KServiceGroup::Ptr& _root, int newId = insertItem(iconset, groupCaption, m, id++); entryMap_.insert(newId, static_cast(g)); + // This submenu will be searched when applying a search string + searchSubMenuIDs[m] = newId; + // Also search the submenu name itself + searchMenuItems.insert(newId); // We have to delete the sub menu our selves! (See Qt docs.) subMenus.append(m); } @@ -214,6 +221,7 @@ void PanelServiceMenu::fillMenu(KServiceGroup::Ptr& _root, } KService::Ptr s(static_cast(e)); + searchMenuItems.insert(id); insertMenuItem(s, id++, -1, &suppressGenericNames); } else if (e->isType(KST_KServiceSeparator)) @@ -797,6 +805,8 @@ void PanelServiceMenu::slotClear() delete *it; } subMenus.clear(); + searchSubMenuIDs.clear(); + searchMenuItems.clear(); } void PanelServiceMenu::selectFirstItem() @@ -804,6 +814,76 @@ void PanelServiceMenu::selectFirstItem() setActiveItem(indexOf(serviceMenuStartId())); } +void PanelServiceMenu::setSearchString(const TQString &searchString) +{ + // We must initialize the menu, because it might have not been opened before + initialize(); + + bool foundSomething = false; + std::set nonemptyMenus; + std::set::const_iterator menuItemIt(searchMenuItems.begin()); + // Apply the filter on this menu + for (; menuItemIt != searchMenuItems.end(); ++menuItemIt) { + int id = *menuItemIt; + KService* s = dynamic_cast< KService* >( static_cast< KSycocaEntry* >( entryMap_[ id ])); + TQString menuText = text(id); + if (menuText.contains(searchString, false) > 0 + || ( s != NULL && ( s->name().contains(searchString, false) > 0 + || s->exec().contains(searchString, false) > 0 + || s->comment().contains(searchString, false) > 0 + || s->genericName().contains(searchString, false) > 0 + || s->exec().contains(searchString, false) > 0 ) + )) { + setItemEnabled(id, true); + foundSomething = true; + nonemptyMenus.insert(id); + } + else { + setItemEnabled(id, false); + } + } + // Apply the filter on this menu + /*for (int i=count()-1; i>=0; --i) { + int id = idAt(i); + TQString menuText = text(id); + if (menuText.contains(searchString, false) > 0) { + setItemEnabled(id, true); + foundSomething = true; + nonemptyMenus.insert(id); + } + else { + setItemEnabled(id, false); + } + }*/ + + PanelServiceMenuMap::iterator it(searchSubMenuIDs.begin()); + // Apply the search filter on submenus + for (; it != searchSubMenuIDs.end(); ++it) { + it.key()->setSearchString(searchString); + if (nonemptyMenus.find(it.data()) != nonemptyMenus.end()) { + // if the current menu is a match already, we don't + // block access to the contained items + setItemEnabled(it.data(), true); + it.key()->setSearchString(TQString()); + foundSomething = true; + } + else if (it.key()->hasSearchResults()) { + setItemEnabled(it.data(), true); + foundSomething = true; + } + else { + setItemEnabled(it.data(), false); + } + } + + hasSearchResults_ = foundSomething; +} + +bool PanelServiceMenu::hasSearchResults() +{ + return hasSearchResults_; +} + // updates "recent" section of KMenu void PanelServiceMenu::updateRecentlyUsedApps(KService::Ptr &service) { diff --git a/kicker/kicker/ui/service_mnu.h b/kicker/kicker/ui/service_mnu.h index 3bc112348..193e4faf8 100644 --- a/kicker/kicker/ui/service_mnu.h +++ b/kicker/kicker/ui/service_mnu.h @@ -25,6 +25,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SERVICE_MENU_H #include +#include #include #include @@ -41,8 +42,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * @author Rik Hemsley */ +class KLineEdit; typedef TQMap EntryMap; typedef TQValueVector PopupMenuList; +class PanelServiceMenu; +typedef TQMap PanelServiceMenuMap; class KDE_EXPORT PanelServiceMenu : public KPanelMenu { @@ -63,6 +67,8 @@ public: virtual void showMenu(); bool highlightMenuItem( const TQString &menuId ); void selectFirstItem(); + void setSearchString(const TQString& searchString); + bool hasSearchResults(); private: void fillMenu( KServiceGroup::Ptr &_root, KServiceGroup::List &_list, @@ -114,6 +120,9 @@ protected: bool addmenumode_; TQPoint startPos_; PopupMenuList subMenus; + PanelServiceMenuMap searchSubMenuIDs; + bool hasSearchResults_; + std::set searchMenuItems; private slots: void slotContextMenu(int);