--- taskbar/taskcontainer.cpp (revision 755866) +++ taskbar/taskcontainer.cpp (revision 774644) @@ -67,7 +67,11 @@ TaskContainer::TaskContainer(Task::Ptr t 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::Pt 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); --- taskbar/taskbar.cpp (revision 755866) +++ taskbar/taskbar.cpp (revision 774644) @@ -61,7 +61,8 @@ TaskBar::TaskBar( QWidget *parent, const m_showIcon(false), m_showOnlyIconified(false), m_textShadowEngine(0), - m_ignoreUpdates(false) + m_ignoreUpdates(false), + m_relayoutTimer(0, "TaskBar::m_relayoutTimer") { setBackgroundOrigin( AncestorOrigin ); --- configure.in.in (revision 0) +++ configure.in.in (revision 774644) @@ -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) --- libkicker/panelbutton.h (revision 755866) +++ libkicker/panelbutton.h (revision 774644) @@ -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: QPixmap 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(QPopupMenu *popup); + void setPopup(QWidget *popup); /** * @return the button's popup menu */ - QPopupMenu *popup() const; + QWidget *popup() const; bool eventFilter(QObject *, QEvent *); virtual void showMenu(); @@ -459,8 +462,8 @@ protected slots: private slots: void menuAboutToHide(); -private: - QPopupMenu *m_popup; +protected: + QWidget *m_popup; bool m_pressedDuringPopup; bool m_initialized; --- libkicker/kickerSettings.kcfg (revision 755866) +++ libkicker/kickerSettings.kcfg (revision 774644) @@ -98,6 +98,70 @@ + + + false + + + + + true + + + + + true + + + + + 0 + + + + + 0 + + + + + 0 + -100 + 100 + + + + + false + + + + + false + + + + + + + + + + + + + + + LabelAndIcon + + + + + + true + + + @@ -172,6 +236,19 @@ false + + + + + + + false + + + + + + @@ -337,6 +414,29 @@ + + + + + + + + 50 + + + + + + + + + + 2 + + + + + --- libkicker/kickertip.cpp (revision 755866) +++ libkicker/kickertip.cpp (revision 774644) @@ -38,6 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE // putting this #include higher results in compile errors #include +#include static const int DEFAULT_FRAMES_PER_SECOND = 30; @@ -71,14 +72,16 @@ KickerTip::KickerTip(QWidget * 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, SIGNAL(timeout()), SLOT(internalUpdate())); + connect(kapp, SIGNAL(settingsChanged(SettingsCategory)), SLOT(slotSettingsChanged())); } KickerTip::~KickerTip() @@ -87,6 +90,11 @@ KickerTip::~KickerTip() delete m_mimeFactory; } +void KickerTip::slotSettingsChanged() +{ + QToolTip::setGloballyEnabled(KickerSettings::showToolTips()); +} + void KickerTip::display() { if (!tippingEnabled()) @@ -192,9 +200,7 @@ void KickerTip::paintEvent(QPaintEvent * void KickerTip::mousePressEvent(QMouseEvent * /*e*/) { - QToolTip::setGloballyEnabled(m_toolTipsEnabled); m_timer.stop(); - m_frameTimer.stop(); hide(); } @@ -395,8 +401,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(); } } @@ -411,6 +420,8 @@ void KickerTip::hide() m_tippingFor = 0; m_frameTimer.stop(); QWidget::hide(); + + QToolTip::setGloballyEnabled(KickerSettings::showToolTips()); } bool KickerTip::eventFilter(QObject *object, QEvent *event) @@ -439,7 +450,6 @@ bool KickerTip::eventFilter(QObject *obj !qApp->activePopupWidget() && !isTippingFor(widget)) { - m_toolTipsEnabled = QToolTip::isGloballyEnabled(); QToolTip::setGloballyEnabled(false); tipFor(widget); @@ -461,8 +471,6 @@ bool KickerTip::eventFilter(QObject *obj } break; case QEvent::Leave: - QToolTip::setGloballyEnabled(m_toolTipsEnabled); - m_timer.stop(); if (isTippingFor(widget) && isVisible()) @@ -475,9 +483,7 @@ bool KickerTip::eventFilter(QObject *obj tipFor(0); break; case QEvent::MouseButtonPress: - QToolTip::setGloballyEnabled(m_toolTipsEnabled); m_timer.stop(); - m_frameTimer.stop(); hide(); default: break; --- libkicker/kickertip.h (revision 755866) +++ libkicker/kickertip.h (revision 774644) @@ -92,6 +92,7 @@ protected slots: void tipperDestroyed(QObject* o); void internalUpdate(); void display(); + void slotSettingsChanged(); private: QBitmap m_mask; @@ -108,7 +109,6 @@ private: QTimer m_timer; QTimer m_frameTimer; bool m_dirty; - bool m_toolTipsEnabled; const QWidget* m_tippingFor; --- libkicker/panelbutton.cpp (revision 755866) +++ libkicker/panelbutton.cpp (revision 774644) @@ -42,6 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE #include #include #include +#include #include "global.h" @@ -65,6 +66,7 @@ PanelButton::PanelButton( QWidget* paren 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) @@ -184,6 +186,12 @@ void PanelButton::setPopupDirection(KPan setArrowDirection(KickerLib::directionToPopupPosition(d)); } +void PanelButton::setIconAlignment(AlignmentFlags align) +{ + m_iconAlignment = align; + update(); +} + void PanelButton::setOrientation(Orientation o) { m_orientation = o; @@ -298,7 +306,9 @@ int PanelButton::widthForHeight(int heig int PanelButton::heightForWidth(int width) const { - return preferredDimension(width); + int rc=preferredDimension(width); + + return rc; } const QPixmap& PanelButton::labelIcon() const @@ -550,11 +560,16 @@ void PanelButton::drawButtonLabel(QPaint 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(); QFont f = font(); @@ -623,8 +638,11 @@ void PanelButton::drawButtonLabel(QPaint } 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); } @@ -786,7 +804,19 @@ void PanelButton::loadIcons() QString 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") + { + QString pth = locate( "data", "kicker/pics/kmenu_basic.mng" ); + if (!pth.isEmpty()) + { + m_icon = QImage(pth); + m_iconh = QPixmap(m_icon); + m_iconz = QPixmap(m_icon); + return; + } + } + else + m_icon = ldr->loadIcon(nm, KIcon::Panel, m_size, defaultState, 0L, true); if (m_icon.isNull()) { @@ -851,7 +881,7 @@ PanelPopupButton::PanelPopupButton(QWidg connect(this, SIGNAL(pressed()), SLOT(slotExecMenu())); } -void PanelPopupButton::setPopup(QPopupMenu *popup) +void PanelPopupButton::setPopup(QWidget *popup) { if (m_popup) { @@ -869,7 +899,7 @@ void PanelPopupButton::setPopup(QPopupMe } } -QPopupMenu *PanelPopupButton::popup() const +QWidget *PanelPopupButton::popup() const { return m_popup; } @@ -948,7 +978,9 @@ void PanelPopupButton::slotExecMenu() } m_popup->adjustSize(); - m_popup->exec(KickerLib::popupPosition(popupDirection(), m_popup, this)); + if(dynamic_cast(m_popup)) + static_cast(m_popup)->exec(KickerLib::popupPosition(popupDirection(), m_popup, this)); + // else.. hmm. some derived class has to fix it. } void PanelPopupButton::menuAboutToHide() @@ -958,8 +990,10 @@ void PanelPopupButton::menuAboutToHide() return; } - setDown(false); - KickerTip::enableTipping(true); + if (isDown()) { + setDown(false); + KickerTip::enableTipping(true); + } } void PanelPopupButton::triggerDrag() @@ -977,3 +1011,5 @@ void PanelPopupButton::setInitialized(bo m_initialized = initialized; } + + --- extensions/kasbar/kasbar.cpp (revision 755866) +++ extensions/kasbar/kasbar.cpp (revision 774644) @@ -719,7 +719,7 @@ void KasBar::addTestItems() i->setText( "Animated" ); i->setIcon( KGlobal::iconLoader()->loadIcon( "icons", KIcon::NoGroup, KIcon::SizeMedium ) ); i->setAnimation( resources()->startupAnimation() ); - QTimer *aniTimer = new QTimer( i ); + QTimer *aniTimer = new QTimer( i, "aniTimer" ); connect( aniTimer, SIGNAL( timeout() ), i, SLOT( advanceAnimation() ) ); aniTimer->start( 100 ); i->setShowAnimation( true ); --- extensions/kasbar/kasclockitem.cpp (revision 755866) +++ extensions/kasbar/kasclockitem.cpp (revision 774644) @@ -38,7 +38,7 @@ KasClockItem::KasClockItem( KasBar *pare { setCustomPopup( true ); - QTimer *t = new QTimer( this ); + QTimer *t = new QTimer( this, "t" ); connect( t, SIGNAL( timeout() ), SLOT( updateTime() ) ); t->start( 1000 ); --- extensions/kasbar/kasstartupitem.cpp (revision 755866) +++ extensions/kasbar/kasstartupitem.cpp (revision 774644) @@ -79,7 +79,7 @@ KasStartupItem::KasStartupItem( KasBar * setShowFrame( false ); setAnimation( resources()->startupAnimation() ); - aniTimer = new QTimer( this ); + aniTimer = new QTimer( this, "aniTimer" ); connect( aniTimer, SIGNAL( timeout() ), SLOT( aniTimerFired() ) ); aniTimer->start( 100 ); } --- extensions/kasbar/kasloaditem.cpp (revision 755866) +++ extensions/kasbar/kasloaditem.cpp (revision 774644) @@ -33,7 +33,7 @@ KasLoadItem::KasLoadItem( KasBar *parent ) : KasItem( parent ) { - QTimer *t = new QTimer( this ); + QTimer *t = new QTimer( this, "KasLoadItem::t" ); connect( t, SIGNAL( timeout() ), SLOT( updateDisplay() ) ); t->start( 1000 ); updateDisplay(); --- kicker/plugins/beaglesearch.cpp (revision 0) +++ kicker/plugins/beaglesearch.cpp (revision 774644) @@ -0,0 +1,362 @@ +/***************************************************************** + + Copyright (c) 2006 Debajyoti Bera + + 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 +#include +#include +#include +#include + +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; + QDictIterator it (property_map); + for( ; it.current(); ++it ) + ((QStringList *)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; + QString key = QString::fromUtf8 (beagle_property_get_key (property)); + if (! property_map [key]) + property_map.insert (key, new QStringList ()); + property_map [key]->append (QString::fromUtf8 (beagle_property_get_value (property))); + } + g_slist_free (prop_list); +} + +const QString Hit::operator[] (QString prop_name) +{ + if (! processed) + processProperties (); + + QStringList *prop_list = property_map [prop_name]; + if (! prop_list) + return QString::null; + if (prop_list->count () != 1) + return QString::null; + return (QString)prop_list->first (); +} + +// ---------------- BeagleSearch ------------------ + +BeagleSearchResult::BeagleSearchResult(int client_id) + : client_id (client_id), total (0) +{ + hitlist = new QPtrList; + hitlist->setAutoDelete (true); +} + + +BeagleSearchResult::~BeagleSearchResult() +{ + // everything is set to autodelete +} + +void BeagleSearchResult::addHit(BeagleHit *_hit) +{ + Hit *hit = new Hit (_hit); + hitlist->prepend (hit); +} + +const QPtrList *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; + + QTime 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; + + QCustomEvent *ev; + if (collate_results) { + result->query_msec = query_timer.elapsed (); + + ev = new QCustomEvent (RESULTFOUND, result); + QApplication::postEvent (object, ev); + } + + ev = new QCustomEvent (KILLME, this); + QApplication::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; + QCustomEvent *ev = new QCustomEvent (RESULTFOUND, search_result); + g_print ("[%ld] event notified \n", time (NULL)); + QApplication::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; + QObject* 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) { + QCustomEvent *ev = new QCustomEvent (SEARCHOVER, bsclient); + g_print ("[%ld] query finish notified \n", time (NULL)); + QApplication::postEvent (receiver, ev); + } +} + +// ----------------- BeagleUtil ------------------- + +BeagleQuery * +BeagleUtil::createQueryFromString (QString query_str, + QStringList &sources_menu, + QStringList &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 ( QStringList::Iterator it = sources_menu.begin(); it != sources_menu.end(); ++it ) + beagle_query_add_source (beagle_query, g_strdup ((*it).utf8 ())); + + for ( QStringList::Iterator it = types_menu.begin(); it != types_menu.end(); ++it ) + beagle_query_add_hit_type (beagle_query, g_strdup ((*it).utf8 ())); + + QStringList query_terms; + QString start_date, end_date; + QStringList words = QStringList::split (' ', query_str, false); + for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) { + QStringList key_value_pair = QStringList::split ('=', *it, false); + if (key_value_pair.count () == 1) + query_terms += *it; + else if (key_value_pair.count () == 2) { + QString key = key_value_pair [0].lower (); + QString 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(QString 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 (QDateTime::currentDateTime ().toTime_t ()); + //QDateTime dt = QDateTime::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); +} + --- kicker/plugins/kickoff-beagle-plugin.cpp (revision 0) +++ kicker/plugins/kickoff-beagle-plugin.cpp (revision 774644) @@ -0,0 +1,499 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner * + * Copyright (c) 2006 Debajyoti Bera * + * * + * 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 +#include + +#include +#include +#include +#include + +QString dc_identifier = "dc:identifier"; +QString dc_title = "dc:title"; +QString parent_dc_title = "parent:dc:title"; +QString exactfilename = "beagle:ExactFilename"; +QString fixme_name = "fixme:Name"; +QString beagle_filename = "beagle:Filename"; +QString fixme_attachment_title = "fixme:attachment_title"; +QString fixme_hasattachments = "fixme:hasAttachments"; +QString parent_prefix = "parent:"; +QString fixme_folder = "fixme:folder"; +QString fixme_categories = "fixme:Categories"; +QString fixme_comment = "fixme:Comment"; +QString fixme_width = "fixme:width"; +QString fixme_height = "fixme:height"; +QString fixme_from_address = "fixme:from_address"; +QString fixme_artist = "fixme:artist"; +QString fixme_album = "fixme:album"; +QString dc_source = "dc:source"; +QString dc_publisher = "dc:publisher"; +QString digikam_tag = "digikam:Tag"; +QString fixme_speakingto = "fixme:speakingto"; +QString fixme_starttime = "fixme:starttime"; +QString comma_string = ","; +QString vCard_FN = "vCard:FN"; +QString vCard_PREFEMAIL = "vCard:PREFEMAIL"; +QString fixme_uid = "fixme:uid"; + +static CATEGORY getHitCategory (Hit *hit) +{ + QString hittype = hit->getType(); + QString 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 + QString 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( "kickoffsearch_beagle" ) ) + +KickoffBeaglePlugin::KickoffBeaglePlugin(QObject *parent, const char* name, const QStringList&) + : 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(QString 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; + } + + QStringList 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 (QCustomEvent *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 (); + QTimer::singleShot (500, this, SLOT (cleanClientList ())); + } + } +} + +// this method decides what to display in the result list +HitMenuItem *KickoffBeaglePlugin::hitToHitMenuItem (int category, Hit *hit) +{ + QString title, info, mimetype, icon; + int score = 0; + KURL uri; + +#if 0 + kdDebug() << "*** " << hit->getUri() << endl; + QDict all = hit->getAllProperties(); + QDictIterator it( all ); + for( ; it.current(); ++it ) + kdDebug() << it.currentKey() << ": " << *(it.current()) << endl; +#endif + + switch (category) { + case FILES: + { + uri = hit->getUri (); + QString 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: + { + QString prefix = QString::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] == QString::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]; + { + QString artist = (*hit) [fixme_artist]; + QString 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 { + QString 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]; + { + QString 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(QRegExp("\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"; + QString publisher = (*hit) [dc_publisher]; + QString source = (*hit) [dc_source]; + if (! publisher.isEmpty ()) + info = publisher; + else if (! source.isEmpty ()) + info = source; + } + break; + case PICS: + { + uri = hit->getUri (); + title = (*hit) [exactfilename]; + QString width = (*hit) [fixme_width]; + QString height = (*hit) [fixme_height]; + if (width.isEmpty () || height.isEmpty ()) { + QString uristr = uri.path (); + int last_slash = uristr.findRev ('/', -1); + info = i18n("Folder: %1") + .arg(last_slash == 0 ? "/" : uristr.section ('/', -2, -2)); + break; + } + info = (QString (" (%1x%2)").arg (width).arg (height)); + const QStringList *tags = hit->getProperties (digikam_tag); + if (tags == NULL) + break; + QString 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(); + QString input = current_query_str.lower(); + QString 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); + QDateTime 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 { + QString 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 QPtrList *hits = result->getHits(); + if (hits == NULL) { + kdDebug () << "Hmm... null" << endl; + delete result; + return; + } + kickoffSearchInterface()->initCategoryTitlesUpdate(); + + QPtrListIterator 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; +} + +QDateTime KickoffBeaglePlugin::datetimeFromString( const QString& 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 QDateTime(QDate(year,month,day),QTime(hour,min,sec)); +} + +#include "kickoff-beagle-plugin.moc" --- kicker/plugins/Makefile.am (revision 0) +++ kicker/plugins/Makefile.am (revision 774644) @@ -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 --- kicker/plugins/kickoffsearch_beagle.desktop (revision 0) +++ kicker/plugins/kickoffsearch_beagle.desktop (revision 774644) @@ -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 --- kicker/plugins/beaglesearch.h (revision 0) +++ kicker/plugins/beaglesearch.h (revision 774644) @@ -0,0 +1,234 @@ +/***************************************************************** + + Copyright (c) 2006 Debajyoti Bera + + 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 +#include +#include +#include +#include + +#include +#include + +extern "C" { +#include +#include +} + +// 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 (QEvent::Type)1001 /* QEvent::User + 1 */ +#define SEARCHOVER (QEvent::Type)1002 /* QEvent::User + 2 */ +#define KILLME (QEvent::Type)1003 /* QEvent::User + 3 */ + +class QStringList; + +// 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 (QString::fromUtf8 (beagle_hit_get_uri (hit)));} + const QString getType () const { return QString::fromUtf8 (beagle_hit_get_type (hit));} + const QString getMimeType () const { return QString::fromUtf8 (beagle_hit_get_mime_type (hit));} + const QString getSource () const { return QString::fromUtf8 (beagle_hit_get_source (hit));} + const KURL getParentUri () const { return KURL (QString::fromUtf8 (beagle_hit_get_parent_uri (hit)));} + const QDict& getAllProperties () + { + if (! processed) + processProperties (); + return property_map; + } + const QStringList* getProperties (QString prop_name) + { + if (! processed) + processProperties (); + return property_map [prop_name]; + } + const QString operator[] (QString prop_name); + +private: + BeagleHit *hit; + QDict 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); + QString 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 QPtrList *getHits () const; + +private: + // lists of hits + QPtrList *hitlist; +}; + +// caller should delete bsclient->result and bsclient +class BeagleSearchClient : public QThread { +public: + // passing NULL for client makes bsclient create client itself and + // delete it later + BeagleSearchClient (int id, + QObject *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 QMutex (); + } + + // 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 + QObject *object; + // mutex to control setting the kill_me shared variable + QMutex *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 (QString query_str, + QStringList &sources, + QStringList &types, + int max_hits_per_source = 100); + static BeagleTimestamp *timestringToBeagleTimestamp (QString timestring); +}; + +#endif --- kicker/plugins/kickoff-beagle-plugin.h (revision 0) +++ kicker/plugins/kickoff-beagle-plugin.h (revision 774644) @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner * + * Copyright (c) 2006 Debajyoti Bera * + * * + * 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(QObject *parent, const char* name, const QStringList&); + + void query(QString, bool); + bool daemonRunning(); + +protected slots: + // to clean beaglesearchclients + void cleanClientList (); + +private: + QString 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 (QCustomEvent *e); + + QPtrList toclean_client_list; + QMutex 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; + QDateTime datetimeFromString( const QString& ); +}; + +#endif /* CAPITALIZEPLUGIN_H */ Property changes on: kicker/plugins ___________________________________________________________________ Added: svn:ignore + .deps kickoffsearch_beagle.la .libs Makefile Makefile.in *.moc --- kicker/interfaces/kickoff-search-plugin.h (revision 0) +++ kicker/interfaces/kickoff-search-plugin.h (revision 774644) @@ -0,0 +1,106 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner * + * Copyright (c) 2006 Debajyoti Bera * + * * + * 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 +#include +#include + +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 (QString name, QString info, KURL uri, QString mimetype, int id, int category, QString icon=QString::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 + QString display_name; // name to display + QString display_info; // other information to display + KURL uri; // uri to open when clicked + QString mimetype; + int id; // id of the item in the menu + int category; + QString icon; + int score; + KService::Ptr service; + + QString quotedPath () const + { + return uri.path ().replace ('"', "\\\""); + } +}; + +namespace KickoffSearch { + + class Plugin : public QObject + { + Q_OBJECT + + public: + Plugin(QObject *parent, const char* name=0); + virtual ~Plugin(); + + virtual bool daemonRunning()=0; + virtual void query(QString,bool)=0; + + KickoffSearchInterface * kickoffSearchInterface(); + }; +}; + +#endif /* KICKOFF_SEARCH_PLUGIN_H */ --- kicker/interfaces/kickoffsearchinterface.cpp (revision 0) +++ kicker/interfaces/kickoffsearchinterface.cpp (revision 774644) @@ -0,0 +1,27 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner * + * * + * 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( QObject* parent, const char* name ) + :QObject( parent, name ) +{ +} + +#include "kickoffsearchinterface.moc" --- kicker/interfaces/Makefile.am (revision 0) +++ kicker/interfaces/Makefile.am (revision 774644) @@ -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 --- kicker/interfaces/kickoffsearchinterface.h (revision 0) +++ kicker/interfaces/kickoffsearchinterface.h (revision 774644) @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner * + * * + * 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 + +class HitMenuItem; + +namespace KickoffSearch +{ + class KickoffSearchInterface :public QObject + { + Q_OBJECT + + public: + KickoffSearchInterface( QObject* 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 */ + --- kicker/interfaces/kickoffsearchplugin.desktop (revision 0) +++ kicker/interfaces/kickoffsearchplugin.desktop (revision 774644) @@ -0,0 +1,4 @@ +[Desktop Entry] +Type=ServiceType +X-KDE-ServiceType=KickoffSearch/Plugin +Comment=A search plugin for Kickoff --- kicker/interfaces/kickoff-search-plugin.cpp (revision 0) +++ kicker/interfaces/kickoff-search-plugin.cpp (revision 774644) @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2006 by Stephan Binner * + * * + * 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 + +KickoffSearch::Plugin::Plugin(QObject *parent, const char* name ) + :QObject( parent, name ) +{ +} + +KickoffSearch::Plugin::~Plugin() +{ +} + +KickoffSearch::KickoffSearchInterface* KickoffSearch::Plugin::kickoffSearchInterface() +{ + return static_cast( parent()->child( 0, "KickoffSearch::KickoffSearchInterface" ) ); +} + +#include "kickoff-search-plugin.moc" Property changes on: kicker/interfaces ___________________________________________________________________ Added: svn:ignore + .deps libkickoffsearch_interfaces.la .libs Makefile Makefile.in *.moc --- kicker/core/menumanager.h (revision 755866) +++ kicker/core/menumanager.h (revision 774644) @@ -28,7 +28,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE #include class PanelKMenu; +class KMenu; class KickerClientMenu; +class KMenuStub; class PanelPopupButton; typedef QValueList KButtonList; @@ -50,13 +52,12 @@ public: bool process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &reply); // KMenu controls - PanelKMenu* kmenu() { return m_kmenu; } - void showKMenu(); + KMenuStub* kmenu() { return m_kmenu; } void popupKMenu(const QPoint &p); void registerKButton(PanelPopupButton *button); void unregisterKButton(PanelPopupButton *button); - PanelPopupButton* findKButtonFor(QPopupMenu* menu); + PanelPopupButton* findKButtonFor(QWidget* menu); ~MenuManager(); public slots: @@ -67,7 +68,7 @@ protected slots: void applicationRemoved(const QCString&); protected: - PanelKMenu* m_kmenu; + KMenuStub* m_kmenu; typedef QValueList ClientMenuList; ClientMenuList clientmenus; --- kicker/core/kicker.cpp (revision 755866) +++ kicker/core/kicker.cpp (revision 774644) @@ -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"); @@ -206,7 +209,7 @@ bool Kicker::highlightMenuItem(const QSt void Kicker::showKMenu() { - MenuManager::the()->showKMenu(); + MenuManager::the()->kmenuAccelActivated(); } void Kicker::popupKMenu(const QPoint &p) --- kicker/core/container_button.cpp (revision 755866) +++ kicker/core/container_button.cpp (revision 774644) @@ -43,6 +43,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE #include "desktopbutton.h" #include "extensionbutton.h" #include "kbutton.h" +#include "knewbutton.h" #include "kicker.h" #include "kickerSettings.h" #include "kickertip.h" @@ -367,14 +368,20 @@ KMenuButtonContainer::KMenuButtonContain : 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(QPopupMenu *opMenu, QWidget* parent) : ButtonContainer(opMenu, parent) { - embedButton( new KButton(this) ); + if(KickerSettings::legacyKMenu()) + embedButton( new KButton(this) ); + else + embedButton( new KNewButton(this) ); _actions = PanelAppletOpMenu::KMenuEditor; } --- kicker/core/main.cpp (revision 755866) +++ kicker/core/main.cpp (revision 774644) @@ -108,7 +108,7 @@ extern "C" KDE_EXPORT int kdemain( int a 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-2004, The KDE Team") ); aboutData.addAuthor("Aaron J. Seigo", I18N_NOOP("Current maintainer"), "aseigo@kde.org"); --- kicker/core/menumanager.cpp (revision 755866) +++ kicker/core/menumanager.cpp (revision 774644) @@ -31,9 +31,12 @@ CONNECTION WITH THE SOFTWARE OR THE USE #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(QObject *parent) : QObject(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(), SIGNAL(applicationRemoved(const QCString&)), this, SLOT(applicationRemoved(const QCString&))); @@ -83,14 +90,8 @@ void MenuManager::slotSetKMenuItemActive m_kmenu->selectFirstItem(); } -void MenuManager::showKMenu() -{ - m_kmenu->showMenu(); -} - void MenuManager::popupKMenu(const QPoint &p) { -// kdDebug(1210) << "popupKMenu()" << endl; if (m_kmenu->isVisible()) { m_kmenu->hide(); @@ -120,7 +121,7 @@ void MenuManager::unregisterKButton(Pane m_kbuttons.remove(button); } -PanelPopupButton* MenuManager::findKButtonFor(QPopupMenu* menu) +PanelPopupButton* MenuManager::findKButtonFor(QWidget* menu) { KButtonList::const_iterator itEnd = m_kbuttons.constEnd(); for (KButtonList::const_iterator it = m_kbuttons.constBegin(); it != itEnd; ++it) @@ -169,7 +170,7 @@ void MenuManager::kmenuAccelActivated() const QSize 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 @@ -189,7 +190,6 @@ void MenuManager::kmenuAccelActivated() menuParent = menuParent->parent(); } - button->showMenu(); } } @@ -213,7 +213,7 @@ QCString MenuManager::createMenu(QPixmap void MenuManager::removeMenu(QCString menu) { - bool iterate = true; + bool iterate = true, need_adjustSize = false; ClientMenuList::iterator it = clientmenus.begin(); for (; it != clientmenus.end(); iterate ? ++it : it) { @@ -224,15 +224,17 @@ void MenuManager::removeMenu(QCString me 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 QCString& appRemoved) { - bool iterate = true; + bool iterate = true, need_adjustSize = false; ClientMenuList::iterator it = clientmenus.begin(); for (; it != clientmenus.end(); iterate ? ++it : it) { @@ -243,9 +245,11 @@ void MenuManager::applicationRemoved(con 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 QCString &fun, const QByteArray &data, --- kicker/core/unhidetrigger.cpp (revision 755866) +++ kicker/core/unhidetrigger.cpp (revision 774644) @@ -39,7 +39,7 @@ UnhideTrigger::UnhideTrigger() , _lastXineramaScreen( -1 ) , enabledCount( 0 ) { - _timer = new QTimer( this ); + _timer = new QTimer( this, "UnhideTrigger" ); connect( _timer, SIGNAL(timeout()), SLOT(pollMouse()) ); } --- kicker/core/applethandle.cpp (revision 755866) +++ kicker/core/applethandle.cpp (revision 774644) @@ -196,7 +196,7 @@ void AppletHandle::setFadeOutHandle(bool { if (!m_handleHoverTimer) { - m_handleHoverTimer = new QTimer(this); + m_handleHoverTimer = new QTimer(this, "m_handleHoverTimer"); connect(m_handleHoverTimer, SIGNAL(timeout()), this, SLOT(checkHandleHover())); m_applet->installEventFilter(this); @@ -223,11 +223,7 @@ bool AppletHandle::eventFilter(QObject * m_drawHandle = true; resetLayout(); - if (m_handleHoverTimer) - { - m_handleHoverTimer->start(250); - } - break; + break; } case QEvent::Leave: @@ -237,6 +233,11 @@ bool AppletHandle::eventFilter(QObject * break; } + if (m_handleHoverTimer) + { + m_handleHoverTimer->start(250); + } + QWidget* w = dynamic_cast(o); bool nowDrawIt = false; @@ -253,11 +254,6 @@ bool AppletHandle::eventFilter(QObject * if (nowDrawIt != m_drawHandle) { - if (m_handleHoverTimer) - { - m_handleHoverTimer->stop(); - } - m_drawHandle = nowDrawIt; resetLayout(); } @@ -345,6 +341,11 @@ void AppletHandle::toggleMenuButtonOff() m_menuButton->setOn(false); m_menuButton->setDown(false); + + if (m_handleHoverTimer) + { + m_handleHoverTimer->start(250); + } } QPixmap AppletHandle::xpmPixmap( const char* const xpm[], const char* _key ) --- kicker/core/containerarea.cpp (revision 755866) +++ kicker/core/containerarea.cpp (revision 774644) @@ -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 ); viewport()->setBackgroundOrigin( AncestorOrigin ); --- kicker/core/Makefile.am (revision 755866) +++ kicker/core/Makefile.am (revision 774644) @@ -1,6 +1,6 @@ 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 --- kicker/Makefile.am (revision 755866) +++ kicker/Makefile.am (revision 774644) @@ -1,6 +1,6 @@ INCLUDES = $(all_includes) -SUBDIRS = core ui buttons . +SUBDIRS = core ui buttons interfaces plugins . bin_PROGRAMS = lib_LTLIBRARIES = @@ -9,7 +9,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) --- kicker/ui/browser_mnu.cpp (revision 755866) +++ kicker/ui/browser_mnu.cpp (revision 774644) @@ -329,7 +329,7 @@ void PanelBrowserMenu::initialize() if(_mimemap.count() > 0) { if(!_mimecheckTimer) - _mimecheckTimer = new QTimer(this); + _mimecheckTimer = new QTimer(this, "_mimecheckTimer"); connect(_mimecheckTimer, SIGNAL(timeout()), SLOT(slotMimeCheck())); _mimecheckTimer->start(0); --- kicker/ui/flipscrollview.cpp (revision 0) +++ kicker/ui/flipscrollview.cpp (revision 774644) @@ -0,0 +1,324 @@ +/***************************************************************** + +Copyright (c) 2006 Will Stephenson + +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 +#include +#include +#include + +#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( QWidget *parent ) + : QFrame( parent ), mouse_inside( false ) +{ + setFrameStyle( QFrame::NoFrame ); + if ( QApplication::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( QPainter *p ) +{ + QColor gray( 230, 230, 230 ); + if ( mouse_inside ) + p->fillRect( 3, 3, width() - 6, height() - 6, colorGroup().color( QColorGroup::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; + QImage i = left_triangle.convertToImage().smoothScale( pixsize, pixsize ); + QPixmap tri; + tri.convertFromImage( i ); + + p->drawPixmap( ( width() - tri.width() ) / 2, ( height() - tri.height() ) / 2, tri ); +} + +void BackFrame::enterEvent( QEvent *e ) +{ + mouse_inside = true; + update(); +} + +void BackFrame::leaveEvent( QEvent *e ) +{ + mouse_inside = false; + update(); +} + +void BackFrame::mousePressEvent ( QMouseEvent * e ) +{ + emit clicked(); +} + +FlipScrollView::FlipScrollView( QWidget * parent, const char * name ) + : QScrollView( parent, name ), mState( StoppedLeft ), mScrollDirection( 1 ), mShowBack( false ) +{ + setVScrollBarMode( QScrollView::AlwaysOff ); + setHScrollBarMode( QScrollView::AlwaysOff ); + setFrameStyle( QFrame::NoFrame ); + mLeftView = new ItemView( this, "left_view" ); + addChild( mLeftView ); + + mRightView = new ItemView( this, "right_view" ); + addChild( mRightView ); + + mTimer = new QTimer( this, "mTimer" ); + connect( mTimer, SIGNAL( timeout() ), SLOT( slotScrollTimer() ) ); + + connect( mLeftView, SIGNAL( startService(KService::Ptr) ), + SIGNAL( startService(KService::Ptr) ) ); + connect( mLeftView, SIGNAL( startURL(const QString& ) ), + SIGNAL( startURL(const QString& ) ) ); + connect( mLeftView, SIGNAL( rightButtonPressed(QListViewItem*,const QPoint&,int) ), + SIGNAL( rightButtonPressed(QListViewItem*,const QPoint&,int) ) ); + connect( mRightView, SIGNAL( startService(KService::Ptr) ), + SIGNAL( startService(KService::Ptr) ) ); + connect( mRightView, SIGNAL( startURL(const QString& ) ), + SIGNAL( startURL(const QString& ) ) ); + connect( mRightView, SIGNAL( rightButtonPressed(QListViewItem*,const QPoint&,int) ), + SIGNAL( rightButtonPressed(QListViewItem*,const QPoint&,int) ) ); + + // wild hack to make sure it has correct width + mLeftView->setVScrollBarMode( QScrollView::AlwaysOn ); + mRightView->setVScrollBarMode( QScrollView::AlwaysOn ); + mLeftView->setVScrollBarMode( QScrollView::Auto ); + mRightView->setVScrollBarMode( QScrollView::Auto ); + + mBackrow = new BackFrame( this ); + mBackrow->resize( 24, 100 ); + connect( mBackrow, SIGNAL( clicked() ), 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 ( QResizeEvent * ) +{ + 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 ( QApplication::reverseLayout() ) + moveChild( mRightView, width(), 0 ); + else + moveChild( mRightView, width() + mBackrow->width(), 0 ); + mRightView->resize( width() - mBackrow->width(), height() ); + mLeftView->resize( width(), height() ); + if ( QApplication::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 ( QApplication::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 { + QListViewItem * child = currentView()->firstChild(); + while( child ) { + KMenuItem* kitem = dynamic_cast(child); + if (kitem && kitem->menuPath()==mSelectMenuPath) { + currentView()->setSelected(child,true); + kdDebug() << "child repaint\n"; + child->repaint(); + break; + } + child = child->nextSibling(); + } + } + } + mLeftView->setVScrollBarMode( QScrollView::Auto ); + mRightView->setVScrollBarMode( QScrollView::Auto ); + mTimer->stop(); + mLeftView->setMouseMoveSelects( true ); + mRightView->setMouseMoveSelects( true ); + } +} + +void FlipScrollView::flipScroll(const QString& selectMenuPath) +{ + if ( mState == StoppedLeft ) + { + mState = ScrollingRight; + mScrollDirection = 1; + } + else + { + mState = ScrollingLeft; + mScrollDirection = -1; + } + + mLeftView->setVScrollBarMode( QScrollView::AlwaysOff ); + mRightView->setVScrollBarMode( QScrollView::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" --- kicker/ui/query.cpp (revision 0) +++ kicker/ui/query.cpp (revision 774644) @@ -0,0 +1,136 @@ +/***************************************************************** + + Copyright (c) 2006 Stephan Binner + + 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 + +Query::Query() +{ + alternatives.setAutoDelete(true); +} + +void Query::clear() +{ + query_term = QString::null; + alternatives.clear(); +} + +void Query::set(const QString &term) +{ + query_term = term; + alternatives.clear(); + + current_alternative = new Alternative; + current_part = QString::null; + within_quotes = false; + exclude_part = false; + + for (uint index=0;indexexcludes+=current_part.lower(); + else + current_alternative->includes+=current_part.lower(); + } + within_quotes = false; + exclude_part = false; + current_part = QString::null; +} + +QString Query::get() const +{ + return query_term; +} + +bool Query::matches(const QString &term) +{ + QString lower_term = term.lower(); + + for (Alternative* alt=alternatives.first(); alt; alt=alternatives.next()) { + if (!alt->includes.count()) + continue; + + bool next_alternative = false; + + for ( QStringList::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 ( QStringList::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; +} --- kicker/ui/k_new_mnu.cpp (revision 0) +++ kicker/ui/k_new_mnu.cpp (revision 774644) @@ -0,0 +1,3779 @@ +/***************************************************************** + + Copyright (c) 1996-2000 the kicker authors. See file AUTHORS. + Copyright (c) 2006 Debajyoti Bera + Copyright (c) 2006 Dirk Mueller + + 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include + +#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 QString calculate(const QString &exp) +{ + QString result, cmd; + const QString bc = KStandardDirs::findExe("bc"); + if ( !bc.isEmpty() ) + cmd = QString("echo %1 | %2").arg(KProcess::quote(exp), KProcess::quote(bc)); + else + cmd = QString("echo $((%1))").arg(exp); + FILE *fs = popen(QFile::encodeName(cmd).data(), "r"); + if (fs) + { + QTextStream ts(fs, IO_ReadOnly); + result = ts.read().stripWhiteSpace(); + pclose(fs); + } + return result; +} + +static QString workaroundStringFreeze(const QString& str) +{ + QString s = str; + + s.replace("","&"); + QRegExp 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 + +static int used_size( QLabel *label, int oldsize ) +{ + QSimpleRichText 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(QString::null), m_orientation(UnDetermined), m_search_plugin( 0 ) +{ + setMouseTracking(true); + connect(&m_sloppyTimer, SIGNAL(timeout()), 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(), SIGNAL(configurationChanged()), + this, 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 %1 on %2" ) + .arg( user->loginName() ).arg( hostname ) ); + setupUi(); + + m_userInfo->setBackgroundMode( PaletteBase ); + QColor userInfoColor = QApplication::palette().color( QPalette::Normal, QColorGroup::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, SIGNAL(tabClicked(QTab*)), SLOT(tabClicked(QTab*))); + + const int tab_icon_size = 32; + + m_tabs[FavoriteTab] = new QTab; + m_tabBar->addTab(m_tabs[FavoriteTab]); + m_tabBar->setToolTip(FavoriteTab, "" + i18n( "Most commonly used applications and documents" ) + "" ); + m_tabs[ApplicationsTab] = new QTab; + m_tabBar->addTab(m_tabs[ApplicationsTab]); + m_tabBar->setToolTip(ApplicationsTab, "" + i18n( "List of installed applications" ) + + "" ); + + m_tabs[ComputerTab] = new QTab; + m_tabBar->addTab(m_tabs[ComputerTab]); + m_tabBar->setToolTip(ComputerTab, "" + i18n( "Information and configuration of your " + "system, access to personal files, network resources and connected disk drives") + + ""); +#if 0 + m_tabs[SearchTab] = new QTab; + m_tabBar->addTab(m_tabs[SearchTab]); +#endif + m_tabs[HistoryTab] = new QTab; + m_tabBar->addTab(m_tabs[HistoryTab]); + m_tabBar->setToolTip(HistoryTab, "" + i18n( "Recently used applications and documents" ) + + "" ); + m_tabs[LeaveTab] = new QTab; + m_tabBar->addTab(m_tabs[LeaveTab]); + m_tabBar->setToolTip(LeaveTab, i18n("Logout, switch user, switch off or reset," + " suspend of the system" ) + "" ); + + if (KickerSettings::kickoffTabBarFormat() != KickerSettings::IconOnly) { + m_tabs[FavoriteTab]->setText(workaroundStringFreeze(i18n("

Favorites

"))); + m_tabs[HistoryTab]->setText(workaroundStringFreeze(i18n("

History

"))); + m_tabs[ComputerTab]->setText( + workaroundStringFreeze(i18n("

Computer

"))); + m_tabs[ApplicationsTab]->setText(workaroundStringFreeze(i18n("

Applications

"))); + m_tabs[LeaveTab]->setText( + workaroundStringFreeze(i18n("

Leave

"))); + } + + 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, SIGNAL(selected(int)), m_stacker, SLOT(raiseWidget(int))); + connect(m_stacker, SIGNAL(aboutToShow(int)), m_tabBar, 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, SIGNAL( backButtonClicked() ), SLOT( slotGoBack() ) ); + + m_exitView = new FlipScrollView(m_stacker, "m_exitView"); + m_stacker->addWidget(m_exitView, LeaveTab); + connect( m_exitView, SIGNAL( backButtonClicked() ), SLOT( slotGoExitMainMenu() ) ); + + m_searchWidget = new QVBox (m_stacker, "m_searchWidget"); + m_searchWidget->setSpacing(0); + m_stacker->addWidget(m_searchWidget, 5); + + // search provider icon + QPixmap icon; + KURIFilterData data; + QStringList list; + data.setData( QString("some keyword") ); + list << "kurisearchfilter" << "kuriikwsfilter"; + + if ( KURIFilter::self()->filterURI(data, list) ) { + QString iconPath = locate("cache", KMimeType::favIconForURL(data.uri()) + ".png"); + if ( iconPath.isEmpty() ) + icon = SmallIcon("enhanced_browsing"); + else + icon = QPixmap( 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(QWidget::NoFocus); + m_searchActions->setItemMargin(4); + m_searchInternet = new QListViewItem(m_searchActions, i18n("Search Internet")); + m_searchInternet->setPixmap(0,icon); + setTabOrder(m_kcommand, m_searchResultsWidget); + + m_kerryInstalled = !KStandardDirs::findExe(QString::fromLatin1("kerry")).isEmpty(); + m_isShowing = false; + + if (!m_kerryInstalled) { + m_searchIndex = 0; + m_searchActions->setMaximumHeight(5+m_searchInternet->height()); + } + else { + m_searchIndex = new QListViewItem(m_searchActions, i18n("Search Index")); + m_searchIndex->setPixmap(0,SmallIcon("kerry")); + m_searchActions->setMaximumHeight(5+m_searchIndex->height()*2); + } + connect(m_searchActions, SIGNAL(clicked(QListViewItem*)), SLOT(searchActionClicked(QListViewItem*))); + connect(m_searchActions, SIGNAL(returnPressed(QListViewItem*)), SLOT(searchActionClicked(QListViewItem*))); + connect(m_searchActions, SIGNAL(spacePressed(QListViewItem*)), SLOT(searchActionClicked(QListViewItem*))); + + connect(m_searchResultsWidget, SIGNAL(startService(KService::Ptr)), SLOT(slotStartService(KService::Ptr))); + connect(m_searchResultsWidget, SIGNAL(startURL(const QString&)), SLOT(slotStartURL(const QString&))); + connect(m_searchResultsWidget, SIGNAL(rightButtonPressed( QListViewItem*, const QPoint &, int )), SLOT(slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); + + connect(m_recentlyView, SIGNAL(startService(KService::Ptr)), SLOT(slotStartService(KService::Ptr))); + connect(m_recentlyView, SIGNAL(startURL(const QString&)), SLOT(slotStartURL(const QString&))); + connect(m_recentlyView, SIGNAL(rightButtonPressed( QListViewItem*, const QPoint &, int )), SLOT(slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); + + connect(m_favoriteView, SIGNAL(startService(KService::Ptr)), SLOT(slotStartService(KService::Ptr))); + connect(m_favoriteView, SIGNAL(startURL(const QString&)), SLOT(slotStartURL(const QString&))); + connect(m_favoriteView, SIGNAL(rightButtonPressed( QListViewItem*, const QPoint &, int )), SLOT(slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); + connect(m_favoriteView, SIGNAL(moved(QListViewItem*, QListViewItem*, QListViewItem*)), SLOT(slotFavoritesMoved( QListViewItem*, QListViewItem*, QListViewItem* ))); + + connect(m_systemView, SIGNAL(startURL(const QString&)), SLOT(slotStartURL(const QString&))); + connect(m_systemView, SIGNAL(startService(KService::Ptr)), SLOT(slotStartService(KService::Ptr))); + connect(m_systemView, SIGNAL(rightButtonPressed( QListViewItem*, const QPoint &, int )), SLOT(slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); + + connect(m_browserView, SIGNAL(startURL(const QString&)), SLOT(slotGoSubMenu(const QString&))); + connect(m_browserView, SIGNAL(startService(KService::Ptr)), SLOT(slotStartService(KService::Ptr))); + connect(m_browserView, SIGNAL(rightButtonPressed( QListViewItem*, const QPoint &, int )), SLOT(slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); + + connect(m_exitView, SIGNAL(startURL(const QString&)), SLOT(slotStartURL(const QString&))); + connect(m_exitView, SIGNAL(rightButtonPressed( QListViewItem*, const QPoint &, int )), SLOT(slotContextMenuRequested( QListViewItem*, const QPoint &, int ))); + + m_kcommand->setDuplicatesEnabled( false ); + m_kcommand->setLineEdit(new KLineEdit(m_kcommand, "m_kcommand-lineedit")); + m_kcommand->setCompletionMode( KGlobalSettings::CompletionAuto ); + connect(m_kcommand, SIGNAL(cleared()), SLOT(clearedHistory())); + connect(m_kcommand->lineEdit(), SIGNAL(returnPressed()), SLOT(searchAccept())); + connect(m_kcommand->lineEdit(), SIGNAL(textChanged(const QString &)), SLOT(searchChanged(const QString &))); + + // 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 QTimer (this, "input_timer"); + connect( input_timer, SIGNAL(timeout()), this, SLOT(doQuery()) ); + + init_search_timer = new QTimer (this, "init_search_timer"); + connect( init_search_timer, SIGNAL(timeout()), this, SLOT(initSearch()) ); + init_search_timer->start(2000, true); + + connect( m_favoriteView, SIGNAL( dropped (QDropEvent *, QListViewItem * ) ), + SLOT( slotFavDropped( QDropEvent *, QListViewItem * ) ) ); + + 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 = QRegExp("^([\\w\\-]+\\.)*[\\w\\-]+@([\\w\\-]+\\.)*[\\w\\-]+$"); + authRegExp = QRegExp("^[a-zA-Z]+://\\w+(:\\w+)?@([\\w\\-]+\\.)*[\\w\\-]+(:\\d+)?(/.*)?$"); + uriRegExp = QRegExp("^[a-zA-Z]+://([\\w\\-]+\\.)*[\\w\\-]+(:\\d+)?(/.*)?$"); + uri2RegExp = QRegExp("^([\\w\\-]+\\.)+[\\w\\-]+(:\\d+)?(/.*)?$"); + + m_resizeHandle = new QLabel(this); + m_resizeHandle->setBackgroundOrigin( QLabel::ParentOrigin ); + m_resizeHandle->setScaledContents(true); + m_resizeHandle->setFixedSize( 16, 16 ); + m_searchFrame->stackUnder( m_resizeHandle ); + m_isresizing = false; + + m_searchPixmap->setPixmap( BarIcon( "find", 32 ) ); + + QFont 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(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 QWidgetStack( this, "m_stacker" ); + m_stacker->setGeometry( QRect( 90, 260, 320, 220 ) ); + m_stacker->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)3, (QSizePolicy::SizeType)3, 1, 1, m_stacker->sizePolicy().hasHeightForWidth() ) ); + m_stacker->setPaletteBackgroundColor( QColor( 255, 255, 255 ) ); + // m_stacker->setFocusPolicy( QWidget::StrongFocus ); + m_stacker->setLineWidth( 0 ); + m_stacker->setFocusPolicy(QWidget::NoFocus); + connect(m_stacker, SIGNAL(aboutToShow(QWidget*)), SLOT(stackWidgetRaised(QWidget*))); + + m_kcommand->setName("m_kcommand"); +} + +KMenu::~KMenu() +{ + saveConfig(); + + clearSubmenus(); + delete m_filterData; +} + +bool KMenu::eventFilter ( QObject * receiver, QEvent* e) +{ +//kdDebug() << "eventFilter receiver=" << receiver->name() << " type=" << e->type() << endl; + QWidget* raiseWidget = 0; + QRect raiseRect; + + if (e->type() == QEvent::KeyPress || + e->type() == QEvent::MouseButtonPress || + e->type() == QEvent::MouseMove + || e->type() == QEvent::FocusIn + || e->type() == QEvent::Wheel) { + QPoint p; + + if (e->type() == QEvent::MouseMove || e->type() == QEvent::MouseButtonPress) { + QMouseEvent* me = static_cast(e); + p = me->globalPos(); + } + else if (e->type() == QEvent::Wheel) { + QWheelEvent* we = static_cast(e); + p = we->globalPos(); + } + + while (receiver) { + if (receiver == m_tabBar && (e->type()!=QEvent::MouseMove || KickerSettings::kickoffSwitchTabsOnHover() ) ) { + QTab* 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 = QRect( 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() == QEvent::KeyPress || e->type() == QEvent::Wheel + || e->type() == QEvent::MouseButtonPress ) ) ) && + !m_isShowing) { + raiseWidget = m_searchWidget; + raiseRect = QRect( m_searchFrame->mapToGlobal(m_searchFrame->rect().topLeft()), + m_searchFrame->size()); + } + + if(raiseWidget) + break; + if(receiver->isWidgetType()) + receiver = static_cast(receiver)->parentWidget(true); + else + break; + } + + if (e->type() == QEvent::FocusIn && receiver && raiseWidget) { + m_searchResultsWidget->setFocusPolicy(QWidget::StrongFocus); + m_searchActions->setFocusPolicy(raiseWidget == m_searchWidget ? + QWidget::StrongFocus : QWidget::NoFocus); + setTabOrder(raiseWidget, m_searchResultsWidget); + if (raiseWidget != m_stacker->visibleWidget() + && static_cast(receiver)->focusPolicy() == QWidget::NoFocus + && m_stacker->id(raiseWidget) >= 0) { + + m_stacker->raiseWidget(raiseWidget); + return true; + } + + if (raiseWidget->focusPolicy() != QWidget::NoFocus) + return false; + } + + if (m_sloppyRegion.contains(p)) { + if (e->type() == QEvent::MouseButtonPress /*&& m_sloppyTimer.isActive()*/) + m_sloppySourceClicked = true; + + if (!m_sloppyTimer.isActive() || m_sloppySource != raiseRect) { + int timeout= style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay); + if (m_sloppySourceClicked) + timeout = 3000; + m_sloppyTimer.start(timeout); + } + + m_sloppyWidget = raiseWidget; + m_sloppySource = raiseRect; + return false; + } + } + + if(e->type() == QEvent::Enter && receiver->isWidgetType()) { + static_cast(receiver)->setMouseTracking(true); + QToolTip::hide(); + } + + if ( ( e->type() == QEvent::DragEnter || e->type() == QEvent::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() == QEvent::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(m_stacker->visibleWidget()); + + if (view) + { + bool handled = true; + switch (static_cast(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(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(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(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() == QEvent::Wheel && raiseWidget ) + { + // due to an ugly Qt bug we have to kill wheel events + // that cause focus switches + r = true; + } + + if (e->type() == QEvent::Enter && receiver == m_stacker) + { + QRect r(m_stacker->mapToGlobal(QPoint(-8,-32)), m_stacker->size()); + r.setSize(r.size()+QSize(16,128)); + + m_sloppyRegion = QRegion(r); + } + + // redo the sloppy region + if (e->type() == QEvent::MouseMove && !r && raiseWidget) + { + QPointArray points(4); + + // hmm, eventually this should be mouse position + 10px, not + // just worst case. but worst case seems to work fine enough. + QPoint 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+QPoint(+raiseRect.width()/4,0)); + points.setPoint(3, edge+QPoint(-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+QPoint(-raiseRect.width()/4,0)); + points.setPoint(3, edge+QPoint(+raiseRect.width()/4,0)); + } + + m_sloppyRegion = QRegion(points); + } + + return r; +} + +void KMenu::slotSloppyTimeout() +{ + if (m_sloppyRegion.contains(QCursor::pos()) && !m_sloppySource.isNull()) + { + if ( m_sloppySource.contains(QCursor::pos())) + { + m_stacker->raiseWidget(m_sloppyWidget); + + m_sloppyWidget = 0; + m_sloppySource = QRect(); + m_sloppyRegion = QRegion(); + m_sloppySourceClicked = false; + } + } + m_sloppyTimer.stop(); +} + +void KMenu::paintSearchTab( bool active ) +{ + QPixmap canvas( m_searchFrame->size() ); + QPainter p( &canvas ); + + QPixmap 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(QWidget* raiseWidget) +{ + paintSearchTab(raiseWidget == m_searchWidget); + + if (raiseWidget == m_browserView) { + if ( m_tabBar->currentTab() == ApplicationsTa