You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1330 lines
46 KiB
1330 lines
46 KiB
14 years ago
|
--- configure.in.in (Revision 0)
|
||
|
+++ configure.in.in (Revision 849791)
|
||
|
@@ -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)
|
||
|
--- kicker/plugins/beaglesearch.cpp (Revision 0)
|
||
|
+++ kicker/plugins/beaglesearch.cpp (Revision 849791)
|
||
|
@@ -0,0 +1,362 @@
|
||
|
+/*****************************************************************
|
||
|
+
|
||
|
+ Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com>
|
||
|
+
|
||
|
+ This program is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ This program is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU General Public License
|
||
|
+ along with this program; see the file COPYING. If not, write to
|
||
|
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
+ Boston, MA 02110-1301, USA.
|
||
|
+
|
||
|
+******************************************************************/
|
||
|
+
|
||
|
+#include "beaglesearch.h"
|
||
|
+
|
||
|
+#include <qdatetime.h>
|
||
|
+#include <qmutex.h>
|
||
|
+#include <qstringlist.h>
|
||
|
+#include <qapplication.h>
|
||
|
+#include <time.h>
|
||
|
+
|
||
|
+void beagle_init ()
|
||
|
+{
|
||
|
+ g_type_init ();
|
||
|
+}
|
||
|
+
|
||
|
+// ---------------- Hit ---------------------------
|
||
|
+
|
||
|
+Hit::Hit (BeagleHit *_hit) : processed (false)
|
||
|
+{
|
||
|
+ hit = beagle_hit_ref (_hit);
|
||
|
+}
|
||
|
+
|
||
|
+Hit::~Hit ()
|
||
|
+{
|
||
|
+ beagle_hit_unref (hit);
|
||
|
+ if (! processed)
|
||
|
+ return;
|
||
|
+ QDictIterator<QStringList> 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<Hit>;
|
||
|
+ hitlist->setAutoDelete (true);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+BeagleSearchResult::~BeagleSearchResult()
|
||
|
+{
|
||
|
+ // everything is set to autodelete
|
||
|
+}
|
||
|
+
|
||
|
+void BeagleSearchResult::addHit(BeagleHit *_hit)
|
||
|
+{
|
||
|
+ Hit *hit = new Hit (_hit);
|
||
|
+ hitlist->prepend (hit);
|
||
|
+}
|
||
|
+
|
||
|
+const QPtrList<Hit> *BeagleSearchResult::getHits () const
|
||
|
+{
|
||
|
+ return hitlist;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int total_hits;
|
||
|
+
|
||
|
+static void print_feed_item_hit (BeagleHit *hit)
|
||
|
+{
|
||
|
+ const char *text;
|
||
|
+
|
||
|
+ if (beagle_hit_get_one_property (hit, "dc:title", &text))
|
||
|
+ g_print ("Blog: %s\n", text);
|
||
|
+}
|
||
|
+
|
||
|
+static void print_file_hit (BeagleHit *hit)
|
||
|
+{
|
||
|
+ g_print ("File: %s, (%s)\n", beagle_hit_get_uri (hit), beagle_hit_get_mime_type (hit));
|
||
|
+}
|
||
|
+
|
||
|
+static void print_other_hit (BeagleHit *hit)
|
||
|
+{
|
||
|
+ const char *text;
|
||
|
+
|
||
|
+ g_print ("%s (%s)", beagle_hit_get_uri (hit),
|
||
|
+ beagle_hit_get_source (hit));
|
||
|
+ if (beagle_hit_get_one_property (hit, "dc:title", &text))
|
||
|
+ g_print ("title = %s\n", text);
|
||
|
+}
|
||
|
+
|
||
|
+static void print_hit (BeagleHit *hit)
|
||
|
+{
|
||
|
+ if (strcmp (beagle_hit_get_type (hit), "FeedItem") == 0) {
|
||
|
+ print_feed_item_hit (hit);
|
||
|
+ }
|
||
|
+ else if (strcmp (beagle_hit_get_type (hit), "File") == 0) {
|
||
|
+ print_file_hit (hit);
|
||
|
+ } else {
|
||
|
+ print_other_hit (hit);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+// ---------------- BeagleSearchClient ------------------
|
||
|
+
|
||
|
+void BeagleSearchClient::run ()
|
||
|
+{
|
||
|
+ kdDebug () << "Starting query ..." << endl;
|
||
|
+
|
||
|
+ 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 849791)
|
||
|
@@ -0,0 +1,499 @@
|
||
|
+/***************************************************************************
|
||
|
+ * Copyright (C) 2006 by Stephan Binner <binner@kde.org> *
|
||
|
+ * Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> *
|
||
|
+ * *
|
||
|
+ * This program is free software; you can redistribute it and/or modify *
|
||
|
+ * it under the terms of the GNU General Public License as published by *
|
||
|
+ * the Free Software Foundation; either version 2 of the License, or *
|
||
|
+ * (at your option) any later version. *
|
||
|
+ * *
|
||
|
+ * This program is distributed in the hope that it will be useful, *
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
|
+ * GNU General Public License for more details. *
|
||
|
+ * *
|
||
|
+ * You should have received a copy of the GNU General Public License *
|
||
|
+ * along with this program; if not, write to the *
|
||
|
+ * Free Software Foundation, Inc., *
|
||
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||
|
+ ***************************************************************************/
|
||
|
+
|
||
|
+#include "kickoff-beagle-plugin.h"
|
||
|
+
|
||
|
+#include <qregexp.h>
|
||
|
+#include <qtimer.h>
|
||
|
+
|
||
|
+#include <kapplication.h>
|
||
|
+#include <kdesktopfile.h>
|
||
|
+#include <kgenericfactory.h>
|
||
|
+#include <kservice.h>
|
||
|
+
|
||
|
+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<KickoffBeaglePlugin>( "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<QStringList> all = hit->getAllProperties();
|
||
|
+ QDictIterator<QStringList> 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<Hit> *hits = result->getHits();
|
||
|
+ if (hits == NULL) {
|
||
|
+ kdDebug () << "Hmm... null" << endl;
|
||
|
+ delete result;
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ kickoffSearchInterface()->initCategoryTitlesUpdate();
|
||
|
+
|
||
|
+ QPtrListIterator<Hit> it (*hits);
|
||
|
+ Hit *hit;
|
||
|
+ for (; (hit = it.current ()) != NULL; ++it) {
|
||
|
+ CATEGORY category = getHitCategory (hit);
|
||
|
+
|
||
|
+ // if category is not handled, continue
|
||
|
+ if (category == OTHER)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if ( category == APPS ) {
|
||
|
+ // we need to check if this is useful
|
||
|
+ KService cs( hit->getUri().path() );
|
||
|
+ if ( cs.noDisplay() )
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!kickoffSearchInterface()->anotherHitMenuItemAllowed(category))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ HitMenuItem *hit_item = hitToHitMenuItem (category, hit);
|
||
|
+
|
||
|
+ if (!hit_item)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ kickoffSearchInterface()->addHitMenuItem(hit_item);
|
||
|
+ }
|
||
|
+
|
||
|
+ kickoffSearchInterface()->updateCategoryTitles();
|
||
|
+
|
||
|
+ delete result;
|
||
|
+}
|
||
|
+
|
||
|
+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 849791)
|
||
|
@@ -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 849791)
|
||
|
@@ -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 849791)
|
||
|
@@ -0,0 +1,234 @@
|
||
|
+/*****************************************************************
|
||
|
+
|
||
|
+ Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com>
|
||
|
+
|
||
|
+ This program is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ This program is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU General Public License
|
||
|
+ along with this program; see the file COPYING. If not, write to
|
||
|
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
+ Boston, MA 02110-1301, USA.
|
||
|
+
|
||
|
+******************************************************************/
|
||
|
+
|
||
|
+#ifndef BEAGLESEARCH_H
|
||
|
+#define BEAGLESEARCH_H
|
||
|
+
|
||
|
+#include <qdict.h>
|
||
|
+#include <qptrlist.h>
|
||
|
+#include <qthread.h>
|
||
|
+#include <qevent.h>
|
||
|
+#include <qmutex.h>
|
||
|
+
|
||
|
+#include <kdebug.h>
|
||
|
+#include <kurl.h>
|
||
|
+
|
||
|
+extern "C" {
|
||
|
+#include <glib.h>
|
||
|
+#include <beagle/beagle.h>
|
||
|
+}
|
||
|
+
|
||
|
+// BeagleSearchClient sends 3 types of events
|
||
|
+// when results are to be sent as they arrive,
|
||
|
+// - RESULTFOUND : when result is found
|
||
|
+// - SEARCHOVER : when search is over
|
||
|
+// - KILLME : just before thread finishes - used to cleanup the thread object
|
||
|
+// when results are to be sent after receiving all of them
|
||
|
+// - RESULTFOUND : when all results are obtained
|
||
|
+// - KILLME : just before thread finishes - used to cleanup the thread object
|
||
|
+#define RESULTFOUND (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<QStringList>& 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<QStringList> 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<Hit> *getHits () const;
|
||
|
+
|
||
|
+private:
|
||
|
+ // lists of hits
|
||
|
+ QPtrList<Hit> *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 849791)
|
||
|
@@ -0,0 +1,64 @@
|
||
|
+/***************************************************************************
|
||
|
+ * Copyright (C) 2006 by Stephan Binner <binner@kde.org> *
|
||
|
+ * Copyright (c) 2006 Debajyoti Bera <dbera.web@gmail.com> *
|
||
|
+ * *
|
||
|
+ * This program is free software; you can redistribute it and/or modify *
|
||
|
+ * it under the terms of the GNU General Public License as published by *
|
||
|
+ * the Free Software Foundation; either version 2 of the License, or *
|
||
|
+ * (at your option) any later version. *
|
||
|
+ * *
|
||
|
+ * This program is distributed in the hope that it will be useful, *
|
||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
|
+ * GNU General Public License for more details. *
|
||
|
+ * *
|
||
|
+ * You should have received a copy of the GNU General Public License *
|
||
|
+ * along with this program; if not, write to the *
|
||
|
+ * Free Software Foundation, Inc., *
|
||
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||
|
+ ***************************************************************************/
|
||
|
+
|
||
|
+#ifndef CAPITALIZEPLUGIN_H
|
||
|
+#define CAPITALIZEPLUGIN_H
|
||
|
+
|
||
|
+#include "../interfaces/kickoff-search-plugin.h"
|
||
|
+#include "beaglesearch.h"
|
||
|
+
|
||
|
+class KickoffBeaglePlugin :public KickoffSearch::Plugin
|
||
|
+{
|
||
|
+ Q_OBJECT
|
||
|
+
|
||
|
+public:
|
||
|
+ KickoffBeaglePlugin(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<BeagleSearchClient> 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 */
|
||
|
|
||
|
Eigenschaftsänderungen: kicker/plugins
|
||
|
___________________________________________________________________
|
||
|
Hinzugefügt: svn:ignore
|
||
|
+ .deps
|
||
|
kickoffsearch_beagle.la
|
||
|
.libs
|
||
|
Makefile
|
||
|
Makefile.in
|
||
|
*.moc
|
||
|
|
||
|
|
||
|
--- kicker/Makefile.am 2010/08/10 08:10:21 1.1
|
||
|
+++ kicker/Makefile.am 2010/08/10 08:10:33
|
||
|
@@ -1,6 +1,6 @@
|
||
|
INCLUDES = $(all_includes)
|
||
|
|
||
|
-SUBDIRS = core ui buttons interfaces .
|
||
|
+SUBDIRS = core ui buttons interfaces plugins .
|
||
|
|
||
|
bin_PROGRAMS =
|
||
|
lib_LTLIBRARIES =
|
||
|
--- kicker/core/Makefile.am 2010/08/10 08:15:06 1.2
|
||
|
+++ kicker/core/Makefile.am 2010/08/10 08:17:08
|
||
|
@@ -1,6 +1,6 @@
|
||
|
INCLUDES = -I$(srcdir)/../../libkicker -I../../libkicker \
|
||
|
-I../ui -I$(srcdir)/../ui -I$(srcdir)/../buttons -I$(top_srcdir)/libkonq \
|
||
|
- $(all_includes)
|
||
|
+ $(all_includes) $(LIBBEAGLE_CFLAGS) $(GLIB_CFLAGS)
|
||
|
|
||
|
noinst_LTLIBRARIES = libkicker_core.la
|
||
|
|
||
|
--- kicker/buttons/Makefile.am 2010/08/10 08:16:06 1.1
|
||
|
+++ kicker/buttons/Makefile.am 2010/08/10 08:16:28
|
||
|
@@ -1,5 +1,5 @@
|
||
|
INCLUDES = -I$(srcdir)/../core -I$(srcdir)/../../libkicker -I../../libkicker \
|
||
|
- -I../ui -I$(srcdir)/../ui -I$(top_srcdir)/libkonq $(all_includes)
|
||
|
+ -I../ui -I$(srcdir)/../ui -I$(top_srcdir)/libkonq $(all_includes) $(LIBBEAGLE_CFLAGS) $(GLIB_CFLAGS)
|
||
|
|
||
|
noinst_LTLIBRARIES = libkicker_buttons.la
|
||
|
|