diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-09-03 20:49:48 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-09-03 20:49:48 +0000 |
commit | fd7a608ffe99df747f0496300276b95f766c18b9 (patch) | |
tree | c54dfe97fb682af9705d2cb09c424c60db861228 /kicker | |
parent | 27856879bf962f178d88e79144e37a47e731b122 (diff) | |
download | tdebase-fd7a608ffe99df747f0496300276b95f766c18b9.tar.gz tdebase-fd7a608ffe99df747f0496300276b95f766c18b9.zip |
* Added Kickoff menu
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebase@1171422 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kicker')
78 files changed, 9806 insertions, 121 deletions
diff --git a/kicker/applets/clock/clock.cpp b/kicker/applets/clock/clock.cpp index 7bc46afa4..26f1ae4c0 100644 --- a/kicker/applets/clock/clock.cpp +++ b/kicker/applets/clock/clock.cpp @@ -901,8 +901,8 @@ ClockApplet::ClockApplet(const TQString& configFile, Type t, int actions, _calendar(0), _disableCalendar(false), _clock(0), - _timer(new TQTimer(this)), - m_layoutTimer(new TQTimer(this)), + _timer(new TQTimer(this, "ClockApplet::_timer")), + m_layoutTimer(new TQTimer(this, "m_layoutTimer")), m_layoutDelay(0), m_followBackgroundSetting(true), m_dateFollowBackgroundSetting(true), diff --git a/kicker/applets/launcher/quicklauncher.cpp b/kicker/applets/launcher/quicklauncher.cpp index 557ea4cd3..a278b39c9 100644 --- a/kicker/applets/launcher/quicklauncher.cpp +++ b/kicker/applets/launcher/quicklauncher.cpp @@ -110,7 +110,7 @@ QuickLauncher::QuickLauncher(const TQString& configFile, Type type, int actions, m_configAction = new KAction(i18n("Configure Quicklauncher..."), "configure", KShortcut(), this, TQT_SLOT(slotConfigure()), this); - m_saveTimer = new TQTimer(this); + m_saveTimer = new TQTimer(this, "m_saveTimer"); connect(m_saveTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(saveConfig())); m_popularity = new PopularityStatistics(); diff --git a/kicker/applets/media/mediumbutton.cpp b/kicker/applets/media/mediumbutton.cpp index 5be2acbab..0fae43441 100644 --- a/kicker/applets/media/mediumbutton.cpp +++ b/kicker/applets/media/mediumbutton.cpp @@ -45,7 +45,8 @@ #include <konq_drag.h> MediumButton::MediumButton(TQWidget *parent, const KFileItem &fileItem) - : PanelPopupButton(parent), mActions(this, this), mFileItem(fileItem) + : PanelPopupButton(parent), mActions(this, this), mFileItem(fileItem), mOpenTimer(0, + "MediumButton::mOpenTimer") { KAction *a = KStdAction::paste(this, TQT_SLOT(slotPaste()), &mActions, "pasteto"); @@ -74,9 +75,9 @@ MediumButton::MediumButton(TQWidget *parent, const KFileItem &fileItem) MediumButton::~MediumButton() { - TQPopupMenu *menu = popup(); - setPopup(0); - delete menu; + TQPopupMenu *menu = static_cast<TQPopupMenu*>(popup()); + setPopup(0); + delete menu; } const KFileItem &MediumButton::fileItem() const @@ -94,29 +95,29 @@ void MediumButton::setFileItem(const KFileItem &fileItem) void MediumButton::initPopup() { - TQPopupMenu *old_popup = popup(); - - KFileItemList items; - items.append(&mFileItem); - - KonqPopupMenu::KonqPopupFlags kpf = - KonqPopupMenu::ShowProperties - | KonqPopupMenu::ShowNewWindow; - - KParts::BrowserExtension::PopupFlags bef = - KParts::BrowserExtension::DefaultPopupItems; - - KonqPopupMenu *new_popup = new KonqPopupMenu(0L, items, - KURL("media:/"), mActions, 0L, - this, kpf, bef); - KPopupTitle *title = new KPopupTitle(new_popup); - title->setTitle(mFileItem.text()); - - new_popup->insertItem(title, -1, 0); - - setPopup(new_popup); - - if (old_popup!=0L) delete old_popup; + TQPopupMenu *old_popup = static_cast<TQPopupMenu*>(popup()); + + KFileItemList items; + items.append(&mFileItem); + + KonqPopupMenu::KonqPopupFlags kpf = + KonqPopupMenu::ShowProperties + | KonqPopupMenu::ShowNewWindow; + + KParts::BrowserExtension::PopupFlags bef = + KParts::BrowserExtension::DefaultPopupItems; + + KonqPopupMenu *new_popup = new KonqPopupMenu(0L, items, + KURL("media:/"), mActions, 0L, + this, kpf, bef); + KPopupTitle *title = new KPopupTitle(new_popup); + title->setTitle(mFileItem.text()); + + new_popup->insertItem(title, -1, 0); + + setPopup(new_popup); + + if (old_popup!=0L) delete old_popup; } void MediumButton::refreshType() diff --git a/kicker/applets/minipager/pagerbutton.cpp b/kicker/applets/minipager/pagerbutton.cpp index c56afca38..10a5aa8c9 100644 --- a/kicker/applets/minipager/pagerbutton.cpp +++ b/kicker/applets/minipager/pagerbutton.cpp @@ -70,6 +70,8 @@ KMiniPagerButton::KMiniPagerButton(int desk, bool useViewPorts, const TQPoint& v m_bgPixmap(0), m_isCommon(false), m_currentWindow(0), + m_updateCompressor(0, "KMiniPagerButton::updateCompressor"), + m_dragSwitchTimer(0, "KMiniPagerButton::dragSwitchTimer"), m_inside(false) { setToggleButton(true); diff --git a/kicker/applets/naughty/NaughtyProcessMonitor.cpp b/kicker/applets/naughty/NaughtyProcessMonitor.cpp index 37cba7a37..6228cfba1 100644 --- a/kicker/applets/naughty/NaughtyProcessMonitor.cpp +++ b/kicker/applets/naughty/NaughtyProcessMonitor.cpp @@ -94,7 +94,7 @@ NaughtyProcessMonitor::NaughtyProcessMonitor d = new NaughtyProcessMonitorPrivate; d->interval_ = interval * 1000; d->triggerLevel_ = triggerLevel; - d->timer_ = new TQTimer(this); + d->timer_ = new TQTimer(this, "NaughtyProcessMonitorPrivate::timer"); connect(d->timer_, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotTimeout())); } diff --git a/kicker/applets/systemtray/systemtrayapplet.cpp b/kicker/applets/systemtray/systemtrayapplet.cpp index 51bf2b9d8..ad44b640f 100644 --- a/kicker/applets/systemtray/systemtrayapplet.cpp +++ b/kicker/applets/systemtray/systemtrayapplet.cpp @@ -401,7 +401,7 @@ void SystemTrayApplet::showExpandButton(bool show) connect(m_expandButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(toggleExpanded())); - m_autoRetractTimer = new TQTimer(this); + m_autoRetractTimer = new TQTimer(this, "m_autoRetractTimer"); connect(m_autoRetractTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkAutoRetract())); } diff --git a/kicker/applets/trash/trashbutton.cpp b/kicker/applets/trash/trashbutton.cpp index eb036c119..19e6be02b 100644 --- a/kicker/applets/trash/trashbutton.cpp +++ b/kicker/applets/trash/trashbutton.cpp @@ -78,7 +78,7 @@ void TrashButton::setItemCount(int count) void TrashButton::initPopup() { - TQPopupMenu *old_popup = popup(); + TQPopupMenu *old_popup = static_cast<TQPopupMenu*>(popup()); KFileItemList items; items.append(&mFileItem); diff --git a/kicker/configure.in.in b/kicker/configure.in.in new file mode 100644 index 000000000..4da44a4a8 --- /dev/null +++ b/kicker/configure.in.in @@ -0,0 +1,78 @@ +dnl Check for pkg-config +AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + +if test "$PKG_CONFIG" = "no"; then + AC_MSG_ERROR([ +This package requires pkg-config. +]) +fi + +dnl Check for Glib-2.0 +# GLIB_CFLAGS: cflags for compiling glib dependant sources +# GLIB_LIBADD: glib libraries (-l options) +# GLIB_LDFLAGS: flags containing path to glib libraries (-L options) + +GLIB_PACKAGES="gmodule-2.0 gthread-2.0" +GLIB_VERSION="1.3.3" +AC_MSG_CHECKING(for GLib-2.0 (at least $GLIB_VERSION)) + +if $PKG_CONFIG --atleast-pkgconfig-version 0.15 ; then + if $PKG_CONFIG --atleast-version $GLIB_VERSION $GLIB_PACKAGES >/dev/null 2>&1 ; then + GLIB_CFLAGS="`$PKG_CONFIG --cflags $GLIB_PACKAGES`" + GLIB_LIBADD="`$PKG_CONFIG --libs-only-l --libs-only-other $GLIB_PACKAGES`" + GLIB_LDFLAGS="`$PKG_CONFIG --libs-only-L $GLIB_PACKAGES`" + AC_MSG_RESULT(yes) + fi +else + if $PKG_CONFIG --atleast-version $GLIB_VERSION $GLIB_PACKAGES >/dev/null 2>&1 ; then + GLIB_CFLAGS="`$PKG_CONFIG --cflags $GLIB_PACKAGES`" + GLIB_LIBADD="`$PKG_CONFIG --libs-only-l $GLIB_PACKAGES`" + GLIB_LDFLAGS="`$PKG_CONFIG --libs-only-L $GLIB_PACKAGES`" + AC_MSG_RESULT(yes) + AC_MSG_WARN([you may need to run make LDFLAGS=-pthread to compile arts]) + fi +fi + +if test -z "$GLIB_LIBADD"; then + AC_MSG_RESULT(not installed) + DO_NOT_COMPILE="$DO_NOT_COMPILE kerry gmcop" +fi + +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBADD) +AC_SUBST(GLIB_LDFLAGS) + +dnl Check for libbeagle 0.2.0 +# LIBBEAGLE_CFLAGS: cflags for compiling libbeagle dependant sources +# LIBBEAGLE_LIBADD: libbeagle libraries (-l options) +# LIBBEAGLE_LDFLAGS: flags containing path to libbeagle libraries (-L options) + +LIBBEAGLE_PACKAGES="libbeagle-0.0" +LIBBEAGLE_VERSION="0.2.4" +AC_MSG_CHECKING(for libbeagle-0.2.4 (at least $LIBBEAGLE_VERSION)) + +if $PKG_CONFIG --atleast-pkgconfig-version 0.15 ; then + if $PKG_CONFIG --atleast-version $LIBBEAGLE_VERSION $LIBBEAGLE_PACKAGES >/dev/null 2>&1 ; then + LIBBEAGLE_CFLAGS="`$PKG_CONFIG --cflags $LIBBEAGLE_PACKAGES`" + LIBBEAGLE_LIBADD="`$PKG_CONFIG --libs-only-l --libs-only-other $LIBBEAGLE_PACKAGES`" + LIBBEAGLE_LDFLAGS="`$PKG_CONFIG --libs-only-L $LIBBEAGLE_PACKAGES`" + AC_MSG_RESULT(yes) + fi +else + if $PKG_CONFIG --atleast-version $LIBBEAGLE_VERSION $LIBBEAGLE_PACKAGES >/dev/null 2>&1 ; then + LIBBEAGLE_CFLAGS="`$PKG_CONFIG --cflags $LIBBEAGLE_PACKAGES`" + LIBBEAGLE_LIBADD="`$PKG_CONFIG --libs-only-l $LIBBEAGLE_PACKAGES`" + LIBBEAGLE_LDFLAGS="`$PKG_CONFIG --libs-only-L $LIBBEAGLE_PACKAGES`" + AC_MSG_RESULT(yes) + AC_MSG_WARN([you may need to run make LDFLAGS=-pthread to compile arts]) + fi +fi + +if test -z "$LIBBEAGLE_LIBADD"; then + AC_MSG_RESULT(not installed) + DO_NOT_COMPILE="$DO_NOT_COMPILE kerry gmcop" +fi + +AC_SUBST(LIBBEAGLE_CFLAGS) +AC_SUBST(LIBBEAGLE_LIBADD) +AC_SUBST(LIBBEAGLE_LDFLAGS) diff --git a/kicker/data/Makefile.am b/kicker/data/Makefile.am index 41d9598ed..53e72912e 100644 --- a/kicker/data/Makefile.am +++ b/kicker/data/Makefile.am @@ -1 +1 @@ -SUBDIRS = icons tiles app_start_anim wallpaper kmenu_side +SUBDIRS = icons tiles app_start_anim wallpaper kmenu_side kickoff diff --git a/kicker/data/kickoff/Makefile.am b/kicker/data/kickoff/Makefile.am new file mode 100644 index 000000000..20ac737ff --- /dev/null +++ b/kicker/data/kickoff/Makefile.am @@ -0,0 +1,14 @@ +kicker_kmenuside_pics_data_DATA = resize_handle.png \ + main_corner_tl.png main_corner_tr.png search-gradient.png \ + menu_separator.png search-tab-center.png search-tab-left.png \ + search-tab-right.png search-tab-top-center.png search-tab-top-left.png \ + left_triangle.png right_triangle.png \ + kmenu_basic.mng kmenu_flipped.mng kmenu_vertical.mng \ + search-tab-top-right.png search-gradient-topdown.png search-running.mng + +kicker_kmenuside_pics_datadir = $(kde_datadir)/kicker/pics + +EXTRA_DIST = $(kicker_kmenuside_pics_data_DATA) + +kickerdir = $(kde_datadir)/kicker/icons +kicker_ICON = leave recently_used suspend2disk suspend2ram diff --git a/kicker/data/kickoff/kmenu_active.png b/kicker/data/kickoff/kmenu_active.png Binary files differindex fa5ae4de1..7a3d6b08f 100644 --- a/kicker/data/kickoff/kmenu_active.png +++ b/kicker/data/kickoff/kmenu_active.png diff --git a/kicker/data/kickoff/kmenu_basic.mng b/kicker/data/kickoff/kmenu_basic.mng Binary files differindex 4cea61fff..d3423d867 100644 --- a/kicker/data/kickoff/kmenu_basic.mng +++ b/kicker/data/kickoff/kmenu_basic.mng diff --git a/kicker/data/kickoff/kmenu_flipped.mng b/kicker/data/kickoff/kmenu_flipped.mng Binary files differindex 2b78b4007..d3423d867 100644 --- a/kicker/data/kickoff/kmenu_flipped.mng +++ b/kicker/data/kickoff/kmenu_flipped.mng diff --git a/kicker/data/kickoff/kmenu_vertical.mng b/kicker/data/kickoff/kmenu_vertical.mng Binary files differindex 9cd3aac2b..7f7047d11 100644 --- a/kicker/data/kickoff/kmenu_vertical.mng +++ b/kicker/data/kickoff/kmenu_vertical.mng diff --git a/kicker/data/kmenu_side/Makefile.am b/kicker/data/kmenu_side/Makefile.am index ee19c9a20..2d3e00932 100644 --- a/kicker/data/kmenu_side/Makefile.am +++ b/kicker/data/kmenu_side/Makefile.am @@ -1,6 +1,5 @@ -kicker_kmenuside_pics_data_DATA = kside.png kside_tile.png - -kicker_kmenuside_pics_datadir = $(kde_datadir)/kicker/pics/ +kicker_kmenuside_pics_data_DATA = kside.png kside_tile.png +kicker_kmenuside_pics_datadir = $(kde_datadir)/kicker/pics EXTRA_DIST = $(kicker_kmenuside_pics_data_DATA) diff --git a/kicker/extensions/kasbar/kasbar.cpp b/kicker/extensions/kasbar/kasbar.cpp index 06bf3c24f..bf2b64ba3 100644 --- a/kicker/extensions/kasbar/kasbar.cpp +++ b/kicker/extensions/kasbar/kasbar.cpp @@ -719,7 +719,7 @@ void KasBar::addTestItems() i->setText( "Animated" ); i->setIcon( KGlobal::iconLoader()->loadIcon( "icons", KIcon::NoGroup, KIcon::SizeMedium ) ); i->setAnimation( resources()->startupAnimation() ); - TQTimer *aniTimer = new TQTimer( i ); + TQTimer *aniTimer = new TQTimer( i, "aniTimer" ); connect( aniTimer, TQT_SIGNAL( timeout() ), i, TQT_SLOT( advanceAnimation() ) ); aniTimer->start( 100 ); i->setShowAnimation( true ); diff --git a/kicker/extensions/kasbar/kasclockitem.cpp b/kicker/extensions/kasbar/kasclockitem.cpp index 386a7922d..f025af857 100644 --- a/kicker/extensions/kasbar/kasclockitem.cpp +++ b/kicker/extensions/kasbar/kasclockitem.cpp @@ -38,7 +38,7 @@ KasClockItem::KasClockItem( KasBar *parent ) { setCustomPopup( true ); - TQTimer *t = new TQTimer( this ); + TQTimer *t = new TQTimer( this, "t" ); connect( t, TQT_SIGNAL( timeout() ), TQT_SLOT( updateTime() ) ); t->start( 1000 ); diff --git a/kicker/extensions/kasbar/kasloaditem.cpp b/kicker/extensions/kasbar/kasloaditem.cpp index 2d33a068d..7b6939760 100644 --- a/kicker/extensions/kasbar/kasloaditem.cpp +++ b/kicker/extensions/kasbar/kasloaditem.cpp @@ -33,7 +33,7 @@ KasLoadItem::KasLoadItem( KasBar *parent ) : KasItem( parent ) { - TQTimer *t = new TQTimer( this ); + TQTimer *t = new TQTimer( this, "KasLoadItem::t" ); connect( t, TQT_SIGNAL( timeout() ), TQT_SLOT( updateDisplay() ) ); t->start( 1000 ); updateDisplay(); diff --git a/kicker/extensions/kasbar/kasstartupitem.cpp b/kicker/extensions/kasbar/kasstartupitem.cpp index 53d823430..4d2ac3b00 100644 --- a/kicker/extensions/kasbar/kasstartupitem.cpp +++ b/kicker/extensions/kasbar/kasstartupitem.cpp @@ -79,7 +79,7 @@ KasStartupItem::KasStartupItem( KasBar *parent, Startup::Ptr startup ) setShowFrame( false ); setAnimation( resources()->startupAnimation() ); - aniTimer = new TQTimer( this ); + aniTimer = new TQTimer( this, "aniTimer" ); connect( aniTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( aniTimerFired() ) ); aniTimer->start( 100 ); } diff --git a/kicker/kicker/Makefile.am b/kicker/kicker/Makefile.am index 857ac9cff..9a89a0ac0 100644 --- a/kicker/kicker/Makefile.am +++ b/kicker/kicker/Makefile.am @@ -1,6 +1,7 @@ INCLUDES = $(all_includes) -SUBDIRS = core ui buttons . +# SUBDIRS = core interfaces ui buttons plugins . +SUBDIRS = core interfaces ui buttons . bin_PROGRAMS = lib_LTLIBRARIES = @@ -9,7 +10,7 @@ kdeinit_LTLIBRARIES = kicker.la CLEANFILES = dummy.cpp kicker_la_LIBADD = core/libkicker_core.la buttons/libkicker_buttons.la \ - ui/libkicker_ui.la ../libkicker/libkickermain.la $(LIB_KIO) $(LIB_KUTILS) + ui/libkicker_ui.la ../libkicker/libkickermain.la $(LIB_KIO) $(LIB_KUTILS) $(LIB_KABC) kicker_la_SOURCES = dummy.cpp kicker_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) diff --git a/kicker/kicker/buttons/Makefile.am b/kicker/kicker/buttons/Makefile.am index 2ba4d20c6..1ec3d42d6 100644 --- a/kicker/kicker/buttons/Makefile.am +++ b/kicker/kicker/buttons/Makefile.am @@ -1,10 +1,10 @@ INCLUDES = -I$(srcdir)/../core -I$(srcdir)/../../libkicker -I../../libkicker \ - -I$(srcdir)/../ui -I$(top_srcdir)/libkonq $(all_includes) + -I../ui -I$(srcdir)/../ui -I$(top_srcdir)/libkonq $(all_includes) $(LIBBEAGLE_CFLAGS) $(GLIB_CFLAGS) noinst_LTLIBRARIES = libkicker_buttons.la libkicker_buttons_la_SOURCES = servicebutton.cpp bookmarksbutton.cpp \ - browserbutton.cpp \ + browserbutton.cpp knewbutton.cpp \ desktopbutton.cpp extensionbutton.cpp kbutton.cpp \ nonkdeappbutton.cpp servicemenubutton.cpp urlbutton.cpp \ windowlistbutton.cpp diff --git a/kicker/kicker/buttons/browserbutton.cpp b/kicker/kicker/buttons/browserbutton.cpp index 950882696..2e2cb5a2d 100644 --- a/kicker/kicker/buttons/browserbutton.cpp +++ b/kicker/kicker/buttons/browserbutton.cpp @@ -65,7 +65,7 @@ void BrowserButton::initialize( const TQString& icon, const TQString& path ) topMenu = new PanelBrowserMenu( path ); setPopup(topMenu); - _menuTimer = new TQTimer( this ); + _menuTimer = new TQTimer( this, "_menuTimer" ); connect( _menuTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotDelayedPopup()) ); TQToolTip::add(this, i18n("Browse: %1").arg(path)); diff --git a/kicker/kicker/buttons/kbutton.cpp b/kicker/kicker/buttons/kbutton.cpp index 73454b99f..d39346edb 100644 --- a/kicker/kicker/buttons/kbutton.cpp +++ b/kicker/kicker/buttons/kbutton.cpp @@ -33,6 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "menumanager.h" #include "k_mnu.h" +#include "k_mnu_stub.h" #include "kbutton.h" #include "kbutton.moc" @@ -43,7 +44,7 @@ KButton::KButton( TQWidget* parent ) TQToolTip::add(this, i18n("Applications, tasks and desktop sessions")); setTitle(i18n("K Menu")); - setPopup(MenuManager::the()->kmenu()); + setPopup(MenuManager::the()->kmenu()->widget()); MenuManager::the()->registerKButton(this); setIcon("kmenu"); diff --git a/kicker/kicker/buttons/knewbutton.cpp b/kicker/kicker/buttons/knewbutton.cpp new file mode 100644 index 000000000..9c9f438ac --- /dev/null +++ b/kicker/kicker/buttons/knewbutton.cpp @@ -0,0 +1,455 @@ +/***************************************************************** + +Copyright (c) 2006 Stephan Binner <binner@kde.org> + Stephan Kulow <coolo@kde.org> + Dirk Mueller <mueller@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <cassert> +#include <cmath> + +#include <tqtooltip.h> +#include <tqpainter.h> +#include <tqcursor.h> +#include <private/qeffects_p.h> + +#include <klocale.h> +#include <kapplication.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kdebug.h> + +#include "kickerSettings.h" + +#include "config.h" +#include "global.h" + +#include "menumanager.h" +#include "k_mnu_stub.h" +#include "k_new_mnu.h" + +#include "knewbutton.h" +#include "knewbutton.moc" + +KNewButton *KNewButton::m_self = 0; + +KNewButton::KNewButton( TQWidget* parent ) + : KButton( parent ), + m_oldPos(0,0) +{ + Q_ASSERT( !m_self ); + m_self = this; + m_hoverTimer = -1; + m_openTimer = -1; + m_active = false; + m_mouseInside = false; + m_drag = false; + + setIconAlignment((Qt::AlignmentFlags)(AlignTop|AlignRight)); + setAcceptDrops(true); + setIcon("kmenu-suse"); + setDrawArrow(false); + + m_movie = new TQMovie(locate("data", "kicker/pics/kmenu_basic.mng")); + m_movie->connectUpdate(this, TQT_SLOT(updateMovie())); + m_movie->connectStatus(this, TQT_SLOT(slotStatus(int))); + m_movie->connectResize(this, TQT_SLOT(slotSetSize(const TQSize&))); + + TQApplication::desktop()->screen()->installEventFilter(this); + setMouseTracking(true); +} + +KNewButton::~KNewButton() +{ + if ( m_self == this ) + m_self = 0; + setMouseTracking(false); + delete m_movie; +} + +void KNewButton::slotStatus(int status) +{ + if(status == TQMovie::EndOfLoop) + slotStopAnimation(); +} + +TQColor KNewButton::borderColor() const +{ + TQImage img = m_active_pixmap.convertToImage(); + + for (int i = 0; i < img.width(); ++i) { + QRgb rgb = img.pixel(orientation() == Qt::Horizontal ? img.width() - i - 1 : + i, 2); + + if (qGreen(rgb) > 0x50) + return rgb; + } + + return img.pixel( orientation() == Qt::Horizontal ? img.width() - 2 : 2, 2); +} + +void KNewButton::show() +{ + KButton::show(); + + if (KickerSettings::firstRun()) { + TQTimer::singleShot(500,this,TQT_SLOT(slotExecMenu())); + KickerSettings::setFirstRun(false); + KickerSettings::writeConfig(); + } +} + +void KNewButton::updateMovie() +{ + m_oldPos = TQPoint( -1, -1 ); + drawEye(); + + if (!m_active && m_movie->running()) + m_movie->pause(); +} + +void KNewButton::setPopupDirection(KPanelApplet::Direction d) +{ + KButton::setPopupDirection(d); + + delete m_movie; + + switch (d) { + case KPanelApplet::Left: + setIconAlignment((Qt::AlignmentFlags)(AlignTop|AlignLeft)); + m_movie = new TQMovie(locate("data", "kicker/pics/kmenu_vertical.mng")); + break; + case KPanelApplet::Right: + setIconAlignment((Qt::AlignmentFlags)(AlignTop|AlignRight)); + m_movie = new TQMovie(locate("data", "kicker/pics/kmenu_vertical.mng")); + break; + case KPanelApplet::Up: + setIconAlignment((Qt::AlignmentFlags)(AlignTop|AlignHCenter)); + m_movie = new TQMovie(locate("data", "kicker/pics/kmenu_basic.mng")); + break; + case KPanelApplet::Down: + setIconAlignment((Qt::AlignmentFlags)(AlignBottom|AlignHCenter)); + m_movie = new TQMovie(locate("data", "kicker/pics/kmenu_flipped.mng")); + } + + m_movie->connectUpdate(this, TQT_SLOT(updateMovie())); + m_movie->connectStatus(this, TQT_SLOT(slotStatus(int))); + m_movie->connectResize(this, TQT_SLOT(slotSetSize(const TQSize&))); +} + +void KNewButton::slotSetSize(const TQSize& s) +{ + m_iconSize = s; +} + +double KNewButton::buttonScaleFactor(const TQSize& s) const +{ + double sf = 1.0; + + switch (popupDirection()) { + case KPanelApplet::Left: + case KPanelApplet::Right: +// sf = kMin(double(s.width()) / m_iconSize.height(), double(s.height()) / m_iconSize.width()); +// break; + case KPanelApplet::Up: + case KPanelApplet::Down: + sf = kMin(double(s.width()) / m_iconSize.width(), double(s.height()) / m_iconSize.height()); + break; + } + + if (sf > 0.8) sf = 1.0; + return sf; +} + +int KNewButton::widthForHeight(int height) const +{ + int r = m_iconSize.width() * buttonScaleFactor(TQSize(m_iconSize.width(), height)); + + if (!m_movie->running() && height != m_active_pixmap.height()) + { + KNewButton* that = const_cast<KNewButton*>(this); + TQTimer::singleShot(0, that, TQT_SLOT(slotStopAnimation())); + } + + return r; +} + +int KNewButton::preferredDimension(int panelDim) const +{ + return kMax(m_icon.width(), m_icon.height()); +} + +int KNewButton::heightForWidth(int width) const +{ + int r = m_iconSize.width() * buttonScaleFactor(TQSize(width, m_iconSize.height())); + if (!m_movie->running() && width != m_active_pixmap.width()) + { + KNewButton* that = const_cast<KNewButton*>(this); + TQTimer::singleShot(0, that, TQT_SLOT(slotStopAnimation())); + } + return r; +} + +bool KNewButton::eventFilter(TQObject *o, TQEvent *e) +{ + if (e->type() == TQEvent::MouseButtonRelease || + e->type() == TQEvent::MouseButtonPress || + e->type() == TQEvent::MouseButtonDblClick ) + { + TQMouseEvent *me = static_cast<TQMouseEvent *>(e); + if (rect().contains(mapFromGlobal(me->globalPos()))) + { + if (m_pressedDuringPopup && m_popup && m_openTimer != -1 + && (me->button() & Qt::LeftButton) ) + return true; + } + } + + if (KickerSettings::kickoffDrawGeekoEye() && e->type() == TQEvent::MouseMove) + { + TQMouseEvent *me = static_cast<TQMouseEvent *>(e); + if ((me->state() & MouseButtonMask) == NoButton) + drawEye(); + } + + return KButton::eventFilter(o, e); +} + +void KNewButton::drawEye() +{ +#define eye_x 62 +#define eye_y 13 + TQPoint mouse = TQCursor::pos(); + TQPoint me = mapToGlobal(TQPoint(eye_x, eye_y)); + double a = atan2(mouse.y() - me.y(), mouse.x() - me.x()); + int dx = int(2.1 * cos(a)); + int dy = int(2.1 * sin(a)); + + TQPoint newpos(eye_x+dx,eye_y+dy); + if (newpos!=m_oldPos) { + m_oldPos = newpos; + TQPixmap pixmap = m_active_pixmap; + + double sf = 1.0; + + if(!m_movie->framePixmap().isNull()) + { + pixmap = m_movie->framePixmap(); + pixmap.detach(); + m_iconSize = pixmap.size(); + sf = buttonScaleFactor(size()); + + if (KickerSettings::kickoffDrawGeekoEye()) { + TQPainter p(&pixmap); + p.setPen(white); + p.setBrush(white); + // p.setPen(TQColor(110,185,55)); + p.drawRect(eye_x+dx, eye_y+dy, 2, 2); + p. end(); + } + } + + TQWMatrix matrix; + switch (popupDirection()) { + case KPanelApplet::Left: + matrix.scale(sf, -sf); + matrix.rotate(90); + break; + case KPanelApplet::Up: + matrix.scale(sf, sf); + break; + case KPanelApplet::Right: + matrix.scale(sf, -sf); + matrix.rotate(90); + break; + case KPanelApplet::Down: + matrix.scale(sf, sf); + break; + } + m_active_pixmap = pixmap.xForm(matrix); + + repaint(false); + } +#undef eye_x +#undef eye_y +} + +void KNewButton::enterEvent(TQEvent* e) +{ + KButton::enterEvent(e); + + TQSize s(size()); + s *= 0.25; + s = s.expandedTo(TQSize(6,6)); + + switch (popupDirection()) { + case KPanelApplet::Left: + m_sloppyRegion = TQRect(rect().topRight() - TQPoint(s.width()-1, 0), s); + break; + case KPanelApplet::Right: + m_sloppyRegion = TQRect(rect().topLeft(), s); + break; + case KPanelApplet::Up: + m_sloppyRegion = TQRect(rect().bottomLeft() - TQPoint(0, s.height()-1), s); + break; + case KPanelApplet::Down: + m_sloppyRegion = TQRect(rect().topLeft(), s); + } + + m_active = true; + m_movie->unpause(); + m_movie->restart(); +} + +void KNewButton::rewindMovie() +{ + m_oldPos = TQPoint( -1, -1 ); + m_movie->unpause(); +} + +void KNewButton::dragEnterEvent(TQDragEnterEvent* /*e*/) +{ + if (m_hoverTimer != -1) + killTimer(m_hoverTimer); + + m_hoverTimer = startTimer(TQApplication::startDragTime()); + m_mouseInside = true; + m_drag = true; +} + +void KNewButton::dragLeaveEvent(TQDragLeaveEvent* /*e*/) +{ + m_mouseInside = false; + m_drag = false; +} + +void KNewButton::leaveEvent(TQEvent* e) +{ + m_mouseInside = false; + if (m_hoverTimer != -1) + killTimer(m_hoverTimer); + m_hoverTimer = -1; + + KButton::leaveEvent(e); +} + +void KNewButton::mouseMoveEvent(TQMouseEvent* e) +{ + KButton::mouseMoveEvent(e); + + m_mouseInside = m_sloppyRegion.contains(e->pos()); + + if ( m_sloppyRegion.contains(e->pos())) + { + if (m_hoverTimer == -1 && KickerSettings::openOnHover()) + m_hoverTimer = startTimer(kMax(200,TQApplication::doubleClickInterval()/2)); + } + else if (m_hoverTimer != -1) + { + killTimer(m_hoverTimer); + m_hoverTimer = -1; + } +} + +void KNewButton::slotStopAnimation() +{ + m_active = false; + m_movie->pause(); + m_movie->restart(); + TQTimer::singleShot(200, this, TQT_SLOT(rewindMovie())); +} + +const TQPixmap& KNewButton::labelIcon() const +{ + return m_active_pixmap; +} + +void KNewButton::slotExecMenu() +{ + if (m_openTimer != -1) + killTimer(m_openTimer); + + m_openTimer = startTimer(TQApplication::doubleClickInterval() * 3); + + if (m_active) + { + m_active = false; + m_movie->pause(); + m_movie->restart(); + } + + KButton::slotExecMenu(); + + assert(!KickerTip::tippingEnabled()); + assert(dynamic_cast<KMenu*>(m_popup)); + + disconnect(dynamic_cast<KMenu*>(m_popup), TQT_SIGNAL(aboutToHide()), this, + TQT_SLOT(slotStopAnimation())); + connect(dynamic_cast<KMenu*>(m_popup), TQT_SIGNAL(aboutToHide()), + TQT_SLOT(slotStopAnimation())); + + m_popup->move(KickerLib::popupPosition(popupDirection(), m_popup, this)); + // I wish KMenu would properly done itself when it closes. But it doesn't. + + bool useEffect = true; // could be TQApplication::isEffectEnabled() + useEffect = false; // too many TQt bugs to be useful + if (m_drag) + useEffect = false; + + m_drag = false; // once is enough + + if (useEffect) + { + switch (popupDirection()) { + case KPanelApplet::Left: + qScrollEffect(m_popup, QEffects::LeftScroll); + break; + case KPanelApplet::Up: + qScrollEffect(m_popup, QEffects::UpScroll); + break; + case KPanelApplet::Right: + qScrollEffect(m_popup, QEffects::RightScroll); + break; + case KPanelApplet::Down: + qScrollEffect(m_popup, QEffects::DownScroll); + break; + } + } + else + static_cast<KMenu*>(m_popup)->show(); +} + +void KNewButton::timerEvent(TQTimerEvent* e) +{ + if (e->timerId() == m_hoverTimer) + { + if (m_mouseInside && !isDown()) + showMenu(); + + killTimer(m_hoverTimer); + m_hoverTimer = -1; + } + if (e->timerId() == m_openTimer) + { + killTimer(m_openTimer); + m_openTimer = -1; + } +} diff --git a/kicker/kicker/buttons/knewbutton.h b/kicker/kicker/buttons/knewbutton.h new file mode 100644 index 000000000..bcb8b8743 --- /dev/null +++ b/kicker/kicker/buttons/knewbutton.h @@ -0,0 +1,98 @@ +/***************************************************************** + +Copyright (c) 2006 Stephan Binner <binner@kde.org> + Stephan Kulow <coolo@kde.org> + Dirk Mueller <mueller@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __knewbutton_h__ +#define __knewbutton_h__ + +#include "kbutton.h" + +#include <tqmovie.h> +#include <tqpoint.h> + +/** + * Button that contains the PanelKMenu and client menu manager. + */ +class KNewButton : public KButton +{ + Q_OBJECT + +public: + KNewButton( TQWidget *parent ); + ~KNewButton(); + + static KNewButton *self() { return m_self; } + + void loadConfig( const KConfigGroup& config ); + + virtual const TQPixmap& labelIcon() const; + + virtual int widthForHeight(int height) const; + virtual int preferredDimension(int panelDim) const; + virtual int heightForWidth(int width) const; + + TQColor borderColor() const; + + virtual void setPopupDirection(KPanelApplet::Direction d); + +private slots: + void slotStatus(int); + void slotSetSize(const TQSize&); + void slotStopAnimation(); + void rewindMovie(); + void updateMovie(); + +protected: + virtual void show(); + virtual void slotExecMenu(); + virtual TQString tileName() { return "KMenu"; } + virtual TQString defaultIcon() const { return "go"; } + + virtual void enterEvent(TQEvent* e); + virtual void leaveEvent(TQEvent* e); + virtual void mouseMoveEvent(TQMouseEvent* e); + virtual void dragEnterEvent(TQDragEnterEvent*); + virtual void dragLeaveEvent(TQDragLeaveEvent*); + virtual bool eventFilter(TQObject *, TQEvent *); + void timerEvent(TQTimerEvent*); + +private: + void drawEye(); + double buttonScaleFactor(const TQSize& s) const; + + TQMovie* m_movie; + TQPixmap m_active_pixmap; + TQPoint m_oldPos; + TQSize m_iconSize; + TQRect m_sloppyRegion; + int m_hoverTimer; + int m_openTimer; + bool m_active; + bool m_mouseInside; + bool m_drag; + + static KNewButton *m_self; +}; + +#endif diff --git a/kicker/kicker/core/Makefile.am b/kicker/kicker/core/Makefile.am index 6986af604..25e7e733a 100644 --- a/kicker/kicker/core/Makefile.am +++ b/kicker/kicker/core/Makefile.am @@ -1,12 +1,14 @@ INCLUDES = -I$(srcdir)/../../libkicker -I../../libkicker \ - -I$(srcdir)/../ui -I$(srcdir)/../buttons -I$(top_srcdir)/libkonq \ - $(all_includes) + -I../ui -I$(srcdir)/../ui -I$(srcdir)/../buttons -I$(top_srcdir)/libkonq \ + $(all_includes) $(LIBBEAGLE_CFLAGS) $(GLIB_CFLAGS) noinst_LTLIBRARIES = libkicker_core.la +libkicker_core_la_COMPILE_FIRST = kmenubase.h + libkicker_core_la_SOURCES = extensionSettings.kcfgc \ main.cpp kicker.cpp kicker.skel \ - userrectsel.cpp containerarea.cpp \ + userrectsel.cpp containerarea.cpp kmenubase.ui \ applethandle.cpp container_base.cpp container_button.cpp \ container_applet.cpp container_extension.cpp extensionmanager.cpp \ menumanager.cpp pluginmanager.cpp showdesktop.cpp \ diff --git a/kicker/kicker/core/applethandle.cpp b/kicker/kicker/core/applethandle.cpp index 251cbc1bd..f5f398136 100644 --- a/kicker/kicker/core/applethandle.cpp +++ b/kicker/kicker/core/applethandle.cpp @@ -150,7 +150,7 @@ void AppletHandle::setFadeOutHandle(bool fadeOut) { if (!m_handleHoverTimer) { - m_handleHoverTimer = new TQTimer(this); + m_handleHoverTimer = new TQTimer(this, "m_handleHoverTimer"); connect(m_handleHoverTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(checkHandleHover())); m_applet->installEventFilter(this); @@ -177,11 +177,7 @@ bool AppletHandle::eventFilter(TQObject *o, TQEvent *e) m_drawHandle = true; resetLayout(); - if (m_handleHoverTimer) - { - m_handleHoverTimer->start(250); - } - break; + break; } case TQEvent::Leave: @@ -191,6 +187,11 @@ bool AppletHandle::eventFilter(TQObject *o, TQEvent *e) break; } + if (m_handleHoverTimer) + { + m_handleHoverTimer->start(250); + } + TQWidget* w = dynamic_cast<TQWidget*>(o); bool nowDrawIt = false; @@ -207,11 +208,6 @@ bool AppletHandle::eventFilter(TQObject *o, TQEvent *e) if (nowDrawIt != m_drawHandle) { - if (m_handleHoverTimer) - { - m_handleHoverTimer->stop(); - } - m_drawHandle = nowDrawIt; resetLayout(); } @@ -297,6 +293,11 @@ void AppletHandle::toggleMenuButtonOff() } m_menuButton->setDown(false); + + if (m_handleHoverTimer) + { + m_handleHoverTimer->start(250); + } } AppletHandleDrag::AppletHandleDrag(AppletHandle* parent) diff --git a/kicker/kicker/core/container_button.cpp b/kicker/kicker/core/container_button.cpp index 8ac39a47f..bb0249843 100644 --- a/kicker/kicker/core/container_button.cpp +++ b/kicker/kicker/core/container_button.cpp @@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "desktopbutton.h" #include "extensionbutton.h" #include "kbutton.h" +#include "knewbutton.h" #include "kicker.h" #include "kickerSettings.h" #include "kickertip.h" @@ -326,14 +327,20 @@ KMenuButtonContainer::KMenuButtonContainer(const KConfigGroup& config, TQPopupMe : ButtonContainer(opMenu, parent) { checkImmutability(config); - embedButton( new KButton(this) ); + if(KickerSettings::legacyKMenu()) + embedButton( new KButton(this) ); + else + embedButton( new KNewButton(this) ); _actions = PanelAppletOpMenu::KMenuEditor; } KMenuButtonContainer::KMenuButtonContainer(TQPopupMenu *opMenu, TQWidget* parent) : ButtonContainer(opMenu, parent) { - embedButton( new KButton(this) ); + if(KickerSettings::legacyKMenu()) + embedButton( new KButton(this) ); + else + embedButton( new KNewButton(this) ); _actions = PanelAppletOpMenu::KMenuEditor; } diff --git a/kicker/kicker/core/containerarea.cpp b/kicker/kicker/core/containerarea.cpp index 7d63d562a..1bd80bc65 100644 --- a/kicker/kicker/core/containerarea.cpp +++ b/kicker/kicker/core/containerarea.cpp @@ -87,7 +87,8 @@ ContainerArea::ContainerArea(KConfig* _c, m_immutable(_c->isImmutable()), m_updateBackgroundsCalled(false), m_layout(0), - m_addAppletDialog(0) + m_addAppletDialog(0), + _autoScrollTimer(0, "ContainerArea::autoScrollTimer") { setBackgroundOrigin( WidgetOrigin ); diff --git a/kicker/kicker/core/kicker.cpp b/kicker/kicker/core/kicker.cpp index de37c609e..d91e1eaf9 100644 --- a/kicker/kicker/core/kicker.cpp +++ b/kicker/kicker/core/kicker.cpp @@ -48,6 +48,8 @@ #include "extensionmanager.h" #include "pluginmanager.h" #include "menumanager.h" +#include "k_new_mnu.h" +#include "k_mnu_stub.h" #include "k_mnu.h" #include "showdesktop.h" #include "panelbutton.h" @@ -106,6 +108,7 @@ Kicker::Kicker() KGlobal::iconLoader()->addExtraDesktopThemes(); + KGlobal::locale()->insertCatalogue("kdmgreet"); KGlobal::locale()->insertCatalogue("libkonq"); KGlobal::locale()->insertCatalogue("libdmctl"); KGlobal::locale()->insertCatalogue("libtaskbar"); @@ -212,7 +215,7 @@ bool Kicker::highlightMenuItem(const TQString &menuId) void Kicker::showKMenu() { - MenuManager::the()->showKMenu(); + MenuManager::the()->kmenuAccelActivated(); } void Kicker::popupKMenu(const TQPoint &p) diff --git a/kicker/kicker/core/kmenubase.ui b/kicker/kicker/core/kmenubase.ui new file mode 100644 index 000000000..1adb59b38 --- /dev/null +++ b/kicker/kicker/core/kmenubase.ui @@ -0,0 +1,300 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KMenuBase</class> +<widget class="QDialog"> + <property name="name"> + <cstring>KMenu</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>723</width> + <height>580</height> + </rect> + </property> + <property name="caption"> + <string>KMenu</string> + </property> + <property name="frameShadow" stdset="0"> + <string>MShadow</string> + </property> + <property name="frameShape" stdset="0"> + <string>MShape</string> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>m_search</cstring> + </property> + <property name="geometry"> + <rect> + <x>20</x> + <y>40</y> + <width>190</width> + <height>54</height> + </rect> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>0</number> + </property> + <widget class="QFrame"> + <property name="name"> + <cstring>m_searchFrame</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>52</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>52</height> + </size> + </property> + <property name="frameShape"> + <enum>StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>Raised</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout18</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_searchLabel</cstring> + </property> + <property name="backgroundOrigin"> + <enum>ParentOrigin</enum> + </property> + <property name="font"> + <font> + <pointsize>14</pointsize> + </font> + </property> + <property name="text"> + <string>Search:</string> + </property> + </widget> + <widget class="KHistoryCombo"> + <property name="name"> + <cstring>m_kcommand</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>m_searchPixmap</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="backgroundMode"> + <enum>PaletteBackground</enum> + </property> + <property name="backgroundOrigin"> + <enum>ParentOrigin</enum> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + </hbox> + </widget> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer5_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>16</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>m_footer</cstring> + </property> + <property name="geometry"> + <rect> + <x>20</x> + <y>110</y> + <width>407</width> + <height>34</height> + </rect> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>4</number> + </property> + <property name="spacing"> + <number>4</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_userInfo</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>User&nbsp;<b>user</b>&nbsp;on&nbsp;<b>host</b></string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer13_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>MinimumExpanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QToolButton"> + <property name="name"> + <cstring>m_branding</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>4</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>90</width> + <height>24</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>image0</iconset> + </property> + <property name="usesBigPixmap"> + <bool>true</bool> + </property> + <property name="autoRaise"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer13</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Fixed</enum> + </property> + <property name="sizeHint"> + <size> + <width>14</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> +</widget> +<customwidgets> +</customwidgets> +<images> + <image name="image0"> + <data format="PNG" length="347">89504e470d0a1a0a0000000d494844520000005a0000001808060000007a38ea6500000122494441546881ed98610e83200c85c7e2a93c0087e6005c0b7f754152ea43a532ec972c512cf5f96c28d3c5183f467fbe4f0b780b66b41266b41266b412cbd302b4594348d2f5e8bd93e2e83a9a93e2ada21b397a51355e57d1794592695c954af16b08899b23e5f955f41a42a25fbbfcbe709a9ed0c9998eb25b3aa2f72e7aef4634fbdf395c3a72d3f346811c73f390b172fcac36eefc2a522172e3746fd1e8b3a2a579523e3ae7c6b9fbf434f46e764623cda18ce78cc973213950b108b99e1ee6235b398e050d44e2f2f1abb966e3f43eba5c0e466ba03df4d4fa0982b8469706b65469f9a0b57d271787beb89ab63b970da9c1b5c4ba59bf4723464b3de9eebfe0531a3de20e64ba6f1da3f50a62ca8a1e91e92a7a54cc6825cc6825cc682536f10e058bc1bcdf310000000049454e44ae426082</data> + </image> +</images> +<includes> + <include location="local" impldecl="in implementation">kmenubase.ui.h</include> +</includes> +<functions> + <function access="private" specifier="non virtual">init()</function> +</functions> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> +</includehints> +</UI> diff --git a/kicker/kicker/core/kmenubase.ui.h b/kicker/kicker/core/kmenubase.ui.h new file mode 100644 index 000000000..e1ed1ac25 --- /dev/null +++ b/kicker/kicker/core/kmenubase.ui.h @@ -0,0 +1,9 @@ +#include <X11/Xlib.h> + +void KMenuBase::init() +{ + XSetWindowAttributes attrs; + attrs.override_redirect = True; + XChangeWindowAttributes( qt_xdisplay(), winId(), CWOverrideRedirect, &attrs ); + setWFlags( Qt::WType_Popup ); +} diff --git a/kicker/kicker/core/main.cpp b/kicker/kicker/core/main.cpp index 16090b9af..76e94a0e3 100644 --- a/kicker/kicker/core/main.cpp +++ b/kicker/kicker/core/main.cpp @@ -108,7 +108,7 @@ extern "C" KDE_EXPORT int kdemain( int argc, char ** argv ) appname.sprintf("kicker-screen-%d", kicker_screen_number); KAboutData aboutData( appname.data(), I18N_NOOP("KDE Panel"), - version, description, KAboutData::License_BSD, + version, description, KAboutData::License_GPL_V2, I18N_NOOP("(c) 1999-2010, The KDE Team") ); aboutData.addAuthor("Timothy Pearson", I18N_NOOP("Current maintainer"), "kb9vqf@pearsoncomputing.net"); diff --git a/kicker/kicker/core/menumanager.cpp b/kicker/kicker/core/menumanager.cpp index 908f6bdf9..61110de14 100644 --- a/kicker/kicker/core/menumanager.cpp +++ b/kicker/kicker/core/menumanager.cpp @@ -31,9 +31,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "client_mnu.h" #include "container_extension.h" #include "global.h" +#include "k_new_mnu.h" #include "k_mnu.h" +#include "k_mnu_stub.h" #include "kicker.h" #include "panelbutton.h" +#include "kickerSettings.h" #include "menumanager.h" #include "menumanager.moc" @@ -62,7 +65,11 @@ MenuManager* MenuManager::the() MenuManager::MenuManager(TQObject *parent) : TQObject(parent, "MenuManager"), DCOPObject("MenuManager") { - m_kmenu = new PanelKMenu; + if (KickerSettings::legacyKMenu()) + m_kmenu = new KMenuStub(new PanelKMenu); + else + m_kmenu = new KMenuStub(new KMenu); + kapp->dcopClient()->setNotifications(true); connect(kapp->dcopClient(), TQT_SIGNAL(applicationRemoved(const TQCString&)), this, TQT_SLOT(applicationRemoved(const TQCString&))); @@ -83,14 +90,8 @@ void MenuManager::slotSetKMenuItemActive() m_kmenu->selectFirstItem(); } -void MenuManager::showKMenu() -{ - m_kmenu->showMenu(); -} - void MenuManager::popupKMenu(const TQPoint &p) { -// kdDebug(1210) << "popupKMenu()" << endl; if (m_kmenu->isVisible()) { m_kmenu->hide(); @@ -120,7 +121,7 @@ void MenuManager::unregisterKButton(PanelPopupButton *button) m_kbuttons.remove(button); } -PanelPopupButton* MenuManager::findKButtonFor(TQPopupMenu* menu) +PanelPopupButton* MenuManager::findKButtonFor(TQWidget* menu) { KButtonList::const_iterator itEnd = m_kbuttons.constEnd(); for (KButtonList::const_iterator it = m_kbuttons.constBegin(); it != itEnd; ++it) @@ -173,7 +174,7 @@ void MenuManager::kmenuAccelActivated() const TQSize size = m_kmenu->sizeHint(); m_kmenu->resize(size.width(),size.height()); - PanelPopupButton* button = findKButtonFor(m_kmenu); + PanelPopupButton* button = findKButtonFor(m_kmenu->widget()); // let's unhide the panel while we're at it. traverse the widget // hierarchy until we find the panel, if any @@ -193,7 +194,6 @@ void MenuManager::kmenuAccelActivated() menuParent = menuParent->parent(); } - button->showMenu(); } } @@ -217,7 +217,7 @@ TQCString MenuManager::createMenu(TQPixmap icon, TQString text) void MenuManager::removeMenu(TQCString menu) { - bool iterate = true; + bool iterate = true, need_adjustSize = false; ClientMenuList::iterator it = clientmenus.begin(); for (; it != clientmenus.end(); iterate ? ++it : it) { @@ -228,15 +228,17 @@ void MenuManager::removeMenu(TQCString menu) m_kmenu->removeClientMenu(m->idInParentMenu); it = clientmenus.erase(it); iterate = false; + need_adjustSize = true; } } - m_kmenu->adjustSize(); + if (need_adjustSize) + m_kmenu->adjustSize(); } void MenuManager::applicationRemoved(const TQCString& appRemoved) { - bool iterate = true; + bool iterate = true, need_adjustSize = false; ClientMenuList::iterator it = clientmenus.begin(); for (; it != clientmenus.end(); iterate ? ++it : it) { @@ -247,9 +249,11 @@ void MenuManager::applicationRemoved(const TQCString& appRemoved) m_kmenu->removeClientMenu(m->idInParentMenu); it = clientmenus.erase(it); iterate = false; + need_adjustSize = true; } } - m_kmenu->adjustSize(); + if (need_adjustSize) + m_kmenu->adjustSize(); } bool MenuManager::process(const TQCString &fun, const TQByteArray &data, diff --git a/kicker/kicker/core/menumanager.h b/kicker/kicker/core/menumanager.h index e9d7dfef4..1139b0b61 100644 --- a/kicker/kicker/core/menumanager.h +++ b/kicker/kicker/core/menumanager.h @@ -28,7 +28,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <tqvaluelist.h> class PanelKMenu; +class KMenu; class KickerClientMenu; +class KMenuStub; class PanelPopupButton; typedef TQValueList<PanelPopupButton*> KButtonList; @@ -50,13 +52,12 @@ public: bool process(const TQCString &fun, const TQByteArray &data, TQCString& replyType, TQByteArray &reply); // KMenu controls - PanelKMenu* kmenu() { return m_kmenu; } - void showKMenu(); + KMenuStub* kmenu() { return m_kmenu; } void popupKMenu(const TQPoint &p); void registerKButton(PanelPopupButton *button); void unregisterKButton(PanelPopupButton *button); - PanelPopupButton* findKButtonFor(TQPopupMenu* menu); + PanelPopupButton* findKButtonFor(TQWidget* menu); ~MenuManager(); public slots: @@ -67,7 +68,7 @@ protected slots: void applicationRemoved(const TQCString&); protected: - PanelKMenu* m_kmenu; + KMenuStub* m_kmenu; typedef TQValueList<KickerClientMenu*> ClientMenuList; ClientMenuList clientmenus; diff --git a/kicker/kicker/core/unhidetrigger.cpp b/kicker/kicker/core/unhidetrigger.cpp index 7dcf1a127..0a5093a61 100644 --- a/kicker/kicker/core/unhidetrigger.cpp +++ b/kicker/kicker/core/unhidetrigger.cpp @@ -39,7 +39,7 @@ UnhideTrigger::UnhideTrigger() , _lastXineramaScreen( -1 ) , enabledCount( 0 ) { - _timer = new TQTimer( this ); + _timer = new TQTimer( this, "UnhideTrigger" ); connect( _timer, TQT_SIGNAL(timeout()), TQT_SLOT(pollMouse()) ); } diff --git a/kicker/kicker/interfaces/Makefile.am b/kicker/kicker/interfaces/Makefile.am new file mode 100644 index 000000000..11f3f94b9 --- /dev/null +++ b/kicker/kicker/interfaces/Makefile.am @@ -0,0 +1,12 @@ +METASOURCES = AUTO +INCLUDES= -I$(top_srcdir)/src $(all_includes) + +# The library containing the plugin base class +lib_LTLIBRARIES = libkickoffsearch_interfaces.la +libkickoffsearch_interfaces_la_SOURCES = kickoff-search-plugin.cpp kickoffsearchinterface.cpp +libkickoffsearch_interfaces_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 + +kickoffsearchincludedir = $(includedir) +kickoffsearchinclude_HEADERS = kickoff-search-plugin.h kickoffsearchinterface.h + +kde_servicetypes_DATA = kickoffsearchplugin.desktop diff --git a/kicker/kicker/interfaces/kickoff-search-plugin.cpp b/kicker/kicker/interfaces/kickoff-search-plugin.cpp new file mode 100644 index 000000000..c229c85b0 --- /dev/null +++ b/kicker/kicker/interfaces/kickoff-search-plugin.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "kickoff-search-plugin.h" +#include <tqobjectlist.h> + +KickoffSearch::Plugin::Plugin(TQObject *parent, const char* name ) + :TQObject( parent, name ) +{ +} + +KickoffSearch::Plugin::~Plugin() +{ +} + +KickoffSearch::KickoffSearchInterface* KickoffSearch::Plugin::kickoffSearchInterface() +{ + return static_cast<KickoffSearchInterface*>( parent()->child( 0, "KickoffSearch::KickoffSearchInterface" ) ); +} + +#include "kickoff-search-plugin.moc" diff --git a/kicker/kicker/interfaces/kickoff-search-plugin.h b/kicker/kicker/interfaces/kickoff-search-plugin.h new file mode 100644 index 000000000..e91d079e7 --- /dev/null +++ b/kicker/kicker/interfaces/kickoff-search-plugin.h @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@kde.org> * + * Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef KICKOFF_SEARCH_PLUGIN_H +#define KICKOFF_SEARCH_PLUGIN_H + +#include "kickoffsearchinterface.h" + +#include <tqobject.h> +#include <kurl.h> +#include <kservice.h> + +typedef enum { + ACTIONS = 0, + APPS, + BOOKMARKS, + NOTES, + MAILS, + FILES, + MUSIC, + WEBHIST, + CHATS, + FEEDS, + PICS, + VIDEOS, + DOCS, + OTHER, + num_categories +} CATEGORY; + +class HitMenuItem +{ +public: + HitMenuItem (int id, int category) + : id (id), category (category),score(0) { } /* dummy */ + HitMenuItem (TQString name, TQString info, KURL uri, TQString mimetype, int id, int category, TQString icon=TQString::null, int score = 0) + : display_name (name) + , display_info (info) + , uri (uri) + , mimetype (mimetype) + , id (id) + , category (category) + , icon (icon) + , score (score) + , service (NULL) { } + + ~HitMenuItem () { } + + bool operator< (HitMenuItem item) + { + return ((category == item.category && score > item.score) || (category == item.category && id < item.id) || + (category < item.category)); + } + + // FIXME: We dont really need to store display_name and display_info + TQString display_name; // name to display + TQString display_info; // other information to display + KURL uri; // uri to open when clicked + TQString mimetype; + int id; // id of the item in the menu + int category; + TQString icon; + int score; + KService::Ptr service; + + TQString quotedPath () const + { + return uri.path ().replace ('"', "\\\""); + } +}; + +namespace KickoffSearch { + + class Plugin : public TQObject + { + Q_OBJECT + + public: + Plugin(TQObject *parent, const char* name=0); + virtual ~Plugin(); + + virtual bool daemonRunning()=0; + virtual void query(TQString,bool)=0; + + KickoffSearchInterface * kickoffSearchInterface(); + }; +}; + +#endif /* KICKOFF_SEARCH_PLUGIN_H */ diff --git a/kicker/kicker/interfaces/kickoffsearchinterface.cpp b/kicker/kicker/interfaces/kickoffsearchinterface.cpp new file mode 100644 index 000000000..6df9d0630 --- /dev/null +++ b/kicker/kicker/interfaces/kickoffsearchinterface.cpp @@ -0,0 +1,27 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "kickoffsearchinterface.h" + +KickoffSearch::KickoffSearchInterface::KickoffSearchInterface( TQObject* parent, const char* name ) + :TQObject( parent, name ) +{ +} + +#include "kickoffsearchinterface.moc" diff --git a/kicker/kicker/interfaces/kickoffsearchinterface.h b/kicker/kicker/interfaces/kickoffsearchinterface.h new file mode 100644 index 000000000..91d28e7e6 --- /dev/null +++ b/kicker/kicker/interfaces/kickoffsearchinterface.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef KICKOFFSEARCHINTERFACE_H +#define KICKOFFSEARCHINTERFACE_H + +#include <tqobject.h> + +class HitMenuItem; + +namespace KickoffSearch +{ + class KickoffSearchInterface :public TQObject + { + Q_OBJECT + + public: + KickoffSearchInterface( TQObject* parent, const char* name = 0); + + public: + virtual bool anotherHitMenuItemAllowed(int cat) = 0; + virtual void addHitMenuItem(HitMenuItem* item) = 0; + virtual void searchOver() = 0; + virtual void initCategoryTitlesUpdate() = 0; + virtual void updateCategoryTitles() = 0; + }; +} + +#endif /* SELECTIONINTERFACE_H */ + diff --git a/kicker/kicker/interfaces/kickoffsearchplugin.desktop b/kicker/kicker/interfaces/kickoffsearchplugin.desktop new file mode 100644 index 000000000..137d10a1d --- /dev/null +++ b/kicker/kicker/interfaces/kickoffsearchplugin.desktop @@ -0,0 +1,4 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KickoffSearch/Plugin +Comment=A search plugin for Kickoff diff --git a/kicker/kicker/plugins/Makefile.am b/kicker/kicker/plugins/Makefile.am new file mode 100644 index 000000000..bab1011f9 --- /dev/null +++ b/kicker/kicker/plugins/Makefile.am @@ -0,0 +1,24 @@ +INCLUDES = -I$(top_srcdir)/interfaces $(all_includes) $(LIBBEAGLE_CFLAGS) $(GLIB_CFLAGS) +METASOURCES = AUTO + +# Install this plugin in the KDE modules directory +kde_module_LTLIBRARIES = kickoffsearch_beagle.la + +# Srcs for the plugin +kickoffsearch_beagle_la_SOURCES = kickoff-beagle-plugin.cpp beaglesearch.cpp + +# Libs needed by the plugin +kickoffsearch_beagle_la_LIBADD = $(LIB_KPARTS) ../interfaces/libkickoffsearch_interfaces.la \ + $(LIBBEAGLE_LIBADD) $(GLIB_LIBADD) + +# LD flags for the plugin +# -module says: this is a module, i.e. something you're going to dlopen +# so e.g. it has no version number like a normal shared lib would have. +kickoffsearch_beagle_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) + +# Install the desktop file needed to detect the plugin +kde_services_DATA = kickoffsearch_beagle.desktop + +# i18n translation messages +messages: rc.cpp + $(XGETTEXT) *.cpp *.h -o $(podir)/kickoffsearch_beagle.pot diff --git a/kicker/kicker/plugins/beaglesearch.cpp b/kicker/kicker/plugins/beaglesearch.cpp new file mode 100644 index 000000000..9f86c8fbd --- /dev/null +++ b/kicker/kicker/plugins/beaglesearch.cpp @@ -0,0 +1,362 @@ +/***************************************************************** + + Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> + + 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 "beaglesearch.h" + +#include <tqdatetime.h> +#include <tqmutex.h> +#include <tqstringlist.h> +#include <tqapplication.h> +#include <time.h> + +void beagle_init () +{ + g_type_init (); +} + +// ---------------- Hit --------------------------- + +Hit::Hit (BeagleHit *_hit) : processed (false) +{ + hit = beagle_hit_ref (_hit); +} + +Hit::~Hit () +{ + beagle_hit_unref (hit); + if (! processed) + return; + TQDictIterator<TQStringList> it (property_map); + for( ; it.current(); ++it ) + ((TQStringList *)it.current())->clear (); + +} + +void Hit::processProperties () +{ + processed = true; + GSList *prop_list = beagle_hit_get_all_properties (hit); + GSList *it; + property_map.setAutoDelete (true); + for (it = prop_list; it; it = it->next) { + BeagleProperty *property = (BeagleProperty *) it->data; + TQString key = TQString::fromUtf8 (beagle_property_get_key (property)); + if (! property_map [key]) + property_map.insert (key, new TQStringList ()); + property_map [key]->append (TQString::fromUtf8 (beagle_property_get_value (property))); + } + g_slist_free (prop_list); +} + +const TQString Hit::operator[] (TQString prop_name) +{ + if (! processed) + processProperties (); + + TQStringList *prop_list = property_map [prop_name]; + if (! prop_list) + return TQString::null; + if (prop_list->count () != 1) + return TQString::null; + return (TQString)prop_list->first (); +} + +// ---------------- BeagleSearch ------------------ + +BeagleSearchResult::BeagleSearchResult(int client_id) + : client_id (client_id), total (0) +{ + hitlist = new TQPtrList<Hit>; + hitlist->setAutoDelete (true); +} + + +BeagleSearchResult::~BeagleSearchResult() +{ + // everything is set to autodelete +} + +void BeagleSearchResult::addHit(BeagleHit *_hit) +{ + Hit *hit = new Hit (_hit); + hitlist->prepend (hit); +} + +const TQPtrList<Hit> *BeagleSearchResult::getHits () const +{ + return hitlist; +} + + +static int total_hits; + +static void print_feed_item_hit (BeagleHit *hit) +{ + const char *text; + + if (beagle_hit_get_one_property (hit, "dc:title", &text)) + g_print ("Blog: %s\n", text); +} + +static void print_file_hit (BeagleHit *hit) +{ + g_print ("File: %s, (%s)\n", beagle_hit_get_uri (hit), beagle_hit_get_mime_type (hit)); +} + +static void print_other_hit (BeagleHit *hit) +{ + const char *text; + + g_print ("%s (%s)", beagle_hit_get_uri (hit), + beagle_hit_get_source (hit)); + if (beagle_hit_get_one_property (hit, "dc:title", &text)) + g_print ("title = %s\n", text); +} + +static void print_hit (BeagleHit *hit) +{ + if (strcmp (beagle_hit_get_type (hit), "FeedItem") == 0) { + print_feed_item_hit (hit); + } + else if (strcmp (beagle_hit_get_type (hit), "File") == 0) { + print_file_hit (hit); + } else { + print_other_hit (hit); + } +} + +// ---------------- BeagleSearchClient ------------------ + +void BeagleSearchClient::run () +{ + kdDebug () << "Starting query ..." << endl; + + TQTime query_timer; + query_timer.start (); + + g_signal_connect (query, "hits-added", + G_CALLBACK (hitsAddedSlot), + this); + g_signal_connect (query, "finished", + G_CALLBACK (finishedSlot), + this); + beagle_client_send_request_async (client, + BEAGLE_REQUEST (query), + NULL); + g_main_loop_run (main_loop); + kdDebug () << "Finished query ..." << endl; + + TQCustomEvent *ev; + if (collate_results) { + result->query_msec = query_timer.elapsed (); + + ev = new TQCustomEvent (RESULTFOUND, result); + TQApplication::postEvent (object, ev); + } + + ev = new TQCustomEvent (KILLME, this); + TQApplication::postEvent (object, ev); + +} + +void BeagleSearchClient::stopClient () +{ + if (finished ()) + return; // duh! + kdDebug () << "Query thread " << id << " not yet finished ..." << endl; + // get ready for suicide + client_mutex->lock (); + kill_me = true; + g_signal_handlers_disconnect_by_func ( + query, + (void *)hitsAddedSlot, + this); + g_signal_handlers_disconnect_by_func ( + query, + (void *)finishedSlot, + this); + g_main_loop_quit (main_loop); + client_mutex->unlock (); +} + +void BeagleSearchClient::hitsAddedSlot (BeagleQuery *query, + BeagleHitsAddedResponse *response, + BeagleSearchClient *bsclient) +{ + GSList *hits, *l; + gint i; + gint nr_hits; + + // check if we are supposed to be killed + bsclient->client_mutex->lock (); + if (bsclient->kill_me) { + kdDebug () << "Suicide time before processing" << endl; + bsclient->client_mutex->unlock (); + return; + } + bsclient->client_mutex->unlock (); + + hits = beagle_hits_added_response_get_hits (response); + + nr_hits = g_slist_length (hits); + total_hits += nr_hits; + g_print ("Found hits (%d) at %ld:\n", nr_hits, time (NULL)); + + BeagleSearchResult *search_result; + if (! bsclient->collate_results) + search_result = new BeagleSearchResult (bsclient->id); + else + search_result = bsclient->result; + search_result->total += nr_hits; + + for (l = hits, i = 1; l; l = l->next, ++i) { + //g_print ("[%d] ", i); + //print_hit (BEAGLE_HIT (l->data)); + //g_print ("\n"); + + search_result->addHit(BEAGLE_HIT (l->data));//hit); + } + g_print ("[%ld] hits adding finished \n", time (NULL)); + + // check if we are supposed to be killed + bsclient->client_mutex->lock (); + if (bsclient->kill_me) { + kdDebug () << "Suicide time before sending ..." << endl; + bsclient->client_mutex->unlock (); + if (! bsclient->collate_results) + delete search_result; + return; + } + bsclient->client_mutex->unlock (); + + // time to send back results, if user asked so + if (bsclient->collate_results) + return; + TQCustomEvent *ev = new TQCustomEvent (RESULTFOUND, search_result); + g_print ("[%ld] event notified \n", time (NULL)); + TQApplication::postEvent (bsclient->object, ev); +} + +void BeagleSearchClient::finishedSlot (BeagleQuery *query, + BeagleFinishedResponse *response, + BeagleSearchClient *bsclient) +{ + // check if we are supposed to be killed + bsclient->client_mutex->lock (); + bool should_kill = bsclient->kill_me; + TQObject* receiver = bsclient->object; + bsclient->client_mutex->unlock (); + + if (should_kill) + return; + + g_main_loop_quit (bsclient->main_loop); + + if (bsclient->collate_results) + return; // if we are collating, everything will be send from a central place + if (receiver) { + TQCustomEvent *ev = new TQCustomEvent (SEARCHOVER, bsclient); + g_print ("[%ld] query finish notified \n", time (NULL)); + TQApplication::postEvent (receiver, ev); + } +} + +// ----------------- BeagleUtil ------------------- + +BeagleQuery * +BeagleUtil::createQueryFromString (TQString query_str, + TQStringList &sources_menu, + TQStringList &types_menu, + int max_hits_per_source) +{ + BeagleQuery *beagle_query = beagle_query_new (); + beagle_query_set_max_hits (beagle_query, max_hits_per_source); // this is per source! + + kdDebug () << "Creating query from \"" << query_str << "\"" << endl; + for ( TQStringList::Iterator it = sources_menu.begin(); it != sources_menu.end(); ++it ) + beagle_query_add_source (beagle_query, g_strdup ((*it).utf8 ())); + + for ( TQStringList::Iterator it = types_menu.begin(); it != types_menu.end(); ++it ) + beagle_query_add_hit_type (beagle_query, g_strdup ((*it).utf8 ())); + + TQStringList query_terms; + TQString start_date, end_date; + TQStringList words = TQStringList::split (' ', query_str, false); + for ( TQStringList::Iterator it = words.begin(); it != words.end(); ++it ) { + TQStringList key_value_pair = TQStringList::split ('=', *it, false); + if (key_value_pair.count () == 1) + query_terms += *it; + else if (key_value_pair.count () == 2) { + TQString key = key_value_pair [0].lower (); + TQString value = key_value_pair [1]; + if (key == "mime") + beagle_query_add_mime_type (beagle_query, g_strdup (value.utf8 ())); + else if (key == "type") + beagle_query_add_hit_type (beagle_query, g_strdup (value.utf8 ())); + else if (key == "source") + beagle_query_add_source (beagle_query, g_strdup (value.utf8 ())); + else if (key == "start") + start_date = value; + else if (key == "end") + end_date = value; + else + query_terms += *it; + } else + query_terms += *it; + } + + beagle_query_add_text (beagle_query, g_strdup (query_terms.join (" ").utf8 ())); + kdDebug () << "Adding query text:" << query_terms.join (" ").utf8 () << endl; + + if (start_date.isNull () && end_date.isNull ()) + return beagle_query; + + //kdDebug () << "Handling dates ..." << endl; + BeagleQueryPartDate * date_part = beagle_query_part_date_new (); + if (! start_date.isNull ()) + beagle_query_part_date_set_start_date (date_part, timestringToBeagleTimestamp (start_date)); + if (! end_date.isNull ()) + beagle_query_part_date_set_end_date (date_part, timestringToBeagleTimestamp (end_date)); + beagle_query_add_part (beagle_query, BEAGLE_QUERY_PART (date_part)); + + return beagle_query; +} + +// timestring format allowed YYYYmmDD +BeagleTimestamp * +BeagleUtil::timestringToBeagleTimestamp(TQString timestring) +{ + //kdDebug () << "datetime string:" << timestring << endl; + // FIXME: error check timestring format + if (timestring.isNull () || timestring.stripWhiteSpace () == "" || timestring.length() != 8 ) + return beagle_timestamp_new_from_unix_time (TQDateTime::currentDateTime ().toTime_t ()); + //TQDateTime dt = TQDateTime::fromString (timestring, Qt::ISODate); + struct tm tm_time; + time_t timet_time; + time (&timet_time); + localtime_r (&timet_time, &tm_time); + strptime (timestring.ascii(), "%Y%m%d", &tm_time); + tm_time.tm_sec = tm_time.tm_min = tm_time.tm_hour = 0; + //kdDebug() << asctime (&tm_time) << endl; + timet_time = mktime (&tm_time); + return beagle_timestamp_new_from_unix_time (timet_time); +} + diff --git a/kicker/kicker/plugins/beaglesearch.h b/kicker/kicker/plugins/beaglesearch.h new file mode 100644 index 000000000..e192f6af3 --- /dev/null +++ b/kicker/kicker/plugins/beaglesearch.h @@ -0,0 +1,234 @@ +/***************************************************************** + + Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> + + 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. + +******************************************************************/ + +#ifndef BEAGLESEARCH_H +#define BEAGLESEARCH_H + +#include <tqdict.h> +#include <tqptrlist.h> +#include <tqthread.h> +#include <tqevent.h> +#include <tqmutex.h> + +#include <kdebug.h> +#include <kurl.h> + +extern "C" { +#include <glib.h> +#include <beagle/beagle.h> +} + +// BeagleSearchClient sends 3 types of events +// when results are to be sent as they arrive, +// - RESULTFOUND : when result is found +// - SEARCHOVER : when search is over +// - KILLME : just before thread finishes - used to cleanup the thread object +// when results are to be sent after receiving all of them +// - RESULTFOUND : when all results are obtained +// - KILLME : just before thread finishes - used to cleanup the thread object +#define RESULTFOUND (TQEvent::Type)1001 /* TQEvent::User + 1 */ +#define SEARCHOVER (TQEvent::Type)1002 /* TQEvent::User + 2 */ +#define KILLME (TQEvent::Type)1003 /* TQEvent::User + 3 */ + +class TQStringList; + +// IMPORTANT: Call this before any beagle calls +void beagle_init (); + +class Hit { +public: + Hit (BeagleHit *_hit); + ~Hit (); + + // convenience wrappers + // remember that the hit values are utf8 strings + const KURL getUri () const { return KURL (TQString::fromUtf8 (beagle_hit_get_uri (hit)));} + const TQString getType () const { return TQString::fromUtf8 (beagle_hit_get_type (hit));} + const TQString getMimeType () const { return TQString::fromUtf8 (beagle_hit_get_mime_type (hit));} + const TQString getSource () const { return TQString::fromUtf8 (beagle_hit_get_source (hit));} + const KURL getParentUri () const { return KURL (TQString::fromUtf8 (beagle_hit_get_parent_uri (hit)));} + const TQDict<TQStringList>& getAllProperties () + { + if (! processed) + processProperties (); + return property_map; + } + const TQStringList* getProperties (TQString prop_name) + { + if (! processed) + processProperties (); + return property_map [prop_name]; + } + const TQString operator[] (TQString prop_name); + +private: + BeagleHit *hit; + TQDict<TQStringList> property_map; + // not every hit may be used. so, do a lazy processing of property_map + bool processed; + void processProperties (); +}; + +class BeagleSearchResult{ +public: + BeagleSearchResult(int client_id); + ~BeagleSearchResult(); + void addHit (BeagleHit *hit); + TQString getHitCategory (Hit *hit); + + // id of the bsclient + int client_id; + // time taken to finish query + int query_msec; + // total number of results in this query + int total; + + const TQPtrList<Hit> *getHits () const; + +private: + // lists of hits + TQPtrList<Hit> *hitlist; +}; + +// caller should delete bsclient->result and bsclient +class BeagleSearchClient : public TQThread { +public: + // passing NULL for client makes bsclient create client itself and + // delete it later + BeagleSearchClient (int id, + TQObject *y, + BeagleClient *client, + BeagleQuery *query, + bool collate_results) + : id (id), kill_me (false), object (y), client (client), + query (query), destroy_client (false), collate_results (collate_results) + { + if (client == NULL) { + client = beagle_client_new (NULL); + destroy_client = true; + } + +// if (client == NULL) +// throw -1; + + main_loop = g_main_loop_new (NULL, FALSE); + if (collate_results) + result = new BeagleSearchResult (id); + + client_mutex = new TQMutex (); + } + + // It is never safe to delete BeagleSearchClient directly, the thread might still be running + ~BeagleSearchClient () + { + if (! finished ()) { + kdDebug () << "Thread " << id << " still running. Waiting.........." << endl; + wait (); + } + + if (destroy_client) + g_object_unref (client); + g_main_loop_unref (main_loop); + g_object_unref (query); + kdDebug() << "Deleting client ..." << id << endl; + delete client_mutex; + } + +private: + static void hitsAddedSlot (BeagleQuery *query, + BeagleHitsAddedResponse *response, + BeagleSearchClient *bsclient); + + static void finishedSlot (BeagleQuery *query, + BeagleFinishedResponse *response, + BeagleSearchClient *bsclient); + +public: + // run() starts the query and sends the result as follows: + // - either wait till get back all results and send it as RESULTFOUND + // - or, send results as it gets them as RESULTFOUND and + // send SEARCHOVER when finished + // collate_results controls the behaviour + virtual void run ( ); + + // after stopClient() is called, application can safely go and remove previous menu entries + // - i.e. after stopClient is called, app doesnt except the eventhandler to receive any results + // - use client_id to determine which is the current client, set it right after stopclient + // - Eventhandler checks client id, if it is current, it adds stuff to the menu + // else, it discards everything + // Once eventhandler is being processed, doQuery() wont be called and vice versa + // so no need to serialize eventhandler and doquery + // + // stopClient needs to make sure that once it is called, the thread is finished asap. Use a mutex + // to serialize actions. callbacks need to use mutex too. + // stopclient has to remove signal handlers to prevent further signal calls, set kill_me flag + // and quite main loop + // stopClient can be called at the following times: + // - Waiting for the first result: + // nothing extra + // - in hitsAddedSlot, processing results + // in callback, before processing, if killme is set, just return. + // - in hitsAddedSlot, after sending results + // before sending, if killme is set, dont send results + // (doing it twice in hitsAdded because forming BeagleSearchResult can take time) + // - Waiting for more results + // nothing extra + // - in finishedSlot, before sending finishedMsg + // if killme is set, just return + // - in finishedSlot, after sending finishedMsg + // if killme is set, just return + // in Run(), when return from mainloop, if killme is set, dont do anything more but call delete this + void stopClient (); + + // id of the client + // this is required in case applications fires many clients in rapid succession + int id; + + GMainLoop * main_loop; + BeagleSearchResult *result; + + // this is set if the client is obsolete now i.e. + // the application doesnt need the results from the client anymore + bool kill_me; +private: + // the application; need this to send events to the application + TQObject *object; + // mutex to control setting the kill_me shared variable + TQMutex *client_mutex; + BeagleClient *client; + BeagleQuery *query; + // should the client be destroyed by the client + // if the client created it, then most probably it should + bool destroy_client; + bool collate_results; +}; + +class BeagleUtil { +public: + + static BeagleQuery *createQueryFromString (TQString query_str, + TQStringList &sources, + TQStringList &types, + int max_hits_per_source = 100); + static BeagleTimestamp *timestringToBeagleTimestamp (TQString timestring); +}; + +#endif diff --git a/kicker/kicker/plugins/kickoff-beagle-plugin.cpp b/kicker/kicker/plugins/kickoff-beagle-plugin.cpp new file mode 100644 index 000000000..3cad77ca4 --- /dev/null +++ b/kicker/kicker/plugins/kickoff-beagle-plugin.cpp @@ -0,0 +1,499 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@kde.org> * + * Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "kickoff-beagle-plugin.h" + +#include <tqregexp.h> +#include <tqtimer.h> + +#include <kapplication.h> +#include <kdesktopfile.h> +#include <kgenericfactory.h> +#include <kservice.h> + +TQString dc_identifier = "dc:identifier"; +TQString dc_title = "dc:title"; +TQString parent_dc_title = "parent:dc:title"; +TQString exactfilename = "beagle:ExactFilename"; +TQString fixme_name = "fixme:Name"; +TQString beagle_filename = "beagle:Filename"; +TQString fixme_attachment_title = "fixme:attachment_title"; +TQString fixme_hasattachments = "fixme:hasAttachments"; +TQString parent_prefix = "parent:"; +TQString fixme_folder = "fixme:folder"; +TQString fixme_categories = "fixme:Categories"; +TQString fixme_comment = "fixme:Comment"; +TQString fixme_width = "fixme:width"; +TQString fixme_height = "fixme:height"; +TQString fixme_from_address = "fixme:from_address"; +TQString fixme_artist = "fixme:artist"; +TQString fixme_album = "fixme:album"; +TQString dc_source = "dc:source"; +TQString dc_publisher = "dc:publisher"; +TQString digikam_tag = "digikam:Tag"; +TQString fixme_speakingto = "fixme:speakingto"; +TQString fixme_starttime = "fixme:starttime"; +TQString comma_string = ","; +TQString vCard_FN = "vCard:FN"; +TQString vCard_PREFEMAIL = "vCard:PREFEMAIL"; +TQString fixme_uid = "fixme:uid"; + +static CATEGORY getHitCategory (Hit *hit) +{ + TQString hittype = hit->getType(); + TQString hitsource = hit->getSource(); + + // if hit source is None, dont handle it. Might be anthrax-envelope :) + if (hitsource.isNull()) + return OTHER; + + if (hitsource == "documentation") + return DOCS; + + if (hittype == "IMLog") + return CHATS; + + // sure shots + if (hittype == "FeedItem") + return FEEDS; + if (hittype == "WebHistory") + return WEBHIST; + if (hittype == "MailMessage") + return MAILS; + if (hittype == "Note") + return NOTES; + + // check for applications + if (hittype == "File" && (*hit) ["beagle:FilenameExtension"] == ".desktop") + return APPS; + + // check for music + TQString hitmimetype = hit->getMimeType(); + if (hitsource == "Amarok" + || hitmimetype.startsWith ("audio") + || hitmimetype == "application/ogg") + return MUSIC; // not an exhaustive search + + // check for images from files + if (hitsource == "Files" && hitmimetype.startsWith ("image")) + return PICS; + + if (hitsource == "Files" && hitmimetype.startsWith ("video")) + return VIDEOS; + + if (hitsource == "Files") + return FILES; + + if (hitsource == "KAddressBook") + return ACTIONS; + + return OTHER; +} + +K_EXPORT_COMPONENT_FACTORY( kickoffsearch_beagle, + KGenericFactory<KickoffBeaglePlugin>( "kickoffsearch_beagle" ) ) + +KickoffBeaglePlugin::KickoffBeaglePlugin(TQObject *parent, const char* name, const TQStringList&) + : KickoffSearch::Plugin(parent, name ), genericTitle( true ) +{ + g_type_init (); + current_beagle_client = NULL; +} + +bool KickoffBeaglePlugin::daemonRunning() +{ + return beagle_util_daemon_is_running(); +} + +void KickoffBeaglePlugin::query(TQString term, bool _genericTitle) +{ + genericTitle = _genericTitle; + current_query_str = term; + + // Beagle search + if (current_beagle_client != NULL) { + kdDebug () << "Previous client w/id " << current_beagle_client->id << " still running ... ignoring it." << endl; + current_beagle_client->stopClient (); + } + current_beagle_client_id = KApplication::random (); + kdDebug () << "Creating client with id:" << current_beagle_client_id << endl; + + BeagleClient *beagle_client = beagle_client_new (NULL); + if (beagle_client == NULL) { + kdDebug() << "beagle service not running ..." << endl; + return; + } + + TQStringList sources, types; + BeagleQuery *beagle_query = BeagleUtil::createQueryFromString (term, sources, types, 99); // maximum 99 results, if this doesnt work, blame the stars + + current_beagle_client = new BeagleSearchClient ( + current_beagle_client_id, + this, + beagle_client, + beagle_query, + false); + current_beagle_client->start(); +// kdDebug () << "Query dispatched at " << time (NULL) << endl; +} + +void KickoffBeaglePlugin::cleanClientList () +{ + toclean_list_mutex.lock (); + BeagleSearchClient *old_client = toclean_client_list.take (0); + if (old_client != NULL) { // failsafe + kdDebug () << "Cleanup old client " << old_client->id << endl; + delete old_client; + } + toclean_list_mutex.unlock (); +} + +void KickoffBeaglePlugin::customEvent (TQCustomEvent *e) +{ + if (e->type () == RESULTFOUND) { +// kdDebug () << "Quick query thread at " << time (NULL) << " with current_id=" << current_beagle_client_id << " finished ..." << endl; + BeagleSearchResult *result = (BeagleSearchResult *) e->data (); + if (current_beagle_client_id != result->client_id) { + kdDebug () << "Stale result from " << result->client_id << endl; + delete result; + // FIXME: Should I also free e ? + } else { + kdDebug () << "Good results ...total=" << result->total << endl; + showResults (result); + } + //KPassivePopup::message( "This is the message", this ); + } else if (e->type () == SEARCHOVER) { + BeagleSearchClient *client = (BeagleSearchClient *) e->data (); + if (client == NULL) { +// kdDebug () << "Query finished event at " << time (NULL) << " but client is already deleted" << endl; + return; + } +// kdDebug () << "Query finished event at " << time (NULL) << " for id=" << client->id << endl; + if (current_beagle_client_id == client->id) { + kickoffSearchInterface()->searchOver(); + current_beagle_client = NULL; // important ! + } + } else if (e->type () == KILLME) { + BeagleSearchClient *client = (BeagleSearchClient *) e->data (); + if (client->finished ()) + delete client; + else { + // add client to cleanup list + toclean_list_mutex.lock (); + toclean_client_list.append (client); + kdDebug () << "Scheduling client to be deleted in 500ms" << endl; + toclean_list_mutex.unlock (); + TQTimer::singleShot (500, this, TQT_SLOT (cleanClientList ())); + } + } +} + +// this method decides what to display in the result list +HitMenuItem *KickoffBeaglePlugin::hitToHitMenuItem (int category, Hit *hit) +{ + TQString title, info, mimetype, icon; + int score = 0; + KURL uri; + +#if 0 + kdDebug() << "*** " << hit->getUri() << endl; + TQDict<TQStringList> all = hit->getAllProperties(); + TQDictIterator<TQStringList> it( all ); + for( ; it.current(); ++it ) + kdDebug() << it.currentKey() << ": " << *(it.current()) << endl; +#endif + + switch (category) { + case FILES: + { + uri = hit->getUri (); + TQString uristr = uri.path (); + title = (*hit) [exactfilename]; + int last_slash = uristr.findRev ('/', -1); + info = i18n("Folder: %1").arg(last_slash == 0 ? "/" + : uristr.section ('/', -2, -2)); + } + break; + case ACTIONS: + { + if (hit->getSource()=="KAddressBook"){ + title = i18n("Send Email to %1").arg((*hit)[vCard_FN]); + info = (*hit)[vCard_PREFEMAIL]; + uri = "mailto:"+(*hit)[vCard_PREFEMAIL]; + mimetype = hit->getMimeType (); + icon = "mail_new"; + + HitMenuItem * first_item=new HitMenuItem (title, info, uri, mimetype, 0, category, icon, score); + kickoffSearchInterface()->addHitMenuItem(first_item); + + title =i18n("Open Addressbook at %1").arg((*hit)[vCard_FN]); + uri = "kaddressbook:/"+(*hit)[fixme_uid]; + icon = "kaddressbook"; + } + break; + } + case MAILS: + { + TQString prefix = TQString::null; + bool is_attachment = ((*hit) [parent_prefix + fixme_hasattachments] == "true"); + bool has_parent = (! hit->getParentUri ().isEmpty ()); + bool parent_mbox_file = false; + if (has_parent) + parent_mbox_file = ((*hit) [parent_prefix + fixme_folder] == TQString::null); + + // Logic: + // If has_parent == false, everything is normal + // If has_parent == true, parent_mbox_file == false, everything is normal, use uri + // FIXME: If has_parent == true, parent_mbox_file == true, ??? + // If has_parent == true, is_attachment == true, hit is attach and access with prefix "parent:", use parenturi + // Else, not attachment (multipart), access with prefix "parent:", use parenturi + + if (has_parent && !parent_mbox_file) { + uri = hit->getParentUri (); + prefix = parent_prefix; + if (is_attachment) + title = (*hit) [fixme_attachment_title]; + if (title.isEmpty ()) + title = (*hit) [prefix + dc_title]; + if (title.isEmpty ()) + title = i18n("No subject"); + if (is_attachment) + title = title.prepend (i18n("(Attachment) ")); + info = (i18n("From %1").arg((*hit) [prefix + fixme_from_address])); + } else { + uri = hit->getUri (); + title = (*hit) [dc_title]; + info = (i18n("From %1").arg((*hit) [fixme_from_address])); + } + } + mimetype = "message/rfc822"; // to handle attachment results + break; + case MUSIC: + uri = hit->getUri (); + title = (*hit) [exactfilename]; + { + TQString artist = (*hit) [fixme_artist]; + TQString album = (*hit) [fixme_album]; + if (! artist.isEmpty ()) + info = (i18n("By %1").arg(artist)); + else if (! album.isEmpty ()) + info = (i18n("From Album %1").arg(album)); + else { + TQString uristr = uri.path (); + int last_slash = uristr.findRev ('/', -1); + info = i18n("Folder: %1") + .arg(last_slash == 0 ? "/" : uristr.section ('/', -2, -2)); + } + } + break; + case VIDEOS: + uri = hit->getUri (); + title = (*hit) [exactfilename]; + { + TQString uristr = uri.path (); + int last_slash = uristr.findRev ('/', -1); + info = i18n("Folder: %1").arg(last_slash == 0 ? "/" : uristr.section ('/', -2, -2)); + } + break; + case WEBHIST: + uri = hit->getUri (); + title = (*hit) [dc_title]; + title = title.replace(TQRegExp("\n")," "); + mimetype = "text/html"; + if (title.isEmpty () || title.stripWhiteSpace ().isEmpty ()) { + title = uri.prettyURL (); + } else { + info = uri.host () + uri.path (); + } + break; + case FEEDS: + { + uri = KURL ((*hit) [dc_identifier]); + title = (*hit) [dc_title]; + mimetype = "text/html"; + TQString publisher = (*hit) [dc_publisher]; + TQString source = (*hit) [dc_source]; + if (! publisher.isEmpty ()) + info = publisher; + else if (! source.isEmpty ()) + info = source; + } + break; + case PICS: + { + uri = hit->getUri (); + title = (*hit) [exactfilename]; + TQString width = (*hit) [fixme_width]; + TQString height = (*hit) [fixme_height]; + if (width.isEmpty () || height.isEmpty ()) { + TQString uristr = uri.path (); + int last_slash = uristr.findRev ('/', -1); + info = i18n("Folder: %1") + .arg(last_slash == 0 ? "/" : uristr.section ('/', -2, -2)); + break; + } + info = (TQString (" (%1x%2)").arg (width).arg (height)); + const TQStringList *tags = hit->getProperties (digikam_tag); + if (tags == NULL) + break; + TQString tags_string = tags->join (comma_string); + info += (" " + tags_string); + } + break; + case APPS: + { + uri = hit->getUri (); + title = (*hit) [dc_title]; + KDesktopFile desktopfile(uri.path(),true); + if (genericTitle && !desktopfile.readGenericName().isEmpty()) { + title = desktopfile.readGenericName(); + info = desktopfile.readName(); + } + else { + title = desktopfile.readName(); + info = desktopfile.readGenericName(); + } + icon = desktopfile.readIcon(); + TQString input = current_query_str.lower(); + TQString command = desktopfile.readEntry("Exec"); + if (command==input) + score = 100; + else if (command.find(input)==0) + score = 50; + else if (command.find(input)!=-1) + score = 10; + else if (title==input) + score = 100; + else if (title.find(input)==0) + score = 50; + else if (title.find(input)!=-1) + score = 10; + break; + } + break; + case NOTES: + { + uri = hit->getUri (); + title = (*hit) [dc_title]; + title = i18n("Title: %1").arg(title.isEmpty() ? i18n("Untitled") : title); + + if (hit->getSource()=="KNotes") + icon="knotes"; + else + icon="contents2"; + } + break; + case CHATS: + { + uri = hit->getUri (); + title = (*hit) [fixme_speakingto]; + title = i18n("Conversation With %1").arg(title.isEmpty() ? i18n("Unknown Person") : title); + TQDateTime datetime; + datetime = datetimeFromString((*hit) [fixme_starttime]); + info=i18n("Date: %1").arg(KGlobal::locale()->formatDateTime(datetime,false)); + if (hit->getMimeType()=="beagle/x-kopete-log") + icon="kopete"; + else + icon="gaim"; + } + break; + case DOCS: + { + uri = hit->getUri (); + title = (*hit) [dc_title]; + if (title.isEmpty () || title.stripWhiteSpace ().isEmpty ()) + title = uri.prettyURL (); + else { + TQString uristr = uri.path (); + int last_slash = uristr.findRev ('/', -1); + info = i18n("Folder: %1").arg(last_slash == 0 ? "/" : uristr.section ('/', + -2, -2)); + } + } + break; + default: + return NULL; + } + if (mimetype.isEmpty ()) + mimetype = hit->getMimeType (); + return new HitMenuItem (title, info, uri, mimetype, 0, category, icon, score); +} + +void KickoffBeaglePlugin::showResults(BeagleSearchResult *result) +{ + if (result->total == 0 ) { + // Dont report error from here ... + kdDebug() << "No matches found" << endl; + delete result; + return; + } + + const TQPtrList<Hit> *hits = result->getHits(); + if (hits == NULL) { + kdDebug () << "Hmm... null" << endl; + delete result; + return; + } + kickoffSearchInterface()->initCategoryTitlesUpdate(); + + TQPtrListIterator<Hit> it (*hits); + Hit *hit; + for (; (hit = it.current ()) != NULL; ++it) { + CATEGORY category = getHitCategory (hit); + + // if category is not handled, continue + if (category == OTHER) + continue; + + if ( category == APPS ) { + // we need to check if this is useful + KService cs( hit->getUri().path() ); + if ( cs.noDisplay() ) + continue; + } + + if (!kickoffSearchInterface()->anotherHitMenuItemAllowed(category)) + continue; + + HitMenuItem *hit_item = hitToHitMenuItem (category, hit); + + if (!hit_item) + continue; + + kickoffSearchInterface()->addHitMenuItem(hit_item); + } + + kickoffSearchInterface()->updateCategoryTitles(); + + delete result; +} + +TQDateTime KickoffBeaglePlugin::datetimeFromString( const TQString& s) +{ + int year( s.mid( 0, 4 ).toInt() ); + int month( s.mid( 4, 2 ).toInt() ); + int day( s.mid( 6, 2 ).toInt() ); + int hour( s.mid( 8, 2 ).toInt() ); + int min( s.mid( 10, 2 ).toInt() ); + int sec( s.mid( 12, 2 ).toInt() ); + return TQDateTime(TQDate(year,month,day),TQTime(hour,min,sec)); +} + +#include "kickoff-beagle-plugin.moc" diff --git a/kicker/kicker/plugins/kickoff-beagle-plugin.h b/kicker/kicker/plugins/kickoff-beagle-plugin.h new file mode 100644 index 000000000..8288ba647 --- /dev/null +++ b/kicker/kicker/plugins/kickoff-beagle-plugin.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@kde.org> * + * Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> * + * * + * 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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef CAPITALIZEPLUGIN_H +#define CAPITALIZEPLUGIN_H + +#include "../interfaces/kickoff-search-plugin.h" +#include "beaglesearch.h" + +class KickoffBeaglePlugin :public KickoffSearch::Plugin +{ + Q_OBJECT + +public: + KickoffBeaglePlugin(TQObject *parent, const char* name, const TQStringList&); + + void query(TQString, bool); + bool daemonRunning(); + +protected slots: + // to clean beaglesearchclients + void cleanClientList (); + +private: + TQString current_query_str; + + // all beagle activity is done through the BSC object + BeagleSearchClient *current_beagle_client; + + // used to send notification from the beagle thread to the main event loop + virtual void customEvent (TQCustomEvent *e); + + TQPtrList<BeagleSearchClient> toclean_client_list; + TQMutex toclean_list_mutex; + + // show the results + void showResults (BeagleSearchResult *); + HitMenuItem *hitToHitMenuItem (int category, Hit *hit); + + // use a different id for each bsc client, and use that to separate stale responses from current ones + int current_beagle_client_id; + + bool genericTitle; + TQDateTime datetimeFromString( const TQString& ); +}; + +#endif /* CAPITALIZEPLUGIN_H */ diff --git a/kicker/kicker/plugins/kickoffsearch_beagle.desktop b/kicker/kicker/plugins/kickoffsearch_beagle.desktop new file mode 100644 index 000000000..2904dcda6 --- /dev/null +++ b/kicker/kicker/plugins/kickoffsearch_beagle.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Name=Beagle Search +Comment=Beagle search plugin for Kickoff search +ServiceTypes=KickoffSearch/Plugin +Type=Service +X-KDE-Library=kickoffsearch_beagle diff --git a/kicker/kicker/ui/Makefile.am b/kicker/kicker/ui/Makefile.am index 1bd54777e..9384c28f5 100644 --- a/kicker/kicker/ui/Makefile.am +++ b/kicker/kicker/ui/Makefile.am @@ -1,39 +1,45 @@ INCLUDES = -I$(srcdir)/../core -I../core -I$(srcdir)/../buttons \ -I../../libkicker -I$(srcdir)/../../libkicker \ - -I$(top_srcdir)/libkonq -I$(top_srcdir)/kdmlib $(all_includes) + -I$(top_srcdir)/libkonq -I$(top_srcdir)/kdmlib $(DBUS_INCS) $(all_includes) noinst_LTLIBRARIES = libkicker_ui.la libkicker_ui_la_SOURCES = addbutton_mnu.cpp appletitem.ui appletview.ui addapplet.cpp \ addapplet_mnu.cpp appletop_mnu.cpp \ browser_mnu.cpp client_mnu.cpp dirdrop_mnu.cpp \ - nonKDEButtonSettings.ui exe_dlg.cpp k_mnu.cpp k_mnu.skel\ - quickbrowser_mnu.cpp service_mnu.cpp \ - addextension_mnu.cpp extensionop_mnu.cpp \ - recentapps.cpp browser_dlg.cpp \ + nonKDEButtonSettings.ui exe_dlg.cpp k_new_mnu.cpp k_mnu.cpp k_mnu.skel\ + quickbrowser_mnu.cpp service_mnu.cpp kmenuitembase.ui \ + addextension_mnu.cpp extensionop_mnu.cpp k_mnu_stub.cpp \ + recentapps.cpp browser_dlg.cpp itemview.cpp kickoff_bar.cpp \ removeapplet_mnu.cpp removeextension_mnu.cpp removecontainer_mnu.cpp \ removebutton_mnu.cpp popupmenutitle.cpp hidebutton.cpp \ - addappletvisualfeedback.cpp clicklineedit.cpp + addappletvisualfeedback.cpp clicklineedit.cpp flipscrollview.cpp \ + media_watcher.cpp media_watcher.skel mykickoffsearchinterface.cpp query.cpp -libkicker_ui_la_LIBADD = $(top_builddir)/libkonq/libkonq.la $(top_builddir)/kdmlib/libdmctl.la +libkicker_ui_la_LIBADD = $(top_builddir)/libkonq/libkonq.la $(top_builddir)/kdmlib/libdmctl.la \ + $(LIB_KABC) ../interfaces/libkickoffsearch_interfaces.la libkicker_ui_la_METASOURCES = AUTO noinst_HEADERS = addapplet.h appletwidget.h addbutton_mnu.h addapplet_mnu.h appletop_mnu.h \ - browser_mnu.h client_mnu.h dirdrop_mnu.h exe_dlg.h k_mnu.h \ + browser_mnu.h client_mnu.h dirdrop_mnu.h exe_dlg.h k_new_mnu.h k_mnu.h \ quickbrowser_mnu.h service_mnu.h \ addextension_mnu.h extensionop_mnu.h \ - recentapps.h browser_dlg.h \ + recentapps.h browser_dlg.h itemview.h query.h \ removeapplet_mnu.h removeextension_mnu.h removecontainer_mnu.h \ removebutton_mnu.h popupmenutitle.h hidebutton.h \ addappletvisualfeedback.h clicklineedit.h +kicker_ui_data_DATA = default-favs +kicker_ui_datadir = $(kde_datadir)/kicker + removecontainer_mnu.lo: ../../libkicker/kickerSettings.h removeextension_mnu.lo: ../../libkicker/kickerSettings.h addextension_mnu.lo: ../core/extensionSettings.h appletop_mnu.lo: ../../libkicker/kickerSettings.h extensionop_mnu.lo: ../../libkicker/kickerSettings.h k_mnu.lo: ../../libkicker/kickerSettings.h +k_new_mnu.lo: ../../libkicker/kickerSettings.h removecontainer_mnu.lo: ../core/extensionSettings.h removeextension_mnu.lo: ../core/extensionSettings.h service_mnu.lo: ../../libkicker/kickerSettings.h diff --git a/kicker/kicker/ui/addappletvisualfeedback.cpp b/kicker/kicker/ui/addappletvisualfeedback.cpp index 38b48fe8e..acd82a066 100644 --- a/kicker/kicker/ui/addappletvisualfeedback.cpp +++ b/kicker/kicker/ui/addappletvisualfeedback.cpp @@ -51,6 +51,7 @@ AddAppletVisualFeedback::AddAppletVisualFeedback(AppletWidget* widget, m_richText(0), m_dissolveDelta(-1), m_frames(1), + m_moveTimer(0, "m_moveTimer"), m_dirty(false) { setFocusPolicy(NoFocus); diff --git a/kicker/kicker/ui/appletop_mnu.cpp b/kicker/kicker/ui/appletop_mnu.cpp index 59ca9c89e..55c181016 100644 --- a/kicker/kicker/ui/appletop_mnu.cpp +++ b/kicker/kicker/ui/appletop_mnu.cpp @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "appletop_mnu.h" #include "container_button.h" #include "containerarea.h" +#include "kickerSettings.h" PanelAppletOpMenu::PanelAppletOpMenu(int actions, TQPopupMenu *opMenu, const TQPopupMenu* appletsMenu, const TQString & title, const TQString &icon, @@ -159,6 +160,20 @@ PanelAppletOpMenu::PanelAppletOpMenu(int actions, TQPopupMenu *opMenu, const TQP } } + if ((actions & PanelAppletOpMenu::KMenuEditor)) + { + if (needSeparator) + { + insertSeparator(); + needSeparator = false; + } + + if (KickerSettings::legacyKMenu()) + insertItem(SmallIcon("kickoff"), i18n("Switch to Kickoff Menu Style"), this, TQT_SLOT(toggleLegacy())); + else + insertItem(SmallIcon("about_kde"), i18n("Switch to KDE Menu Style"), this, TQT_SLOT(toggleLegacy())); + } + if ((actions & PanelAppletOpMenu::KMenuEditor) && kapp->authorizeKAction("menuedit")) { if (needSeparator) @@ -205,4 +220,11 @@ void PanelAppletOpMenu::keyPressEvent(TQKeyEvent* e) TQPopupMenu::keyPressEvent(e); } +void PanelAppletOpMenu::toggleLegacy() +{ + KickerSettings::setLegacyKMenu(!KickerSettings::legacyKMenu()); + KickerSettings::writeConfig(); + Kicker::the()->restart(); +} + #include "appletop_mnu.moc" diff --git a/kicker/kicker/ui/appletop_mnu.h b/kicker/kicker/ui/appletop_mnu.h index e0b219552..4b396a83d 100644 --- a/kicker/kicker/ui/appletop_mnu.h +++ b/kicker/kicker/ui/appletop_mnu.h @@ -47,6 +47,9 @@ public: signals: void escapePressed(); +protected slots: + void toggleLegacy(); + protected: void keyPressEvent(TQKeyEvent* e); }; diff --git a/kicker/kicker/ui/browser_mnu.cpp b/kicker/kicker/ui/browser_mnu.cpp index 88ce30713..2250475b4 100644 --- a/kicker/kicker/ui/browser_mnu.cpp +++ b/kicker/kicker/ui/browser_mnu.cpp @@ -332,7 +332,7 @@ void PanelBrowserMenu::initialize() if(_mimemap.count() > 0) { if(!_mimecheckTimer) - _mimecheckTimer = new TQTimer(this); + _mimecheckTimer = new TQTimer(this, "_mimecheckTimer"); connect(_mimecheckTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotMimeCheck())); _mimecheckTimer->start(0); diff --git a/kicker/kicker/ui/default-favs b/kicker/kicker/ui/default-favs new file mode 100644 index 000000000..8cbff626d --- /dev/null +++ b/kicker/kicker/ui/default-favs @@ -0,0 +1,9 @@ +MozillaFirefox.desktop +kde-Kontact.desktop +writer.desktop +kde-amarok.desktop +kde-digikam.desktop +kde-Home.desktop +kde-KControl.desktop +kde-Help.desktop +kde-konsole.desktop diff --git a/kicker/kicker/ui/flipscrollview.cpp b/kicker/kicker/ui/flipscrollview.cpp new file mode 100644 index 000000000..ae96ebcaa --- /dev/null +++ b/kicker/kicker/ui/flipscrollview.cpp @@ -0,0 +1,324 @@ +/***************************************************************** + +Copyright (c) 2006 Will Stephenson <wstephenson@novell.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <tqapplication.h> +#include <tqhbox.h> +#include <tqheader.h> +#include <assert.h> + +#include "itemview.h" +#include "flipscrollview.h" +#include "kickerSettings.h" + +/* Flip scroll steps, as percentage of itemview width to scroll per + * step. Assumes the itemview is scrolled in ten steps */ + +/* slow start, then fast */ +//static const double scrollSteps[] = { 0.05, 0.05, 0.1125, 0.1125, 0.1125, 0.1125, 0.1125, 0.1125, 0.1125, 0.1125 }; + +/* slow fast slow */ +//static const double scrollSteps[] = { 0.05, 0.05, 0.13, 0.13, 0.15, 0.13, 0.13, 0.13, 0.05, 0.05 }; + +/* slow veryfast slow */ +static const double scrollSteps[] = { 0.03, 0.03, 0.147, 0.147, 0.147, 0.147, 0.147, 0.147, 0.03, 0.028 }; +; + +BackFrame::BackFrame( TQWidget *parent ) + : TQFrame( parent ), mouse_inside( false ) +{ + setFrameStyle( TQFrame::NoFrame ); + if ( TQApplication::reverseLayout() ) + left_triangle.load( locate( "data", "kicker/pics/right_triangle.png" ) ); + else + left_triangle.load( locate( "data", "kicker/pics/left_triangle.png" ) ); +} + +void BackFrame::drawContents( TQPainter *p ) +{ + TQColor gray( 230, 230, 230 ); + if ( mouse_inside ) + p->fillRect( 3, 3, width() - 6, height() - 6, colorGroup().color( TQColorGroup::Highlight ) ); + else + p->fillRect( 3, 3, width() - 6, height() - 6, gray ); + p->setPen( gray.dark(110) ); + p->drawRect( 3, 3, width() - 6, height() - 6 ); + + int pixsize = ( width() - 6 ) * 3 / 5; + TQImage i = left_triangle.convertToImage().smoothScale( pixsize, pixsize ); + TQPixmap tri; + tri.convertFromImage( i ); + + p->drawPixmap( ( width() - tri.width() ) / 2, ( height() - tri.height() ) / 2, tri ); +} + +void BackFrame::enterEvent( TQEvent *e ) +{ + mouse_inside = true; + update(); +} + +void BackFrame::leaveEvent( TQEvent *e ) +{ + mouse_inside = false; + update(); +} + +void BackFrame::mousePressEvent ( TQMouseEvent * e ) +{ + emit clicked(); +} + +FlipScrollView::FlipScrollView( TQWidget * parent, const char * name ) + : TQScrollView( parent, name ), mState( StoppedLeft ), mScrollDirection( 1 ), mShowBack( false ) +{ + setVScrollBarMode( TQScrollView::AlwaysOff ); + setHScrollBarMode( TQScrollView::AlwaysOff ); + setFrameStyle( TQFrame::NoFrame ); + mLeftView = new ItemView( this, "left_view" ); + addChild( mLeftView ); + + mRightView = new ItemView( this, "right_view" ); + addChild( mRightView ); + + mTimer = new TQTimer( this, "mTimer" ); + connect( mTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( slotScrollTimer() ) ); + + connect( mLeftView, TQT_SIGNAL( startService(KService::Ptr) ), + TQT_SIGNAL( startService(KService::Ptr) ) ); + connect( mLeftView, TQT_SIGNAL( startURL(const TQString& ) ), + TQT_SIGNAL( startURL(const TQString& ) ) ); + connect( mLeftView, TQT_SIGNAL( rightButtonPressed(TQListViewItem*,const TQPoint&,int) ), + TQT_SIGNAL( rightButtonPressed(TQListViewItem*,const TQPoint&,int) ) ); + connect( mRightView, TQT_SIGNAL( startService(KService::Ptr) ), + TQT_SIGNAL( startService(KService::Ptr) ) ); + connect( mRightView, TQT_SIGNAL( startURL(const TQString& ) ), + TQT_SIGNAL( startURL(const TQString& ) ) ); + connect( mRightView, TQT_SIGNAL( rightButtonPressed(TQListViewItem*,const TQPoint&,int) ), + TQT_SIGNAL( rightButtonPressed(TQListViewItem*,const TQPoint&,int) ) ); + + // wild hack to make sure it has correct width + mLeftView->setVScrollBarMode( TQScrollView::AlwaysOn ); + mRightView->setVScrollBarMode( TQScrollView::AlwaysOn ); + mLeftView->setVScrollBarMode( TQScrollView::Auto ); + mRightView->setVScrollBarMode( TQScrollView::Auto ); + + mBackrow = new BackFrame( this ); + mBackrow->resize( 24, 100 ); + connect( mBackrow, TQT_SIGNAL( clicked() ), TQT_SIGNAL( backButtonClicked() ) ); +} + +ItemView* FlipScrollView::prepareRightMove() +{ + if ( mState != StoppedLeft ) + { + mTimer->stop(); + ItemView *swap = mLeftView; + mLeftView = mRightView; + mRightView = swap; + moveChild( mLeftView, 0, 0 ); + moveChild( mRightView, width(), 0 ); + mBackrow->hide(); + mRightView->resize( width(), height() ); + mLeftView->resize( width(), height() ); + setContentsPos( 0, 0 ); + } + + mState = StoppedLeft; + mRightView->clear(); + return mRightView; +} + +void FlipScrollView::showBackButton( bool enable ) +{ + kdDebug() << "FlipScrollView::showBackButton " << enable << endl; + mShowBack = enable; +} + +ItemView* FlipScrollView::prepareLeftMove(bool clear) +{ + if ( mState != StoppedRight ) + { + mTimer->stop(); + ItemView *swap = mLeftView; + mLeftView = mRightView; + mRightView = swap; + moveChild( mLeftView, 0, 0 ); + moveChild( mRightView, width(), 0 ); + mRightView->resize( width(), height() ); + mLeftView->resize( width(), height() ); + mBackrow->hide(); + setContentsPos( width(), 0 ); + } + + mState = StoppedRight; + if (clear) + mLeftView->clear(); + return mLeftView; +} + +void FlipScrollView::viewportResizeEvent ( TQResizeEvent * ) +{ + mLeftView->resize( size() ); + mRightView->resize( width() - mBackrow->width(), height() ); + mBackrow->resize( mBackrow->width(), height() ); + resizeContents( width() * 2, height() ); + moveChild( mBackrow, width(), 0 ); + moveChild( mRightView, width() + mBackrow->width(), 0 ); + setContentsPos( 0, 0 ); +} + +ItemView *FlipScrollView::currentView() const +{ + if ( mState == StoppedRight ) + return mRightView; + else + return mLeftView; +} + +ItemView *FlipScrollView::leftView() const +{ + return mLeftView; +} + +ItemView *FlipScrollView::rightView() const +{ + return mRightView; +} + +FlipScrollView::~FlipScrollView() {} + +static const int max_steps = 10; + +void FlipScrollView::slotScrollTimer() +{ + mStepsRemaining--; + assert( mStepsRemaining >= 0 && mStepsRemaining < int(sizeof( scrollSteps ) / sizeof( double )) ); + if (KickerSettings::scrollFlipView()) + scrollBy( ( int )( mScrollDirection * mLeftView->width() * scrollSteps[ mStepsRemaining ] ), 0 ); + else + scrollBy( ( int )( mScrollDirection * mLeftView->width()), 0 ); + + if ( mStepsRemaining == 0 ) + { + if ( mState == ScrollingRight ) + { + mState = StoppedRight; + setContentsPos( width(), 0 ); + } else { + mState = StoppedLeft; + setContentsPos( 0, 0 ); + } + + kdDebug() << "slotScrollTimer " << mShowBack << endl; + + if ( mShowBack ) + { + mBackrow->show(); + if ( mState == StoppedRight ) + { + + if ( TQApplication::reverseLayout() ) + moveChild( mRightView, width(), 0 ); + else + moveChild( mRightView, width() + mBackrow->width(), 0 ); + mRightView->resize( width() - mBackrow->width(), height() ); + mLeftView->resize( width(), height() ); + if ( TQApplication::reverseLayout() ) + moveChild( mBackrow, width() + mRightView->width(), 0 ); + else + moveChild( mBackrow, width(), 0 ); + moveChild( mLeftView, 0, 0 ); + } else + { + moveChild( mRightView, width(), 0 ); + mRightView->resize( width(), height() ); + mLeftView->resize( width() - mBackrow->width(), height() ); + if ( TQApplication::reverseLayout() ) + { + moveChild( mBackrow, mLeftView->width(), 0 ); + moveChild( mLeftView, 0, 0 ); + } + else + { + moveChild( mBackrow, 0, 0 ); + moveChild( mLeftView, mBackrow->width(), 0 ); + } + } + } else + mBackrow->hide(); + + if (!mSelectMenuPath.isEmpty()) { + if (mSelectMenuPath=="kicker:/goup/") { + currentView()->setSelected(currentView()->firstChild(),true); + currentView()->firstChild()->repaint(); + } + else { + TQListViewItem * child = currentView()->firstChild(); + while( child ) { + KMenuItem* kitem = dynamic_cast<KMenuItem*>(child); + if (kitem && kitem->menuPath()==mSelectMenuPath) { + currentView()->setSelected(child,true); + kdDebug() << "child repaint\n"; + child->repaint(); + break; + } + child = child->nextSibling(); + } + } + } + mLeftView->setVScrollBarMode( TQScrollView::Auto ); + mRightView->setVScrollBarMode( TQScrollView::Auto ); + mTimer->stop(); + mLeftView->setMouseMoveSelects( true ); + mRightView->setMouseMoveSelects( true ); + } +} + +void FlipScrollView::flipScroll(const TQString& selectMenuPath) +{ + if ( mState == StoppedLeft ) + { + mState = ScrollingRight; + mScrollDirection = 1; + } + else + { + mState = ScrollingLeft; + mScrollDirection = -1; + } + + mLeftView->setVScrollBarMode( TQScrollView::AlwaysOff ); + mRightView->setVScrollBarMode( TQScrollView::AlwaysOff ); + if (KickerSettings::scrollFlipView()) + mStepsRemaining = max_steps; + else + mStepsRemaining = 1; + mTimer->start( 30 ); + mSelectMenuPath = selectMenuPath; + if (!mSelectMenuPath.isEmpty()) { + mLeftView->setMouseMoveSelects( false ); + mRightView->setMouseMoveSelects( false ); + } +} + +#include "flipscrollview.moc" diff --git a/kicker/kicker/ui/flipscrollview.h b/kicker/kicker/ui/flipscrollview.h new file mode 100644 index 000000000..d2de2ab5e --- /dev/null +++ b/kicker/kicker/ui/flipscrollview.h @@ -0,0 +1,118 @@ +/***************************************************************** + +Copyright (c) 2006 Will Stephenson <wstephenson@novell.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +/* + * Flip scroll menu + * Each level of the menu is a separate TQListView + * Child items are added to their own TQListView. + * When a parent is clicked, we look up its child menu and insert + * that in a TQScrollView, then scroll to it. + * + * Need to intercept TQListViewItems' parent param and instead of + * inserting directly into parent, insert into parent item's listview + * + * So need + * - adapted QLVI + * - wrap QLV and offer same interface + */ + +#ifndef FLIPSCROLLVIEW_H +#define FLIPSCROLLVIEW_H + +#include <tqscrollview.h> +#include <tqlistview.h> +#include <tqframe.h> +#include <tqtimer.h> +#include <tqpainter.h> +#include <kstandarddirs.h> +#include "service_mnu.h" + +class ItemView; + +class BackFrame : public TQFrame +{ + Q_OBJECT + +public: + BackFrame( TQWidget *parent ); + virtual void drawContents( TQPainter *p ); + + void enterEvent ( TQEvent * ); + void leaveEvent( TQEvent * ); + void mousePressEvent ( TQMouseEvent * e ); + +signals: + void clicked(); + +private: + TQPixmap left_triangle; + bool mouse_inside; +}; + +class FlipScrollView : public TQScrollView +{ + Q_OBJECT +public: + enum State{ StoppedLeft, StoppedRight, ScrollingLeft, ScrollingRight }; + FlipScrollView( TQWidget * parent = 0, const char * name = 0 ); + ~FlipScrollView(); + + ItemView *currentView() const; + ItemView *leftView() const; + ItemView *rightView() const; + ItemView *prepareLeftMove(bool clear=true); + ItemView *prepareRightMove(); + + void flipScroll(const TQString& selectMenuPath = TQString::null); + void showBackButton(bool enable); + bool showsBackButton() const {return mShowBack;} + +protected slots: + void slotScrollTimer(); + +signals: + void startService(KService::Ptr kservice); + void startURL(const TQString& u); + void rightButtonPressed(TQListViewItem*,const TQPoint&,int); + void backButtonClicked(); + +protected: + void viewportResizeEvent ( TQResizeEvent * ); + +private: + ItemView * mLeftView; + ItemView * mRightView; +// ItemView * mCurrentView; + int mStepsRemaining; + State mState; + TQTimer * mTimer; + BackFrame *mBackrow; + TQString mSelectMenuPath; + int mScrollDirection; + bool mShowBack; +}; + + + + +#endif diff --git a/kicker/kicker/ui/itemview.cpp b/kicker/kicker/ui/itemview.cpp new file mode 100644 index 000000000..dcb4760c1 --- /dev/null +++ b/kicker/kicker/ui/itemview.cpp @@ -0,0 +1,1257 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <dmctl.h> + +#include <tqapplication.h> +#include <tqimage.h> +#include <tqpainter.h> +#include <tqstyle.h> +#include <tqwidgetstack.h> +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqvbox.h> +#include <tqheader.h> +#include <tqdrawutil.h> +#include <tqdragobject.h> +#include <tqcursor.h> +#include <tqpaintdevicemetrics.h> +#include <tqbuffer.h> +#include <tqtooltip.h> +#include <tqstylesheet.h> +#include <tqiconview.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kaboutkde.h> +#include <kpixmapeffect.h> +#include <kaction.h> +#include <kbookmarkmenu.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kcombobox.h> +#include <kwin.h> +#include <kdebug.h> +#include <kmimetype.h> +#include <kmultipledrag.h> + +#include "client_mnu.h" +#include "container_base.h" +#include "global.h" +#include "kbutton.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "konqbookmarkmanager.h" +#include "menuinfo.h" +#include "menumanager.h" +#include "popupmenutitle.h" +#include "quickbrowser_mnu.h" +#include "recentapps.h" + +#include "k_mnu.h" +#include "k_new_mnu.h" +#include "itemview.h" + +// -------------------------------------------------------------------------- + +KMenuItem::~KMenuItem() +{ + ItemView *listview = dynamic_cast<ItemView*>( listView() ); + if ( listview && listview->m_lastOne == this) { + listview->m_lastOne = 0; + listview->m_old_contentY = -1; + } +} + +static double pointSize( double pixelSize, TQPaintDevice *w ) +{ + return pixelSize * 72. / TQPaintDevice::x11AppDpiY( w->x11Screen () ); +} + +static int pixelSize( double pixelSize, TQPaintDevice *w ) +{ + return qRound( pixelSize * TQPaintDevice::x11AppDpiY( w->x11Screen () ) / 72. ); +} + +void KMenuItem::init() +{ + setMultiLinesEnabled(true); + m_s = 0; + m_path = TQString::null; + m_icon = TQString::null; + m_menuPath = TQString::null; + setDragEnabled(true); + m_has_children = false; + m_old_width = -1; + if ( TQApplication::reverseLayout() ) + right_triangle.load( locate( "data", "kicker/pics/left_triangle.png" ) ); + else + right_triangle.load( locate( "data", "kicker/pics/right_triangle.png" ) ); +} + +void KMenuItem::setTitle(const TQString& txt) +{ + m_title = txt; + setText( 0, txt ); + setup(); +} + +void KMenuItem::setToolTip(const TQString& txt) +{ + m_tooltip = txt; +} + +void KMenuItem::setDescription(const TQString& txt) +{ + m_description = txt; + setup(); +} + +void KMenuItem::setIcon(const TQString& icon, int size) +{ + m_icon = icon; + TQListViewItem::setPixmap(0, KGlobal::iconLoader()->loadIcon(icon, KIcon::Panel, size )); +} + +void KMenuItem::setHasChildren( bool flag ) +{ + m_has_children = flag; + repaint(); +} + +void KMenuItem::setup() +{ + // if someone configured a larger generalFont than 10pt, he might have a _real_ problem with 7pt + // the 7pt could be read out of konquerorrc I guess + float min_font_size = 7. * QMAX(1., KGlobalSettings::generalFont().pointSizeFloat() / 10.); + + const int expected_height = 38; + description_font_size = QMAX( pointSize( expected_height * .3, listView() ) + KickerSettings::kickoffFontPointSizeOffset(), min_font_size ) ; + title_font_size = QMAX( pointSize( expected_height * .25, listView() ) + KickerSettings::kickoffFontPointSizeOffset(), min_font_size + 1 ); + + //kdDebug() << description_font_size << " " << title_font_size << " " << pointSize( expected_height * .25, listView() ) << endl; + TQListViewItem::setup(); + setHeight( (int)QMAX( expected_height, pixelSize( title_font_size + description_font_size * 2.3, listView()))); +} + +void KMenuItem::paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align) +{ + ItemView *listview = static_cast<ItemView*>( listView() ); + int bottom = listView()->itemRect( this ).bottom(); + int diff = bottom - listView()->viewport()->height(); + + KPixmap pm; + pm.resize( width, height() ); + TQPainter pp( &pm ); + paintCellInter( &pp, cg, column, width, align ); + pp.end(); + + if ( diff > 0 && diff <= height() ) // cut off + { + pm.resize( width, height() - diff ); + KPixmapEffect::blend( pm, float( diff ) / height(), + cg.color( TQColorGroup::Background ), + KPixmapEffect::VerticalGradient ); + p->drawPixmap( 0, 0, pm ); + if ( listview->m_lastOne != this ) + { + listview->m_lastOne = this; + listview->m_old_contentY = -1; + } + } + else + { + p->drawPixmap( 0, 0, pm ); + if ( this == listview->m_lastOne ) { + if ( bottom < 0 ) + listview->m_lastOne = static_cast<KMenuItem*>( itemAbove() ); + else + listview->m_lastOne = static_cast<KMenuItem*>( itemBelow() ); + listview->m_old_contentY = -1; + repaint(); + } + } +} + +void KMenuItem::makeGradient( KPixmap &off, const TQColor &c ) +{ + KPixmap blend; + blend.resize( off.width() / 3, off.height() ); + bitBlt( &blend, 0, 0, &off, off.width() - blend.width(), 0, blend.width(), blend.height() ); + KPixmapEffect::blend( blend, 0.2, c, KPixmapEffect::HorizontalGradient ); + TQPainter p( &off ); + p.drawPixmap( off.width() - blend.width(), 0, blend ); + p.end(); +} + +void KMenuItem::paintCellInter(TQPainter* p, const TQColorGroup & cg, int column, int width, int align) +{ + const bool reverseLayout = TQApplication::reverseLayout(); + + const BackgroundMode bgmode = listView()->viewport()->backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + TQColor backg = cg.color( crole ); + + if ( isSelected() ) + backg = cg.color( TQColorGroup::Highlight ); + p->fillRect( 0, 0, width, height(), backg ); + + TQFontMetrics fm( p->fontMetrics() ); + + int pixsize = 32; + if ( height() < 36 ) + pixsize = 16; + const int left_margin = 30; + const int margin = 3; + +// p->drawText( 2, 2, left_margin - 2, height(), align, TQString::number( childCount () ) ); + + const TQPixmap * pix = pixmap( column ); + + if ( pix ) + { + TQPixmap pix32 = *pix; + + if ( pix->width() > pixsize ) + { + TQImage i = pix->convertToImage().smoothScale( pixsize, pixsize ); + pix32.convertFromImage( i ); + } + if ( reverseLayout ) + p->drawPixmap( width - ( (pixsize - pix32.width()) / 2 + left_margin ) - pix32.width(), + ( height() - pix32.height() ) / 2, pix32 ); + else + p->drawPixmap( (pixsize - pix32.width()) / 2 + left_margin, + ( height() - pix32.height() ) / 2, pix32 ); + } + + if ( m_title.isEmpty() ) + return; + + int r = left_margin + pixsize + margin * 2; + + TQFont f1 = p->font(); + f1.setPointSizeFloat( title_font_size ); + f1.setWeight( TQFont::Normal ); // TQFont::DemiBold == 63 + + TQFont f2 = p->font(); + f2.setPointSizeFloat( description_font_size ); + f2.setWeight( TQFont::Light ); + + int f1h = TQFontMetrics( f1 ).height(); + int f2h = TQFontMetrics( f2 ).height(); + + const int text_margin = 2; + int spacing = ( height() - f1h - f2h - text_margin ) / 2; + if ( m_description.isEmpty() ) + spacing = ( height() - f1h ) / 2; + + int right_triangle_size = pixelSize( 7, listView() ); + + int right_margin = listView()->verticalScrollBar()->width(); + if ( m_has_children ) + right_margin += right_triangle_size * 2; + + KPixmap off; + TQPainter pp; + + off.resize( width-text_margin-r-right_margin, height() ); + pp.begin( &off ); + pp.fillRect( 0, 0, off.width(), off.height(), backg ); + + if (isSelected()) + pp.setPen( cg.color( TQColorGroup::HighlightedText ) ); + else + pp.setPen( cg.color( TQColorGroup::Text ) ); + + pp.setFont( f1 ); + pp.drawText( 0, 0, off.width(), off.height(), align, m_title ); + pp.end(); + if ( TQFontMetrics( f1 ).width( m_title ) > off.width() ) + { + makeGradient( off, backg ); + if ( !m_description.isEmpty() ) + setToolTip( m_title + "<br><br>" + m_description ); + else + setToolTip( m_title ); + } + if ( reverseLayout ) + p->drawPixmap( width - off.width() - r, spacing, off ); + else + p->drawPixmap( r, spacing, off ); + + if ( !m_description.isEmpty() ) + { + pp.begin( &off ); + pp.fillRect( 0, 0, off.width(), off.height(), backg ); + + TQColor myColor = cg.color( TQColorGroup::Text ).light( 200 ); + if ( qGray( myColor.rgb() ) == 0 ) + myColor = TQColor( 100, 100, 110 ); + pp.setPen( myColor ); + pp.setPen( isSelected() ? cg.color( TQColorGroup::Mid ) : myColor ); + pp.setFont( f2 ); + pp.drawText( 0, 0, off.width(), off.height(), align, m_description ); + pp.end(); + if ( TQFontMetrics( f2 ).width( m_description ) > off.width() ) + { + makeGradient( off, backg ); + setToolTip( m_title + "<br><br>" + m_description ); + } + if ( reverseLayout ) + p->drawPixmap( width - off.width() - r, spacing + text_margin + f1h, off ); + else + p->drawPixmap( r, spacing + text_margin + f1h, off ); + } + + if ( m_has_children ) + { + TQImage i = right_triangle.convertToImage().smoothScale( right_triangle_size, + right_triangle_size ); + TQPixmap tri; + tri.convertFromImage( i ); + + if ( reverseLayout ) + p->drawPixmap( right_margin - tri.width(), ( height() - f1h ) / 2, tri ); + else + p->drawPixmap( listView()->width() - right_margin, ( height() - f1h ) / 2, tri ); + } + + if ( m_old_width != width ) + { + // the listview caches paint events + m_old_width = width; + repaint(); + } +} + +// -------------------------------------------------------------------------- + +KMenuItemSeparator::KMenuItemSeparator(int nId, TQListView* parent) + : KMenuItem(nId, parent), lv(parent), cached_width( 0 ) +{ + setEnabled(false); + left_margin = 15; +} + +void KMenuItemSeparator::setup() +{ + KMenuItem::setup(); + + TQFont f = TQFont(); + TQFontMetrics fm(f); + f.setPointSize( 8 + KickerSettings::kickoffFontPointSizeOffset() ); + if ( itemAbove() && !text( 0 ).isEmpty() ) + setHeight( (int)QMAX( 34., fm.height() * 1.4) ); + else + setHeight( (int)QMAX( 26., fm.height() * 1.4 ) ); +} + +void KMenuItemSeparator::setLink( const TQString &text, const TQString &url ) +{ + m_link_text = text; + m_link_url = url; + m_link_rect = TQRect(); +} + +bool KMenuItemSeparator::hitsLink( const TQPoint &pos ) +{ + return m_link_rect.contains( pos ); +} + +void KMenuItemSeparator::preparePixmap( int width ) +{ + if ( cached_width != width ) + { + pixmap.load( locate("data", "kicker/pics/menu_separator.png" ) ); + TQImage i = pixmap.convertToImage().smoothScale( width - 15 - left_margin, pixmap.height() ); + pixmap.convertFromImage( i ); + cached_width = width; + } +} + +void KMenuItemSeparator::paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align) +{ + preparePixmap(width); + + const int h = height(); + + if (text(0).isEmpty()) { + KMenuItem::paintCell(p, cg, column, width, align); + p->drawPixmap( 15 , h/2, pixmap ); + } + else { + const BackgroundMode bgmode = lv->viewport()->backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + p->fillRect( 0, 0, width, h, cg.brush( crole ) ); + + int margin = 0; + if ( itemAbove() ) { + p->drawPixmap( 15 , h/4, pixmap ); + margin = h / 4; + } + TQFont f = listView()->font(); + f.setWeight( TQFont::Normal ); + f.setPointSize( 8 + KickerSettings::kickoffFontPointSizeOffset() ); + p->setFont( f ); + TQColor myColor = cg.color( TQColorGroup::Text ).light( 200 ); + if ( qGray( myColor.rgb() ) == 0 ) + myColor = TQColor( 100, 100, 110 ); + p->setPen( myColor ); + int twidth = p->fontMetrics().width(text(0)); + int lwidth = 0; + int swidth = 0; + int fwidth = 0; + + if ( !m_link_text.isEmpty() ) + { + swidth = p->fontMetrics().width( " (" ); + lwidth = p->fontMetrics().width(m_link_text ); + fwidth = p->fontMetrics().width( ")" ); + } + int pos = int(lv->width() * 0.9 - twidth - swidth - lwidth - fwidth); + p->drawText( pos, margin + 5, + width, h - ( margin +5 ), AlignTop, text(0) ); + if ( !m_link_text.isEmpty() ) + { + pos += twidth; + p->drawText( pos, margin + 5, + width, h - ( margin +5 ), AlignTop, " (" ); + pos += swidth; + p->setPen( cg.color( TQColorGroup::Link ) ); + f.setUnderline( true ); + p->setFont( f ); + p->drawText( pos, margin + 5, + width, h - ( margin +5 ), AlignTop, m_link_text ); + m_link_rect = TQRect( pos, margin + 5, lwidth, p->fontMetrics().height() ); + pos += lwidth; + f.setUnderline( false ); + p->setFont( f ); + p->drawText( pos, margin + 5, + width, h - ( margin +5 ), AlignTop, ")" ); + } + } +} + +KMenuItemHeader::KMenuItemHeader(int nId, const TQString& relPath, TQListView* parent) + : KMenuItemSeparator(nId, parent) +{ + setEnabled( false ); + TQString path; + if (relPath.startsWith( "new/" /*"kicker:/new/"*/ )) { + paths.append( "kicker:/goup/" ); + texts.append( i18n("New Applications") ); + icons.append( "clock" ); + } + else if (relPath == "kicker:/restart/") { + texts.append( i18n("Restart Computer") ); + } + else if (relPath == "kicker:/switchuser/") { + texts.append( i18n("Switch User") ); + } + else { + KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(relPath); + TQStringList items = TQStringList::split( '/', relPath ); + for ( TQStringList::ConstIterator it = items.begin(); it != items.end(); ++it ) + { + path += *it + "/"; + paths.append( "kicker:/goup/" + path ); + KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(path); + TQString groupCaption = subMenuRoot->caption(); + texts.append( groupCaption ); + icons.append( subMenuRoot->icon() ); + } + } + + setPath( "kicker:/goup/" + path ); // the last wins for now + left_margin = 10; +} + +void KMenuItemHeader::setup() +{ + KMenuItem::setup(); + + TQFontMetrics fm( listView()->font() ); + setHeight( QMAX( int( texts.count() * fm.height() + ( texts.count() + 1 ) * 2 + 10 ), height()) ); + // nada +} + +void KMenuItemHeader::paintCell(TQPainter* p, const TQColorGroup & cg, int , int width, int align ) +{ + preparePixmap(width); + + const BackgroundMode bgmode = listView()->viewport()->backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + + TQBrush br = cg.brush( crole ); + if ( isSelected() ) { + br = cg.brush( TQColorGroup::Highlight ); + p->fillRect( 0, 0, width, height() - 3, br ); + } else { + p->fillRect( 0, 0, width, height(), br ); + } + + TQFontMetrics fm( p->fontMetrics() ); + const int left_margin = 10; + + const int margin = 3; + + int r = left_margin + margin * 2; + + const int min_font_size = 7; + int title_font_pixelSize = qRound( pixelSize( QMAX( pointSize( 12, listView() ) + KickerSettings::kickoffFontPointSizeOffset(), min_font_size + 1 ), listView() ) ); + + TQFont f1 = p->font(); + f1.setPixelSize( title_font_pixelSize ); + p->setFont( f1 ); + int f1h = TQFontMetrics( f1 ).height(); + + p->setPen( cg.color( TQColorGroup::Text ) ); + + const int text_margin = 2; + int spacing = ( height() - texts.count() * f1h - QMAX( texts.count() - 1, 0 ) * text_margin ) / 2; + + for ( uint i = 0; i < texts.count(); ++i ) + { + if (i==texts.count()-1) { + f1.setWeight( TQFont::DemiBold ); + p->setFont( f1 ); + f1h = TQFontMetrics( f1 ).height(); + } + + p->drawText( r, spacing, width-text_margin-r, height(), align, texts[i] ); + spacing += text_margin + f1h; + r += title_font_pixelSize; + } + + p->drawPixmap( left_margin , height() - 2, pixmap ); +} + +KMenuSpacer::KMenuSpacer(int nId, TQListView* parent) + : KMenuItem(nId, parent) +{ + setEnabled(false); +} + +void KMenuSpacer::setup() +{ + // nada +} + +void KMenuSpacer::paintCell(TQPainter* p, const TQColorGroup & cg, int , int width, int ) +{ + const BackgroundMode bgmode = listView()->viewport()->backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + TQBrush br = cg.brush( crole ); + + p->fillRect( 0, 0, width, height(), br ); +} + +void KMenuSpacer::setHeight( int i ) +{ + KMenuItem::setHeight( i ); +} + +class ItemViewTip : public TQToolTip +{ +public: + ItemViewTip( TQWidget *parent, TQListView *lv ); + + void maybeTip( const TQPoint &pos ); + +private: + TQListView *view; + +}; + +ItemViewTip::ItemViewTip( TQWidget *parent, TQListView *lv ) + : TQToolTip( parent ), view( lv ) +{ +} + +void ItemViewTip::maybeTip( const TQPoint &pos ) +{ + KMenuItem *item = dynamic_cast<KMenuItem*>( view->itemAt( pos ) ); + TQPoint contentsPos = view->viewportToContents( pos ); + if ( !item ) + return; + + if ( item->toolTip().isNull() ) + return; + + TQRect r = view->itemRect( item ); + int headerPos = view->header()->sectionPos( 0 ); + r.setLeft( headerPos ); + r.setRight( headerPos + view->header()->sectionSize( 0 ) ); + tip( r, item->toolTip() ); +} + +// -------------------------------------------------------------------------- + +ItemView::ItemView(TQWidget* parent, const char* name) + : KListView(parent, name), m_spacer( 0 ), + m_mouseMoveSelects(true), m_iconSize(32) +{ + setHScrollBarMode( TQScrollView::AlwaysOff ); + setFrameStyle( TQFrame::NoFrame ); + setSelectionMode(TQListView::Single); + addColumn(""); + header()->setStretchEnabled(1, 0); + //setColumnWidthMode(0, TQListView::Maximum); + header()->hide(); + setMouseTracking(true); + setItemMargin(0); + setSorting(-1); + setTreeStepSize(38); + setFocusPolicy(TQWidget::NoFocus); + + m_lastOne = 0; + m_old_contentY = -1; + + connect(this, TQT_SIGNAL(mouseButtonClicked( int, TQListViewItem*, const TQPoint &, int )), + TQT_SLOT(slotItemClicked(int, TQListViewItem*, const TQPoint &, int))); + + connect(this, TQT_SIGNAL(returnPressed(TQListViewItem*)), TQT_SLOT(slotItemClicked(TQListViewItem*))); + connect(this, TQT_SIGNAL(spacePressed(TQListViewItem*)), TQT_SLOT(slotItemClicked(TQListViewItem*))); + + new ItemViewTip( viewport(), this ); +} + +KMenuItemHeader *ItemView::insertHeader(int id, const TQString &relpath) +{ + KMenuItemHeader *newItem = new KMenuItemHeader(id, relpath, this ); + moveItemToIndex(newItem, 1); + setBackPath( "kicker:/goup/" + relpath ); // the last wins for now + + return newItem; +} + +KMenuItem* ItemView::findItem(int nId) +{ + for (TQListViewItemIterator it(this); it.current(); ++it) + { + if(static_cast<KMenuItem*>(it.current())->id() == nId) + return static_cast<KMenuItem*>(it.current()); + } + + return 0L; +} + +bool ItemView::focusNextPrevChild(bool /*next*/) +{ + return false; +} + +KMenuItem* ItemView::itemAtIndex(int nIndex) +{ + if(nIndex <= 0) + return 0L; + + if(nIndex >= childCount()) + return static_cast<KMenuItem*>(lastItem()); + + int i = 1; + TQListViewItemIterator it(this); + for (;it.current(); ++i, ++it) { + if(i == nIndex) + return static_cast<KMenuItem*>(it.current()); + } + + return static_cast<KMenuItem*>(lastItem()); +} + +KMenuItem* ItemView::insertItem( const TQString& icon, const TQString& text, const TQString& description, const + TQString& path, int nId, int nIndex, KMenuItem *parent) +{ + KMenuItem* newItem = findItem(nId); + + if(!newItem && parent) + newItem = new KMenuItem(nId, parent ); + else if ( !newItem ) + newItem = new KMenuItem(nId, this ); + + newItem->setIcon(icon, m_iconSize); + newItem->setTitle(text); + newItem->setDescription(description); + newItem->setPath(path); + + if (nIndex==-1) + nIndex=childCount(); + + moveItemToIndex(newItem, nIndex); + + return newItem; +} + +KMenuItem* ItemView::insertItem( const TQString& icon, const TQString& text, const TQString& description, + int nId, int nIndex, KMenuItem *parent) +{ + return insertItem( icon, text, description, TQString::null, nId, nIndex, parent); +} + +int ItemView::setItemEnabled(int id, bool enabled) +{ + KMenuItem* item = findItem(id); + + if(item) + item->setEnabled(enabled); + + return 0; +} + +KMenuItemSeparator *ItemView::insertSeparator(int nId, const TQString& text, int nIndex) +{ + KMenuItemSeparator *newItem = new KMenuItemSeparator(nId, this); + + newItem->setText(0, text); + + if (nIndex==-1) + nIndex=childCount(); + + moveItemToIndex(newItem, nIndex); + return newItem; +} + +void ItemView::moveItemToIndex(KMenuItem* item, int nIndex) +{ + + if (nIndex <= 0) { + takeItem(item); + KListView::insertItem(item); + } + else { + item->moveItem(itemAtIndex(nIndex)); + } +} + +void ItemView::slotMoveContent() +{ + if ( !m_spacer ) + return; + + int item_height = 0; + TQListViewItemIterator it( this ); + while ( it.current() ) { + if ( !dynamic_cast<KMenuSpacer*>( it.current() ) && !it.current()->parent() && it.current()->isVisible() ) { + it.current()->invalidateHeight(); + item_height += it.current()->totalHeight(); + } + ++it; + } + + if ( height() > item_height ) + m_spacer->setHeight( height() - item_height ); + else + m_spacer->setHeight( 0 ); +} + +KMenuItem *ItemView::insertMenuItem(KService::Ptr& s, int nId, int nIndex, KMenuItem* parentItem, + const TQString& aliasname, const TQString & label, const TQString & categoryIcon ) +{ + if (!s) + return 0; + + TQString serviceName = aliasname.isEmpty() ? s->name() : aliasname; + + kdDebug() << "insertMenuItem " << nId << " " << nIndex << " " << s->name() << endl; + KMenuItem* newItem = 0; //findItem(nId); + if(!newItem) + newItem = parentItem ? new KMenuItem(nId, parentItem) : new KMenuItem(nId, this); + + newItem->setIcon(s->icon()=="unknown" ? categoryIcon : s->icon(), m_iconSize); + if ((KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() + == KickerSettings::DescriptionOnly) && !s->genericName().isEmpty()) { + newItem->setTitle(s->genericName()); + newItem->setDescription(label.isEmpty() ? serviceName : label); + } + else { + newItem->setTitle(label.isEmpty() ? serviceName : label); + newItem->setDescription(s->genericName()); + } + newItem->setService(s); + + if (nIndex==-2) + return newItem; + + if (nIndex==-1) + nIndex=childCount(); + + moveItemToIndex(newItem, nIndex); + + return newItem; +} + +KMenuItem* ItemView::insertDocumentItem(const TQString& s, int nId, int nIndex, const TQStringList* /*suppressGenericNames*/, + const TQString& /*aliasname*/) +{ + KMenuItem* newItem = findItem(nId); + + if(!newItem) + newItem = new KMenuItem(nId, this); + + KMimeType::Ptr mt = KMimeType::findByURL( s ); + newItem->setIcon(KMimeType::iconForURL( s ), m_iconSize); + newItem->setTitle(s); + newItem->setDescription(mt->comment()); + newItem->setPath(s); + + if (nIndex==-1) + nIndex=childCount(); + + moveItemToIndex(newItem, nIndex); + + return newItem; +} + +KMenuItem* ItemView::insertRecentlyItem(const TQString& s, int nId, int nIndex) +{ + KDesktopFile f(s, true /* read only */); + + KMenuItem* newItem = findItem(nId); + + if(!newItem) + newItem = new KMenuItem(nId, this); + + newItem->setIcon(f.readIcon(), m_iconSize); + + // work around upstream fixed bug + TQString name=f.readName(); + if (name.isEmpty()) + name=f.readURL(); + + newItem->setTitle(name); + + TQString comment = f.readComment(); + if (comment.isEmpty()) { + KURL url(f.readURL()); + if (!url.host().isEmpty()) + comment = i18n("Host: %1").arg(url.host()); + } + + newItem->setDescription(comment); + newItem->setPath(s); + + if (nIndex==-1) + nIndex=childCount(); + + moveItemToIndex(newItem, nIndex); + + return newItem; +} + +int ItemView::insertItem(PopupMenuTitle*, int, int) +{ + return 0; +} + +KMenuItem* ItemView::insertSubItem(const TQString& icon, const TQString& caption, const TQString& description, const TQString& path, KMenuItem* parentItem) +{ +#warning FIXME + KMenuItem* newItem = parentItem ? new KMenuItem(-1, parentItem) : new KMenuItem(-1, this); + newItem->setTitle(caption); + newItem->setDescription(description); + newItem->setIcon(icon, m_iconSize); + newItem->setPath(path); + + return newItem; +} + + + +void ItemView::slotItemClicked(int button, TQListViewItem * item, const TQPoint & /*pos*/, int /*c*/ ) +{ + if (button==1) + slotItemClicked(item); +} + +void ItemView::slotItemClicked(TQListViewItem* item) +{ + KMenuItem* kitem = dynamic_cast<KMenuItem*>(item); + if ( !kitem ) + return; + + if(kitem->service()) { + emit startService(kitem->service()); + } + else if(!kitem->path().isEmpty()) { + emit startURL(kitem->path()); + } +} + +void ItemView::contentsMousePressEvent ( TQMouseEvent * e ) +{ + KListView::contentsMousePressEvent( e ); + + TQPoint vp = contentsToViewport(e->pos()); + KMenuItemSeparator *si = dynamic_cast<KMenuItemSeparator*>( itemAt( vp ) ); + if ( si ) + { + if ( si->hitsLink( vp - itemRect(si).topLeft() ) ) + emit startURL( si->linkUrl() ); + } +} + +void ItemView::contentsMouseMoveEvent(TQMouseEvent *e) +{ + TQPoint vp = contentsToViewport(e->pos()); + TQListViewItem * i = itemAt( vp ); + + bool link_cursor = false; + KMenuItemSeparator *si = dynamic_cast<KMenuItemSeparator*>( i ); + if ( si ) + link_cursor = si->hitsLink( vp - itemRect(si).topLeft() ); + + if (i && !i->isSelectable() && !link_cursor) { + unsetCursor(); + viewport()->unsetCursor(); + return; + } + + KListView::contentsMouseMoveEvent(e); + + if (m_mouseMoveSelects) { + if(i && i->isEnabled() && !i->isSelected() && + // FIXME: This is wrong if you drag over the items. + (e->state() & (LeftButton|MidButton|RightButton)) == 0) + KListView::setSelected(i, true); + else if (!i && selectedItem()) + KListView::setSelected(selectedItem(), false); + } + + if ( link_cursor ) + setCursor( Qt::PointingHandCursor ); + else + unsetCursor(); + +} + +void ItemView::leaveEvent(TQEvent* e) +{ + KListView::leaveEvent(e); + + clearSelection(); +} + +void ItemView::resizeEvent ( TQResizeEvent * e ) +{ + KListView::resizeEvent( e ); +// if ( m_lastOne ) +// int diff = itemRect( m_lastOne ).bottom() - viewport()->height(); +} + +void ItemView::viewportPaintEvent ( TQPaintEvent * pe ) +{ + //kdDebug() << "viewportPaintEvent " << pe->rect() << " " << contentsY () << " " << m_old_contentY << endl; + KListView::viewportPaintEvent( pe ); + + if ( m_lastOne && m_old_contentY != contentsY() ) { + m_old_contentY = contentsY(); + m_lastOne->repaint(); + } +} + +void ItemView::clear() +{ + KListView::clear(); + m_lastOne = 0; + m_old_contentY = -1; + m_back_url = TQString::null; +} + +void ItemView::contentsWheelEvent(TQWheelEvent *e) +{ + KListView::contentsWheelEvent(e); + + TQPoint vp = contentsToViewport(e->pos()); + TQListViewItem * i = itemAt( vp ); + + if(i && i->isEnabled() && !i->isSelected() && + // FIXME: This is wrong if you drag over the items. + (e->state() & (LeftButton|MidButton|RightButton)) == 0) + KListView::setSelected(i, true); + else if (!i && selectedItem()) + KListView::setSelected(selectedItem(), false); +} + +TQDragObject * ItemView::dragObject() +{ + KMultipleDrag* o = 0; + TQListViewItem *item = itemAt( viewport()->mapFromGlobal(TQCursor::pos()) ); + if ( item ) { + KMenuItem* kitem = static_cast<KMenuItem*>(item); + + if (dynamic_cast<KMenuItemHeader*>(item)) + return 0; + + o = new KMultipleDrag(viewport()); + TQPixmap pix = KGlobal::iconLoader()->loadIcon( kitem->icon(), KIcon::Panel, m_iconSize); + TQPixmap add = KGlobal::iconLoader()->loadIcon( "add", KIcon::Small ); + + TQPainter p( &pix ); + p.drawPixmap(pix.height()-add.height(), pix.width()-add.width(), add); + p.end(); + + TQBitmap mask; + + if (pix.mask()) + mask = *pix.mask(); + else { + mask.resize(pix.size()); + mask.fill(Qt::color1); + } + + bitBlt( &mask, pix.width()-add.width(), pix.height()-add.height(), add.mask(), 0, 0, add.width(), add.height(), OrROP ); + pix.setMask( mask ); + o->setPixmap(pix); + + if(kitem->service()) { + // If the path to the desktop file is relative, try to get the full + // path from KStdDirs. + TQString path = kitem->service()->desktopEntryPath(); + path = locate("apps", path); + o->addDragObject(new KURLDrag(KURL::List(KURL(path)), 0)); + } + else if (kitem->path().startsWith("kicker:/new") || kitem->path().startsWith("system:/") + || kitem->path().startsWith("kicker:/switchuser_") || kitem->path().startsWith("kicker:/restart_")) { + delete o; + return 0; + } + else if (kitem->hasChildren()) { + o->addDragObject(new KURLDrag(KURL::List(KURL("programs:/"+kitem->menuPath())), 0)); + return o; + } + else if(!kitem->path().isEmpty() && !kitem->path().startsWith("kicker:/") && !kitem->path().startsWith("kaddressbook:/")) { + TQString uri = kitem->path(); + + if (uri.startsWith(locateLocal("data", TQString::fromLatin1("RecentDocuments/")))) { + KDesktopFile df(uri,true); + uri=df.readURL(); + } + + o->addDragObject(new KURLDrag(KURL::List(KURL(uri)), 0)); + } + + o->addDragObject(new KMenuItemDrag(*kitem,this)); + } + return o; +} + +int ItemView::goodHeight() +{ + int item_height = 0; + TQListViewItemIterator it( this ); + while ( it.current() ) { + if ( !dynamic_cast<KMenuSpacer*>( it.current() ) && !it.current()->parent() && it.current()->isVisible() ) { + item_height += it.current()->height(); + } + ++it; + } + + return item_height; +} + + +KMenuItemDrag::KMenuItemDrag(KMenuItem& item, TQWidget *dragSource) + : TQDragObject(dragSource, 0) +{ + TQBuffer buff(a); + buff.open(IO_WriteOnly); + TQDataStream s(&buff); + + s << item.id() << (item.service() ? item.service()->storageId() : TQString::null) + << item.title() << item.description() << item.icon() << item.path(); +} + +KMenuItemDrag::~KMenuItemDrag() +{ +} + +const char * KMenuItemDrag::format(int i) const +{ + if (i == 0) + return "application/kmenuitem"; + + return 0; +} + +TQByteArray KMenuItemDrag::encodedData(const char* mimeType) const +{ + if (TQString("application/kmenuitem") == mimeType) + return a; + + return TQByteArray(); +} + +bool KMenuItemDrag::canDecode(const TQMimeSource * e) +{ + if (e->provides( "application/kmenuitem" ) ) + return true; + + return false; +} + +bool ItemView::acceptDrag (TQDropEvent* event) const +{ + if ( !acceptDrops() ) + return false; + + if (KMenuItemDrag::canDecode(event)) + return true; + + if (TQTextDrag::canDecode(event)) { + TQString text; + TQTextDrag::decode(event,text); + return !text.startsWith("programs:/"); + } + + return itemsMovable(); +} + +bool KMenuItemDrag::decode(const TQMimeSource* e, KMenuItemInfo& item) +{ + TQByteArray a = e->encodedData("application/kmenuitem"); + + if (a.isEmpty()) { + TQStringList l; + bool ret = TQUriDrag::decodeToUnicodeUris( e, l ); + if ( ret ) + { + for ( TQStringList::ConstIterator it = l.begin(); it != l.end(); ++it ) + { + TQString url = *it; + kdDebug () << "Url " << url << endl; + item.m_path = KURL( url ).path(); + if ( KDesktopFile::isDesktopFile( item.m_path ) ) + { + KDesktopFile df( item.m_path, true ); + item.m_description = df.readGenericName(); + item.m_icon = df.readIcon(); + item.m_title = df.readName(); + } + else + { + item.m_title = item.m_path; + item.m_icon = KMimeType::iconForURL( url ); + item.m_title = item.m_path.section( '/', -1, -1 ); + int last_slash = url.findRev ('/', -1); + if (last_slash == 0) + item.m_description = i18n("Directory: /)"); + else + item.m_description = i18n("Directory: ") + url.section ('/', -2, -2); + } + + return true; + } + } + return false; + } + + TQBuffer buff(a); + buff.open(IO_ReadOnly); + TQDataStream s(&buff); + + KMenuItemInfo i; + TQString storageId; + s >> i.m_id >> storageId >> i.m_title >> i.m_description >> i.m_icon >> i.m_path; + + i.m_s = storageId.isEmpty() ? 0 : KService::serviceByStorageId(storageId); + item = i; + + return true; +} + +FavoritesItemView::FavoritesItemView(TQWidget* parent, const char* name) + : ItemView(parent, name) +{ +} + +bool FavoritesItemView::acceptDrag (TQDropEvent* event) const +{ + if (event->source()==this->viewport()) + return true; + + if (KMenuItemDrag::canDecode(event)) { + KMenuItemInfo item; + KMenuItemDrag::decode(event,item); + TQStringList favs = KickerSettings::favorites(); + + if (item.m_s) + return favs.find(item.m_s->storageId())==favs.end(); + else { + TQStringList::Iterator it; + + TQString uri = item.m_path; + + if (uri.startsWith(locateLocal("data", TQString::fromLatin1("RecentDocuments/")))) { + KDesktopFile df(uri,true); + uri=df.readURL(); + } + + for (it = favs.begin(); it != favs.end(); ++it) { + if ((*it)[0]=='/') { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==uri) + break; + } + } + return it==favs.end(); + } + } + + if (TQTextDrag::canDecode(event)) { + TQString text; + TQTextDrag::decode(event,text); + TQStringList favs = KickerSettings::favorites(); + + if (text.endsWith(".desktop")) { + KService::Ptr p = KService::serviceByDesktopPath(text.replace("file://",TQString::null)); + return (p && favs.find(p->storageId())==favs.end()); + } + else { + TQStringList::Iterator it; + for (it = favs.begin(); it != favs.end(); ++it) { + if ((*it)[0]=='/') { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==text) + break; + } + } + return it==favs.end(); + } + } + + return itemsMovable(); +} + +#include "itemview.moc" + +// vim:cindent:sw=4: diff --git a/kicker/kicker/ui/itemview.h b/kicker/kicker/ui/itemview.h new file mode 100644 index 000000000..c8b95ee42 --- /dev/null +++ b/kicker/kicker/ui/itemview.h @@ -0,0 +1,260 @@ +/***************************************************************** + +Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __itemview_h__ +#define __itemview_h__ + +#include <dcopobject.h> +#include <tqintdict.h> +#include <tqpixmap.h> +#include <tqframe.h> +#include <tqtoolbutton.h> +#include <klistview.h> +#include <tqdragobject.h> + +#include "kmenubase.h" +#include "kmenuitembase.h" +#include "service_mnu.h" + +class KickerClientMenu; +class KBookmarkMenu; +class KActionCollection; +class KBookmarkOwner; +class Panel; +class TQWidgetStack; +class KHistoryCombo; +class TQScrollView; +class PopupMenuTitle; +class TQWidget; +class TQVBoxLayout; +class TQTimer; +class KPixmap; + +class KMenuItem : public TQListViewItem +{ +public: + KMenuItem(int nId, TQListView* parent) : TQListViewItem(parent), m_id(nId) { init(); } + KMenuItem(int nId, TQListViewItem* parent) : TQListViewItem(parent), m_id(nId) { init(); } + ~KMenuItem(); + + void setIcon(const TQString& icon, int size); + TQString icon() const { return m_icon; } + void setTitle( const TQString& text ); + TQString title() const { return m_title; } + void setToolTip( const TQString& text ); + TQString toolTip() const { return m_tooltip; } + void setDescription(const TQString& text); + TQString description() const { return m_description; } + void setService(KService::Ptr& s) { m_s = s; } + KService::Ptr service() { return m_s; } + void setPath(const TQString& u) { m_path = u; } + TQString path() const { return m_path; } + void setMenuPath(const TQString& u) { m_menuPath = u; } + TQString menuPath() const { return m_menuPath; } + int id() const { return m_id; } + void setHasChildren(bool flag); + bool hasChildren() const { return m_has_children; } + void makeGradient(KPixmap &off, const TQColor& c); + +protected: + virtual void paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align); + virtual void paintCellInter(TQPainter* p, const TQColorGroup & cg, int column, int width, int align); + virtual void setup(); + +private: + void init(); + + int m_id; + KService::Ptr m_s; + TQString m_title; + TQString m_description; + TQString m_path; + TQString m_icon; + TQString m_tooltip; + TQString m_menuPath; + float title_font_size; + float description_font_size; + bool m_has_children; + int m_old_width; + TQPixmap right_triangle; +}; + +class KMenuItemSeparator : public KMenuItem +{ +public: + KMenuItemSeparator(int nId, TQListView* parent); + virtual void setup(); + + virtual void paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align); + void setLink(const TQString &text, const TQString &link = TQString::null ); + + TQString linkUrl() const { return m_link_url; } + + /// returns true if the cursor has to change + bool hitsLink(const TQPoint &pos); + +protected: + void preparePixmap(int width); + TQPixmap pixmap; + int left_margin; + +private: + TQListView* lv; + int cached_width; + TQString m_link_text, m_link_url; + TQRect m_link_rect; + +}; + +class KMenuItemHeader : public KMenuItemSeparator +{ +public: + KMenuItemHeader( int nId, const TQString &relpath, TQListView* parent); + virtual void setup(); + + virtual void paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align); + +private: + TQListView* lv; + TQStringList paths; + TQStringList texts; + TQStringList icons; + TQPixmap left_triangle; +}; + +class KMenuSpacer : public KMenuItem +{ +public: + KMenuSpacer(int nId, TQListView* parent); + virtual void paintCell(TQPainter* p, const TQColorGroup & cg, int column, int width, int align); + virtual void setup(); + + void setHeight(int); +}; + +class ItemView : public KListView +{ + friend class KMenuItem; + + Q_OBJECT +public: + ItemView(TQWidget* parent, const char* name = 0); + + KMenuItem* insertItem( const TQString& icon, const TQString& text, const TQString& description, int nId, int nIndex, KMenuItem* parentItem = 0 ); + KMenuItem* insertItem( const TQString& icon, const TQString& text, const TQString& description, const TQString& path, int nId, int nIndex, KMenuItem* parentItem = 0 ); + int insertItem( PopupMenuTitle*, int, int); + int setItemEnabled(int id, bool enabled); + KMenuItemSeparator *insertSeparator(int id, const TQString& text, int nIndex); + KMenuItemHeader *insertHeader(int id, const TQString &relpath); + KMenuItem* insertMenuItem(KService::Ptr & s, int nId, int nIndex = -1, KMenuItem* parentItem = 0, + const TQString &aliasname = TQString::null, const TQString &label = TQString::null, + const TQString &categoryIcon = TQString::null); + KMenuItem* insertRecentlyItem(const TQString& s, int nId, int nIndex = -1); + KMenuItem* insertDocumentItem(const TQString& s, int nId, int nIndex = -1 , const TQStringList* suppressGenericNames = 0, + const TQString& aliasname = TQString::null); + KMenuItem* insertSubItem(const TQString& icon, const TQString& caption, const TQString& description, const TQString& path, KMenuItem* parentItem); + KMenuItem* findItem(int nId); + + void setIconSize(int size) { m_iconSize = size; } + void setMouseMoveSelects(bool select) { m_mouseMoveSelects = select; } + void clear(); + int goodHeight(); + TQString path; + void setBackPath( const TQString &str ) { m_back_url = str; } + TQString backPath() const { return m_back_url; } + +public slots: + void slotItemClicked(TQListViewItem*); + void slotMoveContent(); + +signals: + void startService(KService::Ptr kservice); + void startURL(const TQString& u); + +protected: + void contentsMouseMoveEvent(TQMouseEvent *e); + void contentsMousePressEvent ( TQMouseEvent * e ); + void contentsWheelEvent(TQWheelEvent *e); + void leaveEvent(TQEvent *e); + virtual void resizeEvent ( TQResizeEvent * e ); + virtual void viewportPaintEvent ( TQPaintEvent * pe ); + virtual TQDragObject* dragObject (); + virtual bool acceptDrag (TQDropEvent* event) const; + virtual bool focusNextPrevChild(bool next); + +private slots: + void slotItemClicked(int button, TQListViewItem * item, const TQPoint & pos, int c ); + +private: + KMenuItem* itemAtIndex(int nIndex); + void moveItemToIndex(KMenuItem*, int); + + TQWidget* m_itemBox; + TQVBoxLayout* m_itemLayout; + KMenuItem *m_lastOne; + KMenuSpacer *m_spacer; + + TQString m_back_url; + + bool m_mouseMoveSelects; + int m_iconSize; + int m_old_contentY; +}; + +class FavoritesItemView : public ItemView +{ +public: + FavoritesItemView(TQWidget* parent, const char* name = 0); + +protected: + virtual bool acceptDrag (TQDropEvent* event) const; +}; + +class KMenuItemInfo +{ +public: + int m_id; + KService::Ptr m_s; + TQString m_title; + TQString m_description; + TQString m_path; + TQString m_icon; +}; + +class KMenuItemDrag : public TQDragObject +{ + public: + KMenuItemDrag(KMenuItem& item, TQWidget *dragSource); + ~KMenuItemDrag(); + + virtual const char * format(int i = 0) const; + virtual TQByteArray encodedData(const char *) const; + + static bool canDecode(const TQMimeSource * e); + static bool decode(const TQMimeSource* e, KMenuItemInfo& item); + + private: + TQByteArray a; +}; + +#endif diff --git a/kicker/kicker/ui/k_mnu_stub.cpp b/kicker/kicker/ui/k_mnu_stub.cpp new file mode 100644 index 000000000..b02d2bcbf --- /dev/null +++ b/kicker/kicker/ui/k_mnu_stub.cpp @@ -0,0 +1,141 @@ +/***************************************************************** + +Copyright (c) 2006 Dirk Mueller <mueller@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "k_mnu_stub.h" +#include "k_new_mnu.h" +#include "k_mnu.h" + +void KMenuStub::removeClientMenu(int id) +{ + if(m_type == t_KMenu) + return m_w.kmenu->removeClientMenu(id); + return m_w.panelkmenu->removeClientMenu(id); +} + +int KMenuStub::insertClientMenu(KickerClientMenu *p) +{ + if(m_type == t_KMenu) + return m_w.kmenu->insertClientMenu(p); + return m_w.panelkmenu->insertClientMenu(p); +} + +void KMenuStub::adjustSize() +{ + if(m_type == t_KMenu) + return m_w.kmenu->adjustSize(); + return m_w.panelkmenu->adjustSize(); +} + +void KMenuStub::hide() +{ + if(m_type == t_KMenu) + return m_w.kmenu->hide(); + return m_w.panelkmenu->hide(); +} + +void KMenuStub::show() +{ + if(m_type == t_KMenu) + return m_w.kmenu->show(); + return m_w.panelkmenu->show(); +} + +void KMenuStub::showMenu() +{ + if(m_type == t_KMenu) + return m_w.kmenu->showMenu(); + return m_w.panelkmenu->showMenu(); +} + +#if 0 +void KMenuStub::resize() +{ + if(m_type == t_KMenu) + return m_w.kmenu->resize(); + return m_w.panelkmenu->resize(); +} +#endif + +void KMenuStub::popup(const TQPoint &pos, int indexAtPoint) +{ + return m_type == t_KMenu ? + m_w.kmenu->popup(pos, indexAtPoint) + : m_w.panelkmenu->popup(pos, indexAtPoint); +} + +void KMenuStub::selectFirstItem() +{ + if(m_type == t_KMenu) + return m_w.kmenu->selectFirstItem(); + return m_w.panelkmenu->selectFirstItem(); +} + +void KMenuStub::resize(int w, int h) +{ + if(m_type == t_KMenu) + return m_w.kmenu->resize(w, h); + return m_w.panelkmenu->resize(w, h); +} + +TQSize KMenuStub::sizeHint() const +{ + if(m_type == t_KMenu) + return m_w.kmenu->sizeHint(); + return m_w.panelkmenu->sizeHint(); +} + +bool KMenuStub::highlightMenuItem( const TQString &menuId ) +{ + if(m_type == t_KMenu) + return m_w.kmenu->highlightMenuItem(menuId); + return m_w.panelkmenu->highlightMenuItem(menuId); +} + +void KMenuStub::clearRecentMenuItems() +{ + if(m_type == t_KMenu) + return m_w.kmenu->clearRecentAppsItems(); + return m_w.panelkmenu->clearRecentMenuItems(); +} + +void KMenuStub::initialize() +{ + if(m_type == t_KMenu) + return m_w.kmenu->initialize(); + return m_w.panelkmenu->initialize(); +} + +bool KMenuStub::isVisible() const +{ + if(m_type == t_KMenu) + return m_w.kmenu->isVisible(); + return m_w.panelkmenu->isVisible(); +} + +TQWidget* KMenuStub::widget() +{ + if(m_type == t_KMenu) + return m_w.kmenu; + return m_w.panelkmenu; +} + diff --git a/kicker/kicker/ui/k_mnu_stub.h b/kicker/kicker/ui/k_mnu_stub.h new file mode 100644 index 000000000..362d132b2 --- /dev/null +++ b/kicker/kicker/ui/k_mnu_stub.h @@ -0,0 +1,72 @@ +/***************************************************************** + +Copyright (c) 2006 Dirk Mueller <mueller@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __k_mnu_stub_h__ +#define __k_mnu_stub_h__ + +#include <tqstring.h> +#include <tqpoint.h> + +class KickerClientMenu; +class KMenu; +class PanelKMenu; + + + + +class KMenuStub +{ +public: + KMenuStub(KMenu* _kmenu) + : m_type(t_KMenu) { m_w.kmenu = _kmenu; } + KMenuStub(PanelKMenu* _panelkmenu) + : m_type(t_PanelKMenu) { m_w.panelkmenu = _panelkmenu; } + ~KMenuStub() {} + + void removeClientMenu(int id); + int insertClientMenu(KickerClientMenu *p); + void adjustSize(); + void hide(); + void show(); + void showMenu(); + void resize(); + void popup(const TQPoint &pos, int indexAtPoint = -1); + void selectFirstItem(); + void resize(int, int); + TQSize sizeHint() const; + bool highlightMenuItem( const TQString &menuId ); + void clearRecentMenuItems(); + void initialize(); + + TQWidget* widget(); + + bool isVisible() const; +private: + enum {t_PanelKMenu, t_KMenu} m_type; + union { + KMenu* kmenu; + PanelKMenu* panelkmenu; + } m_w; +}; + +#endif diff --git a/kicker/kicker/ui/k_new_mnu.cpp b/kicker/kicker/ui/k_new_mnu.cpp new file mode 100644 index 000000000..34b11790b --- /dev/null +++ b/kicker/kicker/ui/k_new_mnu.cpp @@ -0,0 +1,3779 @@ +/***************************************************************** + + Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> + Copyright (c) 2006 Dirk Mueller <mueller@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 <stdlib.h> +#include <sys/types.h> +#include <unistd.h> +#include <dmctl.h> +#include <inttypes.h> + +#include <tqimage.h> +#include <tqpainter.h> +#include <tqstyle.h> +#include <tqwidgetstack.h> +#include <tqlayout.h> +#include <tqlabel.h> +#include <tqregexp.h> +#include <tqfile.h> +#include <tqstylesheet.h> +#include <tqaccel.h> +#include <tqcursor.h> +#include <tqdir.h> +#include <tqsimplerichtext.h> +#include <tqtooltip.h> +#include <tqtabbar.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kaboutkde.h> +#include <kaction.h> +#include <kbookmarkmenu.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klineedit.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <kcombobox.h> +#include <kwin.h> +#include <kdebug.h> +#include <kuser.h> +#include <kurllabel.h> +#include <krun.h> +#include <kmimetype.h> +#include <krecentdocument.h> +#include <kcompletionbox.h> +#include <kurifilter.h> +#include <kbookmarkmanager.h> +#include <kbookmark.h> +#include <kprocess.h> +#include <kio/jobclasses.h> +#include <kio/job.h> +#include <dcopref.h> +#include <konq_popupmenu.h> +#include <konqbookmarkmanager.h> +#include <kparts/componentfactory.h> + +#include "client_mnu.h" +#include "container_base.h" +#include "global.h" +#include "knewbutton.h" +#include "kicker.h" +#include "kickerSettings.h" +#include "konqbookmarkmanager.h" +#include "menuinfo.h" +#include "menumanager.h" +#include "popupmenutitle.h" +#include "quickbrowser_mnu.h" +#include "recentapps.h" +#include "flipscrollview.h" +#include "itemview.h" +#include <dmctl.h> +#include <sys/vfs.h> +#include <mykickoffsearchinterface.h> + +#include "media_watcher.h" +#include "k_mnu.h" +#include "k_new_mnu.h" +#include "k_new_mnu.moc" +#include "kickoff_bar.h" + +#define WAIT_BEFORE_QUERYING 700 + +#define IDS_PER_CATEGORY 20 +#define ACTIONS_ID_BASE 10 +#define APP_ID_BASE 10 + IDS_PER_CATEGORY +#define BOOKMARKS_ID_BASE 10 + (IDS_PER_CATEGORY * 2) +#define NOTES_ID_BASE 10 + (IDS_PER_CATEGORY * 3) +#define MAIL_ID_BASE 10 + (IDS_PER_CATEGORY * 4) +#define FILE_ID_BASE 10 + (IDS_PER_CATEGORY * 5) +#define MUSIC_ID_BASE 10 + (IDS_PER_CATEGORY * 6) +#define WEBHIST_ID_BASE 10 + (IDS_PER_CATEGORY * 7) +#define CHAT_ID_BASE 10 + (IDS_PER_CATEGORY * 8) +#define FEED_ID_BASE 10 + (IDS_PER_CATEGORY * 9) +#define PIC_ID_BASE 10 + (IDS_PER_CATEGORY * 10) +#define VIDEO_ID_BASE 10 + (IDS_PER_CATEGORY * 11) +#define DOC_ID_BASE 10 + (IDS_PER_CATEGORY * 12) +#define OTHER_ID_BASE 10 + (IDS_PER_CATEGORY * 13) + +static TQString calculate(const TQString &exp) +{ + TQString result, cmd; + const TQString bc = KStandardDirs::findExe("bc"); + if ( !bc.isEmpty() ) + cmd = TQString("echo %1 | %2").arg(KProcess::quote(exp), KProcess::quote(bc)); + else + cmd = TQString("echo $((%1))").arg(exp); + FILE *fs = popen(TQFile::encodeName(cmd).data(), "r"); + if (fs) + { + TQTextStream ts(fs, IO_ReadOnly); + result = ts.read().stripWhiteSpace(); + pclose(fs); + } + return result; +} + +static TQString workaroundStringFreeze(const TQString& str) +{ + TQString s = str; + + s.replace("<u>","&"); + TQRegExp re("<[^>]+>"); + re.setMinimal(true); + re.setCaseSensitive(false); + + s.replace(re, ""); + s = s.simplifyWhiteSpace(); + + return s; +} + +int base_category_id[] = {ACTIONS_ID_BASE, APP_ID_BASE, BOOKMARKS_ID_BASE, NOTES_ID_BASE, MAIL_ID_BASE, + FILE_ID_BASE, MUSIC_ID_BASE, WEBHIST_ID_BASE, CHAT_ID_BASE, FEED_ID_BASE, + PIC_ID_BASE, VIDEO_ID_BASE, DOC_ID_BASE, OTHER_ID_BASE}; + +#include <assert.h> + +static int used_size( TQLabel *label, int oldsize ) +{ + TQSimpleRichText st( label->text(), KGlobalSettings::toolBarFont() ); + st.setWidth( oldsize ); + return QMAX( st.widthUsed(), oldsize ); +} + +KMenu::KMenu() + : KMenuBase(0, "SUSE::Kickoff::KMenu") + , m_sloppyTimer(0, "KNewMenu::sloppyTimer"), m_mediaFreeTimer(0, "KNewMenu::mediaFreeTimer"), + m_iconName(TQString::null), m_orientation(UnDetermined), m_search_plugin( 0 ) +{ + setMouseTracking(true); + connect(&m_sloppyTimer, TQT_SIGNAL(timeout()), TQT_SLOT(slotSloppyTimeout())); + + // set the first client id to some arbitrarily large value. + client_id = 10000; + // Don't automatically clear the main menu. + actionCollection = new KActionCollection(this); + + connect(Kicker::the(), TQT_SIGNAL(configurationChanged()), + this, TQT_SLOT(configChanged())); + + KUser * user = new KUser(); + + char hostname[256]; + hostname[0] = '\0'; + if (!gethostname( hostname, sizeof(hostname) )) + hostname[sizeof(hostname)-1] = '\0'; + + m_userInfo->setText( i18n( "User <b>%1</b> on <b>%2</b>" ) + .arg( user->loginName() ).arg( hostname ) ); + setupUi(); + + m_userInfo->setBackgroundMode( PaletteBase ); + TQColor userInfoColor = TQApplication::palette().color( TQPalette::Normal, TQColorGroup::Mid ); + if ( qGray( userInfoColor.rgb() ) > 120 ) + userInfoColor = userInfoColor.dark( 200 ); + else + userInfoColor = userInfoColor.light( 200 ); + m_userInfo->setPaletteForegroundColor( userInfoColor ); + + m_tabBar = new KickoffTabBar(this, "m_tabBar"); + connect(m_tabBar, TQT_SIGNAL(tabClicked(TQTab*)), TQT_SLOT(tabClicked(TQTab*))); + + const int tab_icon_size = 32; + + m_tabs[FavoriteTab] = new TQTab; + m_tabBar->addTab(m_tabs[FavoriteTab]); + m_tabBar->setToolTip(FavoriteTab, "<qt>" + i18n( "Most commonly used applications and documents" ) + "</qt>" ); + m_tabs[ApplicationsTab] = new TQTab; + m_tabBar->addTab(m_tabs[ApplicationsTab]); + m_tabBar->setToolTip(ApplicationsTab, "<qt>" + i18n( "List of installed applications" ) + + "</qt>" ); + + m_tabs[ComputerTab] = new TQTab; + m_tabBar->addTab(m_tabs[ComputerTab]); + m_tabBar->setToolTip(ComputerTab, "<qt>" + i18n( "Information and configuration of your " + "system, access to personal files, network resources and connected disk drives") + + "</qt>"); +#if 0 + m_tabs[SearchTab] = new TQTab; + m_tabBar->addTab(m_tabs[SearchTab]); +#endif + m_tabs[HistoryTab] = new TQTab; + m_tabBar->addTab(m_tabs[HistoryTab]); + m_tabBar->setToolTip(HistoryTab, "<qt>" + i18n( "Recently used applications and documents" ) + + "</qt>" ); + m_tabs[LeaveTab] = new TQTab; + m_tabBar->addTab(m_tabs[LeaveTab]); + m_tabBar->setToolTip(LeaveTab, i18n("<qt>Logout, switch user, switch off or reset," + " suspend of the system" ) + "</qt>" ); + + if (KickerSettings::kickoffTabBarFormat() != KickerSettings::IconOnly) { + m_tabs[FavoriteTab]->setText(workaroundStringFreeze(i18n("<p align=\"center\"> <u>F</u>avorites</p>"))); + m_tabs[HistoryTab]->setText(workaroundStringFreeze(i18n("<p align=\"center\"><u>H</u>istory</p>"))); + m_tabs[ComputerTab]->setText( + workaroundStringFreeze(i18n("<p align=\"center\"> <u>C</u>omputer</p>"))); + m_tabs[ApplicationsTab]->setText(workaroundStringFreeze(i18n("<p align=\"center\"><u>A</u>pplications</p>"))); + m_tabs[LeaveTab]->setText( + workaroundStringFreeze(i18n("<p align=\"center\"><u>L</u>eave</p>"))); + } + + if (KickerSettings::kickoffTabBarFormat() != KickerSettings::LabelOnly) { + m_tabs[FavoriteTab]->setIconSet(BarIcon("bookmark", tab_icon_size)); + m_tabs[HistoryTab]->setIconSet(BarIcon("recently_used", tab_icon_size)); + m_tabs[ComputerTab]->setIconSet(BarIcon("system", tab_icon_size)); + m_tabs[ApplicationsTab]->setIconSet(BarIcon("player_playlist", tab_icon_size)); + m_tabs[LeaveTab]->setIconSet(BarIcon("leave", tab_icon_size)); + } + + connect(m_tabBar, TQT_SIGNAL(selected(int)), m_stacker, TQT_SLOT(raiseWidget(int))); + connect(m_stacker, TQT_SIGNAL(aboutToShow(int)), m_tabBar, TQT_SLOT(setCurrentTab(int))); + + m_favoriteView = new FavoritesItemView (m_stacker, "m_favoriteView"); + m_favoriteView->setAcceptDrops(true); + m_favoriteView->setItemsMovable(true); + m_stacker->addWidget(m_favoriteView, FavoriteTab); + + m_recentlyView = new ItemView (m_stacker, "m_recentlyView"); + m_stacker->addWidget(m_recentlyView, HistoryTab); + + m_systemView = new ItemView(m_stacker, "m_systemView"); + m_stacker->addWidget(m_systemView, ComputerTab ); + + m_browserView = new FlipScrollView(m_stacker, "m_browserView"); + m_stacker->addWidget(m_browserView, ApplicationsTab); + connect( m_browserView, TQT_SIGNAL( backButtonClicked() ), TQT_SLOT( slotGoBack() ) ); + + m_exitView = new FlipScrollView(m_stacker, "m_exitView"); + m_stacker->addWidget(m_exitView, LeaveTab); + connect( m_exitView, TQT_SIGNAL( backButtonClicked() ), TQT_SLOT( slotGoExitMainMenu() ) ); + + m_searchWidget = new TQVBox (m_stacker, "m_searchWidget"); + m_searchWidget->setSpacing(0); + m_stacker->addWidget(m_searchWidget, 5); + + // search provider icon + TQPixmap icon; + KURIFilterData data; + TQStringList list; + data.setData( TQString("some keyword") ); + list << "kurisearchfilter" << "kuriikwsfilter"; + + if ( KURIFilter::self()->filterURI(data, list) ) { + TQString iconPath = locate("cache", KMimeType::favIconForURL(data.uri()) + ".png"); + if ( iconPath.isEmpty() ) + icon = SmallIcon("enhanced_browsing"); + else + icon = TQPixmap( iconPath ); + } + else + icon = SmallIcon("enhanced_browsing"); + + m_searchResultsWidget = new ItemView (m_searchWidget, "m_searchResultsWidget"); + m_searchResultsWidget->setItemMargin(4); + m_searchResultsWidget->setIconSize(16); + m_searchActions = new ItemView (m_searchWidget, "m_searchActions"); + m_searchActions->setFocusPolicy(TQWidget::NoFocus); + m_searchActions->setItemMargin(4); + m_searchInternet = new TQListViewItem(m_searchActions, i18n("Search Internet")); + m_searchInternet->setPixmap(0,icon); + setTabOrder(m_kcommand, m_searchResultsWidget); + + m_kerryInstalled = !KStandardDirs::findExe(TQString::fromLatin1("kerry")).isEmpty(); + m_isShowing = false; + + if (!m_kerryInstalled) { + m_searchIndex = 0; + m_searchActions->setMaximumHeight(5+m_searchInternet->height()); + } + else { + m_searchIndex = new TQListViewItem(m_searchActions, i18n("Search Index")); + m_searchIndex->setPixmap(0,SmallIcon("kerry")); + m_searchActions->setMaximumHeight(5+m_searchIndex->height()*2); + } + connect(m_searchActions, TQT_SIGNAL(clicked(TQListViewItem*)), TQT_SLOT(searchActionClicked(TQListViewItem*))); + connect(m_searchActions, TQT_SIGNAL(returnPressed(TQListViewItem*)), TQT_SLOT(searchActionClicked(TQListViewItem*))); + connect(m_searchActions, TQT_SIGNAL(spacePressed(TQListViewItem*)), TQT_SLOT(searchActionClicked(TQListViewItem*))); + + connect(m_searchResultsWidget, TQT_SIGNAL(startService(KService::Ptr)), TQT_SLOT(slotStartService(KService::Ptr))); + connect(m_searchResultsWidget, TQT_SIGNAL(startURL(const TQString&)), TQT_SLOT(slotStartURL(const TQString&))); + connect(m_searchResultsWidget, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint &, int )), TQT_SLOT(slotContextMenuRequested( TQListViewItem*, const TQPoint &, int ))); + + connect(m_recentlyView, TQT_SIGNAL(startService(KService::Ptr)), TQT_SLOT(slotStartService(KService::Ptr))); + connect(m_recentlyView, TQT_SIGNAL(startURL(const TQString&)), TQT_SLOT(slotStartURL(const TQString&))); + connect(m_recentlyView, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint &, int )), TQT_SLOT(slotContextMenuRequested( TQListViewItem*, const TQPoint &, int ))); + + connect(m_favoriteView, TQT_SIGNAL(startService(KService::Ptr)), TQT_SLOT(slotStartService(KService::Ptr))); + connect(m_favoriteView, TQT_SIGNAL(startURL(const TQString&)), TQT_SLOT(slotStartURL(const TQString&))); + connect(m_favoriteView, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint &, int )), TQT_SLOT(slotContextMenuRequested( TQListViewItem*, const TQPoint &, int ))); + connect(m_favoriteView, TQT_SIGNAL(moved(TQListViewItem*, TQListViewItem*, TQListViewItem*)), TQT_SLOT(slotFavoritesMoved( TQListViewItem*, TQListViewItem*, TQListViewItem* ))); + + connect(m_systemView, TQT_SIGNAL(startURL(const TQString&)), TQT_SLOT(slotStartURL(const TQString&))); + connect(m_systemView, TQT_SIGNAL(startService(KService::Ptr)), TQT_SLOT(slotStartService(KService::Ptr))); + connect(m_systemView, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint &, int )), TQT_SLOT(slotContextMenuRequested( TQListViewItem*, const TQPoint &, int ))); + + connect(m_browserView, TQT_SIGNAL(startURL(const TQString&)), TQT_SLOT(slotGoSubMenu(const TQString&))); + connect(m_browserView, TQT_SIGNAL(startService(KService::Ptr)), TQT_SLOT(slotStartService(KService::Ptr))); + connect(m_browserView, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint &, int )), TQT_SLOT(slotContextMenuRequested( TQListViewItem*, const TQPoint &, int ))); + + connect(m_exitView, TQT_SIGNAL(startURL(const TQString&)), TQT_SLOT(slotStartURL(const TQString&))); + connect(m_exitView, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint &, int )), TQT_SLOT(slotContextMenuRequested( TQListViewItem*, const TQPoint &, int ))); + + m_kcommand->setDuplicatesEnabled( false ); + m_kcommand->setLineEdit(new KLineEdit(m_kcommand, "m_kcommand-lineedit")); + m_kcommand->setCompletionMode( KGlobalSettings::CompletionAuto ); + connect(m_kcommand, TQT_SIGNAL(cleared()), TQT_SLOT(clearedHistory())); + connect(m_kcommand->lineEdit(), TQT_SIGNAL(returnPressed()), TQT_SLOT(searchAccept())); + connect(m_kcommand->lineEdit(), TQT_SIGNAL(textChanged(const TQString &)), TQT_SLOT(searchChanged(const TQString &))); + + // URI Filter meta object... + m_filterData = new KURIFilterData(); + + max_category_id = new int [num_categories]; + categorised_hit_total = new int [num_categories]; + + input_timer = new TQTimer (this, "input_timer"); + connect( input_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(doQuery()) ); + + init_search_timer = new TQTimer (this, "init_search_timer"); + connect( init_search_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(initSearch()) ); + init_search_timer->start(2000, true); + + connect( m_favoriteView, TQT_SIGNAL( dropped (TQDropEvent *, TQListViewItem * ) ), + TQT_SLOT( slotFavDropped( TQDropEvent *, TQListViewItem * ) ) ); + + this->installEventFilter(this); + m_tabBar->installEventFilter(this); + m_favoriteView->installEventFilter(this); + m_recentlyView->installEventFilter(this); + m_browserView->leftView()->installEventFilter(this); + m_browserView->rightView()->installEventFilter(this); + m_systemView->installEventFilter(this); + m_exitView->leftView()->installEventFilter(this); + m_exitView->rightView()->installEventFilter(this); + m_kcommand->lineEdit()->installEventFilter(this); + m_searchLabel->installEventFilter(this); + m_searchPixmap->installEventFilter(this); + m_stacker->installEventFilter(this); + + emailRegExp = TQRegExp("^([\\w\\-]+\\.)*[\\w\\-]+@([\\w\\-]+\\.)*[\\w\\-]+$"); + authRegExp = TQRegExp("^[a-zA-Z]+://\\w+(:\\w+)?@([\\w\\-]+\\.)*[\\w\\-]+(:\\d+)?(/.*)?$"); + uriRegExp = TQRegExp("^[a-zA-Z]+://([\\w\\-]+\\.)*[\\w\\-]+(:\\d+)?(/.*)?$"); + uri2RegExp = TQRegExp("^([\\w\\-]+\\.)+[\\w\\-]+(:\\d+)?(/.*)?$"); + + m_resizeHandle = new TQLabel(this); + m_resizeHandle->setBackgroundOrigin( TQLabel::ParentOrigin ); + m_resizeHandle->setScaledContents(true); + m_resizeHandle->setFixedSize( 16, 16 ); + m_searchFrame->stackUnder( m_resizeHandle ); + m_isresizing = false; + + m_searchPixmap->setPixmap( BarIcon( "find", 32 ) ); + + TQFont f = font(); + f.setPointSize( kMax( 7, (f.pointSize() * 4 / 5 ) + KickerSettings::kickoffFontPointSizeOffset() ) ); + m_tabBar->setFont ( f ); + f.setPointSize( kMax( 7, (f.pointSize() * 3 / 2 ) + KickerSettings::kickoffFontPointSizeOffset() ) ); + m_searchLabel->setFont( f ); + + static_cast<KLineEdit*>(m_kcommand->lineEdit())->setClickMessage(i18n( "Applications, Contacts and Documents" ) ); + + bookmarkManager = 0; + m_addressBook = 0; + m_popupMenu = 0; + + main_border_tl.load( locate("data", "kicker/pics/main_corner_tl.png" ) ); + main_border_tr.load( locate("data", "kicker/pics/main_corner_tr.png" ) ); + + search_tab_left.load( locate("data", "kicker/pics/search-tab-left.png" ) ); + search_tab_right.load( locate("data", "kicker/pics/search-tab-right.png" ) ); + search_tab_center.load( locate("data", "kicker/pics/search-tab-center.png" ) ); + + search_tab_top_left.load( locate("data", "kicker/pics/search-tab-top-left.png" ) ); + search_tab_top_right.load( locate("data", "kicker/pics/search-tab-top-right.png" ) ); + search_tab_top_center.load( locate("data", "kicker/pics/search-tab-top-center.png" ) ); +} + +void KMenu::setupUi() +{ + m_stacker = new TQWidgetStack( this, "m_stacker" ); + m_stacker->setGeometry( TQRect( 90, 260, 320, 220 ) ); + m_stacker->setSizePolicy( TQSizePolicy( (TQSizePolicy::SizeType)3, (TQSizePolicy::SizeType)3, 1, 1, m_stacker->sizePolicy().hasHeightForWidth() ) ); + m_stacker->setPaletteBackgroundColor( TQColor( 255, 255, 255 ) ); + // m_stacker->setFocusPolicy( TQWidget::StrongFocus ); + m_stacker->setLineWidth( 0 ); + m_stacker->setFocusPolicy(TQWidget::NoFocus); + connect(m_stacker, TQT_SIGNAL(aboutToShow(TQWidget*)), TQT_SLOT(stackWidgetRaised(TQWidget*))); + + m_kcommand->setName("m_kcommand"); +} + +KMenu::~KMenu() +{ + saveConfig(); + + clearSubmenus(); + delete m_filterData; +} + +bool KMenu::eventFilter ( TQObject * receiver, TQEvent* e) +{ +//kdDebug() << "eventFilter receiver=" << receiver->name() << " type=" << e->type() << endl; + TQWidget* raiseWidget = 0; + TQRect raiseRect; + + if (e->type() == TQEvent::KeyPress || + e->type() == TQEvent::MouseButtonPress || + e->type() == TQEvent::MouseMove + || e->type() == TQEvent::FocusIn + || e->type() == TQEvent::Wheel) { + TQPoint p; + + if (e->type() == TQEvent::MouseMove || e->type() == TQEvent::MouseButtonPress) { + TQMouseEvent* me = static_cast<TQMouseEvent*>(e); + p = me->globalPos(); + } + else if (e->type() == TQEvent::Wheel) { + TQWheelEvent* we = static_cast<TQWheelEvent*>(e); + p = we->globalPos(); + } + + while (receiver) { + if (receiver == m_tabBar && (e->type()!=TQEvent::MouseMove || KickerSettings::kickoffSwitchTabsOnHover() ) ) { + TQTab* s = m_tabBar->selectTab(m_tabBar->mapFromGlobal(p)); + if (s && s->identifier() == ApplicationsTab) + raiseWidget = m_browserView; + if (s && s->identifier() == FavoriteTab) + raiseWidget = m_favoriteView; + if (s && s->identifier() == HistoryTab) + raiseWidget = m_recentlyView; + if (s && s->identifier() == ComputerTab) + raiseWidget = m_systemView; + if (s && s->identifier() == LeaveTab) + raiseWidget = m_exitView; + + if (raiseWidget) + raiseRect = TQRect( m_tabBar->mapToGlobal(s->rect().topLeft()), + s->rect().size()); + } + + /* we do not want hover activation for the search line edit as this can be + * pretty disturbing */ + if ( (receiver == m_searchPixmap || + ( ( receiver == m_searchLabel || receiver==m_kcommand->lineEdit() ) && + ( e->type() == TQEvent::KeyPress || e->type() == TQEvent::Wheel + || e->type() == TQEvent::MouseButtonPress ) ) ) && + !m_isShowing) { + raiseWidget = m_searchWidget; + raiseRect = TQRect( m_searchFrame->mapToGlobal(m_searchFrame->rect().topLeft()), + m_searchFrame->size()); + } + + if(raiseWidget) + break; + if(receiver->isWidgetType()) + receiver = static_cast<TQWidget*>(receiver)->parentWidget(true); + else + break; + } + + if (e->type() == TQEvent::FocusIn && receiver && raiseWidget) { + m_searchResultsWidget->setFocusPolicy(TQWidget::StrongFocus); + m_searchActions->setFocusPolicy(raiseWidget == m_searchWidget ? + TQWidget::StrongFocus : TQWidget::NoFocus); + setTabOrder(raiseWidget, m_searchResultsWidget); + if (raiseWidget != m_stacker->visibleWidget() + && static_cast<TQWidget*>(receiver)->focusPolicy() == TQWidget::NoFocus + && m_stacker->id(raiseWidget) >= 0) { + + m_stacker->raiseWidget(raiseWidget); + return true; + } + + if (raiseWidget->focusPolicy() != TQWidget::NoFocus) + return false; + } + + if (m_sloppyRegion.contains(p)) { + if (e->type() == TQEvent::MouseButtonPress /*&& m_sloppyTimer.isActive()*/) + m_sloppySourceClicked = true; + + if (!m_sloppyTimer.isActive() || m_sloppySource != raiseRect) { + int timeout= style().styleHint(TQStyle::SH_PopupMenu_SubMenuPopupDelay); + if (m_sloppySourceClicked) + timeout = 3000; + m_sloppyTimer.start(timeout); + } + + m_sloppyWidget = raiseWidget; + m_sloppySource = raiseRect; + return false; + } + } + + if(e->type() == TQEvent::Enter && receiver->isWidgetType()) { + static_cast<TQWidget*>(receiver)->setMouseTracking(true); + TQToolTip::hide(); + } + + if ( ( e->type() == TQEvent::DragEnter || e->type() == TQEvent::DragMove ) && + raiseWidget == m_favoriteView ) + { + m_stacker->raiseWidget(m_favoriteView); + + return false; + } + + // This is a nightmare of a hack, look away. Logic needs + // to be moved to the stacker and all widgets in the stacker + // must have focusNextPrevChild() overwritten to do nothing + if (e->type() == TQEvent::KeyPress && !raiseRect.isNull()) { + ItemView* view; + if (m_browserView==m_stacker->visibleWidget()) + view = m_browserView->currentView(); + else if (m_exitView==m_stacker->visibleWidget()) + view = m_exitView->currentView(); + else + view = dynamic_cast<ItemView*>(m_stacker->visibleWidget()); + + if (view) + { + bool handled = true; + switch (static_cast<TQKeyEvent*>(e)->key()) { + case Key_Up: + if (view->selectedItem()) { + view->setSelected(view->selectedItem()->itemAbove(),true); + } + else { + view->setSelected(view->lastItem(),true); + } + break; + case Key_Down: + if (view->selectedItem()) { + view->setSelected(view->selectedItem()->itemBelow(),true); + } + else { + if (view->firstChild() && view->firstChild()->isSelectable()) + view->setSelected(view->firstChild(),true); + else if (view->childCount()>2) + view->setSelected(view->firstChild()->itemBelow(),true); + } + break; + case Key_Right: + if (view->selectedItem() && !static_cast<KMenuItem*>(view->selectedItem())->hasChildren()) + break; + // nobreak + case Key_Enter: + case Key_Return: + if (view->selectedItem()) + view->slotItemClicked(view->selectedItem()); + + break; + case Key_Left: + if (m_browserView == m_stacker->visibleWidget() || m_exitView == m_stacker->visibleWidget()) { + FlipScrollView* flip = dynamic_cast<FlipScrollView*>(m_stacker->visibleWidget()); + if (flip->showsBackButton()) { + if (m_browserView == m_stacker->visibleWidget()) + goSubMenu( m_browserView->currentView()->backPath(), true ); + else + view->slotItemClicked(view->firstChild()); + } + break; + } + // nobreak + case Key_Backspace: + if (m_browserView == m_stacker->visibleWidget() || m_exitView == m_stacker->visibleWidget()) { + FlipScrollView* flip = dynamic_cast<FlipScrollView*>(m_stacker->visibleWidget()); + if (flip->showsBackButton()) { + if (m_browserView == m_stacker->visibleWidget()) + goSubMenu( m_browserView->currentView()->backPath(), true ); + else + view->slotItemClicked(view->firstChild()); + } + } + + break; + default: + handled = false; + } + + if (handled) + view->ensureItemVisible(view->selectedItem()); + + return handled; + } + } + + bool r = KMenuBase::eventFilter(receiver, e); + + if (!r && raiseWidget) + m_stacker->raiseWidget(raiseWidget); + + if (e->type() == TQEvent::Wheel && raiseWidget ) + { + // due to an ugly TQt bug we have to kill wheel events + // that cause focus switches + r = true; + } + + if (e->type() == TQEvent::Enter && receiver == m_stacker) + { + TQRect r(m_stacker->mapToGlobal(TQPoint(-8,-32)), m_stacker->size()); + r.setSize(r.size()+TQSize(16,128)); + + m_sloppyRegion = TQRegion(r); + } + + // redo the sloppy region + if (e->type() == TQEvent::MouseMove && !r && raiseWidget) + { + TQPointArray points(4); + + // hmm, eventually this should be mouse position + 10px, not + // just worst case. but worst case seems to work fine enough. + TQPoint edge(raiseRect.topLeft()); + edge.setX(edge.x()+raiseRect.center().x()); + + if (m_orientation == BottomUp) + { + points.setPoint(0, m_stacker->mapToGlobal(m_stacker->rect().bottomLeft())); + points.setPoint(1, m_stacker->mapToGlobal(m_stacker->rect().bottomRight())); + + edge.setY(edge.y()+raiseRect.height()); + points.setPoint(2, edge+TQPoint(+raiseRect.width()/4,0)); + points.setPoint(3, edge+TQPoint(-raiseRect.width()/4,0)); + } + else + { + points.setPoint(0, m_stacker->mapToGlobal(m_stacker->rect().topLeft())); + points.setPoint(1, m_stacker->mapToGlobal(m_stacker->rect().topRight())); + points.setPoint(2, edge+TQPoint(-raiseRect.width()/4,0)); + points.setPoint(3, edge+TQPoint(+raiseRect.width()/4,0)); + } + + m_sloppyRegion = TQRegion(points); + } + + return r; +} + +void KMenu::slotSloppyTimeout() +{ + if (m_sloppyRegion.contains(TQCursor::pos()) && !m_sloppySource.isNull()) + { + if ( m_sloppySource.contains(TQCursor::pos())) + { + m_stacker->raiseWidget(m_sloppyWidget); + + m_sloppyWidget = 0; + m_sloppySource = TQRect(); + m_sloppyRegion = TQRegion(); + m_sloppySourceClicked = false; + } + } + m_sloppyTimer.stop(); +} + +void KMenu::paintSearchTab( bool active ) +{ + TQPixmap canvas( m_searchFrame->size() ); + TQPainter p( &canvas ); + + TQPixmap pix; + + if ( m_orientation == BottomUp ) + pix.load( locate("data", "kicker/pics/search-gradient.png" ) ); + else + pix.load( locate("data", "kicker/pics/search-gradient-topdown.png" ) ); + + pix.convertFromImage( pix.convertToImage().scale(pix.width(), m_searchFrame->height())); + p.drawTiledPixmap( 0, 0, m_searchFrame->width(), m_searchFrame->height(), pix ); + + if ( active ) { + + m_tabBar->deactivateTabs(true); + + p.setBrush( Qt::white ); + p.setPen( Qt::NoPen ); + + if ( m_orientation == BottomUp ) { + search_tab_center.convertFromImage( search_tab_center.convertToImage().scale(search_tab_center.width(), m_searchFrame->height())); + p.drawTiledPixmap( search_tab_left.width(), 0, m_searchFrame->width()-search_tab_left.width()-search_tab_right.width(), m_searchFrame->height(), search_tab_center ); + + search_tab_left.convertFromImage( search_tab_left.convertToImage().scale(search_tab_left.width(), m_searchFrame->height())); + p.drawPixmap( 0, 0, search_tab_left ); + + search_tab_right.convertFromImage( search_tab_right.convertToImage().scale(search_tab_right.width(), m_searchFrame->height())); + p.drawPixmap( m_searchFrame->width()-search_tab_right.width(), 0, search_tab_right ); + } + else { + search_tab_top_center.convertFromImage( search_tab_top_center.convertToImage().scale(search_tab_top_center.width(), m_searchFrame->height())); + p.drawTiledPixmap( search_tab_top_left.width(), 0, m_searchFrame->width()-search_tab_top_left.width()-search_tab_top_right.width(), m_searchFrame->height(), search_tab_top_center ); + + search_tab_top_left.convertFromImage( search_tab_top_left.convertToImage().scale(search_tab_top_left.width(), m_searchFrame->height())); + p.drawPixmap( 0, 0, search_tab_top_left ); + + search_tab_top_right.convertFromImage( search_tab_top_right.convertToImage().scale(search_tab_top_right.width(), m_searchFrame->height())); + p.drawPixmap( m_searchFrame->width()-search_tab_top_right.width(), 0, search_tab_top_right ); + } + } + else + m_tabBar->deactivateTabs(false); + + p.end(); + m_searchFrame->setPaletteBackgroundPixmap( canvas ); +} + +void KMenu::stackWidgetRaised(TQWidget* raiseWidget) +{ + paintSearchTab(raiseWidget == m_searchWidget); + + if (raiseWidget == m_browserView) { + if ( m_tabBar->currentTab() == ApplicationsTab) + slotGoSubMenu(TQString::null); + if (m_browserDirty ) { + createNewProgramList(); + m_browserView->prepareRightMove(); + m_browserView->currentView()->clear(); + fillSubMenu(TQString::null, m_browserView->currentView()); + m_browserDirty = false; + } + } + else if (raiseWidget == m_recentlyView) { + if (m_recentDirty) + updateRecent(); + } + else if (raiseWidget == m_exitView) { + if (m_tabBar->currentTab() == LeaveTab) + slotGoExitMainMenu(); + } + + +#warning TQtab fixme +#if 0 + else if (raiseWidget == m_systemView) + frame = m_system; + else if (raiseWidget == m_favoriteView) + frame = m_btnFavorites; + if (!frame) + return; + + if ( m_activeTab == frame ) + return; + + paintTab( m_activeTab, false ); + paintTab( frame, true ); + + // if (dynamic_cast<TQScrollView*>(raiseWidget)) + // m_activeTab->setFocusProxy(static_cast<TQScrollView*>(raiseWidget)->viewport()); + + if (0 && /*raiseWidget == m_stacker->visibleWidget() &&*/ !raiseWidget->hasFocus()) { + + if (dynamic_cast<TQScrollView*>(raiseWidget)) + static_cast<TQScrollView*>(raiseWidget)->viewport()->setFocus(); + else + raiseWidget->setFocus(); + } + + m_activeTab = frame; + + m_sloppyRegion = TQRegion(); + m_sloppyTimer.stop(); + + ItemView* view; + if (raiseWidget == m_browserView) + view = m_browserView->currentView(); + else if (raiseWidget == m_exitView) + view = m_exitView->currentView(); + else + view = dynamic_cast<ItemView*>(m_stacker->visibleWidget()); + if (view && !view->selectedItem()) { + if (view->firstChild() && view->firstChild()->isSelectable()) { + view->setSelected(view->firstChild(),true); + } + else if (view->childCount()>1) { + view->setSelected(view->firstChild()->itemBelow(),true); + } + } +#endif +} + +void KMenu::paletteChanged() +{ +} + +void KMenu::tabClicked(TQTab* t) +{ + if (t==m_tabs[ApplicationsTab]) + slotGoSubMenu(TQString::null); + else if (t==m_tabs[LeaveTab]) + slotGoExitMainMenu(); +} + +void KMenu::slotGoBack() +{ + goSubMenu( m_browserView->currentView()->backPath() ); +} + +void KMenu::slotGoExitMainMenu() +{ + if (m_exitView->currentView()==m_exitView->rightView()) { + m_exitView->prepareLeftMove(false); + m_exitView->showBackButton(false); + m_exitView->flipScroll(TQString::null); + } +} + +void KMenu::slotGoExitSubMenu(const TQString& url) +{ + m_exitView->prepareRightMove(); + m_exitView->showBackButton(true); + + int nId = serviceMenuEndId() + 1; + int index = 1; + + if (url=="kicker:/restart/") { + TQStringList rebootOptions; + int def, cur; + if ( DM().bootOptions( rebootOptions, def, cur ) ) + { + if ( cur == -1 ) + cur = def; + + int boot_index = 0; + TQStringList::ConstIterator it = rebootOptions.begin(); + for (; it != rebootOptions.end(); ++it, ++boot_index) + { + + TQString option = i18n( "Start '%1'" ).arg( *it ); + if (boot_index == cur) + option = i18n("Start '%1' (current)").arg( *it ); + m_exitView->rightView()->insertItem( "reload", option, + i18n( "Restart and boot directly into '%1'").arg( *it ), + TQString( "kicker:/restart_%1" ).arg( boot_index ), nId++, index++ ); + } + m_exitView->rightView()->insertHeader( nId++, "kicker:/restart/" ); + } + } + else /*if (url=="kicker:/switchuser/") */{ + m_exitView->rightView()->insertItem( "switchuser", i18n( "Start New Session" ), + i18n( "Start a parallel session" ), "kicker:/switchuser", nId++, index++ ); + + m_exitView->rightView()->insertItem( "lock", i18n( "Lock Current && Start New Session").replace("&&","&"), + i18n( "Lock screen and start a parallel session" ), "kicker:/switchuserafterlock", nId++, index++ ); + + SessList sess; + if (DM().localSessions( sess )) { + if (sess.count()>1) + m_exitView->rightView()->insertSeparator( nId++, TQString::null, index++ ); + for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + if ((*it).vt && !(*it).self) { + TQString user, loc; + DM().sess2Str2( *it, user, loc ); + TQStringList list = TQStringList::split(":", user); + m_exitView->rightView()->insertItem( "switchuser", i18n( "Switch to Session of User '%1'").arg(list[0]), + i18n("Session: %1").arg(list[1].mid(1)+", "+loc) , TQString("kicker:/switchuser_%1").arg((*it).vt), nId++, index++ ); + } + } + } + + m_exitView->rightView()->insertHeader( nId++, "kicker:/switchuser/" ); + } + m_exitView->flipScroll(TQString::null); +} + +void KMenu::slotGoSubMenu(const TQString& relPath) +{ + goSubMenu(relPath); +} + +void KMenu::goSubMenu(const TQString& relPath, bool keyboard) +{ + if ( relPath.startsWith( "kicker:/goup/" ) ) + { + TQString rel = relPath.mid( strlen( "kicker:/goup/" ) ); + int index = rel.length() - 1; + if ( rel.endsWith( "/" ) ) + index--; + index = rel.findRev( '/', index ); + kdDebug() << "goup, rel '" << rel << "' " << index << endl; + TQString currel = rel; + rel = rel.left( index + 1 ); + if ( rel == "/" ) + rel = TQString::null; + + kdDebug() << "goup, rel '" << rel << "' " << rel.isEmpty() << endl; + fillSubMenu( rel, m_browserView->prepareLeftMove() ); + m_browserView->flipScroll(keyboard ? currel : TQString::null); + return; + } else if (relPath.isEmpty()) + { + if (m_browserView->currentView()->path.isEmpty()) + return; + fillSubMenu( relPath, m_browserView->prepareLeftMove() ); + } else if ( relPath.startsWith( "kicker:/new/" ) ) + { + ItemView* view = m_browserView->prepareRightMove(); + m_browserView->showBackButton( true ); + + int nId = serviceMenuEndId() + 1; + view->insertHeader( nId++, "new/" ); + int index = 2; + for (TQStringList::ConstIterator it = m_newInstalledPrograms.begin(); + it != m_newInstalledPrograms.end(); ++it) { + KService::Ptr p = KService::serviceByStorageId((*it)); + view->insertMenuItem(p, nId++, index++); + } + } else + { + //m_browserView->clear(); + fillSubMenu(relPath, m_browserView->prepareRightMove()); + } + m_browserView->flipScroll(keyboard ? "kicker:/goup/": TQString::null); +} + +void KMenu::fillSubMenu(const TQString& relPath, ItemView *view) +{ + kdDebug() << "fillSubMenu() " << relPath << endl; + KServiceGroup::Ptr root = KServiceGroup::group(relPath); + Q_ASSERT( root ); + + KServiceGroup::List list = root->entries(true, true, true, KickerSettings:: + menuEntryFormat() == KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() + == KickerSettings::DescriptionOnly); + + int nId = serviceMenuStartId(); + m_browserView->showBackButton( !relPath.isEmpty() ); + if ( !relPath.isEmpty() ) + { + view->insertHeader( nId++, relPath ); + } + else if ( m_newInstalledPrograms.count() ) { + KMenuItem *item = view->insertItem( "clock", i18n( "New Applications" ), + TQString::null, "kicker:/new/", nId++, -1 ); + item->setHasChildren( true ); + view->insertSeparator( nId++, TQString::null, -1 ); + } + + view->path = relPath; + + fillMenu (root, list, relPath, view, nId); +} + +void KMenu::fillMenu(KServiceGroup::Ptr& +#ifdef KDELIBS_SUSE + _root +#endif + , KServiceGroup::List& _list, + const TQString& _relPath, + ItemView* view, + int& id) +{ + bool separatorNeeded = false; + KServiceGroup::List::ConstIterator it = _list.begin(); +#ifdef KDELIBS_SUSE + KSortableValueList<KSharedPtr<KSycocaEntry>,TQCString> slist; + KSortableValueList<KSharedPtr<KSycocaEntry>,TQCString> glist; + TQMap<TQString,TQString> specialTitle; + TQMap<TQString,TQString> categoryIcon; + TQMap<TQString,TQString> shortenedMenuPath; +#endif + + for (; it != _list.end(); ++it) + { + KSycocaEntry * e = *it; + + if (e->isType(KST_KServiceGroup)) + { + KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e)); +#ifdef KDELIBS_SUSE + if ( true /*KickerSettings::reduceMenuDepth()*/ && g->SuSEshortMenu() ){ + KServiceGroup::List l = g->entries(true, true /*excludeNoDisplay_*/ ); + if ( l.count() == 1 ) { + // the special case, we want to short the menu. + // TOFIX? : this works only for one level + KServiceGroup::List::ConstIterator _it=l.begin(); + KSycocaEntry *_e = *_it; + if (_e->isType(KST_KService)) { + KService::Ptr s(static_cast<KService *>(_e)); + TQString key; + if ( g->SuSEgeneralDescription() ) { + // we use the application name + key = s->name(); + } + else { + // we use the normal menu description + key = s->name(); + if( !s->genericName().isEmpty() && g->caption()!=s->genericName()) { + if (KickerSettings::menuEntryFormat() == KickerSettings::NameAndDescription) + key = s->name() + " (" + g->caption() + ")"; + else if (KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName) + key = g->caption() + " (" + s->name() + ")"; + else if (KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly) + key = g->caption(); + } + } + specialTitle.insert( _e->name(), key ); + categoryIcon.insert( _e->name(), g->icon() ); + slist.insert( key.local8Bit(), _e ); + shortenedMenuPath.insert( _e->name(), g->relPath() ); + // and escape from here + continue; + } + } + } + glist.insert( g->caption().local8Bit(), e ); + }else if( e->isType(KST_KService)) { + KService::Ptr s(static_cast<KService *>(e)); + slist.insert( s->name().local8Bit(), e ); + } else + slist.insert( e->name().local8Bit(), e ); + } + + _list = _root->SuSEsortEntries( slist, glist, true /*excludeNoDisplay_*/, true ); + it = _list.begin(); + + for (; it != _list.end(); ++it) { + + KSycocaEntry * e = *it; + + if (e->isType(KST_KServiceGroup)) { + + KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e)); + if ( true /*KickerSettings::reduceMenuDepth()*/ && g->SuSEshortMenu() ){ + KServiceGroup::List l = g->entries(true, true /*excludeNoDisplay_*/ ); + if ( l.count() == 1 ) { + continue; + } + } + // standard sub menu +#endif + TQString groupCaption = g->caption(); + + // Avoid adding empty groups. + KServiceGroup::Ptr subMenuRoot = KServiceGroup::group(g->relPath()); + + int nbChildCount = subMenuRoot->childCount(); + if (nbChildCount == 0 && !g->showEmptyMenu()) + { + continue; + } + + bool is_description = KickerSettings::menuEntryFormat() == KickerSettings::DescriptionAndName || + KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly; + + TQString inlineHeaderName = g->showInlineHeader() ? groupCaption : ""; + + if ( nbChildCount == 1 && g->allowInline() && g->inlineAlias()) + { + KServiceGroup::Ptr element = KServiceGroup::group(g->relPath()); + if ( element ) + { + //just one element + + KServiceGroup::List listElement = element->entries(true, true, true, is_description ); + KSycocaEntry * e1 = *( listElement.begin() ); + if ( e1->isType( KST_KService ) ) + { + KService::Ptr s(static_cast<KService *>(e1)); + view->insertMenuItem(s, id++, -1, 0); + continue; + } + } + } + + if (g->allowInline() && ((nbChildCount <= g->inlineValue() ) || (g->inlineValue() == 0))) + { + //inline all entries + KServiceGroup::Ptr rootElement = KServiceGroup::group(g->relPath()); + + if (!rootElement || !rootElement->isValid()) + { + break; + } + + + KServiceGroup::List listElement = rootElement->entries(true, true, true, is_description ); + +#if 0 + if ( !g->inlineAlias() && !inlineHeaderName.isEmpty() ) + { + int mid = view->insertItem(new PopupMenuTitle(inlineHeaderName, font()), id++, id, 0); + m_browserView->setItemEnabled( mid, false ); + } +#endif + + fillMenu( rootElement, listElement, g->relPath(), 0, id ); + continue; + } + + // Ignore dotfiles. + if ((g->name().at(0) == '.')) + { + continue; + } + + KMenuItem *item = view->insertItem(g->icon(), groupCaption, TQString::null, g->relPath(), id++, -1); + item->setMenuPath(g->relPath()); + item->setHasChildren( true ); + +#warning FIXME +#if 0 + PanelServiceMenu * m = + newSubMenu(g->name(), g->relPath(), this, g->name().utf8(), inlineHeaderName); + m->setCaption(groupCaption); + + TQIconSet iconset = KickerLib::menuIconSet(g->icon()); + + if (separatorNeeded) + { + insertSeparator(); + separatorNeeded = false; + } + + int newId = insertItem(iconset, groupCaption, m, id++); + entryMap_.insert(newId, static_cast<KSycocaEntry*>(g)); + // We have to delete the sub menu our selves! (See TQt docs.) + subMenus.append(m); +#endif + } + if (e->isType(KST_KService)) + { + KService::Ptr s(static_cast<KService *>(e)); + if (_relPath.isEmpty()) { + TQStringList favs = KickerSettings::favorites(); + if (favs.find(s->storageId())!=favs.end()) + continue; + } +#ifdef KDELIBS_SUSE + KMenuItem *item = view->insertMenuItem(s, id++, -1, 0, TQString::null, specialTitle[s->name()], categoryIcon[s->name()] ); + if (shortenedMenuPath[s->name()].isEmpty()) + item->setMenuPath(_relPath+s->menuId()); + else + item->setMenuPath(shortenedMenuPath[s->name()]+s->menuId()); +#else + KMenuItem *item = view->insertMenuItem(s, id++, -1); + item->setMenuPath(_relPath+s->menuId()); +#endif + } + else if (e->isType(KST_KServiceSeparator)) + { + separatorNeeded = true; + } + } + + view->slotMoveContent(); +} + +void KMenu::initialize() +{ + static bool m_initialized=false; + if (m_initialized) + return; + m_initialized = true; + + kdDebug(1210) << "KMenu::initialize()" << endl; + + // in case we've been through here before, let's disconnect + disconnect(kapp, TQT_SIGNAL(kdisplayPaletteChanged()), + this, TQT_SLOT(paletteChanged())); + connect(kapp, TQT_SIGNAL(kdisplayPaletteChanged()), + this, TQT_SLOT(paletteChanged())); + + /* + If the user configured ksmserver to + */ + KConfig ksmserver("ksmserverrc", false, false); + ksmserver.setGroup("General"); + connect( m_branding, TQT_SIGNAL(clicked()), TQT_SLOT(slotOpenHomepage())); + m_tabBar->setTabEnabled(LeaveTab, kapp->authorize("logout")); + + // load search field history + TQStringList histList = KickerSettings::history(); + int maxHistory = KickerSettings::historyLength(); + + bool block = m_kcommand->signalsBlocked(); + m_kcommand->blockSignals( true ); + m_kcommand->setMaxCount( maxHistory ); + m_kcommand->setHistoryItems( histList ); + m_kcommand->blockSignals( block ); + + TQStringList compList = KickerSettings::completionItems(); + if( compList.isEmpty() ) + m_kcommand->completionObject()->setItems( histList ); + else + m_kcommand->completionObject()->setItems( compList ); + + KCompletionBox* box = m_kcommand->completionBox(); + if (box) + box->setActivateOnSelect( false ); + + m_finalFilters = KURIFilter::self()->pluginNames(); + m_finalFilters.remove("kuriikwsfilter"); + + m_middleFilters = m_finalFilters; + m_middleFilters.remove("localdomainurifilter"); + + TQStringList favs = KickerSettings::favorites(); + if (favs.isEmpty()) { + TQFile f(locate("data", "kicker/default-favs")); + if (f.open(IO_ReadOnly)) { + TQTextStream is(&f); + + while (!is.eof()) + favs << is.readLine(); + + f.close(); + } + KickerSettings::setFavorites(favs); + KickerSettings::writeConfig(); + } + + int nId = serviceMenuEndId() + 1; + int index = 1; + for (TQStringList::ConstIterator it = favs.begin(); it != favs.end(); ++it) + { + if ((*it)[0]=='/') { + KDesktopFile df((*it),true); + TQString url = df.readURL(); + if (!KURL(url).isLocalFile() || TQFile::exists(url.replace("file://",TQString::null))) + m_favoriteView->insertItem(df.readIcon(),df.readName(),df.readGenericName(), url, nId++, index++); + } + else { + KService::Ptr p = KService::serviceByStorageId((*it)); + m_favoriteView->insertMenuItem(p, nId++, index++); + } + } + + //nId = m_favoriteView->insertSeparator( nId, TQString::null, index++ ); +// m_favoriteView->insertDocument(KURL("help:/khelpcenter/userguide/index.html"), nId++); + + insertStaticItems(); + + m_stacker->raiseWidget (m_favoriteView); +} + +void KMenu::insertStaticExitItems() +{ + int nId = serviceMenuEndId() + 1; + int index = 1; + + m_exitView->leftView()->insertSeparator( nId++, i18n("Session"), index++ ); + if (kapp->authorize("logout")) + m_exitView->leftView()->insertItem( "undo", i18n( "Logout" ), + i18n( "End session" ), "kicker:/logout", nId++, index++ ); + if (kapp->authorize("lock_screen")) + m_exitView->leftView()->insertItem( "lock", i18n( "Lock" ), + i18n( "Lock screen" ), "kicker:/lock", nId++, index++ ); + + KConfig ksmserver("ksmserverrc", false, false); + ksmserver.setGroup("General"); + if (ksmserver.readEntry( "loginMode" ) == "restoreSavedSession") + { + m_exitView->leftView()->insertItem("filesave", i18n("Save Session"), + i18n("Save current Session for next login"), + "kicker:/savesession", nId++, index++ ); + } + if (DM().isSwitchable() && kapp->authorize("switch_user")) + { + KMenuItem *switchuser = m_exitView->leftView()->insertItem( "switchuser", i18n( "Switch User" ), + i18n( "Manage parallel sessions" ), "kicker:/switchuser/", nId++, index++ ); + switchuser->setHasChildren(true); + } + + bool maysd = false; + if (ksmserver.readBoolEntry( "offerShutdown", true ) && DM().canShutdown()) + maysd = true; + + if ( maysd ) + { + m_exitView->leftView()->insertSeparator( nId++, i18n("System"), index++ ); + m_exitView->leftView()->insertItem( "exit", i18n( "Shutdown Computer" ), + i18n( "Turn off computer" ), "kicker:/shutdown", nId++, index++ ); + + m_exitView->leftView()->insertItem( "reload", i18n( "&Restart Computer" ).replace("&",""), + i18n( "Restart and boot the default system" ), + "kicker:/restart", nId++, index++ ); + + insertSuspendOption(nId, index); + + int def, cur; + TQStringList dummy_opts; + if ( DM().bootOptions( dummy_opts, def, cur ) ) + { + + KMenuItem *restart = m_exitView->leftView()->insertItem( "reload", i18n( "Start Operating System" ), + i18n( "Restart and boot another operating system" ), + "kicker:/restart/", nId++, index++ ); + restart->setHasChildren(true); + } + } +} + +void KMenu::insertStaticItems() +{ + insertStaticExitItems(); + + int nId = serviceMenuEndId() + 10; + int index = 1; + + m_systemView->insertSeparator( nId++, i18n("Applications"), index++); + + KService::Ptr p = KService::serviceByStorageId("/usr/share/applications/YaST.desktop"); + m_systemView->insertMenuItem(p, nId++, index++); + + m_systemView->insertItem( "info", i18n( "System Information" ), + "sysinfo:/", "sysinfo:/", nId++, index++ ); + + m_systemView->insertSeparator( nId++, i18n("System Folders"), index++ ); + + m_systemView->insertItem( "folder_home", i18n( "Home Folder" ), + TQDir::homeDirPath(), "file://"+TQDir::homeDirPath(), nId++, index++ ); + + if ( KStandardDirs::exists( KGlobalSettings::documentPath() + "/" ) ) + { + TQString documentPath = KGlobalSettings::documentPath(); + if ( documentPath.endsWith( "/" ) ) + documentPath = documentPath.left( documentPath.length() - 1 ); + if (documentPath!=TQDir::homeDirPath()) + m_systemView->insertItem( "folder_man", i18n( "My Documents" ), documentPath, documentPath, nId++, index++ ); + } + + m_systemView->insertItem( "network", i18n( "Network Folders" ), + "remote:/", "remote:/", nId++, index++ ); + + m_mediaWatcher = new MediaWatcher( this ); + connect( m_mediaWatcher, TQT_SIGNAL( mediumChanged() ), TQT_SLOT( updateMedia() ) ); + m_media_id = 0; + + connect(&m_mediaFreeTimer, TQT_SIGNAL(timeout()), TQT_SLOT( updateMedia())); +} + +int KMenu::insertClientMenu(KickerClientMenu *) +{ +#if 0 + int id = client_id; + clients.insert(id, p); + return id; +#endif + return 0; +} + +void KMenu::removeClientMenu(int) +{ +#if 0 + clients.remove(id); + slotClear(); +#endif +} + +extern int kicker_screen_number; + +void KMenu::slotLock() +{ + kdDebug() << "slotLock " << endl; + accept(); + TQCString appname( "kdesktop" ); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + kapp->dcopClient()->send(appname, "KScreensaverIface", "lock()", ""); +} + +void KMenu::slotOpenHomepage() +{ + accept(); + kapp->invokeBrowser("http://opensuse.org"); +} + +void KMenu::slotLogout() +{ + kapp->requestShutDown(); +} + +void KMenu::slotPopulateSessions() +{ + int p = 0; + DM dm; + + sessionsMenu->clear(); + if (kapp->authorize("start_new_session") && (p = dm.numReserve()) >= 0) + { + if (kapp->authorize("lock_screen")) + sessionsMenu->insertItem(/*SmallIconSet("lockfork"),*/ i18n("Lock Current && Start New Session"), 100 ); + sessionsMenu->insertItem(SmallIconSet("fork"), i18n("Start New Session"), 101 ); + if (!p) { + sessionsMenu->setItemEnabled( 100, false ); + sessionsMenu->setItemEnabled( 101, false ); + } + sessionsMenu->insertSeparator(); + } + SessList sess; + if (dm.localSessions( sess )) + for (SessList::ConstIterator it = sess.begin(); it != sess.end(); ++it) { + int id = sessionsMenu->insertItem( DM::sess2Str( *it ), (*it).vt ); + if (!(*it).vt) + sessionsMenu->setItemEnabled( id, false ); + if ((*it).self) + sessionsMenu->setItemChecked( id, true ); + } +} + +void KMenu::slotSessionActivated( int ent ) +{ + if (ent == 100) + doNewSession( true ); + else if (ent == 101) + doNewSession( false ); + else if (!sessionsMenu->isItemChecked( ent )) + DM().lockSwitchVT( ent ); +} + +void KMenu::doNewSession( bool lock ) +{ + int result = KMessageBox::warningContinueCancel( + kapp->desktop()->screen(kapp->desktop()->screenNumber(this)), + i18n("<p>You have chosen to open another desktop session.<br>" + "The current session will be hidden " + "and a new login screen will be displayed.<br>" + "An F-key is assigned to each session; " + "F%1 is usually assigned to the first session, " + "F%2 to the second session and so on. " + "You can switch between sessions by pressing " + "Ctrl, Alt and the appropriate F-key at the same time. " + "Additionally, the KDE Panel and Desktop menus have " + "actions for switching between sessions.</p>") + .arg(7).arg(8), + i18n("Warning - New Session"), + KGuiItem(i18n("&Start New Session"), "fork"), + ":confirmNewSession", + KMessageBox::PlainCaption | KMessageBox::Notify); + + if (result==KMessageBox::Cancel) + return; + + if (lock) + slotLock(); + + DM().startReserve(); +} + +void KMenu::searchAccept() +{ + TQString cmd = m_kcommand->currentText().stripWhiteSpace(); + + bool logout = (cmd == "logout"); + bool lock = (cmd == "lock"); + + addToHistory(); + + if ( !logout && !lock ) + { + // first try if we have any search action + if (m_searchResultsWidget->currentItem()) { + m_searchResultsWidget->slotItemClicked(m_searchResultsWidget->currentItem()); + return; + } + } + + accept(); + saveConfig(); + + if ( logout ) + { + kapp->propagateSessionManager(); + kapp->requestShutDown(); + } + if ( lock ) + { + TQCString appname( "kdesktop" ); + int kicker_screen_number = qt_xscreen(); + if ( kicker_screen_number ) + appname.sprintf("kdesktop-screen-%d", kicker_screen_number); + kapp->dcopClient()->send(appname, "KScreensaverIface", "lock()", ""); + } +} + +bool KMenu::runCommand() +{ + kdDebug() << "runCommand() " << m_kcommand->lineEdit()->text() << endl; + // Ignore empty commands... + if ( m_kcommand->lineEdit()->text().isEmpty() ) + return true; + + accept(); + + if (input_timer->isActive ()) + input_timer->stop (); + + // Make sure we have an updated data + parseLine( true ); + + bool block = m_kcommand->signalsBlocked(); + m_kcommand->blockSignals( true ); + m_kcommand->clearEdit(); + m_kcommand->setFocus(); + m_kcommand->reset(); + m_kcommand->blockSignals( block ); + + + TQString cmd; + KURL uri = m_filterData->uri(); + if ( uri.isLocalFile() && !uri.hasRef() && uri.query().isEmpty() ) + cmd = uri.path(); + else + cmd = uri.url(); + + TQString exec; + + switch( m_filterData->uriType() ) + { + case KURIFilterData::LOCAL_FILE: + case KURIFilterData::LOCAL_DIR: + case KURIFilterData::NET_PROTOCOL: + case KURIFilterData::HELP: + { + // No need for kfmclient, KRun does it all (David) + (void) new KRun( m_filterData->uri(), parentWidget()); + return false; + } + case KURIFilterData::EXECUTABLE: + { + if( !m_filterData->hasArgsAndOptions() ) + { + // Look for desktop file + KService::Ptr service = KService::serviceByDesktopName(cmd); + if (service && service->isValid() && service->type() == "Application") + { + notifyServiceStarted(service); + KRun::run(*service, KURL::List()); + return false; + } + } + } + // fall-through to shell case + case KURIFilterData::SHELL: + { + if (kapp->authorize("shell_access")) + { + exec = cmd; + + if( m_filterData->hasArgsAndOptions() ) + cmd += m_filterData->argsAndOptions(); + + break; + } + else + { + KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n" + "You do not have permission to execute " + "this command.") + .arg( TQStyleSheet::convertFromPlainText(cmd) )); + return true; + } + } + case KURIFilterData::UNKNOWN: + case KURIFilterData::ERROR: + default: + { + // Look for desktop file + KService::Ptr service = KService::serviceByDesktopName(cmd); + if (service && service->isValid() && service->type() == "Application") + { + notifyServiceStarted(service); + KRun::run(*service, KURL::List(), this); + return false; + } + + service = KService::serviceByName(cmd); + if (service && service->isValid() && service->type() == "Application") + { + notifyServiceStarted(service); + KRun::run(*service, KURL::List(), this); + return false; + } + + KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n" + "Could not run the specified command.") + .arg( TQStyleSheet::convertFromPlainText(cmd) )); + return true; + } + } + + if ( KRun::runCommand( cmd, exec, m_iconName ) ) + return false; + + KMessageBox::sorry( this, i18n("<center><b>%1</b></center>\n" + "The specified command does not exist.").arg(cmd) ); + return true; // Let the user try again... +} + +void KMenu::show() +{ + m_isShowing = true; + emit aboutToShow(); + + initialize(); + + PanelPopupButton *kButton = MenuManager::the()->findKButtonFor( this ); + if (kButton) + { + TQPoint center = kButton->center(); + TQRect screen = TQApplication::desktop()->screenGeometry( center ); + setOrientation((center.y()-screen.y()<screen.height()/2) + ? TopDown : BottomUp); + } + + m_browserDirty=true; + m_recentDirty=true; + + updateMedia(); + m_mediaFreeTimer.start(10 * 1000); // refresh all 10s + + m_stacker->raiseWidget(FavoriteTab); + m_kcommand->clear(); + current_query.clear(); + m_kcommand->setFocus(); + + // we need to reenable it + m_toolTipsEnabled = TQToolTip::isGloballyEnabled(); + TQToolTip::setGloballyEnabled(KickerSettings::showToolTips()); + + KMenuBase::show(); + m_isShowing = false; +} + +void KMenu::setOrientation(MenuOrientation orientation) +{ + if (m_orientation == orientation) + return; + + m_orientation=orientation; + + m_resizeHandle->setCursor(m_orientation == BottomUp ? Qt::sizeBDiagCursor : Qt::sizeFDiagCursor); + + TQPixmap pix; + if ( m_orientation == BottomUp ) + pix.load( locate("data", "kicker/pics/search-gradient.png" ) ); + else + pix.load( locate("data", "kicker/pics/search-gradient-topdown.png" ) ); + + pix.convertFromImage( pix.convertToImage().scale(pix.width(), m_searchFrame->height())); + m_search->mainWidget()->setPaletteBackgroundPixmap( pix ); + m_resizeHandle->setPaletteBackgroundPixmap( pix ); + + m_tabBar->setShape( m_orientation == BottomUp + ? TQTabBar::RoundedBelow : TQTabBar::RoundedAbove); + + TQPixmap respix = TQPixmap( locate("data", "kicker/pics/resize_handle.png" ) ); + if ( m_orientation == TopDown ) { + TQWMatrix m; + m.rotate( 90.0 ); + respix=respix.xForm(m); + } + m_resizeHandle->setPixmap(respix); + + { + TQWidget *footer = m_footer->mainWidget(); + TQPixmap pix( 64, footer->height() ); + TQPainter p( &pix ); + p.fillRect( 0, 0, 64, footer->height(), m_branding->colorGroup().brush( TQColorGroup::Base ) ); + p.fillRect( 0, m_orientation == BottomUp ? footer->height() - 2 : 0, + 64, 3, KNewButton::self()->borderColor() ); + p.end(); + footer->setPaletteBackgroundPixmap( pix ); + } + + resizeEvent(new TQResizeEvent(sizeHint(), sizeHint())); +} + +void KMenu::showMenu() +{ + kdDebug() << "KMenu::showMenu()" << endl; + PanelPopupButton *kButton = MenuManager::the()->findKButtonFor(this); + if (kButton) + { + adjustSize(); + kButton->showMenu(); + } + else + { + show(); + } + kdDebug() << "end KMenu::showMenu()" << endl; +} + +void KMenu::hide() +{ + //kdDebug() << "KMenu::hide() from " << kdBacktrace() << endl; + + // TODO: hide popups + + emit aboutToHide(); + + if (m_popupMenu) { + m_popupMenu->deleteLater(); + m_popupMenu=0; + } + m_mediaFreeTimer.stop(); + + m_isresizing = false; + + KickerSettings::setKMenuWidth(width()); + KickerSettings::setKMenuHeight(height()); + KickerSettings::writeConfig(); + + TQToolTip::setGloballyEnabled(m_toolTipsEnabled); + + // remove focus from lineedit again, otherwise it doesn't kill its timers + m_stacker->raiseWidget(FavoriteTab); + + TQWidget::hide(); +} + +void KMenu::paintEvent(TQPaintEvent * e) +{ + KMenuBase::paintEvent(e); + + TQPainter p(this); + p.setClipRegion(e->region()); + + const BackgroundMode bgmode = backgroundMode(); + const TQColorGroup::ColorRole crole = TQPalette::backgroundRoleFromMode( bgmode ); + p.setBrush( colorGroup().brush( crole ) ); + + p.drawRect( 0, 0, width(), height() ); + int ypos = m_search->mainWidget()->geometry().bottom(); + + p.drawPixmap( 0, ypos, main_border_tl ); + p.drawPixmap( width() - main_border_tr.width(), ypos, main_border_tr ); + // p.drawPixmap( 0, ->y(), button_box_left ); +} + + +void KMenu::configChanged() +{ + RecentlyLaunchedApps::the().m_bNeedToUpdate = false; + RecentlyLaunchedApps::the().configChanged(); + + m_exitView->leftView()->clear(); + insertStaticExitItems(); +} + +// create and fill "recent" section at first +void KMenu::createRecentMenuItems() +{ + RecentlyLaunchedApps::the().init(); + + if (!KickerSettings::numVisibleEntries()) + KickerSettings::setNumVisibleEntries(5); + + int nId = serviceMenuEndId() + 1; + m_recentlyView->insertSeparator( nId++, i18n( "Applications" ), -1 ); + + TQStringList RecentApps; + + if (!KickerSettings::recentVsOften()) { + KickerSettings::setRecentVsOften(true); + RecentlyLaunchedApps::the().configChanged(); + RecentlyLaunchedApps::the().getRecentApps(RecentApps); + KickerSettings::setRecentVsOften(false); + RecentlyLaunchedApps::the().configChanged(); + } + else + RecentlyLaunchedApps::the().getRecentApps(RecentApps); + + + if (RecentApps.count() > 0) + { +// bool bSeparator = KickerSettings::showMenuTitles(); + int nIndex = 0; + + for (TQValueList<TQString>::ConstIterator it = + RecentApps.begin(); it!=RecentApps.end(); ++it) + { + KService::Ptr s = KService::serviceByStorageId(*it); + if (!s) + { + RecentlyLaunchedApps::the().removeItem(*it); + } + else + m_recentlyView->insertMenuItem(s, nIndex++); + } + + } + + m_recentlyView->insertSeparator( nId++, i18n( "Documents" ), -1 ); + + TQStringList fileList = KRecentDocument::recentDocuments(); + kdDebug() << "createRecentMenuItems=" << fileList << endl; + for (TQStringList::ConstIterator it = fileList.begin(); + it != fileList.end(); + ++it) + m_recentlyView->insertRecentlyItem(*it, nId++); + +} + +void KMenu::clearSubmenus() +{ + // we don't need to delete these on the way out since the libloader + // handles them for us + if (TQApplication::closingDown()) + { + return; + } + + for (PopupMenuList::const_iterator it = dynamicSubMenus.constBegin(); + it != dynamicSubMenus.constEnd(); + ++it) + { + delete *it; + } + dynamicSubMenus.clear(); +} + +void KMenu::updateRecent() +{ + m_recentlyView->clear(); + + createRecentMenuItems(); + + m_recentDirty = false; +} + +void KMenu::popup(const TQPoint&, int) +{ + showMenu(); +} + +void KMenu::clearRecentAppsItems() +{ + RecentlyLaunchedApps::the().clearRecentApps(); + RecentlyLaunchedApps::the().save(); + RecentlyLaunchedApps::the().m_bNeedToUpdate = true; + updateRecent(); +} + +void KMenu::clearRecentDocsItems() +{ + KRecentDocument::clear(); + updateRecent(); +} + +void KMenu::searchChanged(const TQString & text) +{ + if (!text.isEmpty()) { + const TQColor on = TQColor( 244, 244, 244 ); + const TQColor off = TQColor( 181, 181, 181 ); + m_stacker->raiseWidget(m_searchWidget); + paintSearchTab(true); + } + + m_searchActions->clearSelection(); + m_searchResultsWidget->clearSelection(); + + if (input_timer->isActive ()) + input_timer->stop (); + input_timer->start (WAIT_BEFORE_QUERYING, TRUE); +} + +bool KMenu::dontQueryNow (const TQString& str) +{ + if (str.isEmpty ()) + return true; + if (str == current_query.get()) + return true; + int length = str.length (); + int last_whitespace = str.findRev (' ', -1); + if (last_whitespace == length-1) + return false; // if the user typed a space, search + if (last_whitespace >= length-2) + return true; // dont search if the user only typed one character + TQChar lastchar = str[length-1]; + if (lastchar == ":" || lastchar == "=") + return true; + return false; +} + +void KMenu::createNewProgramList() +{ + m_seenProgramsChanged = false; + m_seenPrograms = KickerSettings::firstSeenApps(); + m_newInstalledPrograms.clear(); + + m_currentDate = TQDate::currentDate().toString(Qt::ISODate); + + bool initialize = (m_seenPrograms.count() == 0); + + createNewProgramList(TQString::null); + + if (initialize) { + for (TQStringList::Iterator it = m_seenPrograms.begin(); it != m_seenPrograms.end(); ++it) + *(++it)="-"; + + m_newInstalledPrograms.clear(); + } + + if (m_seenProgramsChanged) { + KickerSettings::setFirstSeenApps(m_seenPrograms); + KickerSettings::writeConfig(); + } +} + +void KMenu::createNewProgramList(TQString relPath) +{ + KServiceGroup::Ptr group = KServiceGroup::group(relPath); + if (!group || !group->isValid()) + return; + + KServiceGroup::List list = group->entries(); + if (list.isEmpty()) + return; + + KServiceGroup::List::ConstIterator it = list.begin(); + for(; it != list.end(); ++it) { + KSycocaEntry *e = *it; + + if(e != 0) { + if(e->isType(KST_KServiceGroup)) { + KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e)); + if(!g->noDisplay()) + createNewProgramList(g->relPath()); + } else if(e->isType(KST_KService)) { + KService::Ptr s(static_cast<KService *>(e)); + if(s->type() == "Application" && !s->noDisplay() ) { + TQString shortStorageId = s->storageId().replace(".desktop",TQString::null); + TQStringList::Iterator it_find = m_seenPrograms.begin(); + TQStringList::Iterator it_end = m_seenPrograms.end(); + bool found = false; + for (; it_find != it_end; ++it_find) { + if (*(it_find)==shortStorageId) { + found = true; + break; + } + ++it_find; + } + if (!found) { + m_seenProgramsChanged=true; + m_seenPrograms+=shortStorageId; + m_seenPrograms+=m_currentDate; + if (m_newInstalledPrograms.find(s->storageId())==m_newInstalledPrograms.end()) + m_newInstalledPrograms+=s->storageId(); + } + else { + ++it_find; + if (*(it_find)!="-") { + TQDate date = TQDate::fromString(*(it_find),Qt::ISODate); + if (date.daysTo(TQDate::currentDate())<3) { + if (m_newInstalledPrograms.find(s->storageId())==m_newInstalledPrograms.end()) + m_newInstalledPrograms+=s->storageId(); + } + else { + m_seenProgramsChanged=true; + (*it_find)="-"; + } + } + } + } + } + } + } +} + +void KMenu::searchProgramList(TQString relPath) +{ + KServiceGroup::Ptr group = KServiceGroup::group(relPath); + if (!group || !group->isValid()) + return; + + KServiceGroup::List list = group->entries(); + if (list.isEmpty()) + return; + + KServiceGroup::List::ConstIterator it = list.begin(); + for(; it != list.end(); ++it) { + KSycocaEntry *e = *it; + + if(e != 0) { + if(e->isType(KST_KServiceGroup)) { + KServiceGroup::Ptr g(static_cast<KServiceGroup *>(e)); + if(!g->noDisplay()) + searchProgramList(g->relPath()); + } else if(e->isType(KST_KService)) { + KService::Ptr s(static_cast<KService *>(e)); + if(s->type() == "Application" && !s->noDisplay() && !checkUriInMenu(s->desktopEntryPath())) { + if (!current_query.matches(s->name()+' '+s->genericName()+' '+s->exec()+' '+ + s->keywords().join(",")+' '+s->comment()+' '+group->caption()+' '+ + s->categories().join(",")) || !anotherHitMenuItemAllowed(APPS)) + continue; + + TQString input = current_query.get(); + int score = 0; + if (s->exec()==input) + score = 100; + else if (s->exec().find(input)==0) + score = 50; + else if (s->exec().find(input)!=-1) + score = 10; + else if (s->name().lower()==input) + score = 100; + else if (s->genericName().lower()==input) + score = 100; + else if (s->name().lower().find(input)==0) + score = 50; + else if (s->genericName().lower().find(input)==0) + score = 50; + else if (s->name().lower().find(input)!=-1) + score = 10; + else if (s->genericName().lower().find(input)!=-1) + score = 10; + + if (s->exec().find(' ')==-1) + score+=1; + + if (s->substituteUid()) + score-=1; + + if (s->noDisplay()) + score -= 100; + else if (s->terminal()) + score -= 50; + else + score += kMin(10, s->initialPreference()); + + TQString firstLine, secondLine; + if ((KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly) && !s->genericName().isEmpty()) { + firstLine = s->genericName(); + secondLine = s->name(); + } + else { + firstLine = s->name(); + secondLine = s->genericName(); + } + + HitMenuItem *hit_item = new HitMenuItem (firstLine, secondLine, + s->desktopEntryPath(), TQString::null, 0, APPS, s->icon(), score); + if (hit_item == NULL) + continue; + + hit_item->service = s; + insertSearchResult(hit_item); + + TQString exe = s->exec(); + int pos = exe.find(' '); + if (pos>0) + exe=exe.left(pos); + m_programsInMenu+=KGlobal::dirs()->findExe(exe); + } + } + } + } +} + +void KMenu::searchBookmarks(KBookmarkGroup group) +{ + KBookmark bookmark = group.first(); + while(!bookmark.isNull()) { + if (bookmark.isGroup()) { + searchBookmarks(bookmark.toGroup()); + } else if (!bookmark.isSeparator() && !bookmark.isNull()) { + if (!current_query.matches(bookmark.fullText()+' '+bookmark.url().url()) || !anotherHitMenuItemAllowed(BOOKMARKS)) { + bookmark = group.next(bookmark); + continue; + } + + HitMenuItem *hit_item = new HitMenuItem (bookmark.fullText(), bookmark.fullText(), + bookmark.url(), TQString::null, 0, BOOKMARKS, bookmark.icon()); + + insertSearchResult(hit_item); + } + bookmark = group.next(bookmark); + } +} + +void KMenu::initSearch() +{ + if (!m_addressBook && KickerSettings::kickoffSearchAddressBook()) + m_addressBook = KABC::StdAddressBook::self( false ); + + if (!bookmarkManager) + bookmarkManager = KBookmarkManager::userBookmarksManager(); + + if (!m_search_plugin) { + m_search_plugin_interface = new TQObject( this, "m_search_plugin_interface" ); + new MyKickoffSearchInterface( this, m_search_plugin_interface, "kickoffsearch interface" ); + KTrader::OfferList offers = KTrader::self()->query("KickoffSearch/Plugin"); + + KService::Ptr service = *offers.begin(); + if (service) { + int errCode = 0; + m_search_plugin = KParts::ComponentFactory::createInstanceFromService<KickoffSearch::Plugin> + ( service, m_search_plugin_interface, 0, TQStringList(), &errCode); + } + } +} + +void KMenu::searchAddressbook() +{ + if (!KickerSettings::kickoffSearchAddressBook()) + return; + + if (!m_addressBook) + m_addressBook = KABC::StdAddressBook::self( false ); + + KABC::AddressBook::ConstIterator it = m_addressBook->begin(); + while (it!=m_addressBook->end()) { + if (!current_query.matches((*it).assembledName()+' '+(*it).fullEmail())) { + it++; + continue; + } + + HitMenuItem *hit_item; + TQString realName = (*it).realName(); + if (realName.isEmpty()) + realName=(*it).preferredEmail(); + + if (!(*it).preferredEmail().isEmpty()) { + if (!anotherHitMenuItemAllowed(ACTIONS)) { + it++; + continue; + } + + hit_item = new HitMenuItem (i18n("Send Email to %1").arg(realName), (*it).preferredEmail(), + "mailto:"+(*it).preferredEmail(), TQString::null, 0, ACTIONS, "mail_new"); + + insertSearchResult(hit_item); + } + + if (!anotherHitMenuItemAllowed(ACTIONS)) { + it++; + continue; + } + + hit_item = new HitMenuItem (i18n("Open Addressbook at %1").arg(realName), (*it).preferredEmail(), + "kaddressbook:/"+(*it).uid(), TQString::null, 0, ACTIONS, "kaddressbook"); + + insertSearchResult(hit_item); + + it++; + } +} + +TQString KMenu::insertBreaks(const TQString& text, TQFontMetrics fm, int width, TQString leadInsert) +{ + TQString result, line; + TQStringList words = TQStringList::split(' ', text); + + for(TQStringList::Iterator it = words.begin(); it != words.end(); ++it) { + if (fm.width(line+' '+*it) >= width) { + if (!result.isEmpty()) + result = result + '\n'; + result = result + line; + line = leadInsert + *it; + } + else + line = line + ' ' + *it; + } + if (!result.isEmpty()) + result = result + '\n'; + + return result + line; +} + +void KMenu::clearSearchResults(bool showHelp) +{ + m_searchResultsWidget->clear(); + m_searchResultsWidget->setFocusPolicy(showHelp ? TQWidget::NoFocus : TQWidget::StrongFocus); + setTabOrder(m_kcommand, m_searchResultsWidget); + + if (showHelp) { + const int width = m_searchResultsWidget->width()-10; + TQFontMetrics fm = m_searchResultsWidget->fontMetrics(); + + TQListViewItem* item; + item = new TQListViewItem( m_searchResultsWidget, insertBreaks(i18n("- Add ext:type to specify a file extension."), fm, width, " ") ); + item->setSelectable(false); + item->setMultiLinesEnabled(true); + item = new TQListViewItem( m_searchResultsWidget, insertBreaks(i18n("- When searching for a phrase, add quotes."), fm, width, " " ) ); + item->setSelectable(false); + item->setMultiLinesEnabled(true); + item = new TQListViewItem( m_searchResultsWidget, insertBreaks(i18n("- To exclude search terms, use the minus symbol in front."), fm, width, " " ) ); + item->setSelectable(false); + item->setMultiLinesEnabled(true); + item = new TQListViewItem( m_searchResultsWidget, insertBreaks(i18n("- To search for optional terms, use OR."), fm, width, " ") ); + item->setSelectable(false); + item->setMultiLinesEnabled(true); + item = new TQListViewItem( m_searchResultsWidget, insertBreaks(i18n("- You can use upper and lower case."), fm, width, " ") ); + item->setSelectable(false); + item->setMultiLinesEnabled(true); + item = new TQListViewItem( m_searchResultsWidget, i18n("Search Quick Tips")); + item->setSelectable(false); + } + + for (int i=0; i<num_categories; ++i) { + categorised_hit_total [i] = 0; + max_category_id [i] = base_category_id [i]; + } +} + +void KMenu::doQuery (bool return_pressed) +{ + TQString query_str = m_kcommand->lineEdit()->text ().simplifyWhiteSpace (); + if (! return_pressed && dontQueryNow (query_str)) { + if (query_str.length()<3) + clearSearchResults(); + else { + if (m_searchResultsWidget->firstChild() && m_searchResultsWidget->firstChild()->isSelectable()) { + m_searchResultsWidget->setSelected(m_searchResultsWidget->firstChild(),true); + } + else if (m_searchResultsWidget->childCount()>1) { + m_searchResultsWidget->setSelected(m_searchResultsWidget->firstChild()->itemBelow(),true); + } + } + return; + } + kdDebug() << "Querying for [" << query_str << "]" << endl; + current_query.set(query_str); + + // reset search results + HitMenuItem *hit_item; + while ((hit_item = m_current_menu_items.take ()) != NULL) { + //kndDebug () << " (" << hit_item->id << "," << hit_item->category << ")" << endl; + delete hit_item; + } + + clearSearchResults(false); + m_searchPixmap->setMovie(TQMovie(locate( "data", "kicker/pics/search-running.mng" ))); + + resetOverflowCategory(); + + initCategoryTitlesUpdate(); + + // calculate ? + TQString cmd = query_str.stripWhiteSpace(); + if (!cmd.isEmpty() && (cmd[0].isNumber() || (cmd[0] == '(')) && + (TQRegExp("[a-zA-Z\\]\\[]").search(cmd) == -1)) + { + TQString result = calculate(cmd); + if (!result.isEmpty()) + { + categorised_hit_total[ACTIONS] ++; + HitMenuItem *hit_item = new HitMenuItem (i18n("%1 = %2").arg(query_str, result), TQString::null, + "kcalc", TQString::null, (++max_category_id [ACTIONS]), ACTIONS, "kcalc"); + int index = getHitMenuItemPosition (hit_item); + m_searchResultsWidget->insertItem(iconForHitMenuItem(hit_item), hit_item->display_name, + hit_item->display_info, KGlobal::dirs()->findExe("kcalc"), max_category_id [ACTIONS], index); + } + } + + // detect email address + if (emailRegExp.exactMatch(query_str)) { + categorised_hit_total[ACTIONS] ++; + HitMenuItem *hit_item = new HitMenuItem (i18n("Send Email to %1").arg(query_str), TQString::null, + "mailto:"+query_str, TQString::null, (++max_category_id [ACTIONS]), ACTIONS, "mail_new"); + int index = getHitMenuItemPosition (hit_item); + m_searchResultsWidget->insertItem(iconForHitMenuItem(hit_item), hit_item->display_name, hit_item->display_info, "mailto:"+query_str, max_category_id [ACTIONS], index); + } + + // quick own application search + m_programsInMenu.clear(); + searchProgramList(TQString::null); + + KURIFilterData filterData; + filterData.setData(query_str); + filterData.setCheckForExecutables(true); + + if (KURIFilter::self()->filterURI(filterData)) { + + TQString description; + TQString exe; + + switch (filterData.uriType()) { + case KURIFilterData::LOCAL_FILE: + description = i18n("Open Local File: %1").arg(filterData.uri().url()); + break; + case KURIFilterData::LOCAL_DIR: + description = i18n("Open Local Dir: %1").arg(filterData.uri().url()); + break; + case KURIFilterData::NET_PROTOCOL: + description = i18n("Open Remote Location: %1").arg(filterData.uri().url()); + break; + case KURIFilterData::SHELL: + case KURIFilterData::EXECUTABLE: + { + exe = KGlobal::dirs()->findExe(filterData.uri().url()); +#ifdef KDELIBS_SUSE + bool gimp_hack = false; + if (exe.endsWith("/bin/gimp")) { + TQStringList::ConstIterator it = m_programsInMenu.begin(); + for (; it != m_programsInMenu.end(); ++it) + if ((*it).find("bin/gimp-remote-")!=-1) { + gimp_hack = true; + break; + } + } +#endif + if (m_programsInMenu.find(exe)!=m_programsInMenu.end() +#ifdef KDELIBS_SUSE + || gimp_hack +#endif + ) + exe = TQString::null; + else if (kapp->authorize("shell_access")) + { + if( filterData.hasArgsAndOptions() ) + exe += filterData.argsAndOptions(); + + description = i18n("Run '%1'").arg(exe); + exe = "kicker:/runcommand"; + } + } + default: + break; + } + + if (!description.isEmpty()) { + categorised_hit_total[ACTIONS] ++; + HitMenuItem *hit_item = new HitMenuItem (description, TQString::null, + exe.isEmpty() ? filterData.uri() : exe, TQString::null, + (++max_category_id [ACTIONS]), ACTIONS, exe.isEmpty() ? "fileopen": "run"); + int index = getHitMenuItemPosition (hit_item); + m_searchResultsWidget->insertItem(iconForHitMenuItem(hit_item), hit_item->display_name, + hit_item->display_info, + exe.isEmpty() ? filterData.uri().url() : exe, max_category_id [ACTIONS], index); + } + } + + // search Konqueror bookmarks; + if (!bookmarkManager) + bookmarkManager = KBookmarkManager::userBookmarksManager(); + + if (query_str.length()>=3) + searchBookmarks(bookmarkManager->root()); + + // search KDE addressbook + if (query_str.length()>=3) + searchAddressbook(); + + updateCategoryTitles(); + + if (m_searchResultsWidget->childCount()>1) + m_searchResultsWidget->setSelected(m_searchResultsWidget->firstChild()->itemBelow(),true); + m_searchActions->clearSelection(); + + if (!m_search_plugin) + initSearch(); + + // start search plugin only with at least 3 characters + if (query_str.length()<3 || !m_search_plugin || (m_search_plugin && !m_search_plugin->daemonRunning()) ) { + m_searchPixmap->setPixmap( BarIcon( "find", 32 ) ); + fillOverflowCategory(); + if (query_str.length()>2 && m_current_menu_items.isEmpty()) + reportError (i18n("No matches found")); + return; + } + + if (m_search_plugin) { + m_search_plugin->query(current_query.get(), KickerSettings::DescriptionAndName || KickerSettings::menuEntryFormat() == KickerSettings::DescriptionOnly); + } +} + +bool KMenu::anotherHitMenuItemAllowed(int cat, bool count) +{ + // update number of hits in this category + if (count) + categorised_hit_total [cat] ++; + + // if number of hits in this category is more than allowed, dont process this + if (max_category_id [cat] - base_category_id [cat] < max_items(cat)) + return true; + + if (m_overflowCategoryState==None || (m_overflowCategoryState==Filling && m_overflowCategory==cat && + max_category_id [cat] + m_overflowList.count() - base_category_id [cat] < max_items(cat) * 2.0)) + return true; + + return false; +} + +void KMenu::addHitMenuItem(HitMenuItem* item) +{ + if (checkUriInMenu(item->uri)) + return; + + // if number of hits in this category is more than allowed, dont process this + if (!anotherHitMenuItemAllowed(item->category, false)) + return; + + insertSearchResult(item); +} + +void KMenu::insertSearchResult(HitMenuItem* item) +{ + if (m_overflowCategoryState==None) { + m_overflowCategoryState = Filling; + m_overflowCategory = item->category; + } + else if (m_overflowCategoryState==Filling && m_overflowCategory!=item->category) + m_overflowCategoryState = NotNeeded; + + if (max_category_id [item->category] - base_category_id [item->category] < max_items(item->category)) { + max_category_id [item->category]++; + item->id=max_category_id [item->category]; + + int index = getHitMenuItemPosition (item); + + kdDebug () << "Adding " << item->uri + << "(" << item->mimetype << ") with id=" + << max_category_id [item->category] << " at " << index << endl; + + KMenuItem *hit_item = m_searchResultsWidget->insertItem(iconForHitMenuItem(item), item->display_name, item->display_info, item->uri.url(), max_category_id [item->category], index); + hit_item->setService(item->service); + + kdDebug () << "Done inserting ... " << endl; + } + else if (m_overflowCategoryState==Filling && m_overflowCategory==item->category && + max_category_id [item->category] - base_category_id [item->category] < max_items(item->category) * 2) + m_overflowList.append(item); +} + +void KMenu::searchOver() +{ + m_searchPixmap->setPixmap( BarIcon( "find", 32 ) ); + fillOverflowCategory(); + if (m_current_menu_items.isEmpty()) { + kdDebug() << "No matches found" << endl; + reportError (i18n("No matches found")); + } + if (!m_searchResultsWidget->selectedItem() && !m_searchActions->selectedItem() && m_searchResultsWidget->childCount()>1) { + m_searchResultsWidget->setSelected(m_searchResultsWidget->firstChild()->itemBelow(),true); + } +} + +void KMenu::initCategoryTitlesUpdate() +{ + // Need to know if each category was updated with hits or had the first hit + // That way we know if we need to changetitle or inserttitle + already_added = new bool [num_categories]; + for (int i=0; i<num_categories; ++i) + already_added [i] = (max_category_id [i] != base_category_id [i]); +} + +void KMenu::updateCategoryTitles() +{ + // update category title + for (int i=0; i<num_categories; ++i) { + if (i == OTHER) + continue; + // nothing is in this category + if (max_category_id [i] == base_category_id [i]) + continue; + + KMenuItemSeparator *sep = 0; + + // if nothing was in this category before but now there is + if (! already_added [i]) { + // insert a new title for this category + int index = getHitMenuItemPosition (new HitMenuItem ( + base_category_id[i], + i)); + TQString title = TQString ("%1").arg (i18n(categories [i].utf8())); + sep = m_searchResultsWidget->insertSeparator(base_category_id [i], title, index); + kdDebug () << "Inserting heading with id=" << base_category_id[i] << " for " << categories[i] << " at " << index << endl; + } else { + // something was already displayed in this category + // update the title to reflect the total + sep = dynamic_cast<KMenuItemSeparator*>( m_searchResultsWidget->findItem(base_category_id [i]) ); + if ( !sep ) + continue; + kdDebug () << "Changing heading of id=" << base_category_id[i] << " for " << categories[i] << endl; + } + + int max = max_items(i); + if (m_overflowCategoryState == Filling && m_overflowCategory == i) + max *= 2; + + if ( categorised_hit_total [i] > max ) { + if (m_kerryInstalled) + sep->setLink( i18n( "top %1 of %2" ).arg( max ).arg( categorised_hit_total [i] ), TQString( "kerry:/%1" ).arg( i ) ); + else + sep->setText( 0, i18n( "%1 (top %2 of %3)" ).arg( i18n(categories [i].utf8()) ).arg( max ).arg( categorised_hit_total [i] ) ); + } + else { + sep->setLink( TQString::null ); + } + } + delete[] already_added; + already_added = 0; +} + +TQString KMenu::iconForHitMenuItem(HitMenuItem *hit_item) +{ + // get the icon + if (!hit_item->icon.isEmpty()) + return hit_item->icon; + + if (hit_item->category == WEBHIST) { + TQString favicon = KMimeType::favIconForURL (hit_item->uri); + if (! favicon.isEmpty ()) + return favicon; + } + + if (mimetype_iconstore.contains (hit_item->mimetype)) + return (mimetype_iconstore [hit_item->mimetype]); + else { + KMimeType::Ptr mimetype_ptr = KMimeType::mimeType (hit_item->mimetype); + TQString mimetype_icon = mimetype_ptr->icon(TQString::null, FALSE); + mimetype_iconstore [hit_item->mimetype] = mimetype_icon; + return mimetype_icon; + } + return TQString::null; +} + +void KMenu::slotStartService(KService::Ptr ptr) +{ + accept(); + + addToHistory(); + KApplication::startServiceByDesktopPath(ptr->desktopEntryPath(), + TQStringList(), 0, 0, 0, "", true); + updateRecentlyUsedApps(ptr); +} + + +void KMenu::slotStartURL(const TQString& u) +{ + if ( u == "kicker:/goup/" ) { + // only m_exitView is connected to this slot, not m_browserView + slotGoExitMainMenu(); + return; + } + + if ( u == "kicker:/restart/" || u=="kicker:/switchuser/") { + slotGoExitSubMenu(u); + return; + } + + accept(); + + if ( u == "kicker:/lock" ) { + slotLock(); + } + else if ( u == "kicker:/logout" ) { +#ifdef KDELIBS_SUSE + TQByteArray params; + TQDataStream stream(params, IO_WriteOnly); + stream << 0 << -1 << ""; + + kapp->dcopClient()->send("ksmserver", "default", "logoutTimed(int,int,TQString)", params); +#else + DCOPRef mediamanager("ksmserver", "ksmserver"); + DCOPReply reply = mediamanager.call( "logoutTimed", (int)KApplication::ShutdownTypeNone, (int)KApplication::ShutdownModeDefault ); + if (!reply.isValid() && KMessageBox::Continue==KMessageBox::warningContinueCancel(this, i18n("Do you really want to end the session?"), + i18n("Logout Confirmation"), KGuiItem(i18n("Logout"),"undo"))) + kapp->requestShutDown( KApplication::ShutdownConfirmNo, + KApplication::ShutdownTypeNone, + KApplication::ShutdownModeDefault ); + +#endif + } + else if ( u == "kicker:/runcommand" ) + { + runCommand(); + } + else if ( u == "kicker:/shutdown" ) { +#ifdef KDELIBS_SUSE + TQByteArray params; + TQDataStream stream(params, IO_WriteOnly); + stream << 2 << -1 << ""; + + kapp->dcopClient()->send("ksmserver", "default", "logoutTimed(int,int,TQString)", params); +#else + if (KMessageBox::Continue==KMessageBox::warningContinueCancel(this, i18n("Do you really want to turn off the computer?"), + i18n("Shutdown Confirmation"), KGuiItem(i18n("Shutdown"),"exit"))) + kapp->requestShutDown( KApplication::ShutdownConfirmNo, + KApplication::ShutdownTypeHalt, + KApplication::ShutdownModeDefault ); +#endif + } + else if ( u == "kicker:/restart" ) { +#ifdef KDELIBS_SUSE + TQByteArray params; + TQDataStream stream(params, IO_WriteOnly); + stream << 1 << -1 << TQString::null; + + kapp->dcopClient()->send("ksmserver", "default", "logoutTimed(int,int,TQString)", params); +#else + if (KMessageBox::Continue==KMessageBox::warningContinueCancel(this, i18n("Do you really want to reset the computer and boot (another operating system)?"), + i18n("Restart Confirmation"), KGuiItem(i18n("Restart"),"reload"))) + kapp->requestShutDown( KApplication::ShutdownConfirmNo, + KApplication::ShutdownTypeReboot, + KApplication::ShutdownModeDefault ); +#endif + } +#ifdef KDELIBS_SUSE + else if ( u == "kicker:/suspend_disk" ) { + slotSuspend( 1 ); + } + else if ( u == "kicker:/suspend_ram" ) { + slotSuspend( 2 ); + } + else if ( u == "kicker:/standby" ) { + slotSuspend( 3 ); + } +#endif + else if ( u == "kicker:/savesession" ) { + TQByteArray data; + kapp->dcopClient()->send( "ksmserver", "default", + "saveCurrentSession()", data ); + } + else if ( u == "kicker:/switchuser" ) { + DM().startReserve(); + } + else if ( u == "kicker:/switchuserafterlock" ) { + slotLock(); + DM().startReserve(); + } + else if ( u.startsWith("kicker:/switchuser_") ) + DM().lockSwitchVT( u.mid(19).toInt() ); + else if ( u.startsWith("kicker:/restart_") ) { +#ifdef KDELIBS_SUSE + TQStringList rebootOptions; + int def, cur; + DM().bootOptions( rebootOptions, def, cur ); + + TQByteArray params; + TQDataStream stream(params, IO_WriteOnly); + stream << 1 << -1 << rebootOptions[u.mid(16).toInt()]; + + kapp->dcopClient()->send("ksmserver", "default", "logoutTimed(int,int,TQString)", params); +#else + KMessageBox::error( this, TQString( "Sorry, not implemented." )); +#endif + } +#warning restart entry not supported +#if 0 + else if ( u == "kicker:/restart_windows" ) { + if (KMessageBox::Continue==KMessageBox::warningContinueCancel(this, i18n("Do you really want to reset the computer and boot Microsoft Windows"), i18n("Start Windows Confirmation"), KGuiItem(i18n("Start Windows"),"reload"))) + KMessageBox::error( this, TQString( "kicker:/restart_windows is not yet implemented " ) ); + } +#endif + else if ( u.startsWith("kerry:/")) + { + TQByteArray data; + TQDataStream arg(data, IO_WriteOnly); + arg << m_kcommand->currentText() << kerry_categories[u.mid(7).toInt()]; + if (ensureServiceRunning("kerry")) + kapp->dcopClient()->send("kerry","search","search(TQString,TQString)", data); + } + else { + addToHistory(); + if (u.startsWith("kaddressbook:/")) { + KProcess *proc = new KProcess; + *proc << "kaddressbook" << "--uid" << u.mid(14); + proc->start(); + accept(); + return; + } else if (u.startsWith("note:/")) { + KProcess *proc = new KProcess; + *proc << "tomboy"; + *proc << "--open-note" << u; + if (!proc->start()) + KMessageBox::error(0,i18n("Could not start Tomboy.")); + return; + } + else if (u.startsWith("knotes:/") ) { + if (ensureServiceRunning("knotes")) { + TQByteArray data; + TQDataStream arg(data, IO_WriteOnly); + arg << u.mid(9,22); + + kapp->dcopClient()->send("knotes","KNotesIface","showNote(TQString)", data); + } + return; + } + + kapp->propagateSessionManager(); + (void) new KRun( u, parentWidget()); + } +} + +void KMenu::slotContextMenuRequested( TQListViewItem * item, const TQPoint & pos, int /*col*/ ) +{ + const TQObject* source = sender(); + + if (!item) + return; + + KMenuItem* kitem = dynamic_cast<KMenuItem*>(item); + if (!kitem) + return; + + KFileItemList _items; + _items.setAutoDelete(true); + + if (dynamic_cast<KMenuItemSeparator*>(item)) + return; + + m_popupService = kitem->service(); + m_popupPath.menuPath = kitem->menuPath(); + if (!m_popupService) { + m_popupPath.title = kitem->title(); + m_popupPath.description = kitem->description(); + m_popupPath.path = kitem->path(); + m_popupPath.icon = kitem->icon(); + + if (m_popupPath.path.startsWith(locateLocal("data", TQString::fromLatin1("RecentDocuments/")))) { + KDesktopFile df(m_popupPath.path,true); + m_popupPath.path=df.readURL(); + } + } + + m_popupMenu = new KPopupMenu(this); + connect(m_popupMenu, TQT_SIGNAL(activated(int)), TQT_SLOT(slotContextMenu(int))); + bool hasEntries = false; + + m_popupMenu->insertTitle(SmallIcon(kitem->icon()),kitem->title()); + + if (source==m_favoriteView) + { + hasEntries = true; + m_popupMenu->insertItem(SmallIconSet("remove"), + i18n("Remove From Favorites"), RemoveFromFavorites); + } + else if (!kitem->hasChildren() && !m_popupPath.path.startsWith("system:/") && + !m_popupPath.path.startsWith("kicker:/switchuser_") && !m_popupPath.path.startsWith("kicker:/restart_")) + { + hasEntries = true; + int num = m_popupMenu->insertItem(SmallIconSet("bookmark_add"), + i18n("Add to Favorites"), AddToFavorites); + + TQStringList favs = KickerSettings::favorites(); + if (m_popupService && favs.find(m_popupService->storageId())!=favs.end()) + m_popupMenu->setItemEnabled(num, false); + else { + TQStringList::Iterator it; + for (it = favs.begin(); it != favs.end(); ++it) + { + if ((*it)[0]=='/') + { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==m_popupPath.path) + break; + } + } + if (it!=favs.end()) + m_popupMenu->setItemEnabled(num, false); + } + } + + if (source!=m_exitView) { + if (m_popupService || (!m_popupPath.path.startsWith("kicker:/") && !m_popupPath.path.startsWith("system:/") && !m_popupPath.path.startsWith("kaddressbook:/"))) { + if (hasEntries) + m_popupMenu->insertSeparator(); + + if (kapp->authorize("editable_desktop_icons") ) + { + hasEntries = true; + if (m_popupPath.menuPath.endsWith("/")) + m_popupMenu->insertItem(SmallIconSet("desktop"), + i18n("Add Menu to Desktop"), AddMenuToDesktop); + else + m_popupMenu->insertItem(SmallIconSet("desktop"), + i18n("Add Item to Desktop"), AddItemToDesktop); + } + if (kapp->authorizeKAction("kicker_rmb") && !Kicker::the()->isImmutable()) + { + hasEntries = true; + if (m_popupPath.menuPath.endsWith("/")) + m_popupMenu->insertItem(SmallIconSet("kicker"), + i18n("Add Menu to Main Panel"), AddMenuToPanel); + else + m_popupMenu->insertItem(SmallIconSet("kicker"), + i18n("Add Item to Main Panel"), AddItemToPanel); + } + if (kapp->authorizeKAction("menuedit") && !kitem->menuPath().isEmpty()) + { + hasEntries = true; + if (kitem->menuPath().endsWith("/")) + m_popupMenu->insertItem(SmallIconSet("kmenuedit"), i18n("Edit Menu"), EditMenu); + else + m_popupMenu->insertItem(SmallIconSet("kmenuedit"), i18n("Edit Item"), EditItem); + } + if (kapp->authorize("run_command") && (m_popupService || (!m_popupPath.menuPath.isEmpty() && !m_popupPath.menuPath.endsWith("/")))) + { + hasEntries = true; + m_popupMenu->insertItem(SmallIconSet("run"), + i18n("Put Into Run Dialog"), PutIntoRunDialog); + } + } + if (source==m_searchResultsWidget || ((source==m_favoriteView || source==m_recentlyView || source == m_systemView) && !m_popupService && !m_popupPath.path.startsWith("kicker:/")) ) { + TQString uri; + if (m_popupService) + uri = locate("apps", m_popupService->desktopEntryPath()); + else + uri = m_popupPath.path; + + TQString mimetype = TQString::null; + if ( m_popupPath.path.startsWith( "system:/media/" ) ) + mimetype = media_mimetypes[m_popupPath.path]; + + KFileItem* item = new KFileItem(uri, mimetype, KFileItem::Unknown); + _items.append( item ); + + const KURL kurl(uri); + KActionCollection act(this); + + KonqPopupMenu * konqPopupMenu = new KonqPopupMenu( KonqBookmarkManager::self(), _items, + kurl, act, (KNewMenu*)NULL, this, + item->isLocalFile() ? KonqPopupMenu::ShowProperties : KonqPopupMenu::NoFlags, + KParts::BrowserExtension::DefaultPopupItems ); + + if (konqPopupMenu->count()) { + if (hasEntries) { + m_popupMenu->insertSeparator(); + m_popupMenu->insertItem(SmallIconSet("add"),i18n("Advanced"), konqPopupMenu); + } + else { + delete m_popupMenu; + m_popupMenu = (KPopupMenu*)konqPopupMenu; + m_popupMenu->insertTitle(SmallIcon(kitem->icon()),kitem->title(),-1,0); + } + hasEntries = true; + } + } + } + + if (source==m_recentlyView) { + m_popupMenu->insertSeparator(); + if (m_popupService) + m_popupMenu->insertItem(SmallIconSet("history_clear"), + i18n("Clear Recently Used Applications"), ClearRecentlyUsedApps); + else + m_popupMenu->insertItem(SmallIconSet("history_clear"), + i18n("Clear Recently Used Documents"), ClearRecentlyUsedDocs); + } + + if (hasEntries) { + m_isShowing = true; + m_popupMenu->exec(pos); + m_isShowing = false; + } + + delete m_popupMenu; + m_popupMenu = 0; +} + +void KMenu::slotContextMenu(int selected) +{ + KServiceGroup::Ptr g; + TQByteArray ba; + TQDataStream ds(ba, IO_WriteOnly); + + KURL src,dest; + KIO::CopyJob *job; + + KProcess *proc; + + TQStringList favs = KickerSettings::favorites(); + + switch (selected) { + case AddItemToDesktop: + accept(); + if (m_popupService) { + src.setPath( KGlobal::dirs()->findResource( "apps", m_popupService->desktopEntryPath() ) ); + dest.setPath( KGlobalSettings::desktopPath() ); + dest.setFileName( src.fileName() ); + + job = KIO::copyAs( src, dest ); + job->setDefaultPermissions( true ); + } + else { + KDesktopFile* df = new KDesktopFile( newDesktopFile(KURL(m_popupPath.path), KGlobalSettings::desktopPath() ) ); + df->writeEntry("GenericName", m_popupPath.description); + df->writeEntry( "Icon", m_popupPath.icon ); + df->writePathEntry( "URL", m_popupPath.path ); + df->writeEntry( "Name", m_popupPath.title ); + df->writeEntry( "Type", "Link" ); + df->sync(); + delete df; + } + accept(); + break; + + case AddItemToPanel: + accept(); + if (m_popupService) + kapp->dcopClient()->send("kicker", "Panel", "addServiceButton(TQString)", m_popupService->desktopEntryPath()); + else +#warning FIXME special RecentDocuments/foo.desktop handling + kapp->dcopClient()->send("kicker", "Panel", "addURLButton(TQString)", m_popupPath.path); + accept(); + break; + + case EditItem: + case EditMenu: + accept(); + proc = new KProcess(this); + *proc << KStandardDirs::findExe(TQString::fromLatin1("kmenuedit")); + *proc << "/"+m_popupPath.menuPath.section('/',-200,-2) << m_popupPath.menuPath.section('/', -1); + proc->start(); + break; + + case PutIntoRunDialog: + accept(); + if (m_popupService) + kapp->dcopClient()->send("kdesktop", "default", "popupExecuteCommand(TQString)", m_popupService->exec()); + else +#warning FIXME special RecentDocuments/foo.desktop handling + kapp->dcopClient()->send("kdesktop", "default", "popupExecuteCommand(TQString)", m_popupPath.path); + accept(); + break; + + case AddMenuToDesktop: { + accept(); + KDesktopFile *df = new KDesktopFile( newDesktopFile(KURL("programs:/"+m_popupPath.menuPath),KGlobalSettings::desktopPath())); + df->writeEntry( "Icon", m_popupPath.icon ); + df->writePathEntry( "URL", "programs:/"+m_popupPath.menuPath ); + df->writeEntry( "Name", m_popupPath.title ); + df->writeEntry( "Type", "Link" ); + df->sync(); + delete df; + + break; + } + case AddMenuToPanel: + accept(); + ds << "foo" << m_popupPath.menuPath; + kapp->dcopClient()->send("kicker", "Panel", "addServiceMenuButton(TQString,TQString)", ba); + break; + + case AddToFavorites: + if (m_popupService) { + if (favs.find(m_popupService->storageId())==favs.end()) { + KService::Ptr p = KService::serviceByStorageId(m_popupService->storageId()); + m_favoriteView->insertMenuItem(p, serviceMenuEndId()+favs.count()+1); + favs+=m_popupService->storageId(); + } + } + else { + TQStringList::Iterator it; + for (it = favs.begin(); it != favs.end(); ++it) { + if ((*it)[0]=='/') { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==m_popupPath.path) + break; + } + } + if (it==favs.end()) { + TQString file = KickerLib::newDesktopFile(m_popupPath.path); + KDesktopFile df(file); + df.writeEntry("Encoding", "UTF-8"); + df.writeEntry("Type","Link"); + df.writeEntry("Name", m_popupPath.title); + df.writeEntry("GenericName", m_popupPath.description); + df.writeEntry("Icon", m_popupPath.icon); + df.writeEntry("URL", m_popupPath.path); + + m_favoriteView->insertItem(m_popupPath.icon, m_popupPath.title, m_popupPath.description, + m_popupPath.path, serviceMenuEndId()+favs.count()+1, -1); + + favs+=file; + } + } + KickerSettings::setFavorites(favs); + KickerSettings::writeConfig(); + m_browserDirty=true; + m_stacker->raiseWidget(FavoriteTab); + break; + + case RemoveFromFavorites: + if (m_popupService) { + favs.erase(favs.find(m_popupService->storageId())); + + for (TQListViewItemIterator it(m_favoriteView); it.current(); ++it) { + KMenuItem* kitem = static_cast<KMenuItem*>(it.current()); + if (kitem->service() && kitem->service()->storageId() == m_popupService->storageId()) { + delete it.current(); + break; + } + } + } + else { + for (TQStringList::Iterator it = favs.begin(); it != favs.end(); ++it) { + if ((*it)[0]=='/') { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==m_popupPath.path) { + TQFile::remove((*it)); + favs.erase(it); + break; + } + } + } + for (TQListViewItemIterator it(m_favoriteView); it.current(); ++it) { + KMenuItem* kitem = static_cast<KMenuItem*>(it.current()); + if (!kitem->service() && kitem->path() == m_popupPath.path) { + delete it.current(); + break; + } + } + } + m_favoriteView->slotMoveContent(); + KickerSettings::setFavorites(favs); + KickerSettings::writeConfig(); + m_browserDirty=true; + m_stacker->raiseWidget(FavoriteTab); + break; + + case ClearRecentlyUsedApps: + clearRecentAppsItems(); + break; + + case ClearRecentlyUsedDocs: + clearRecentDocsItems(); + break; + + default: + break; + } +} + +void KMenu::resizeEvent ( TQResizeEvent * e ) +{ + //kdDebug() << "resizeEvent " << size() << endl; + KMenuBase::resizeEvent(e); + int ypos = 0; + // this is the height remaining to fill + int left_height = height(); + + if ( m_orientation == BottomUp ) + { + m_resizeHandle->move( e->size().width() - 19, 3); + + // put the search widget at the top of the menu and give it its desired + // height + m_search->mainWidget()->setGeometry( 0, ypos, width(), + m_search->minimumSize().height() ); + left_height -= m_search->minimumSize().height(); + ypos += m_search->minimumSize().height(); + + // place the footer widget at the bottom of the menu and give it its desired + // height + m_footer->mainWidget()->setGeometry( 0, height() - m_footer->minimumSize().height(), + width(), m_footer->minimumSize().height() ); + left_height -= m_footer->minimumSize().height(); + + // place the button box above the footer widget, horizontal placement + // has the width of the edge graphics subtracted + m_tabBar->setGeometry(button_box_left.width(), + height() - m_footer->minimumSize().height() - + m_tabBar->sizeHint().height(), + width() - button_box_left.width(), + m_tabBar->sizeHint().height() ); + left_height -= m_tabBar->sizeHint().height(); + + // place the main (stacker) widget below the search widget, + // in the remaining vertical space + m_stacker->setGeometry(0, ypos, + width(), + left_height ); + + } + else // TopDown orientation + { + // place the 'footer' widget at the top of the menu and give it + // its desired height + m_footer->mainWidget()->setGeometry( 0, + ypos /*height() - m_footer->minimumSize().height()*/, + width(), + m_footer->minimumSize().height() ); + ypos += m_footer->minimumSize().height(); + left_height -= m_footer->minimumSize().height(); + + // place the button box next at the top of the menu. + // has the width of the edge graphics subtracted + m_tabBar->setGeometry(button_box_left.width(), ypos, width() - button_box_left.width(), + m_tabBar->sizeHint().height()); + + ypos += m_tabBar->sizeHint().height(); + left_height -= m_tabBar->sizeHint().height(); + + // put the search widget above the footer widget + // height + m_search->mainWidget()->setGeometry( 0, + height() - m_search->minimumSize().height(), + width(), + m_search->minimumSize().height() + ); + left_height -= m_search->minimumSize().height(); + + // place the main (stacker) widget below the button box, + // in the remaining vertical space + m_stacker->setGeometry(0, ypos, + width(), + left_height ); + m_resizeHandle->move( e->size().width() - 19, e->size().height() - 19); + } + paintSearchTab( false ); +} + +void KMenu::mousePressEvent ( TQMouseEvent * e ) +{ + if ( m_orientation == BottomUp ) { + if (e->x() > width() - m_resizeHandle->width() && + e->y() < m_resizeHandle->height() ) + { + m_isresizing = true; + } + } + else { + if (e->x() > width() - m_resizeHandle->width() && + e->y() > height() - m_resizeHandle->height() ) + { + m_isresizing = true; + } + } + KMenuBase::mousePressEvent(e); +} + +void KMenu::mouseReleaseEvent ( TQMouseEvent * /*e*/ ) +{ + m_isresizing = false; +} + +void KMenu::mouseMoveEvent ( TQMouseEvent * e ) +{ + if ( hasMouseTracking() && m_isresizing ) { + m_stacker->setMinimumSize( TQSize(0, 0) ); + m_stacker->setMaximumSize( TQSize(32000, 32000) ); + int newWidth = QMAX( e->x() - x(), minimumSizeHint().width() ); + if ( m_orientation == BottomUp ) { + int newHeight = QMAX( height() - e->y(), minimumSizeHint().height() + 10 ); + int newY = y() + height() - newHeight; + setGeometry( x(), newY, newWidth, newHeight); + } + else { + setGeometry( x(), y(), newWidth, QMAX( e->y(), minimumSizeHint().height() + 10 )); + } + } +} + +void KMenu::clearedHistory() +{ + saveConfig(); +} + +void KMenu::saveConfig() +{ + KickerSettings::setHistory( m_kcommand->historyItems() ); + KickerSettings::setCompletionItems( m_kcommand->completionObject()->items() ); + KickerSettings::writeConfig(); +} + +void KMenu::notifyServiceStarted(KService::Ptr service) +{ + // Inform other applications (like the quickstarter applet) + // that an application was started + TQByteArray params; + TQDataStream stream(params, IO_WriteOnly); + stream << "minicli" << service->storageId(); + kdDebug() << "minicli appLauncher dcop signal: " << service->storageId() << endl; + KApplication::kApplication()->dcopClient()->emitDCOPSignal("appLauncher", + "serviceStartedByStorageId(TQString,TQString)", params); +} + +void KMenu::parseLine( bool final ) +{ + TQString cmd = m_kcommand->currentText().stripWhiteSpace(); + m_filterData->setData( cmd ); + + if( final ) + KURIFilter::self()->filterURI( *(m_filterData), m_finalFilters ); + else + KURIFilter::self()->filterURI( *(m_filterData), m_middleFilters ); + + m_iconName = m_filterData->iconName(); + + kdDebug (1207) << "Command: " << m_filterData->uri().url() << endl; + kdDebug (1207) << "Arguments: " << m_filterData->argsAndOptions() << endl; +} + +// report error as a title in the menu +void KMenu::reportError (TQString error) +{ + int index = 1000; //getHitMenuItemPosition (new HitMenuItem (base_category_id[0], 0)); + kndDebug () << "Inserting error:" << error << " at position " << index << endl; + m_searchResultsWidget->insertSeparator(OTHER_ID_BASE + 120, error, index); +} + +int KMenu::getHitMenuItemPosition ( HitMenuItem *hit_item) +{ + TQPtrListIterator<HitMenuItem> it (m_current_menu_items); + const HitMenuItem *cur_item; + int pos = 0; + while ((cur_item = it.current ()) != NULL) { + ++it; + if ((cur_item->category!=hit_item->category || !cur_item->display_name.isEmpty()) && (*hit_item) < (*cur_item)) + break; + pos++; + } + m_current_menu_items.insert (pos, hit_item); + + return pos + 1; +} + +bool KMenu::checkUriInMenu( const KURL &uri) +{ + TQPtrListIterator<HitMenuItem> it (m_current_menu_items); + const HitMenuItem *cur_item; + while ((cur_item = it.current ()) != NULL) { + ++it; + if (cur_item->uri == uri ) + return true; + } + + return false; +} + +void KMenu::searchActionClicked(TQListViewItem* item) +{ + accept(); + + addToHistory(); + if (item==m_searchIndex) { + TQByteArray data; + TQDataStream arg(data, IO_WriteOnly); + arg << m_kcommand->currentText(); + + if (ensureServiceRunning("kerry")) + kapp->dcopClient()->send("kerry","search","search(TQString)", data); + } + else { + KURIFilterData data; + TQStringList list; + data.setData( m_kcommand->currentText() ); + list << "kurisearchfilter" << "kuriikwsfilter"; + + if( !KURIFilter::self()->filterURI(data, list) ) { + KDesktopFile file("searchproviders/google.desktop", true, "services"); + data.setData(file.readEntry("Query").replace("\\{@}", m_kcommand->currentText())); + } + + (void) new KRun( data.uri(), parentWidget()); + } +} + +void KMenu::addToHistory() +{ + TQString search = m_kcommand->currentText().stripWhiteSpace(); + + if (search.length()<4) + return; + + m_kcommand->addToHistory( search ); +} + +TQString KMenu::newDesktopFile(const KURL& url, const TQString &directory) +{ + TQString base = url.fileName(); + if (base.endsWith(".desktop")) + base.truncate(base.length()-8); + TQRegExp r("(.*)(?=-\\d+)"); + if (r.search(base) > -1) + base = r.cap(1); + + TQString file = base + ".desktop"; + + for(int n = 1; ++n; ) + { + if (!TQFile::exists(directory+file)) + break; + + file = TQString("%2-%1.desktop").arg(n).arg(base); + } + return directory+file; +} + +void KMenu::updateRecentlyUsedApps(KService::Ptr &service) +{ + TQString strItem(service->desktopEntryPath()); + + // don't add an item from root kmenu level + if (!strItem.contains('/')) + { + return; + } + + // add it into recent apps list + RecentlyLaunchedApps::the().appLaunched(strItem); + RecentlyLaunchedApps::the().save(); + RecentlyLaunchedApps::the().m_bNeedToUpdate = true; +} + +TQSize KMenu::sizeHint() const +{ +#warning FIXME + // this should be only for the inner area so layout changes do not break it + const int width = kMin(KickerSettings::kMenuWidth(), TQApplication::desktop()->screen()->width()-50); + + const int height = kMin(KickerSettings::kMenuHeight(), TQApplication::desktop()->screen()->height()-50); + TQSize wanted(width, height); + kdDebug() << "show " << minimumSizeHint() << " " << m_stacker->minimumSizeHint() << " " + << m_searchFrame->minimumSizeHint() << " " << wanted << endl; + bool isDefault = wanted.isNull(); + wanted = wanted.expandedTo(minimumSizeHint()); + if ( isDefault ) + wanted.setHeight( wanted.height() + ( m_favoriteView->goodHeight() - m_stacker->minimumSizeHint().height() ) ); + + return wanted; +} + +TQSize KMenu::minimumSizeHint() const +{ + TQSize minsize; + minsize.setWidth( minsize.width() + m_tabBar->sizeHint().width() ); + minsize.setWidth( QMAX( minsize.width(), + m_search->minimumSize().width() ) ); + minsize.setWidth( QMAX( minsize.width(), + m_search->minimumSize().width() ) ); + + minsize.setHeight( minsize.height() + + m_search->minimumSize().height() + + m_footer->minimumSize().height() + + 180 ); // 180 is a very rough guess for 32 icon size + return minsize; +} + +void KMenu::slotFavoritesMoved( TQListViewItem* item, TQListViewItem* /*afterFirst*/, TQListViewItem* afterNow) +{ + KMenuItem* kitem = dynamic_cast<KMenuItem*>(item); + KMenuItem* kafterNow = dynamic_cast<KMenuItem*>(afterNow); + + TQStringList favs = KickerSettings::favorites(); + TQStringList::Iterator it; + TQString addFav = TQString::null; + + // remove at old position + if (kitem->service()) + { + favs.erase(favs.find(kitem->service()->storageId())); + addFav = kitem->service()->storageId(); + } + else + { + for (it = favs.begin(); it != favs.end(); ++it) + { + if ((*it)[0]=='/') + { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==kitem->path()) + { + addFav = *it; + favs.erase(it); + break; + } + } + } + } + + if (addFav.isEmpty()) + return; + + if (!kafterNow || dynamic_cast<KMenuSpacer*>(afterNow)) + { + favs.prepend(addFav); + } + else + { + // add at new position + for (it = favs.begin(); it != favs.end(); ++it) + { + if ((*it)[0]=='/' && !kafterNow->service()) + { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==kafterNow->path()) + { + kdDebug() << "insert after " << kafterNow->path() << endl; + favs.insert(++it,addFav); + break; + } + } + else if (kafterNow->service() && *it==kafterNow->service()->storageId()) + { + kdDebug() << "insert after service " << kafterNow->service() << endl; + favs.insert(++it,addFav); + break; + } + } + } + kdDebug() << "favs " << favs << endl; + + KickerSettings::setFavorites(favs); + KickerSettings::writeConfig(); + + m_favoriteView->slotMoveContent(); +} + +void KMenu::updateMedia() +{ + TQStringList devices = m_mediaWatcher->devices(); + if ( devices.isEmpty() ) + return; + + int nId = serviceMenuStartId(); + if ( m_media_id ) { + for ( int i = m_media_id + 1 ;; ++i ) + { + KMenuItem *item = m_systemView->findItem( i ); + if ( !item ) + break; + if ( !item->path().startsWith( "system:/" ) ) + break; + media_mimetypes.remove(item->path()); + delete item; + } + nId = m_media_id + 1; + } else { + m_media_id = nId; + m_systemView->insertSeparator( nId++, i18n("Media"), -1); + } + + for ( TQStringList::ConstIterator it = devices.constBegin(); it != devices.constEnd(); ++it ) + { + TQString id = ( *it ); + TQString name = *++it; + TQString label = *++it; + TQString userLabel = ( *++it ); + bool mountable = ( *++it == "true" ); // bool + ( void )mountable; + TQString deviceNode = ( *++it ); + TQString mountPoint = ( *++it ); + TQString fsType = ( *++it ); + bool mounted = ( *++it == "true" ); // bool + TQString baseURL = ( *++it ); + TQString mimeType = ( *++it ); + TQString iconName = ( *++it ); + + media_mimetypes["system:/media/"+name] = mimeType; + + if ( iconName.isEmpty() ) // no user icon, query the MIME type + { + KMimeType::Ptr mime = KMimeType::mimeType( mimeType ); + iconName = mime->icon( TQString::null, false ); + } + + TQString descr = deviceNode; + if ( mounted ) + { + descr = mountPoint; + // calc the free/total space + struct statfs sfs; + if ( statfs( TQFile::encodeName( mountPoint ), &sfs ) == 0 ) + { + uint64_t total = ( uint64_t )sfs.f_blocks * sfs.f_bsize; + uint64_t avail = ( uint64_t )( getuid() ? sfs.f_bavail : sfs.f_bfree ) * sfs.f_bsize; + if ( avail < total && avail > 1024 ) { + label += " " + i18n( "(%1 available)" ).arg( KIO::convertSize(avail) ); + } + } + } + m_systemView->insertItem( iconName, userLabel.isEmpty() ? label : userLabel, + descr, "system:/media/" + name, nId++, -1 ); + + ++it; // skip separator + } +} + +bool KMenu::ensureServiceRunning(const TQString & service) +{ + TQStringList URLs; + TQByteArray data, replyData; + TQCString replyType; + TQDataStream arg(data, IO_WriteOnly); + arg << service << URLs; + + if ( !kapp->dcopClient()->call( "klauncher", "klauncher", "start_service_by_desktop_name(TQString,TQStringList)", + data, replyType, replyData) ) { + qWarning( "call to klauncher failed."); + return false; + } + TQDataStream reply(replyData, IO_ReadOnly); + + if ( replyType != "serviceResult" ) + { + qWarning( "unexpected result '%s' from klauncher.", replyType.data()); + return false; + } + int result; + TQCString dcopName; + TQString error; + reply >> result >> dcopName >> error; + if (result != 0) + { + qWarning("Error starting: %s", error.local8Bit().data()); + return false; + } + return true; +} + +void KMenu::slotFavDropped(TQDropEvent * ev, TQListViewItem *after ) +{ + TQStringList favs = KickerSettings::favorites(); + KMenuItem *newItem = 0; + + if (KMenuItemDrag::canDecode(ev)) + { + KMenuItemInfo item; + KMenuItemDrag::decode(ev,item); + + if (item.m_s) + { + if (favs.find(item.m_s->storageId())==favs.end()) + { + newItem = m_favoriteView->insertMenuItem(item.m_s, serviceMenuEndId()+favs.count()+1); + favs += item.m_s->storageId(); + } + } + else + { + TQString uri = item.m_path; + if (uri.startsWith(locateLocal("data", TQString::fromLatin1("RecentDocuments/")))) { + KDesktopFile df(uri,true); + uri=df.readURL(); + } + + TQStringList::Iterator it; + for (it = favs.begin(); it != favs.end(); ++it) + { + if ((*it)[0]=='/') + { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==uri) + break; + } + } + if (it==favs.end()) + { + TQString file = KickerLib::newDesktopFile(uri); + KDesktopFile df(file); + df.writeEntry("Encoding", "UTF-8"); + df.writeEntry("Type","Link"); + df.writeEntry("Name", item.m_title); + df.writeEntry("GenericName", item.m_description); + df.writeEntry("Icon", item.m_icon); + df.writeEntry("URL", uri); + + newItem = m_favoriteView->insertItem(item.m_icon, item.m_title, item.m_description, + uri, serviceMenuEndId()+favs.count()+1, -1); + favs += file; + } + } + } + else if (TQTextDrag::canDecode(ev)) + { + TQString text; + TQTextDrag::decode(ev,text); + + if (text.endsWith(".desktop")) + { + KService::Ptr p = KService::serviceByDesktopPath(text.replace("file://",TQString::null)); + if (p && favs.find(p->storageId())==favs.end()) { + newItem = m_favoriteView->insertMenuItem(p, serviceMenuEndId()+favs.count()+1); + favs+=p->storageId(); + } + } + else + { + TQStringList::Iterator it; + for (it = favs.begin(); it != favs.end(); ++it) + { + if ((*it)[0]=='/') + { + KDesktopFile df((*it),true); + if (df.readURL().replace("file://",TQString::null)==text) + break; + } + } + if (it==favs.end()) + { + KFileItem* item = new KFileItem(text, TQString::null, KFileItem::Unknown); + KURL kurl(text); + + TQString file = KickerLib::newDesktopFile(text); + KDesktopFile df(file); + df.writeEntry("Encoding", "UTF-8"); + df.writeEntry("Type","Link"); + df.writeEntry("Name", item->name()); + df.writeEntry("GenericName", i18n("Directory: %1").arg(kurl.upURL().path())); + df.writeEntry("Icon", item->iconName()); + df.writeEntry("URL", text); + + newItem = m_favoriteView->insertItem(item->iconName(), item->name(), i18n("Directory: %1").arg(kurl.upURL().path()), text, serviceMenuEndId()+favs.count()+1, -1); + favs += file; + } + } + } + + if ( newItem ) { + if (!after && m_favoriteView->childCount()>0) { + newItem->moveItem( m_favoriteView->firstChild() ); + m_favoriteView->firstChild()->moveItem( newItem ); + } + else + newItem->moveItem( after ); + KickerSettings::setFavorites(favs); + slotFavoritesMoved( newItem, 0, after ); + } + m_stacker->raiseWidget(m_favoriteView); +} + +void KMenu::resetOverflowCategory() +{ + if (m_overflowCategoryState==NotNeeded) + m_overflowList.setAutoDelete( true ); + + m_overflowList.clear(); + m_overflowList.setAutoDelete( false ); + m_overflowCategoryState = None; + m_overflowCategory = num_categories; +} + +void KMenu::fillOverflowCategory() +{ + if (m_overflowCategoryState==Filling) { + initCategoryTitlesUpdate(); + for (HitMenuItem * item = m_overflowList.first(); item; item = m_overflowList.next() ) { + max_category_id [item->category]++; + item->id=max_category_id [item->category]; + + KMenuItem *hit_item = m_searchResultsWidget->insertItem(iconForHitMenuItem(item), item->display_name, item->display_info, item->uri.url(), max_category_id [item->category], getHitMenuItemPosition (item)); + hit_item->setService(item->service); + } + updateCategoryTitles(); + } +} + +int KMenu::max_items(int category) const +{ + if (category==ACTIONS) + return 10; + + return 5; +} + +#define DBUS_HAL_INTERFACE "org.freedesktop.Hal" +#define DBUS_HAL_SYSTEM_POWER_INTERFACE "org.freedesktop.Hal.Device.SystemPowerManagement" +#define HAL_UDI_COMPUTER "/org/freedesktop/Hal/devices/computer" + +#ifdef KDELIBS_SUSE +#include <liblazy.h> +#endif + +void KMenu::insertSuspendOption( int &nId, int &index ) +{ +#ifdef KDELIBS_SUSE + int supported = -1; + bool suspend_ram, suspend_disk, standby; + + liblazy_hal_get_property_bool(HAL_UDI_COMPUTER, "power_management.can_suspend", &supported); + if (supported == 1) + suspend_ram = true; + else + suspend_ram = false; + liblazy_hal_get_property_bool(HAL_UDI_COMPUTER, "power_management.can_standby", &supported); + if (supported == 1) + standby = true; + else + standby = false; + liblazy_hal_get_property_bool(HAL_UDI_COMPUTER, "power_management.can_hibernate", &supported); + if (supported == 1) + suspend_disk = true; + else + suspend_disk = false; + + if (liblazy_hal_is_caller_privileged("org.freedesktop.hal.power-management.hibernate") != 1) + suspend_disk = false; + if (liblazy_hal_is_caller_privileged("org.freedesktop.hal.power-management.suspend") != 1) + suspend_ram = false; + if (liblazy_hal_is_caller_privileged("org.freedesktop.hal.power-management.standby") != 1) + standby = false; + + if ( ! ( standby + suspend_ram + suspend_disk ) ) + return; + + i18n("Suspend Computer"); + + if ( suspend_disk ) + m_exitView->leftView()->insertItem( "suspend2disk", i18n( "Suspend to Disk" ), + i18n( "Pause without logging out" ), "kicker:/suspend_disk", nId++, index++ ); + + if ( suspend_ram ) + m_exitView->leftView()->insertItem( "suspend2ram", i18n( "Suspend to RAM" ), + i18n( "Pause without logging out" ), "kicker:/suspend_ram", nId++, index++ ); + + if ( standby ) + m_exitView->leftView()->insertItem( "player_pause", i18n( "Standby" ), + i18n( "Pause without logging out" ), "kicker:/standby", nId++, index++ ); +#endif +} + +void KMenu::slotSuspend(int id) +{ +#ifdef KDELIBS_SUSE + int error = 0; + int wake = 0; + DBusMessage *reply = 0; + + if (id == 1) { + error = liblazy_dbus_system_send_method_call(DBUS_HAL_INTERFACE, + HAL_UDI_COMPUTER, + DBUS_HAL_SYSTEM_POWER_INTERFACE, + "Hibernate", + &reply, + DBUS_TYPE_INVALID); + } else if (id == 2) + error = liblazy_dbus_system_send_method_call(DBUS_HAL_INTERFACE, + HAL_UDI_COMPUTER, + DBUS_HAL_SYSTEM_POWER_INTERFACE, + "Suspend", + &reply, + DBUS_TYPE_INT32, + &wake, + DBUS_TYPE_INVALID); + else if (id == 3) + error = liblazy_dbus_system_send_method_call(DBUS_HAL_INTERFACE, + HAL_UDI_COMPUTER, + DBUS_HAL_SYSTEM_POWER_INTERFACE, + "Standby", + &reply, + DBUS_TYPE_INVALID); + else + return; + if (error) +#endif + KMessageBox::error(this, i18n("Suspend failed")); + +} + +// vim:cindent:sw=4: diff --git a/kicker/kicker/ui/k_new_mnu.h b/kicker/kicker/ui/k_new_mnu.h new file mode 100644 index 000000000..ef45ef815 --- /dev/null +++ b/kicker/kicker/ui/k_new_mnu.h @@ -0,0 +1,343 @@ +/***************************************************************** + + Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> + + 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. + +******************************************************************/ + +#ifndef __k_new_mnu_h__ +#define __k_new_mnu_h__ + +#include <dcopobject.h> +#include <tqintdict.h> +#include <tqpixmap.h> +#include <tqframe.h> +#include <tqtoolbutton.h> +#include <tqscrollview.h> +#include <tqtimer.h> +#include <tqbitmap.h> +#include <tqvbox.h> +#include <tqregexp.h> + +#include <kabc/addressbook.h> +#include <kabc/stdaddressbook.h> +#include "../interfaces/kickoff-search-plugin.h" + +// #include "kmenubase.h" +#include "../core/kmenubase.h" +#include "service_mnu.h" +#include "query.h" + +class KickerClientMenu; +class KickoffTabBar; +class KBookmarkMenu; +class KActionCollection; +class KBookmarkOwner; +class Panel; +class TQWidgetStack; +class KHistoryCombo; +class TQScrollView; +class PopupMenuTitle; +class MediaWatcher; +class KURIFilterData; +class KBookmarkGroup; +class KBookmarkManager; +class ItemView; +class FlipScrollView; +class TQListViewItem; +class KMenuItem; +class TQListView; +class TQTabBar; +class TQTab; + +static TQString categories[14] = {I18N_NOOP("Actions"), I18N_NOOP("Applications"), I18N_NOOP("Bookmarks"), + I18N_NOOP("Notes"), I18N_NOOP("Emails"), I18N_NOOP("Files"), I18N_NOOP("Music"), + I18N_NOOP("Browsing History"), I18N_NOOP("Chat Logs"), I18N_NOOP("Feeds"), + I18N_NOOP("Pictures"), I18N_NOOP("Videos"), I18N_NOOP("Documentation"), + I18N_NOOP("Others")}; + +static TQString kerry_categories[14] = {"contacts", "applications", "webpages", "everything", "conversations", + "everything", "media", "webpages", "conversations", "webpages", "images", + "media", "everything", "everything"}; + +enum MenuOrientation { BottomUp, TopDown, UnDetermined }; +enum OverflowCategoryState { None, Filling, NotNeeded }; + +class KMenu : public KMenuBase +{ + Q_OBJECT + Q_PROPERTY (bool KStyleMenuDropShadow READ useKStyleMenuDropShadow ) + +public: + KMenu(); + ~KMenu(); + + int insertClientMenu(KickerClientMenu *p); + void removeClientMenu(int id); + + bool useKStyleMenuDropShadow() const { return true; } + + virtual void showMenu(); + virtual bool eventFilter(TQObject*, TQEvent*); + + void clearRecentAppsItems(); + void clearRecentDocsItems(); + bool highlightMenuItem(const TQString& /*id*/) { return false;} + + void selectFirstItem() {} + void popup(const TQPoint&, int indexAtPoint); + + enum MaskEffect { Plain, Dissolve }; + + virtual TQSize sizeHint() const; + virtual TQSize minimumSizeHint() const; + + void searchOver(); + void initCategoryTitlesUpdate(); + bool anotherHitMenuItemAllowed(int cat, bool count=true); + void addHitMenuItem(HitMenuItem*); + void insertSearchResult(HitMenuItem* item); + + void updateCategoryTitles(); + +signals: + void aboutToHide(); + void aboutToShow(); + +public slots: + virtual void initialize(); + + virtual void hide(); + virtual void show(); + + void stackWidgetRaised(TQWidget*); + +protected slots: + void slotLock(); + void slotOpenHomepage(); + void slotLogout(); + void slotPopulateSessions(); + void slotSessionActivated( int ); + void slotGoSubMenu(const TQString& relPath); + void slotGoBack(); + void slotGoExitMainMenu(); + void slotGoExitSubMenu(const TQString& url); + void tabClicked(TQTab*); + + void paletteChanged(); + virtual void configChanged(); + void updateRecent(); + + void initSearch(); + void searchAccept(); + void searchChanged(const TQString &); + // when timeout happens or doQueryNow calls + void doQuery (bool return_pressed = false); + void searchActionClicked(TQListViewItem*); + + void slotStartService(KService::Ptr); + void slotStartURL(const TQString&); + void slotContextMenuRequested( TQListViewItem * item, const TQPoint & pos, int col ); + + void clearedHistory(); + + void slotSloppyTimeout(); + + void slotContextMenu(int); + void slotFavoritesMoved( TQListViewItem*, TQListViewItem*, TQListViewItem* ); + + void updateMedia(); + void slotFavDropped(TQDropEvent * e, TQListViewItem *after ); + void slotSuspend(int id); + +protected: + virtual void paintEvent(TQPaintEvent *); + virtual void resizeEvent ( TQResizeEvent * ); + virtual void mousePressEvent ( TQMouseEvent * e ); + virtual void mouseReleaseEvent ( TQMouseEvent * e ); + virtual void mouseMoveEvent ( TQMouseEvent * e ); + + void doNewSession(bool lock); + void createRecentMenuItems(); + void insertStaticItems(); + void insertStaticExitItems(); + void insertSuspendOption( int &id, int &index ); + virtual void clearSubmenus(); +// void raiseStackWidget(TQWidget *view); + + bool runCommand(); + + void setupUi(); + + void saveConfig(); + void searchProgramList(TQString relPath); + void searchBookmarks(KBookmarkGroup); + void searchAddressbook(); + + void createNewProgramList(); + void createNewProgramList(TQString relPath); + + void paintSearchTab( bool active ); + + void goSubMenu(const TQString& relPath, bool keyboard = false); + void setOrientation(MenuOrientation orientation); + +private: + int serviceMenuStartId() { return 5242; } + int serviceMenuEndId() { return 5242; } + + void fillMenu( KServiceGroup::Ptr &_root, KServiceGroup::List &_list, + const TQString &_relPath, ItemView* view, int & id ); + + void fillSubMenu(const TQString& relPath, ItemView *view); + + TQPopupMenu *sessionsMenu; + int client_id; + bool delay_init; + TQIntDict<KickerClientMenu> clients; + KActionCollection *actionCollection; + PopupMenuList dynamicSubMenus; + + TQTimer m_sloppyTimer; + TQTimer m_mediaFreeTimer; + MediaWatcher * m_mediaWatcher; + TQRegion m_sloppyRegion; + TQRect m_sloppySource; + bool m_sloppySourceClicked; + TQWidget * m_sloppyWidget; + ItemView * m_recentlyView; + ItemView * m_favoriteView; + ItemView * m_searchResultsWidget; + TQListView * m_searchActions; + FlipScrollView * m_browserView; + ItemView * m_systemView; + FlipScrollView * m_exitView; + TQVBox * m_searchWidget; + TQLabel * m_resizeHandle; + + bool m_isresizing; + // timer for search without pressing enter feature + TQTimer *input_timer, *init_search_timer; + + Query current_query; + + bool dontQueryNow(const TQString &); + + // start timeout timer to call doQuery is enough time has passed since last keypress + void checkToDoQuery (const TQString &); + // when return is pressed + void doQueryNow (); + void clearSearchResults(bool showHelp = true); + + int *max_category_id; // maximum id in this category: max_category_id - base_category_id gives the current number of hits displayed in this category + int *categorised_hit_total; // current number of hits returned in each category + + bool ensureServiceRunning(const TQString & service); + + TQString iconForHitMenuItem(HitMenuItem *hit_item); + + int getHitMenuItemPosition (HitMenuItem *hit_item); + TQMap<TQString, TQString> mimetype_iconstore; + TQMap<TQString, TQString> media_mimetypes; + // report error as a menu item + void reportError (TQString err); + void addToHistory(); + + int max_items(int category) const; + TQString TOP_CATEGORY_STRING; + bool *already_added; + + void notifyServiceStarted(KService::Ptr service); + void parseLine( bool final ); + TQString m_iconName; + TQStringList m_middleFilters; + TQStringList m_finalFilters; + KURIFilterData* m_filterData; + TQPtrList<HitMenuItem> m_current_menu_items; + TQListViewItem *m_searchIndex, *m_searchInternet; + + bool checkUriInMenu(const KURL &uri); + + TQRegExp emailRegExp,uriRegExp,uri2RegExp,authRegExp; + + KBookmarkManager *bookmarkManager; + KABC::AddressBook* m_addressBook; + + enum ContextMenuEntry { AddItemToPanel, EditItem, AddMenuToPanel, EditMenu, + AddItemToDesktop, AddMenuToDesktop, PutIntoRunDialog, + AddToFavorites, RemoveFromFavorites, ClearRecentlyUsedApps, + ClearRecentlyUsedDocs }; + struct PopupPath + { + TQString title, description, icon, path, menuPath; + }; + + enum KickoffTabEntry { FavoriteTab, ApplicationsTab, ComputerTab, + HistoryTab, LeaveTab, SearchTab, NumTabs }; + + KPopupMenu* m_popupMenu; + KService* m_popupService; + PopupPath m_popupPath; + + KickoffTabBar* m_tabBar; + TQTab* m_tabs[NumTabs]; + + TQString newDesktopFile(const KURL& url, const TQString &directory); + void updateRecentlyUsedApps(KService::Ptr &service); + + TQPixmap main_border_lc; + TQPixmap main_border_rc; + TQPixmap main_border_tl; + TQPixmap main_border_tr; + TQPixmap button_box_left; + + TQPixmap search_tab_left; + TQPixmap search_tab_right; + TQPixmap search_tab_center; + + TQPixmap search_tab_top_left; + TQPixmap search_tab_top_right; + TQPixmap search_tab_top_center; + + TQWidgetStack *m_stacker; + + TQStringList m_programsInMenu; + TQStringList m_newInstalledPrograms, m_seenPrograms; + bool m_seenProgramsChanged; + TQString m_currentDate; + + MenuOrientation m_orientation; + bool m_toolTipsEnabled; + int m_media_id; + + bool m_recentDirty, m_browserDirty, m_kerryInstalled, m_isShowing; + + KickoffSearch::Plugin* m_search_plugin; + TQObject* m_search_plugin_interface; + + OverflowCategoryState m_overflowCategoryState; + TQPtrList<HitMenuItem> m_overflowList; + int m_overflowCategory; + + void resetOverflowCategory(); + void fillOverflowCategory(); + + TQString insertBreaks(const TQString& text, TQFontMetrics fm, int width, TQString leadInsert = TQString::null); +}; + +#endif diff --git a/kicker/kicker/ui/kickoff_bar.cpp b/kicker/kicker/ui/kickoff_bar.cpp new file mode 100644 index 000000000..2f0de9aea --- /dev/null +++ b/kicker/kicker/ui/kickoff_bar.cpp @@ -0,0 +1,200 @@ +/***************************************************************** + + Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + Copyright (c) 2006 Dirk Mueller <mueller@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 "kickoff_bar.h" +#include "itemview.h" + +#include <tqiconset.h> +#include <tqpainter.h> +#include <tqcursor.h> +#include <tqstyle.h> +#include <tqapplication.h> + +#include <kdebug.h> +#include "kickerSettings.h" + +KickoffTabBar::KickoffTabBar(TQWidget* parent, const char* name) + : TQTabBar(parent, name), m_tabsActivated(true) +{ + setAcceptDrops(true); +} + +void KickoffTabBar::deactivateTabs(bool b) +{ + m_tabsActivated = !b; + + update(); +} + +void KickoffTabBar::paint(TQPainter* p, TQTab* t, bool selected) const +{ + TQStyle::SFlags flags = TQStyle::Style_Default; + + if (isEnabled() && t->isEnabled()) + flags |= TQStyle::Style_Enabled; + if ( m_tabsActivated && selected ) + flags |= TQStyle::Style_Selected; +// else if(t == d->pressed) +// flags |= TQStyle::Style_Sunken; + //selection flags + if(t->rect().contains(mapFromGlobal(TQCursor::pos()))) + flags |= TQStyle::Style_MouseOver; + style().drawControl( TQStyle::CE_TabBarTab, p, this, t->rect(), + colorGroup(), flags, TQStyleOption(t) ); + + paintLabel( p, t->rect(), t, t->identifier() == keyboardFocusTab() ); +} + + +void KickoffTabBar::paintLabel(TQPainter* p, const TQRect& br, TQTab* t, bool has_focus) const +{ + TQRect r = br; + + bool selected = m_tabsActivated && (currentTab() == t->identifier()); + int vframe = style().pixelMetric( TQStyle::PM_TabBarTabVSpace, this ); + + p->setFont( font() ); + TQFontMetrics fm = p->fontMetrics(); + int fw = fm.size( Qt::SingleLine|Qt::ShowPrefix, t->text() ).width(); + + TQRect rt(r); + rt.setWidth(fw); + + if ( t->iconSet()) + { + // the tab has an iconset, draw it in the right mode + TQIconSet::Mode mode = (t->isEnabled() && isEnabled()) + ? TQIconSet::Normal : TQIconSet::Disabled; + if ( mode == TQIconSet::Normal && has_focus ) + mode = TQIconSet::Active; + TQPixmap pixmap = t->iconSet()->pixmap( TQIconSet::Large, mode ); + int pixw = pixmap.width(); + int pixh = pixmap.height(); + int xoff = br.x() + (br.width() - pixw)/2; + int yoff = br.y() + (br.height() - 4 - pixh - ((KickerSettings::kickoffTabBarFormat() != KickerSettings::IconOnly) ? fm.height() : 0) - vframe)/2; + + p->drawPixmap( xoff, 4 + yoff, pixmap ); + + r.setTop(vframe/2 + yoff + pixh - 8); + rt.setTop(vframe/2 + yoff + pixh - 8); + rt.setHeight(((KickerSettings::kickoffTabBarFormat() != KickerSettings::IconOnly) ? fm.height() : 0) + vframe/2); + } + else + rt.setHeight(vframe/2 + fm.height()); + + rt.setWidth(fw+8); + rt.moveCenter(r.center()); + + TQStyle::SFlags flags = TQStyle::Style_Default; + + if (isEnabled() && t->isEnabled()) + flags |= TQStyle::Style_Enabled; + if (has_focus) + flags |= TQStyle::Style_HasFocus; + if ( selected ) + flags |= TQStyle::Style_Selected; + // else if(t == d->pressed) + // flags |= TQStyle::Style_Sunken; + if(t->rect().contains(mapFromGlobal(TQCursor::pos()))) + flags |= TQStyle::Style_MouseOver; + style().drawControl( TQStyle::CE_TabBarLabel, p, this, rt, + t->isEnabled() ? colorGroup(): palette().disabled(), + flags, TQStyleOption(t) ); +} + +TQSize KickoffTabBar::sizeHint() const +{ + TQSize s = TQTabBar::sizeHint(); + + return s; +} + +void KickoffTabBar::layoutTabs() +{ + TQTabBar::layoutTabs(); + + TQFontMetrics fm = fontMetrics(); + int fh = ((KickerSettings::kickoffTabBarFormat() != KickerSettings::IconOnly) ? fm.height() : 0) + 4; + + int hframe = style().pixelMetric( TQStyle::PM_TabBarTabHSpace, this ); + int vframe = style().pixelMetric( TQStyle::PM_TabBarTabVSpace, this ); + int overlap = style().pixelMetric( TQStyle::PM_TabBarTabOverlap, this ); + + TQSize s; + for (int t = 0; t < count(); ++t) + { + TQTab* tab = tabAt(t); + if (tab->iconSet()) + s = s.expandedTo(tab->iconSet()->pixmap(TQIconSet::Large, TQIconSet::Normal).size()); + } + + int x = 0; + for (int t = 0; t < count(); ++t) { + TQTab* tab = tabAt(TQApplication::reverseLayout() ? count() - t - 1 : t); + int h = fh; + if (tab->iconSet()) + h += 4 + s.height() + 4; + TQRect r = tab->rect(); + + int fw = fm.size( Qt::SingleLine|Qt::ShowPrefix, tab->text() ).width(); + int iw = 0; + if ( tab->iconSet() != 0 ) + iw = tab->iconSet()->pixmap( TQIconSet::Large, TQIconSet::Normal ).width(); + int w = QMAX(iw, fw + 6 + 6 ) + hframe; + h += ((KickerSettings::kickoffTabBarFormat() != KickerSettings::IconOnly) ? fm.height() : 0) + vframe; + tab->setRect(TQRect(TQPoint(x, 0), style().sizeFromContents(TQStyle::CT_TabBarTab, this, + TQSize(w, h), TQStyleOption(tab)))); + x += tab->rect().width() - overlap; + } +} + +void KickoffTabBar::dragEnterEvent(TQDragEnterEvent* event) +{ + event->accept(KMenuItemDrag::canDecode(event)); +} + +void KickoffTabBar::dragMoveEvent(TQDragMoveEvent* event) +{ + TQTab* t = selectTab(event->pos()); + + // ### uhhh, look away + if (t && t->identifier() == 0) + { + setCurrentTab(t); + } +} + +void KickoffTabBar::mousePressEvent( TQMouseEvent * e ) +{ + if ( e->button() != LeftButton ) { + e->ignore(); + return; + } + TQTab *t = selectTab( e->pos() ); + if ( t && t->isEnabled() ) { + emit tabClicked(t); + } + TQTabBar::mousePressEvent(e); +} + +#include "kickoff_bar.moc" +// vim:cindent:sw=4: diff --git a/kicker/kicker/ui/kickoff_bar.h b/kicker/kicker/ui/kickoff_bar.h new file mode 100644 index 000000000..2330ffe39 --- /dev/null +++ b/kicker/kicker/ui/kickoff_bar.h @@ -0,0 +1,53 @@ +/***************************************************************** + + Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + Copyright (c) 2006 Dirk Mueller <mueller@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. + +******************************************************************/ + +#ifndef __kickoff_bar_h__ +#define __kickoff_bar_h__ + +#include <tqtabbar.h> + +class KickoffTabBar : public TQTabBar +{ + Q_OBJECT +public: + KickoffTabBar(TQWidget* parent, const char* name); + + void deactivateTabs(bool b); + virtual TQSize sizeHint() const; + +protected: + virtual void paint(TQPainter*, TQTab*, bool) const; + virtual void paintLabel(TQPainter* p, const TQRect& br, TQTab* t, bool has_focus) const; + virtual void layoutTabs(); + virtual void dragEnterEvent(TQDragEnterEvent*); + virtual void dragMoveEvent(TQDragMoveEvent*); + virtual void mousePressEvent ( TQMouseEvent * ); + +signals: + void tabClicked(TQTab*); + +private: + bool m_tabsActivated; +}; + + +#endif diff --git a/kicker/kicker/ui/kmenuitembase.ui b/kicker/kicker/ui/kmenuitembase.ui new file mode 100644 index 000000000..0cbea1155 --- /dev/null +++ b/kicker/kicker/ui/kmenuitembase.ui @@ -0,0 +1,141 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>KMenuItemBase</class> +<widget class="QWidget"> + <property name="name"> + <cstring>KMenuItemBase</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>514</width> + <height>80</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>32767</width> + <height>80</height> + </size> + </property> + <property name="caption"> + <string>KMenuItemBase</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>2</number> + </property> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout11</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>itemTitle</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>14</pointsize> + </font> + </property> + <property name="text"> + <string></string> + </property> + <property name="textFormat"> + <enum>RichText</enum> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>itemDescription</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="paletteForegroundColor"> + <color> + <red>188</red> + <green>188</green> + <blue>188</blue> + </color> + </property> + <property name="text"> + <string></string> + </property> + <property name="textFormat"> + <enum>RichText</enum> + </property> + <property name="alignment"> + <set>WordBreak|AlignTop</set> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>itemPixmap</cstring> + </property> + <property name="minimumSize"> + <size> + <width>64</width> + <height>64</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="alignment"> + <set>AlignTop|AlignHCenter</set> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kicker/kicker/ui/media_watcher.cpp b/kicker/kicker/ui/media_watcher.cpp new file mode 100644 index 000000000..72efc897f --- /dev/null +++ b/kicker/kicker/ui/media_watcher.cpp @@ -0,0 +1,57 @@ +/***************************************************************** + +Copyright (c) 2006 Stephan Kulow <coolo@novell.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include "media_watcher.h" +#include <kapplication.h> +#include <kdebug.h> +#include <dcopclient.h> +#include <dcopref.h> + +MediaWatcher::MediaWatcher( TQObject *parent ) : + TQObject( parent ), DCOPObject("mediawatcher") +{ + connectDCOPSignal( "kded", "mediamanager", "mediumAdded(TQString,bool)", + "slotMediumAdded(TQString,bool)", true ); + connectDCOPSignal( "kded", "mediamanager", "mediumRemoved(TQString,bool)", + "slotMediumAdded(TQString,bool)", true ); + connectDCOPSignal( "kded", "mediamanager", "mediumChanged(TQString,bool)", + "slotMediumAdded(TQString,bool)", true ); + + updateDevices(); +} + +void MediaWatcher::updateDevices() +{ + DCOPRef nsd( "kded", "mediamanager" ); + nsd.setDCOPClient( kapp->dcopClient() ); + m_devices = nsd.call( "fullList" ); +} + +void MediaWatcher::slotMediumAdded( TQString item, bool a ) +{ + updateDevices(); + + emit mediumChanged(); +} + +#include "media_watcher.moc" diff --git a/kicker/kicker/ui/media_watcher.h b/kicker/kicker/ui/media_watcher.h new file mode 100644 index 000000000..604fcaabe --- /dev/null +++ b/kicker/kicker/ui/media_watcher.h @@ -0,0 +1,51 @@ +/***************************************************************** + +Copyright (c) 2006 Stephan Kulow <coolo@novell.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef _media_watcher_ +#define _media_watcher_ + +#include <dcopobject.h> +#include <tqobject.h> +#include <tqstringlist.h> + +class MediaWatcher : public TQObject, public DCOPObject +{ + Q_OBJECT + K_DCOP + + TQStringList m_devices; + void updateDevices(); + +k_dcop: + void slotMediumAdded(TQString medium, bool a); + +signals: + void mediumChanged(); + +public: + MediaWatcher(TQObject *parent); + + TQStringList devices() const { return m_devices; } +}; + +#endif diff --git a/kicker/kicker/ui/mykickoffsearchinterface.cpp b/kicker/kicker/ui/mykickoffsearchinterface.cpp new file mode 100644 index 000000000..e66c0ca85 --- /dev/null +++ b/kicker/kicker/ui/mykickoffsearchinterface.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "mykickoffsearchinterface.h" +#include "../ui/k_new_mnu.h" + +MyKickoffSearchInterface::MyKickoffSearchInterface( KMenu* menu, TQObject* parent, const char* name ) + : KickoffSearchInterface( parent, name ), _menu( menu ) +{ +} + +bool MyKickoffSearchInterface::anotherHitMenuItemAllowed(int cat) +{ + return _menu->anotherHitMenuItemAllowed(cat); +} + +void MyKickoffSearchInterface::addHitMenuItem(HitMenuItem* item) +{ + _menu->addHitMenuItem(item); +} + + +void MyKickoffSearchInterface::searchOver() +{ + _menu->searchOver(); +} + +void MyKickoffSearchInterface::initCategoryTitlesUpdate() +{ + _menu->initCategoryTitlesUpdate(); +} + +void MyKickoffSearchInterface::updateCategoryTitles() +{ + _menu->updateCategoryTitles(); +} + +#include "mykickoffsearchinterface.moc" diff --git a/kicker/kicker/ui/mykickoffsearchinterface.h b/kicker/kicker/ui/mykickoffsearchinterface.h new file mode 100644 index 000000000..b728718c4 --- /dev/null +++ b/kicker/kicker/ui/mykickoffsearchinterface.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner <binner@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; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef MYKICKOFFSEARCHINTERFACE_H +#define MYKICKOFFSEARCHINTERFACE_H + +#include "../interfaces/kickoffsearchinterface.h" + +class KMenu; + +using namespace KickoffSearch; + +class MyKickoffSearchInterface :public KickoffSearchInterface +{ + Q_OBJECT + +public: + MyKickoffSearchInterface( KMenu*, TQObject* parent, const char* name = 0 ); + + bool anotherHitMenuItemAllowed(int cat); + void addHitMenuItem(HitMenuItem* item); + void searchOver(); + void initCategoryTitlesUpdate(); + void updateCategoryTitles(); + +private: + KMenu* _menu; + +}; + +#endif /* MYKICKOFFSEARCHINTERFACE_H */ diff --git a/kicker/kicker/ui/query.cpp b/kicker/kicker/ui/query.cpp new file mode 100644 index 000000000..12b9b6910 --- /dev/null +++ b/kicker/kicker/ui/query.cpp @@ -0,0 +1,136 @@ +/***************************************************************** + + Copyright (c) 2006 Stephan Binner <binner@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 "query.h" +#include <kdebug.h> + +Query::Query() +{ + alternatives.setAutoDelete(true); +} + +void Query::clear() +{ + query_term = TQString::null; + alternatives.clear(); +} + +void Query::set(const TQString &term) +{ + query_term = term; + alternatives.clear(); + + current_alternative = new Alternative; + current_part = TQString::null; + within_quotes = false; + exclude_part = false; + + for (uint index=0;index<term.length();index++) { + if (current_part.isEmpty() && query_term[index]=='-') + exclude_part = true; + else if (term[index]=='\'' || term[index]=='"') { + if (within_quotes) + add_term(); + else + within_quotes = true; + } + else if (!within_quotes && query_term[index]==' ') + add_term(); + else if (!exclude_part && !within_quotes && query_term[index]=='O' && index+1<term.length() && query_term[index+1]=='R') { + index++; + alternatives.append(current_alternative); + current_alternative = new Alternative; + within_quotes = false; + exclude_part = false; + current_part = TQString::null; + } + else + current_part+=term[index]; + } + add_term(); + alternatives.append(current_alternative); + +#if 0 + for (Alternative* alt=alternatives.first(); alt; alt=alternatives.next()) { + kdDebug() << "---" << endl; + kdDebug() << "*** includes = " << alt->includes << endl; + kdDebug() << "*** excludes = " << alt->excludes << endl; + } +#endif +} + +void Query::add_term() { + if (!current_part.isEmpty()) { + if (current_part.startsWith("*")) + current_part=current_part.mid(1); + + if (current_part.endsWith("*")) + current_part=current_part.mid(0,current_part.length()-1); + + if (exclude_part) + current_alternative->excludes+=current_part.lower(); + else + current_alternative->includes+=current_part.lower(); + } + within_quotes = false; + exclude_part = false; + current_part = TQString::null; +} + +TQString Query::get() const +{ + return query_term; +} + +bool Query::matches(const TQString &term) +{ + TQString lower_term = term.lower(); + + for (Alternative* alt=alternatives.first(); alt; alt=alternatives.next()) { + if (!alt->includes.count()) + continue; + + bool next_alternative = false; + + for ( TQStringList::ConstIterator it = alt->excludes.begin(); it != alt->excludes.end(); ++it ) { + if ( lower_term.find(*it)!=-1 ) { + next_alternative = true; + continue; + } + } + if (next_alternative) + continue; + + for ( TQStringList::ConstIterator it = alt->includes.begin(); it != alt->includes.end(); ++it ) { + if ( lower_term.find(*it)==-1 ) { + next_alternative = true; + continue; + } + } + if (next_alternative) + continue; + +//kdDebug() << "Found hit in '" << term << "'" << endl; + return true; + } + + return false; +} diff --git a/kicker/kicker/ui/query.h b/kicker/kicker/ui/query.h new file mode 100644 index 000000000..ea3eab43e --- /dev/null +++ b/kicker/kicker/ui/query.h @@ -0,0 +1,55 @@ +/***************************************************************** + + Copyright (c) 2006 Stephan Binner <binner@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. + +******************************************************************/ + +#ifndef QUERY_H +#define QUERY_H + +#include <tqstringlist.h> +#include <tqptrlist.h> + +class Alternative +{ +public: + TQStringList includes; + TQStringList excludes; +}; + +class Query +{ + public: + Query(); + void clear(); + void set(const TQString &); + TQString get() const; + bool matches(const TQString &); + + private: + TQString query_term; + TQPtrList<Alternative> alternatives; + + void add_term(); + TQString current_part; + Alternative *current_alternative; + bool within_quotes; + bool exclude_part; +}; + +#endif diff --git a/kicker/libkicker/kickerSettings.kcfg b/kicker/libkicker/kickerSettings.kcfg index 6f7f2427e..99625809d 100644 --- a/kicker/libkicker/kickerSettings.kcfg +++ b/kicker/libkicker/kickerSettings.kcfg @@ -98,6 +98,70 @@ <label>A list of extensions that have been loaded at runtime. In the case of a crash these extensions will not be loaded at the next Kicker start, in case they caused the crash</label> </entry> +<entry name="LegacyKMenu" type="Bool" > + <label>When this option is enabled, the classic K Menu is used.</label> + <default>true</default> + </entry> + +<entry name="OpenOnHover" type="Bool" > + <label>When this option is enabled, the Kickoff Menu opens on mouse hover.</label> + <default>true</default> + </entry> + +<entry name="ScrollFlipView" type="Bool" > + <label>When this option is enabled, the Kickoff Menu application view switching will scroll.</label> + <default>true</default> + </entry> + +<entry name="KMenuWidth" type="Int"> + <label>Preferred width of the KMenu</label> + <default>0</default> + </entry> + +<entry name="KMenuHeight" type="Int"> + <label>Preferred width of the KMenu</label> + <default>0</default> + </entry> + +<entry name="KickoffFontPointSizeOffset" type="Int" > + <label>With this option the scale of the fonts Kickoff uses can be influenced</label> + <default>0</default> + <min>-100</min> + <max>100</max> + </entry> + +<entry name="KickoffSearchAddressBook" type="Bool" > + <label>When this option is enabled, kabc is utilized to search for addresses. This may start KMail.</label> + <default>false</default> + </entry> + +<entry name="KickoffDrawGeekoEye" type="Bool" > + <label>When this option is enabled, the Geeko eye moves when the mouse hovers the start menu button</label> + <default>false</default> + </entry> + +<entry name="KickoffTabBarFormat" type="Enum" > + <choices> + <choice name="LabelAndIcon"> + <label>Show names and icons on tabs</label> + </choice> + <choice name="LabelOnly"> + <label>Show only the names</label> + </choice> + <choice name="IconOnly"> + <label>Show only the icons</label> + </choice> + </choices> + <default>LabelAndIcon</default> + <label>Appearace of the Kickoff tabbar</label> + </entry> + +<entry name="KickoffSwitchTabsOnHover" type="Bool" > + <label>When this option is enabled, the tabs in the Kickoff menu will switch without the need to click</label> + <default>true</default> + </entry> + + </group> <group name="menus"> @@ -177,6 +241,19 @@ <default>false</default> </entry> +<entry name="Favorites" type="StringList"> + <label>The menu entries shown in the Favorites tab</label> + </entry> + +<entry name="FirstRun" type="Bool" > + <label>Whether the panel has been started before or not</label> + <default>false</default> + </entry> + +<entry name="FirstSeenApps" type="StringList"> + <label>When the applications were first seen by Kickoff</label> + </entry> + </group> <group name="button_tiles"> @@ -352,6 +429,29 @@ </group> + <group name="SearchField"> + <entry key="History" type="PathList"> + <default></default> + <label></label> + <whatsthis></whatsthis> + </entry> + <entry key="HistoryLength" type="Int"> + <default>50</default> + <label></label> + <whatsthis></whatsthis> + </entry> + <entry key="CompletionItems" type="PathList"> + <default></default> + <label></label> + <whatsthis></whatsthis> + </entry> + <entry key="CompletionMode" type="Int"> + <default>2</default> + <label></label> + <whatsthis></whatsthis> + </entry> + </group> + </kcfg> diff --git a/kicker/libkicker/kickertip.cpp b/kicker/libkicker/kickertip.cpp index 34cf65c56..215320c84 100644 --- a/kicker/libkicker/kickertip.cpp +++ b/kicker/libkicker/kickertip.cpp @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // putting this #include higher results in compile errors #include <netwm.h> +#include <assert.h> static const int DEFAULT_FRAMES_PER_SECOND = 30; @@ -71,14 +72,16 @@ KickerTip::KickerTip(TQWidget * parent) m_dissolveDelta(-1), m_direction(KPanelApplet::Up), m_dirty(false), - m_toolTipsEnabled(KickerSettings::showToolTips()), - m_tippingFor(0) + m_tippingFor(0), + m_timer(0, "KickerTip::m_timer"), + m_frameTimer(0, "KickerTip::m_frameTimer") { setFocusPolicy(NoFocus); setBackgroundMode(NoBackground); resize(0, 0); hide(); connect(&m_frameTimer, TQT_SIGNAL(timeout()), TQT_SLOT(internalUpdate())); + connect(kapp, TQT_SIGNAL(settingsChanged(SettingsCategory)), TQT_SLOT(slotSettingsChanged())); } KickerTip::~KickerTip() @@ -87,6 +90,11 @@ KickerTip::~KickerTip() delete m_mimeFactory; } +void KickerTip::slotSettingsChanged() +{ + TQToolTip::setGloballyEnabled(KickerSettings::showToolTips()); +} + void KickerTip::display() { if (!tippingEnabled()) @@ -194,7 +202,7 @@ void KickerTip::paintEvent(TQPaintEvent * e) void KickerTip::mousePressEvent(TQMouseEvent * /*e*/) { - TQToolTip::setGloballyEnabled(m_toolTipsEnabled); + m_timer.stop(); hide(); } @@ -463,8 +471,11 @@ void KickerTip::enableTipping(bool tip) m_tippingEnabled--; } + assert(m_tippingEnabled >= -1); + if (m_tippingEnabled < 1 && m_self) { + m_self->m_timer.stop(); m_self->hide(); } } @@ -480,6 +491,8 @@ void KickerTip::hide() m_timer.stop(); m_frameTimer.stop(); TQWidget::hide(); + + TQToolTip::setGloballyEnabled(KickerSettings::showToolTips()); } bool KickerTip::eventFilter(TQObject *object, TQEvent *event) @@ -508,7 +521,6 @@ bool KickerTip::eventFilter(TQObject *object, TQEvent *event) !qApp->activePopupWidget() && !isTippingFor(widget)) { - m_toolTipsEnabled = TQToolTip::isGloballyEnabled(); TQToolTip::setGloballyEnabled(false); tipFor(widget); @@ -530,8 +542,6 @@ bool KickerTip::eventFilter(TQObject *object, TQEvent *event) } break; case TQEvent::Leave: - TQToolTip::setGloballyEnabled(m_toolTipsEnabled); - m_timer.stop(); if (isTippingFor(widget) && isVisible()) @@ -544,7 +554,7 @@ bool KickerTip::eventFilter(TQObject *object, TQEvent *event) tipFor(0); break; case TQEvent::MouseButtonPress: - TQToolTip::setGloballyEnabled(m_toolTipsEnabled); + m_timer.stop(); hide(); default: break; diff --git a/kicker/libkicker/kickertip.h b/kicker/libkicker/kickertip.h index 6bcc863f8..14118029b 100644 --- a/kicker/libkicker/kickertip.h +++ b/kicker/libkicker/kickertip.h @@ -92,6 +92,7 @@ protected slots: void tipperDestroyed(TQObject* o); void internalUpdate(); void display(); + void slotSettingsChanged(); private: TQBitmap m_mask; @@ -108,7 +109,6 @@ private: TQTimer m_timer; TQTimer m_frameTimer; bool m_dirty; - bool m_toolTipsEnabled; const TQWidget* m_tippingFor; diff --git a/kicker/libkicker/panelbutton.cpp b/kicker/libkicker/panelbutton.cpp index 972e5195e..f1ab69fb8 100644 --- a/kicker/libkicker/panelbutton.cpp +++ b/kicker/libkicker/panelbutton.cpp @@ -44,6 +44,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <kipc.h> #include <kstandarddirs.h> #include <klocale.h> +#include <kdebug.h> #include "global.h" @@ -67,6 +68,7 @@ PanelButton::PanelButton( TQWidget* parent, const char* name ) m_hasAcceptedDrag(false), m_arrowDirection(KPanelExtension::Bottom), m_popupDirection(KPanelApplet::Up), + m_iconAlignment(AlignCenter), m_orientation(Horizontal), m_size((KIcon::StdSizes)-1), m_fontPercent(0.40) @@ -188,6 +190,12 @@ void PanelButton::setPopupDirection(KPanelApplet::Direction d) setArrowDirection(KickerLib::directionToPopupPosition(d)); } +void PanelButton::setIconAlignment(AlignmentFlags align) +{ + m_iconAlignment = align; + update(); +} + void PanelButton::setOrientation(Orientation o) { m_orientation = o; @@ -303,7 +311,9 @@ int PanelButton::widthForHeight(int height) const int PanelButton::heightForWidth(int width) const { - return preferredDimension(width); + int rc=preferredDimension(width); + + return rc; } const TQPixmap& PanelButton::labelIcon() const @@ -562,11 +572,16 @@ void PanelButton::drawButtonLabel(TQPainter *p) icon.height() - 2); } + int y = 0; + if (m_iconAlignment & AlignVCenter) + y = (height() - icon.height()) / 2; + else if (m_iconAlignment & AlignBottom) + y = (height() - icon.height()); + if (!m_buttonText.isEmpty() && orientation() == Horizontal) { int h = height(); int w = width(); - int y = (h - icon.height())/2; p->save(); TQFont f = font(); @@ -635,8 +650,11 @@ void PanelButton::drawButtonLabel(TQPainter *p) } else if (!icon.isNull()) { - int y = (height() - icon.height()) / 2; - int x = (width() - icon.width()) / 2; + int x = 0; + if (m_iconAlignment & AlignHCenter) + x = (width() - icon.width()) / 2; + else if (m_iconAlignment & AlignRight) + x = (width() - icon.width()); p->drawPixmap(x, y, icon); } @@ -798,7 +816,19 @@ void PanelButton::loadIcons() TQString nm = m_iconName; KIcon::States defaultState = isEnabled() ? KIcon::DefaultState : KIcon::DisabledState; - m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState, 0L, true); + if (nm=="kmenu-suse") + { + TQString pth = locate( "data", "kicker/pics/kmenu_basic.mng" ); + if (!pth.isEmpty()) + { + m_icon = TQImage(pth); + m_iconh = TQPixmap(m_icon); + m_iconz = TQPixmap(m_icon); + return; + } + } + else + m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState, 0L, true); if (m_icon.isNull()) { @@ -863,7 +893,7 @@ PanelPopupButton::PanelPopupButton(TQWidget *parent, const char *name) connect(this, TQT_SIGNAL(pressed()), TQT_SLOT(slotExecMenu())); } -void PanelPopupButton::setPopup(TQPopupMenu *popup) +void PanelPopupButton::setPopup(TQWidget *popup) { if (m_popup) { @@ -881,7 +911,7 @@ void PanelPopupButton::setPopup(TQPopupMenu *popup) } } -TQPopupMenu *PanelPopupButton::popup() const +TQWidget *PanelPopupButton::popup() const { return m_popup; } @@ -960,7 +990,9 @@ void PanelPopupButton::slotExecMenu() } m_popup->adjustSize(); - m_popup->exec(KickerLib::popupPosition(popupDirection(), m_popup, this)); + if(dynamic_cast<TQPopupMenu*>(m_popup)) + static_cast<TQPopupMenu*>(m_popup)->exec(KickerLib::popupPosition(popupDirection(), m_popup, this)); + // else.. hmm. some derived class has to fix it. } void PanelPopupButton::menuAboutToHide() @@ -970,8 +1002,10 @@ void PanelPopupButton::menuAboutToHide() return; } - setDown(false); - KickerTip::enableTipping(true); + if (isDown()) { + setDown(false); + KickerTip::enableTipping(true); + } } void PanelPopupButton::triggerDrag() @@ -989,3 +1023,5 @@ void PanelPopupButton::setInitialized(bool initialized) m_initialized = initialized; } + + diff --git a/kicker/libkicker/panelbutton.h b/kicker/libkicker/panelbutton.h index 78f36ed5c..770d0e1be 100644 --- a/kicker/libkicker/panelbutton.h +++ b/kicker/libkicker/panelbutton.h @@ -254,9 +254,11 @@ public slots: /** * Sets the direction to pop up the contents of the button. */ - void setPopupDirection(KPanelApplet::Direction d); + virtual void setPopupDirection(KPanelApplet::Direction d); protected: + + void setIconAlignment(AlignmentFlags align); /** * Subclasses must implement this to define the name of the button which is * used to identify this button for saving and loading. It must be unique @@ -391,6 +393,7 @@ private: TQPixmap m_iconz; // mouse over KPanelExtension::Position m_arrowDirection; KPanelApplet::Direction m_popupDirection; + AlignmentFlags m_iconAlignment; Orientation m_orientation; int m_size; double m_fontPercent; @@ -419,12 +422,12 @@ public: * Sets the button's popup menu. * @param popup the menu to pop up */ - void setPopup(TQPopupMenu *popup); + void setPopup(TQWidget *popup); /** * @return the button's popup menu */ - TQPopupMenu *popup() const; + TQWidget *popup() const; bool eventFilter(TQObject *, TQEvent *); virtual void showMenu(); @@ -459,8 +462,8 @@ protected slots: private slots: void menuAboutToHide(); -private: - TQPopupMenu *m_popup; +protected: + TQWidget *m_popup; bool m_pressedDuringPopup; bool m_initialized; diff --git a/kicker/taskbar/taskbar.cpp b/kicker/taskbar/taskbar.cpp index 88768e811..808408fc9 100644 --- a/kicker/taskbar/taskbar.cpp +++ b/kicker/taskbar/taskbar.cpp @@ -59,7 +59,8 @@ TaskBar::TaskBar( TQWidget *parent, const char *name ) m_showIcon(false), m_showOnlyIconified(false), m_textShadowEngine(0), - m_ignoreUpdates(false) + m_ignoreUpdates(false), + m_relayoutTimer(0, "TaskBar::m_relayoutTimer") { arrowType = LeftArrow; blocklayout = true; diff --git a/kicker/taskbar/taskcontainer.cpp b/kicker/taskbar/taskcontainer.cpp index 6bc74044e..1e4829a38 100644 --- a/kicker/taskbar/taskcontainer.cpp +++ b/kicker/taskbar/taskcontainer.cpp @@ -67,7 +67,11 @@ TaskContainer::TaskContainer(Task::Ptr task, TaskBar* bar, discardNextMouseEvent(false), aboutToActivate(false), m_mouseOver(false), - m_paintEventCompression(false) + animationTimer(0, "TaskContainer::animationTimer"), + dragSwitchTimer(0, "TaskContainer::dragSwitchTimer"), + attentionTimer(0, "TaskContainer::attentionTimer"), + m_paintEventCompression(false), + m_paintEventCompressionTimer(0, "TaskContainer::paintEventCompressionTimer") { init(); setAcceptDrops(true); // Always enabled to activate task during drag&drop. @@ -95,7 +99,11 @@ TaskContainer::TaskContainer(Startup::Ptr startup, PixmapList& startupFrames, discardNextMouseEvent(false), aboutToActivate(false), m_mouseOver(false), - m_paintEventCompression(false) + animationTimer(0, "TaskContainer::animationTimer"), + dragSwitchTimer(0, "TaskContainer::dragSwitchTimer"), + attentionTimer(0, "TaskContainer::attentionTimer"), + m_paintEventCompression(false), + m_paintEventCompressionTimer(0, "TaskContainer::paintEventCompressionTimer") { init(); setEnabled(false); |