/***************************************************************************
 *   Copyright (C) 2005 Novell, Inc.                                       *
 *                                                                         *
 *   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 "kerryapp.h"
#include "searchdlg.h"
#include "hitwidget.h"
#include "kwidgetlistbox.h"
#include "kerrylabel.h"

#include <QtGui/QClipboard>
#include <QtGui/QLayout>
#include <QtCore/QTextCodec>
#include <QtGui/QMovie>
#include <QtGui/QPixmap>
#include <QtGui/QShowEvent>
#include <QtGui/QKeyEvent>
#include <QtCore/QEvent>
#include <QtCore/QCustomEvent>
#include <QtCore/QByteArray>

#include <kdebug.h>
#include <kfiledialog.h>
#include <kpushbutton.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kapplication.h>
#include <kfileitem.h>
#include <kiconloader.h>
#include <klocale.h>
#include <klineedit.h>
#include <kurllabel.h>
#include <krun.h>
#include <q3table.h>
#include <QDir>
#include <QLabel>
#include <QComboBox>
#include <kio/job.h>
#include <kprotocolinfo.h>
#include <ktrader.h>
#include <kprocess.h>
#include <QRegExp>
#include <kaction.h>
#include <kmenu.h>
#include <QCheckBox>
#include <kdesktopfile.h>
#include <QToolButton>
#include <kcombobox.h>
#include <kservicegroup.h>
#include <kbookmarkmanager.h>
#include <QCursor>

#include <kwindowsystem.h>
#include <kwindowsystem.h>
#include <krandom.h>
#include <ktoolinvocation.h>

#define WAIT_BEFORE_QUERYING 700

SearchDlg::SearchDlg(QWidget *parent)
 : QDialog(parent)
{
  setupUi(this);

#define switchLabelCount 19
static QLabel* switchLabel[switchLabelCount] = {showEverything, showApplications, showContacts, showDocuments,
                                  showConversations, showImages, showMedia, showWebPages, showFilePathName, sortByType, sortByDate, sortByName, sortByRelevance, showAnyDate, showToday, showSinceYesterday, showThisWeek, 
                                  showThisMonth, showThisYear};

  g_type_init();
  beagle_search = NULL;
  editSearch->setMaxCount(MAX_HISTORY_ITEMS);
  editSearch->setDuplicatesEnabled(false);

  KLineEdit *lineedit = new KLineEdit(editSearch);
  lineedit->setClickMessage(i18n( "Applications, Contacts, Conversations, Files and more..." ) );
  editSearch->setLineEdit(lineedit);

  connect(editSearch->lineEdit(), SIGNAL(returnPressed()), SLOT(search()));
  connect(editSearch, SIGNAL(activated(const QString &)), SLOT(search(const QString &)));
  connect(editSearch->lineEdit(), SIGNAL(textChanged(const QString &)), SLOT(searchChanged(const QString &)));
  showMode = Everywhere;
  dateRange = AnyDate;
  showBigTiles = false;
  searchAsYouType = true;

  QFont f= sortByRelevance->font();
  f.setBold(true);
  QFontMetrics fm(f);
  int minWidth=0;
  for (int i=0; i<switchLabelCount; ++i)
     minWidth = MAX(minWidth, fm.width(switchLabel[i]->text()));
  frame3->setMinimumWidth(minWidth+25);

  showEverything->installEventFilter(this);
  showApplications->installEventFilter(this);
  showContacts->installEventFilter(this);
  showDocuments->installEventFilter(this);
  showConversations->installEventFilter(this);
  showImages->installEventFilter(this);
  showMedia->installEventFilter(this);
  showWebPages->installEventFilter(this);
  showFilePathName->installEventFilter(this);
  sortByType->installEventFilter(this);
  sortByDate->installEventFilter(this);
  sortByName->installEventFilter(this);
  sortByRelevance->installEventFilter(this);
  showAnyDate->installEventFilter(this);
  showToday->installEventFilter(this);
  showSinceYesterday->installEventFilter(this);
  showThisWeek->installEventFilter(this);
  showThisMonth->installEventFilter(this);
  showThisYear->installEventFilter(this);
  buttonClear->installEventFilter(this);
  buttonClear->setIcon(KIcon(QApplication::isRightToLeft() ? "edit-clear-locationbar-rtl" : "edit-clear-locationbar-ltr"));
  buttonClose->setIcon(KIcon("window-close"));
  buttonPrevious->setIcon(KIcon("go-previous"));
  buttonNext->setIcon(KIcon("go-next"));
  connect(buttonFind, SIGNAL(clicked()), SLOT(search()));
  connect(buttonClear, SIGNAL(clicked()), SLOT(slotButtonClear()));
  connect(buttonPrevious, SIGNAL(clicked()), SLOT(slotPrevious()));
  connect(buttonNext, SIGNAL(clicked()), SLOT(slotNext()));
  connect(tableHits, SIGNAL(contextMenuRequested (int, int, const QPoint &)), SLOT(slotContextMenu(int, int, const QPoint &)));
  connect(hideIndexingInfoBtn, SIGNAL(clicked()), SLOT(hideIndexingInfo()));
  indexingInfoLabel->setPixmap( BarIcon("dialog-information", 32 ));
  indexingInfoFrame->hide();
  userHidIndexingInfo=false;

  buttonFind->setIconSet( BarIcon( "go-jump-locationbar", 22 ) );
  buttonConfigure->setGuiItem(KStandardGuiItem::configure());
  connect(buttonConfigure, SIGNAL(clicked()), SIGNAL(configure()));
  setMouseTracking(true);
  results.setAutoDelete(true);
  results.clear();
  displayed_results.clear();
  displayAmount = 5;
  displayOffset = 0;
  labelStatus->setAlignment(Qt::TextSingleLine);
  pPreviewJob = 0;
  pPreviewMimeTypes = 0;
  previewItems.clear();
  pending_showQuickTips=true;
  updateStatus();
  defaultSortOrder = Modified;
  currentSortOrder = defaultSortOrder;
//  kapp->dcopClient()->setDefaultObject( objId() );
  beagleJustStarted = false;
  m_searchPixmap->setPixmap( BarIcon( "edit-find", 32 ) );

  QTextCodec::setCodecForCStrings(QTextCodec::codecForName( "utf8" ));
  encodingRegexp = QRegExp("%[\\dA-F][\\dA-F]");

  input_timer = new QTimer(this);
  connect( input_timer, SIGNAL(timeout()), this, SLOT(search()) );

  bookmarkManager = 0;
  m_addressBook = 0;
  still_searching = false;
}

SearchDlg::~SearchDlg()
{
}

void SearchDlg::hideIndexingInfo()
{
  indexingInfoFrame->hide();
  userHidIndexingInfo=true;
}

void SearchDlg::showQuickTips()
{
  tableHits->clear();

  HitWidget* item = new HitWidget(QString::null, QString::null);
  QLabel *headerLabel = new QLabel(item);
  headerLabel->setText(i18n("Quick Tips"));
  item->insertHeaderWidget(0,headerLabel);

  item->setIcon("dialog-information");
  item->setDescriptionText("<qt>"+i18n("- You can use upper and lower case; search is case-insensitive.<br>"
                           "- To search for optional terms, use OR.  ex: <b>George OR Ringo</b><br>"
                           "- To exclude search terms, use the minus symbol in front, such as <b>-cats</b><br>"
                           "- When searching for a phrase, add quotes. ex: <b>\"There be dragons\"</b><br>"
                           "- Add ext:type to specify a file extension, ex: <b>ext:txt</b> or <b>ext:</b> for none")+"</qt>");
  tableHits->insertItem(item);

  item = new HitWidget(QString::null, QString::null);
  headerLabel = new QLabel(item);
  headerLabel->setText(i18n("Configuration"));
  item->insertHeaderWidget(0,headerLabel);

  item->setIcon("preferences-other");
  item->setDescriptionText("<qt>"+i18n("- Choose what folders and resources shall be indexed - or not.<br>"
                           "- Change the sort order and the number of shown results.<br>"
                           "- Define your own shortcuts to invoke the search dialog.")+"</qt>");
  KUrlLabel *buttonStart = new KUrlLabel(item);
  buttonStart->setPixmap(SmallIcon("system-run"));
  item->insertHitWidget(0,buttonStart);
  connect(buttonStart, SIGNAL(leftClickedUrl()), SIGNAL(configure()));

  buttonStart = new KUrlLabel(item);
  buttonStart->setText(i18n("Open configuration dialog"));
  item->insertHitWidget(1,buttonStart);
  connect(buttonStart, SIGNAL(leftClickedUrl()), SIGNAL(configure()));

  tableHits->insertItem(item);

  labelStatus->setText("");
}

void SearchDlg::search(const QString & search)
{
  SearchDlg::search(search, "everything");
}

void SearchDlg::search(const QString & search, const QString &scope)
{
  input_timer->stop();

#define showSwitchesCount 9
static QLabel* showSwitches[showSwitchesCount] = {showEverything, showApplications, showContacts, showDocuments,
                                   showConversations, showImages, showMedia, showWebPages, showFilePathName};
static QString nameSwitches[showSwitchesCount] = {"everything", "applications", "contacts", "documents",
                                  "conversations", "images", "media", "webpages", "path"};

  pending_showQuickTips=false;
  showSearchDialog();

  QLabel* newShowLabel = showEverything;
  ScopeType newShowMode = Everywhere;
  for (int i=0; i<showSwitchesCount; ++i)
     if (scope == nameSwitches[i]) {
        newShowLabel = showSwitches[i];
        newShowMode = (ScopeType)i;
        break;
     }

  if (showMode!=newShowMode) {
     QFont f= showSwitches[showMode]->font();
     f.setBold(false);
     showSwitches[showMode]->setFont(f);
     showMode = newShowMode;
     f.setBold(true);
     newShowLabel->setFont(f);
  }
  editSearch->lineEdit()->setText(search);
  this->search();
}

void SearchDlg::searchChanged(const QString & search)
{
  QString _search = search;
  buttonFind->setEnabled(_search.replace("*", QString::null).length()>2);
  if (!search.isEmpty() && displayed_results.count()==0 && tableHits->count()==1)
    tableHits->clear();
  if (search.isEmpty() && displayed_results.count()==0 && tableHits->count()==0)
    showQuickTips();

  if (searchAsYouType && buttonFind->isEnabled())
    input_timer->start (WAIT_BEFORE_QUERYING, true);
}

void SearchDlg::setDisplayAmount(int amount)
{
    if (amount<1 || displayAmount==amount)
	return;

    buttonPrevious->setShown(amount>1);
    buttonNext->setShown(amount>1);

    displayAmount = amount;
    displayOffset = 0;
    tableHits->setUpdatesEnabled(false);
    fillTableHits();
    tableHits->setUpdatesEnabled(true);
    updateStatus();
}

void SearchDlg::setSortOrder(int order)
{
static QLabel* sortSwitches[4] = {sortByType, sortByDate, sortByName, sortByRelevance};

    defaultSortOrder = order;

    if (currentSortOrder==order)
        return;

    QFont f= sortSwitches[currentSortOrder]->font();
    f.setBold(false);
    sortSwitches[currentSortOrder]->setFont(f);
    f.setBold(true);
    sortSwitches[order]->setFont(f);

    currentSortOrder = order;
    if (displayed_results.count())
        sortFilterResults();
}

void SearchDlg::slotButtonClear()
{
    editSearch->clear();
    slotClear();
    showQuickTips();
    currentSortOrder = defaultSortOrder;
}

void SearchDlg::slotClear()
{
    if (beagle_search != NULL) {
	kDebug () << "Previous client w/id " << beagle_search->id << " running ... stopping it." << endl;
	beagle_search->stopClient ();
    }

    displayOffset = 0;
    stopPreview();
    tableHits->clear();
    displayed_results.clear();
    results.clear();
    updateStatus();
}

void SearchDlg::slotPrevious()
{
    if (displayOffset==0)
      return;

    displayOffset-=displayAmount;
    tableHits->setUpdatesEnabled(false);
    fillTableHits();
    tableHits->setUpdatesEnabled(true);
    updateStatus();
}

void SearchDlg::slotNext()
{
    if (displayAmount==1 || displayOffset+displayAmount>=(int)displayed_results.count())
      return;

    displayOffset+=displayAmount;
    tableHits->setUpdatesEnabled(false);
    fillTableHits();
    tableHits->setUpdatesEnabled(true);
    updateStatus();
}

void SearchDlg::sortFilterResults()
{
    displayOffset = 0;
    stopPreview();
    tableHits->clear();
    displayed_results.clear();
    displayResults(results);
    updateStatus();
}

void SearchDlg::fillTableHits()
{
    stopPreview();
    tableHits->clear();
    previewItems.clear();
    if (displayAmount==1) {
        for(int i = 0; i < (int)displayed_results.count(); ++i) {
	    insertResult(displayed_results.at(i),i);
        }
    }
    else {
      if (displayOffset+displayAmount<=(int)displayed_results.count()) {
        for(int i = displayOffset; i < displayOffset+displayAmount; ++i) {
	    insertResult(displayed_results.at(i),i-displayOffset);
        }
      }
      else
      for(uint i = displayOffset; i < (displayed_results.count() % displayAmount)+displayOffset; ++i) {
	    insertResult(displayed_results.at(i),i-displayOffset);
      }
    }
    if (previewItems.count()) {
      startPreview(previewItems);
    }
}

void SearchDlg::updateStatus()
{
    buttonPrevious->setEnabled(displayOffset>0);
    buttonNext->setEnabled(displayOffset+displayAmount<(int)displayed_results.count());
    labelStatus->setAlignment(Qt::TextSingleLine);
    const int count = displayed_results.count();
    QString text;
    if (displayAmount==1)
       text=i18np("<b>1 result</b> found.", "<b>%1 results</b> found.", count);
    else if (count==0)
       text=i18n("<qt>No results.</qt>").replace("<qt>",QString::null).replace("</qt>",QString::null);
    else if (displayOffset==0)
       text=i18n("Best <b>%1 results of %2</b> shown.", tableHits->count(), count);
    else
       text=i18n("Results <b>%1 through %2 of %3</b> are shown.", displayOffset+1, displayOffset+tableHits->count(), count);

#if 0
    if (still_searching)
       text=text+" <b>"+i18n("(still searching)")+"</b>";
#endif

    labelStatus->setText(text);
}

void SearchDlg::search()
{
    current_query.set(editSearch->lineEdit()->text());
    if (current_query.get().replace("*", QString::null).length()<3)
       return;

    editSearch->addToHistory(current_query.get());

    if (!beagle_util_daemon_is_running()) {
       tableHits->clear();
       HitWidget* item = new HitWidget(QString::null, QString::null);
       QLabel *headerLabel = new QLabel(item);
       headerLabel->setText(i18n("The query for \"%1\" failed.").arg(current_query.get()));
       item->insertHeaderWidget(0,headerLabel);

       item->setIcon("dialog-error");
       item->setDescriptionText("<qt>"+i18n("The likely cause is that the Beagle daemon is not running.")+"</qt>");

       cb_beagleStart = new QCheckBox(i18n("Automatically start Beagle daemon at login"),item);
       item->insertTextWidget(1,cb_beagleStart);

       KUrlLabel *buttonStart = new KUrlLabel(item);
       buttonStart->setPixmap(SmallIcon("system-run"));
       item->insertHitWidget(0,buttonStart);
       connect(buttonStart, SIGNAL(leftClickedUrl()), SLOT(slotStartBeagle()));

       buttonStart = new KUrlLabel(item);
       buttonStart->setText(i18n("Click to start the Beagle daemon"));
       item->insertHitWidget(1,buttonStart);
       connect(buttonStart, SIGNAL(leftClickedUrl()), SLOT(slotStartBeagle()));

       tableHits->insertItem(item);
       labelStatus->setText("");
       return;
    }

    slotClear();
    labelStatus->setText(i18n("Searching..."));

    // Beagle search
    if (beagle_search != NULL) {
	kDebug () << "Previous client w/id " << beagle_search->id << " still running ... ignoring it." << endl;
	beagle_search->stopClient ();
    }

    current_beagle_client_id = KRandom::random ();
    kDebug () << "Creating client with id:" << current_beagle_client_id << endl;

    m_searchPixmap->setMovie(&QMovie(KStandardDirs::locate( "appdata", "search-running.mng" )));

    new_results.clear();

    kDebug() << "searchProgramList" << endl;
    searchProgramList(QString::null);

    kDebug() << "searchBookmars" << endl;
    if (!bookmarkManager)
      bookmarkManager = KBookmarkManager::userBookmarksManager();
    searchBookmarks(bookmarkManager->root());

    kDebug() << "searchAddressBook" << endl;
    searchAddressbook();

    displayResults(new_results);

    kDebug() << "starting BeagleSearch" << endl;
    beagle_search = new BeagleSearch(current_beagle_client_id, this, current_query.get());
    beagle_search->start();
    still_searching = true;
}

QString SearchDlg::takeProperty( const QString& property, QStringList& propertyList )
{
      QString ret = QString::null;
      QStringList::iterator it;
      for ( it = propertyList.begin(); it != propertyList.end(); ++it ) {
         const QString search = property+'=';
         if ((*it).startsWith(search)) {
           ret = (*it).remove(search);
           propertyList.erase(it);
           break;
         }
      }
      return ret;
}

QDateTime SearchDlg::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));
}

void SearchDlg::slotCleanClientList ()
{
    toclean_list_mutex.lock ();
    BeagleSearch *old_client = toclean_client_list.take (0);
    if (old_client != NULL) { // failsafe
	kDebug () << "Cleanup old client " << old_client->id << endl;
	delete old_client;
    }
    toclean_list_mutex.unlock ();
}

void SearchDlg::customEvent (QCustomEvent *e)
{
    if (e->type () == RESULTFOUND) {
        BeagleSearch::BeagleResultList* items = (BeagleSearch::BeagleResultList*) e->data();
        if (items->count() == 0 || current_beagle_client_id != items->first()->client_id) {
            kDebug () << "Stale result" << endl;
	    delete items;
        } else {
            kDebug () << "Good results ...total=" << items->count() << endl;
            searchHasOutput(*items);
        }
    } else if (e->type () == RESULTGONE) {
        BeagleSearch::BeagleVanishedURIList* items = (BeagleSearch::BeagleVanishedURIList*) e->data();
        if (items->list.count() == 0 || current_beagle_client_id != items->client_id) {
            kDebug () << "Stale leaving from " << items->client_id << endl;
	    delete items;
        } else {
            kDebug () << "Good leavings ...total=" << items->list.count() << endl;
            searchLostOutput(items->list);
        }
    } else if (e->type () == SEARCHOVER) {
        BeagleSearch *client = (BeagleSearch *) e->data ();
	if (client == NULL) {
	    kDebug () << "Query finished but client is already deleted" << endl;
	    searchFinished();
	    return;
	}
//        kDebug () << "Query finished for id=" << client->id << endl;
	if (current_beagle_client_id == client->id) {
	    searchFinished();
	}
    } else if (e->type () == KILLME) {
        BeagleSearch *client = (BeagleSearch *) e->data ();
        if (client==beagle_search)
            beagle_search = NULL;

	if (client->isFinished ())
	    delete client;
	else {
	    // add client to cleanup list
	    toclean_list_mutex.lock ();
	    toclean_client_list.append (client);
	    kDebug () << "Scheduling client to be deleted in 500ms" << endl;
	    toclean_list_mutex.unlock ();
	    QTimer::singleShot (500, this, SLOT (slotCleanClientList ()));
	}
    } else if (e->type () == STILLINDEXING && !userHidIndexingInfo) {
         indexingInfoFrame->show();
    } else if (e->type () == DONEINDEXING) {
         indexingInfoFrame->hide();
    }

}

void SearchDlg::insertResult(BeagleSearch::beagle_result_struct *result,int index)
{
      KUrl url(*(result->uri));

      HitWidget* item = new HitWidget(*(result->uri),*(result->mime_type),tableHits);
      if (result->parent_uri)
        item->setParentUri(*(result->parent_uri));
      item->setCollapsible(result);
      item->setCollapsed(!result->show_expanded);
      connect(item, SIGNAL(uncollapsed(HitWidget*)), SLOT(itemUncollapsed(HitWidget*)));

      item->hiticon->setUrl(*(result->uri));
      connect(item->hiticon, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));

      KUrlLabel *buttonGo = new KerryLabel(item);
      buttonGo->setPixmap(SmallIcon( *(result->mime_type)=="application/x-desktop" ? "system-run" : "document-open") );
      buttonGo->setUrl(*(result->uri));
      item->insertHitWidget(0,buttonGo);
      connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));

      buttonGo = new KerryLabel(item);
      buttonGo->setText( *(result->mime_type)=="application/x-desktop" ? i18n("Run") : i18n("Open") );
      buttonGo->setUrl(*(result->uri));
      item->insertHitWidget(1,buttonGo);
      connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));

      if (result->tilegroup == BeagleSearch::Website) {
        item->setIcon("network"); // KDE 4 name: text-html?

        QString description = "<qt>";
        if (result->hit_type!="Google") {
          QDateTime datetime;
          datetime.setTime_t(result->last_index_time);
          if (datetime.date().year()>1970)
             description = description + i18n("Last viewed: %1").arg(KGlobal::locale()->formatDateTime(datetime))+"<br>";
        }

        item->setDescriptionText(description +i18n("URL:")+" "+*(result->uri)+"</qt>");

        if (result->snippet)
            item->setPropertiesText("<qt>"+*(result->snippet)+"</qt>");

        KerryLabel *headerFileLabel = new KerryLabel(item);
        QStringList _properties(result->properties);
        QString title = takeProperty("dc:title",_properties);
        if (title.isEmpty())
           title = takeProperty("Title",_properties);

        headerFileLabel->setText(title.isEmpty() ? i18n("Untitled Page") : title);
        headerFileLabel->setAlignment(headerFileLabel->alignment() | Qt::TextSingleLine);
        headerFileLabel->setUrl(*(result->uri));
        item->insertHeaderWidget(0,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
      }
      else if (result->tilegroup == BeagleSearch::Feed) {
        item->setIcon("network"); // KDE 4 name: unsure at the time of writing

        QDateTime datetime;
        datetime.setTime_t(result->last_index_time);
        item->setDescriptionText("<qt>"+ i18n("Published: %1").arg(KGlobal::locale()->formatDateTime(datetime))+"<br>");

        if (result->snippet)
          item->setPropertiesText("<qt>"+*(result->snippet)+"</qt>");

        QLabel *headerLabel = new QLabel(item);
        headerLabel->setText(i18n("Weblog:"));
        headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
        item->insertHeaderWidget(0,headerLabel);

        QStringList _properties(result->properties);
        QString title = takeProperty("dc:title",_properties);
        QString identifier = takeProperty("dc:identifier", _properties);
        item->setUri(identifier);
        buttonGo->setUrl(identifier);

        KerryLabel *headerFileLabel = new KerryLabel(item);
        headerFileLabel->setText(title.isEmpty() ? i18n("Untitled Entry") : title);
        headerFileLabel->setAlignment(headerFileLabel->alignment() | Qt::TextSingleLine);
        headerFileLabel->setUrl(identifier);
        item->insertHeaderWidget(1,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
      }
      else if ((*(result->uri)).startsWith("knotes:/")) {
        item->setIcon("knotes");

        QDateTime datetime;
        datetime.setTime_t(result->last_index_time);
        item->setDescriptionText("<qt>"+ i18n("Last modified: %1").arg(KGlobal::locale()->formatDateTime(datetime))+"<br>");

        if (result->snippet)
          item->setPropertiesText("<qt>"+*(result->snippet)+"</qt>");

        QStringList _properties(result->properties);
        QString title = takeProperty("dc:title",_properties);

        KerryLabel *headerNameLabel = new KerryLabel(item);
        headerNameLabel->setText(title.isEmpty() ? i18n("Untitled") : title);
        headerNameLabel->setUrl(item->uri());
        item->insertHeaderWidget(0,headerNameLabel);
        connect(headerNameLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
      }
      else if (result->tilegroup == BeagleSearch::Note) {
        item->setIcon("contents2"); // KDE 4 name: help-contents?
        QDateTime datetime;
        datetime.setTime_t(result->last_index_time);
        item->setDescriptionText("<qt>"+ i18n("Last modified: %1").arg(KGlobal::locale()->formatDateTime(datetime))+"<br>");


        if (result->snippet)
          item->setPropertiesText("<qt>"+*(result->snippet)+"</qt>");

        QStringList _properties(result->properties);
        QString title = takeProperty("dc:title",_properties);

        KerryLabel *headerNoteLabel = new KerryLabel(item);
        headerNoteLabel->setText(title.isEmpty() ? i18n("Untitled Entry") : title);
        headerNoteLabel->setAlignment(headerNoteLabel->alignment() | Qt::TextSingleLine);
        headerNoteLabel->setUrl(item->uri());
        item->insertHeaderWidget(0,headerNoteLabel);
        connect(headerNoteLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
      }
      else if ((*(result->uri)).startsWith("calendar:/")) {
        item->setIcon("office-address-book");

        QStringList _properties(result->properties);
        QString summary = takeProperty("fixme:summary",_properties);

        QString properties;
        QDateTime datetime;
        datetime = datetimeFromString(takeProperty("fixme:starttime",_properties));
        properties = properties + i18n("Start time: %1").arg(KGlobal::locale()->formatDateTime(datetime)) + "<br>";
        datetime = datetimeFromString(takeProperty("fixme:endtime",_properties));
        properties = properties + i18n("End time: %1").arg(KGlobal::locale()->formatDateTime(datetime)) + "<br>";

        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
                properties=properties+(*it);

        item->setDescriptionText("<qt>"+properties+"</qt>");

        KerryLabel *headerSummaryLabel = new KerryLabel(item);
        headerSummaryLabel->setText(summary.isEmpty() ? i18n("No Summary Specified") : summary);
        headerSummaryLabel->setUrl(item->uri());
        item->insertHeaderWidget(0,headerSummaryLabel);
        connect(headerSummaryLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotOpenEvolution(const QString&)));
      }
      else if ((*(result->uri)).startsWith("contacts:/")) {
        item->setIcon("office-address-book");

        QStringList _properties(result->properties);
        QString name = takeProperty("fixme:Name",_properties);
        QString email = takeProperty("fixme:Email1",_properties);

        QString properties;
        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
                properties=properties+(*it);

        if (!properties.isEmpty())
           item->setDescriptionText("<qt>"+properties+"</qt>");

        KerryLabel *headerNameLabel = new KerryLabel(item);
        headerNameLabel->setText(name.isEmpty() ? i18n("No Name Known") : name);
        headerNameLabel->setUrl(item->uri());
        item->insertHeaderWidget(0,headerNameLabel);
        connect(headerNameLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotOpenEvolution(const QString&)));

        QLabel *headerLabel = new QLabel(item);
        headerLabel->setText(i18n(","));
        item->insertHeaderWidget(1,headerLabel);

        KerryLabel *headerEmailLabel = new KerryLabel(item);
        headerEmailLabel->setText(email);
        headerEmailLabel->setUrl(email);
        item->insertHeaderWidget(2,headerEmailLabel);
        connect(headerEmailLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotMailTo(const QString&)));
      }
      else if (*(result->mime_type)=="text/x-korganizer-event" || *(result->mime_type)=="text/x-korganizer-todo") {
        item->setIcon("office-calendar");

        QStringList _properties(result->properties);
        QString title = takeProperty("dc:title",_properties);

        QString properties;
        QDateTime datetime;

        QString starttime = takeProperty("fixme:starttime",_properties);
        if (!starttime.isEmpty()) {
           datetime = datetimeFromString(starttime);
           properties = properties + i18n("Start time: %1").arg(KGlobal::locale()->formatDateTime(datetime)) + "<br>";
           item->setDate(datetime.date());
        }

        QString startdate = takeProperty("fixme:startdate",_properties);
        if (!startdate.isEmpty()) {
           datetime = datetimeFromString(startdate);
           properties = properties + i18n("Start date: %1").arg(KGlobal::locale()->formatDate(datetime.date())) + "<br>";
           item->setDate(datetime.date());
        }

        QString endtime = takeProperty("fixme:endtime",_properties);
        if (!endtime.isEmpty())
           properties = properties + i18n("End time: %1").arg(KGlobal::locale()->formatDateTime(datetimeFromString(endtime))) + "<br>";

        QString enddate = takeProperty("fixme:enddate",_properties);
        if (!enddate.isEmpty())
           properties = properties + i18n("End date: %1").arg(KGlobal::locale()->formatDate(datetimeFromString(enddate).date())) + "<br>";

        QString duetime = takeProperty("fixme:duetime",_properties);
        if (!duetime.isEmpty())
           properties = properties + i18n("Due time: %1").arg(KGlobal::locale()->formatDateTime(datetimeFromString(duetime))) + "<br>";

        QString duedate = takeProperty("fixme:duedate",_properties);
        if (!duedate.isEmpty())
           properties = properties + i18n("Due date: %1").arg(KGlobal::locale()->formatDate(datetimeFromString(duedate).date())) + "<br>";

        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
                properties=properties+(*it);

        if (!properties.isEmpty())
           item->setDescriptionText("<qt>"+properties+"</qt>");

        if (result->snippet)
            item->setPropertiesText("<qt>"+*(result->snippet)+"</qt>");

        QLabel *headerLabel = new QLabel(item);
        if (*(result->mime_type)=="text/x-korganizer-event")
           headerLabel->setText(i18n("Meeting:"));
        else
           headerLabel->setText(i18n("To-do:"));
        headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
        item->insertHeaderWidget(0,headerLabel);

        KerryLabel *headerNameLabel = new KerryLabel(item);
        headerNameLabel->setText(title);
        headerNameLabel->setUrl(item->uri());
        item->insertHeaderWidget(1,headerNameLabel);
        connect(headerNameLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotOpenKOrganizer(const QString&)));
      }
      else if ((*(result->uri)).startsWith("kabc:/")) {
        item->setIcon("office-address-book");

        QStringList _properties(result->properties);
        QString name = takeProperty("vCard:FN",_properties);
        QString email = takeProperty("vCard:EMAIL",_properties);
        QString homepage = takeProperty("vCard:URL",_properties);

        QString properties;
        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
                properties=properties+(*it);

        if (!properties.isEmpty())
           item->setDescriptionText("<qt>"+properties+"</qt>");

        KerryLabel *headerNameLabel = new KerryLabel(item);
        headerNameLabel->setText(name.isEmpty() ? i18n("No Name Known") : name);
        headerNameLabel->setUrl(item->uri());
        item->insertHeaderWidget(0,headerNameLabel);
        connect(headerNameLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));

        if (!email.isEmpty()) {
        	QLabel *headerLabel = new QLabel(item);
        	headerLabel->setText(i18n(","));
        	item->insertHeaderWidget(1,headerLabel);
		
        	KerryLabel *headerEmailLabel = new KerryLabel(item);
        	headerEmailLabel->setText(email);
        	headerEmailLabel->setUrl(email);
        	item->insertHeaderWidget(2,headerEmailLabel);
        	connect(headerEmailLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotMailTo(const QString&)));
        }

      }
      else if (*(result->mime_type)=="message/rfc822" || (*(result->uri)).startsWith("email:/") ) {
        item->setIcon("mail_generic"); // KDE 4 icon name: unsure at the time of writing

        QStringList _properties(result->properties);
        QString subject = takeProperty("dc:title",_properties);
        QString from = takeProperty("fixme:from",_properties);
        QString received = takeProperty("fixme:date",_properties);

        QDateTime received_datetime;
        received_datetime = datetimeFromString(received);
        if (!received.isEmpty())
          item->setDescriptionText("<qt>"+i18n("Received: %1").arg(KGlobal::locale()->formatDateTime(received_datetime))+"</qt>");

        QString properties;
        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
                properties=properties+(*it);

        if (result->snippet) {
          if (!properties.isEmpty())
             properties=properties+"<br>";
          properties=properties+*(result->snippet);
        }

        if (!properties.isEmpty())
            item->setPropertiesText("<qt>"+properties+"</qt>");

        KerryLabel *headerSubjectLabel = new KerryLabel(item);
        headerSubjectLabel->setText(subject.isEmpty() ? i18n("No Subject") : subject);
        item->insertHeaderWidget(0,headerSubjectLabel);
        headerSubjectLabel->setUrl(*(result->uri));
        connect(headerSubjectLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));

        QLabel *headerLabel = new QLabel(item);
        headerLabel->setText(i18n("From"));
        headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
        item->insertHeaderWidget(1,headerLabel);

        KerryLabel *headerFromLabel = new KerryLabel(item);
        headerFromLabel->setText(from.isEmpty() ? i18n("Unknown Person") : from);
        headerFromLabel->setUrl(from);
        item->insertHeaderWidget(2,headerFromLabel);
        connect(headerFromLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotMailTo(const QString&)));
      }
      else if (*(result->mime_type)=="application/x-desktop") {
        KFileItem *fileitem=new KFileItem(*(result->uri),*(result->mime_type),KFileItem::Unknown);
        item->setIcon(fileitem->iconName());
        if (!item->isCollapsed() && canPreview(fileitem))
            previewItems.append(*fileitem);
        else
            delete fileitem;

        KDesktopFile desktopfile(url.path());
        if (!desktopfile.readGenericName().isNull()) {
	    item->setDescriptionText("<qt>"+desktopfile.readGenericName()+"</qt>");
        }

        QLabel *headerLabel = new QLabel(item);
        headerLabel->setText(i18n("Application:"));
        headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
        item->insertHeaderWidget(0,headerLabel);

        KerryLabel *headerFileLabel = new KerryLabel(item);
        QStringList _properties(result->properties);
        QString title = takeProperty("fixme:Name",_properties);
        headerFileLabel->setText(title.isEmpty() ? desktopfile.readName() : title);
        headerFileLabel->setUrl(*(result->uri));
        item->insertHeaderWidget(1,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
      }
      else if (*(result->mime_type)=="beagle/x-kopete-log" || *(result->mime_type)=="beagle/x-gaim-log" || (*(result->uri)).startsWith("konversation:/")) {
        if (*(result->mime_type)=="beagle/x-kopete-log")
          item->setIcon("kopete");
        else if ((*(result->uri)).startsWith("konversation://"))
          item->setIcon("konversation");
        else
          item->setIcon("gaim");

        QDateTime datetime;
        datetime.setTime_t(result->last_index_time);
        item->setDescriptionText("<qt>"+i18n("Date: %1").arg(KGlobal::locale()->formatDateTime(datetime)+"</qt>"));

        if (result->snippet)
            item->setPropertiesText("<qt>"+*(result->snippet)+ "</qt>");

        KerryLabel *headerFileLabel = new KerryLabel(item);
        headerFileLabel->setUrl(*(result->uri));
        QStringList _properties(result->properties);
        QString person = takeProperty("fixme:speakingto",_properties);
        QString person_alias = takeProperty("fixme:speakingto_alias",_properties);
        if (!person_alias.isEmpty())
           person = person_alias;
        headerFileLabel->setText(i18n("Conversation With %1").arg(person.isEmpty() ? i18n("Unknown Person") : person));
        item->insertHeaderWidget(0,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
      }
      else if (result->tilegroup == BeagleSearch::Packages) {
        QString icon;
        if (*(result->mime_type)=="application/x-rpm")
	    icon = "application-x-rpm";
	else if (*(result->mime_type)=="application/x-deb")
	    icon = "application-x-deb";
	else
	    icon = "kuroo"; // KDE 4 icon name: probably package-x-generic, but look it up first
        item->setIcon(icon);
    
        KerryLabel *headerFileLabel = new KerryLabel(item);
        headerFileLabel->setText(url.fileName());
        headerFileLabel->setTipText(url.prettyUrl());
        headerFileLabel->setUseTips();
        headerFileLabel->setUrl(*(result->uri));
        item->insertHeaderWidget(0,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
    
        QStringList _properties(result->properties);
        QString homepage = takeProperty("dc:source",_properties);
	if (!homepage.isEmpty())
	{
		QLabel *headerLabel = new QLabel(item);
		headerLabel->setText(i18n("From"));
		headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
		item->insertHeaderWidget(1,headerLabel);
    
		KerryLabel *headerFileLabel = new KerryLabel(item);
		headerFileLabel->setText(homepage);
		headerFileLabel->setAlignment(headerFileLabel->alignment() | Qt::TextSingleLine);
		headerFileLabel->setUrl(homepage);
		item->insertHeaderWidget(2,headerFileLabel);
		connect(headerFileLabel, SIGNAL(leftClickedUrl(const QString&)), SLOT(slotOpenURL(const QString&)));
	}

        item->setDescriptionText(takeProperty("dc:subject", _properties));
    
        QString properties;
	QString install_time_str = takeProperty("fixme:install_time", _properties);
	if (!install_time_str.isEmpty())
	{
            properties=properties+i18n("Installed on: %1").arg(KGlobal::locale()->formatDateTime(datetimeFromString(install_time_str)))+"<br>";
	}

	QString install_size_str = takeProperty("fixme:contents_byte_count", _properties);
	if (!install_size_str.isEmpty())
	{
            properties=properties+i18n("Installed size: %1").arg(formatBytes(install_size_str))+"<br>";
	}

	QString download_size_str = takeProperty("fixme:size", _properties);
	if (!download_size_str.isEmpty())
	{
            properties=properties+i18n("Download size: %1").arg(formatBytes(download_size_str))+"<br>";
	}
		
        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
	{
                properties=properties+(*it);
	}

        if (result->snippet) {
          if (!properties.isEmpty())
             properties=properties+"<br>";
          properties=properties+*(result->snippet);
        }
   
        if (!properties.isEmpty())
            item->setPropertiesText("<qt>"+properties+"</qt>");
    

        item->insertHitSpacing(2,10);
        buttonGo = new KUrlLabel(item);
        buttonGo->setPixmap(SmallIcon("system-file-manager"));
        item->insertHitWidget(3,buttonGo);
        connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));
    
        buttonGo = new KUrlLabel(item);
        buttonGo->setText(i18n("Reveal in File Manager"));
        item->insertHitWidget(4,buttonGo);
        connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));
      }
      else if ((*(result->mime_type)).startsWith("audio/")) {
        KFileItem *fileitem=new KFileItem(*(result->uri),*(result->mime_type),KFileItem::Unknown);
        item->setIcon(fileitem->iconName());
        if (!item->isCollapsed() && canPreview(fileitem))
            previewItems.append(*fileitem);
        else
            delete fileitem;
    
        QStringList _properties(result->properties);
        QString title = takeProperty("fixme:title",_properties);

        KerryLabel *headerFileLabel = new KerryLabel(item);
        if (title.isEmpty())
            headerFileLabel->setText(url.fileName());
        else
            headerFileLabel->setText(title);
        
        headerFileLabel->setTipText(url.prettyUrl());
        headerFileLabel->setUseTips();
        headerFileLabel->setUrl(*(result->uri));
        item->insertHeaderWidget(0,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
    
        QLabel *headerLabel = new QLabel(item);
        headerLabel->setText(i18n("In Folder"));
        headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
        item->insertHeaderWidget(1,headerLabel);

        KerryLabel *headerDirLabel = new KerryLabel(item);
        QString directory=url.directory();
        int i = directory.findRev('/');
        if (i>0)
            directory=directory.mid(i+1);
        headerDirLabel->setText(directory);
        headerDirLabel->setUrl(url.directory());
        headerDirLabel->setTipText(url.directory());
        headerDirLabel->setUseTips();
        item->insertHeaderWidget(2,headerDirLabel);
        connect(headerDirLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));

        QDateTime datetime;
        datetime.setTime_t(result->last_index_time);
        title = i18n("Last modified: %1").arg(KGlobal::locale()->formatDateTime(datetime));
        item->setDescriptionText("<qt>"+title+"</qt>");

        QString properties;
        BeagleSearch::PropertyList::iterator it;
        for ( it = _properties.begin(); it != _properties.end(); ++it )
                properties=properties+(*it);

        if (result->snippet) {
          if (!properties.isEmpty())
             properties=properties+"<br>";
          properties=properties+*(result->snippet);
        }

        if (!properties.isEmpty())
            item->setPropertiesText("<qt>"+properties+"</qt>");

        item->insertHitSpacing(2,10);
        buttonGo = new KUrlLabel(item);
        buttonGo->setPixmap(SmallIcon("system-file-manager"));
        item->insertHitWidget(3,buttonGo);
        connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));

        buttonGo = new KUrlLabel(item);
        buttonGo->setText(i18n("Reveal in File Manager"));
        item->insertHitWidget(4,buttonGo);
        connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));
      }
      else {
        KFileItem *fileitem=new KFileItem(*(result->uri),*(result->mime_type),KFileItem::Unknown);
        item->setIcon(fileitem->iconName());
        if (!item->isCollapsed() && canPreview(fileitem))
            previewItems.append(*fileitem);
        else
            delete fileitem;
    
        KerryLabel *headerFileLabel = new KerryLabel(item);
        headerFileLabel->setText(url.fileName());
        headerFileLabel->setTipText(url.prettyUrl());
        headerFileLabel->setUseTips();
        headerFileLabel->setUrl(*(result->uri));
        item->insertHeaderWidget(0,headerFileLabel);
        connect(headerFileLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpen()));
    
        QLabel *headerLabel = new QLabel(item);
        headerLabel->setText(i18n("In Folder"));
        headerLabel->setAlignment(headerLabel->alignment() | Qt::TextSingleLine);
        item->insertHeaderWidget(1,headerLabel);
    
        KerryLabel *headerDirLabel = new KerryLabel(item);
        QString directory=url.directory();
        int i = directory.findRev('/');
        if (i>0)
            directory=directory.mid(i+1);
        headerDirLabel->setText(directory);
        headerDirLabel->setUrl(url.directory());
        headerDirLabel->setTipText(url.directory());
        headerDirLabel->setUseTips();
        item->insertHeaderWidget(2,headerDirLabel);
        connect(headerDirLabel, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));


        QString title;
        if (*(result->mime_type)=="inode/directory") {
            int count = QDir(url.path()).count() -2 ;
            if (count==0)
              title=i18n("Empty");
            else
              title=i18np("Contains 1 item", "Contains %1 items", count);
        }
        else {
            QDateTime datetime;
            datetime.setTime_t(result->last_index_time);
            title = i18n("Last modified: %1").arg(KGlobal::locale()->formatDateTime(datetime));
        }
        item->setDescriptionText("<qt>"+title+"</qt>");
    
        QString properties;
        BeagleSearch::PropertyList::iterator it;
        for ( it = result->properties.begin(); it != result->properties.end(); ++it )
                properties=properties+(*it);

        if (result->snippet) {
          if (!properties.isEmpty())
             properties=properties+"<br>";
          properties=properties+*(result->snippet);
        }
   
        if (!properties.isEmpty())
            item->setPropertiesText("<qt>"+properties+"</qt>");
    

        item->insertHitSpacing(2,10);
        buttonGo = new KUrlLabel(item);
        buttonGo->setPixmap(SmallIcon("system-file-manager"));
        item->insertHitWidget(3,buttonGo);
        connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));
    
        buttonGo = new KUrlLabel(item);
        buttonGo->setText(i18n("Reveal in File Manager"));
        item->insertHitWidget(4,buttonGo);
        connect(buttonGo, SIGNAL(leftClickedUrl()), SLOT(slotOpenDir()));
      }

      item->score->setText(i18n("<p align=\"center\">Score: %1</p>").arg(result->score,0,'f',1));
    
      tableHits->insertItem(item,index);
}

void SearchDlg::itemUncollapsed(HitWidget* item)
{
   KFileItem *fileitem=new KFileItem(item->uri(),item->mimetype(),KFileItem::Unknown);
   if (canPreview(fileitem))
       previewItems.append(*fileitem);
   startPreview(previewItems);
}

void SearchDlg::searchHasOutput(BeagleSearch::BeagleResultList &items)
{
    BeagleSearch::BeagleResultList* searchResults = new BeagleSearch::BeagleResultList;
    bool forceRebuildDisplay = false;

    for (BeagleSearch::BeagleResultList::ConstIterator it = items.begin(); it != items.end(); ++it) {
      BeagleSearch::beagle_result_struct* result = (*it); 
      if ((*(result->uri)).find(encodingRegexp)>0) {
          KUrl kurl(*(result->uri));
          *(result->uri)=kurl.url();
      }

      if ((*(result->uri)).startsWith("kbookmark:/"))
	 continue;

      if (!checkUriInResults(*(result->uri))) {
         result->show_expanded=showBigTiles;
         results.append(result);
         searchResults->append(result);
      } else if (((*result->uri)).startsWith("kabc:/")) {
	 int i;
	 // Replace the previous kabc result with this one
	 // The only duplicates will be between kabc and kaddrbook backend, and the backend
	 // results will override kabc ones.
	 kDebug() << "Replacing old result" << endl;
	 forceRebuildDisplay = true;
	 for(i = 0; i < (int)displayed_results.count(); ++i)
      	 {
      	    BeagleSearch::beagle_result_struct *old_result = displayed_results.at(i);
      	    if (*(result->uri)==(*(old_result->uri))) {
      	      displayed_results.replace(i,result);
      	      break;
      	   }
      	 }
      	 for(i = 0; i < (int)results.count(); ++i)
      	 {
      	    BeagleSearch::beagle_result_struct *old_result = results.at(i);
      	    if (*(result->uri)==(*(old_result->uri))) {
      	      results.replace(i,result);
      	      break;
	    }
	 }
      }
    }
    displayResults(*searchResults, forceRebuildDisplay);
}

void SearchDlg::displayResults(BeagleSearch::BeagleResultList &items, bool rebuildDisplay)
{
    if (displayAmount==1)
      tableHits->setUpdatesEnabled(false);
    for (BeagleSearch::BeagleResultList::ConstIterator it = items.begin(); it != items.end(); ++it) {
        BeagleSearch::beagle_result_struct *result = *it;

        bool show = false;
        switch (showMode)
        {
	  case Everywhere:
		show = true;
		break;
	  case Applications:
                show = ( result->tilegroup == BeagleSearch::Application );
		break;
          case Contacts:
		show = ( result->tilegroup == BeagleSearch::Contact );
		break;
          case Documents:
		show = ( result->tilegroup == BeagleSearch::Documents );
		break;
          case Conversations:
		show = ( result->tilegroup == BeagleSearch::Conversations );
		break;
          case Images:
		show = ( result->tilegroup == BeagleSearch::Image );
		break;
          case Media:
		show = ( result->tilegroup == BeagleSearch::Audio || result->tilegroup == BeagleSearch::Video);
		break;
          case Website:
		show = ( result->tilegroup == BeagleSearch::Website);
		break;
          case FilePathName:
		show = current_query.matches(*(result->uri));
          default:
		break;
        }

        if (!show)
           continue;

        QDateTime datetime;
        datetime.setTime_t(result->last_index_time);
        QDate date = datetime.date();

	show = false;
        switch (dateRange)
        {
           case AnyDate:
		show = true;
		break;
           case Today:
		show = ( datetime.date()==QDate::currentDate() );
		break;
           case SinceYesterday:
		show = ( datetime.date()>QDate::currentDate().addDays(-1) );
		break;
           case ThisWeek:
		show = ( datetime.date().year()==QDate::currentDate().year() &&
			datetime.date().weekNumber()==QDate::currentDate().weekNumber() );
		break;
           case ThisMonth:
		show = ( datetime.date().year()==QDate::currentDate().year() &&
			datetime.date().month()==QDate::currentDate().month() );
                break;
           case ThisYear:
		show = ( datetime.date().year()==QDate::currentDate().year() );
		break;
	   default:
                break;
        }
        if (!show)
           continue;

        int i = 0;
        for (BeagleSearch::BeagleResultList::ConstIterator result_it = displayed_results.begin(); result_it != displayed_results.end(); ++result_it) {
           bool foundplace = false;
           switch (currentSortOrder)
           {
                case Type:
                        if ( result->tilegroup < (*result_it)->tilegroup || 
                            (result->tilegroup == (*result_it)->tilegroup &&                           (*result->mime_type) < (*(*result_it)->mime_type)) ||
                            (result->tilegroup == (*result_it)->tilegroup &&                           (*result->mime_type) == (*(*result_it)->mime_type) && result->last_index_time >= (*result_it)->last_index_time) ) 
                                foundplace = true;
                        break;
		case Name:
           		if (KUrl(*(result->uri)).fileName().lower() < KUrl(*((*(result_it))->uri)).fileName().lower())
              			foundplace = true;
			break;
		case Modified:
           		if (result->last_index_time >= (*result_it)->last_index_time)
              			foundplace = true;
			break;
		default:
           		if (result->score >= (*result_it)->score)
              			foundplace = true;
			break;
           }
           if (foundplace)
		break;
           ++i;
        }
        if (displayed_results.count()==0)
          tableHits->clear();
        displayed_results.insert(i, result);
        if (displayAmount==1)
          insertResult(result,i);
        else if (i<=displayOffset+displayAmount)
          rebuildDisplay = true;
    }
    if (displayAmount==1)
      tableHits->setUpdatesEnabled(true);
    else if (rebuildDisplay) {
      tableHits->setUpdatesEnabled(false);
      fillTableHits();
      tableHits->setUpdatesEnabled(true);
    }
    updateStatus();
}

void SearchDlg::slotOpen()
{
    HitWidget* item = static_cast<HitWidget*>(sender()->parent());
    if (item) {
      QString mimetype = item->mimetype();
      if (mimetype=="beagle/x-kopete-log" || mimetype=="beagle/x-gaim-log" || item->uri().startsWith("konversation:/")) {
        KProcess *proc = new KProcess;
        *proc << "beagle-imlogviewer";
        KUrl kuri = KUrl(item->uri());
        QString uri = kuri.path();
        if (mimetype=="beagle/x-kopete-log")
          *proc << "--client" << "kopete" << "--highlight-search" << current_query.get() << uri;
        else if (item->uri().startsWith("konversation:/"))
	  *proc << "--client" << "konversation" << "--highlight-search" << current_query.get() << KUrl(item->parentUri()).path();
        else
          *proc << "--client" << "gaim" << "--highlight-search" << current_query.get() << uri;
        if (!proc->startDetached()) {
//        KMessageBox::error(0,i18n("Could not start instant message log viewer."));
          if (mimetype=="beagle/x-kopete-log")
            KRun::runUrl(uri, "text/plain", false, true);
          else if (item->uri().startsWith("konversation:/"))
	    KRun::runUrl(KUrl(item->parentUri()), "text/plain", false, true);
          else
            KRun::runUrl(uri, "text/html", false, true);
          return;
        }
      }
      else if (item->uri().startsWith("calendar:/") || item->uri().startsWith("contacts:/") 
            || item->uri().startsWith("email:/"))
      {
        slotOpenEvolution(item->uri());
      }
      else if (item->uri().startsWith("korganizer:/"))
      {
        slotOpenKOrganizer(item->uri());
      }
      else if (item->uri().startsWith("mailbox:/") && item->uri().find("thunderbird")>0)
      {
        slotOpenThunderbird(item->uri());
      }
      else if (item->uri().startsWith("kabc:/") )
      {
        slotOpenKAddressBook(item->uri().mid(8,10));
      }
      else if (item->uri().startsWith("knotes:/") )
      {
        slotOpenKNotes(item->uri().mid(9,22));
      }
      else if (item->uri().startsWith("note:/")) {
        KProcess *proc = new KProcess;
        *proc << "tomboy";
        *proc << "--open-note" << item->uri() << "--highligh-search" << "\""+current_query.get()+"\"";
        if (!proc->startDetached()) {
          KMessageBox::error(0,i18n("Could not start Tomboy."));
          return;
        }
      }
      else {
        if (mimetype=="beagle/x-konq-cache")
          mimetype = "text/html";
        KRun::runUrl(item->uri(), mimetype, false, true);
      }
    }
}

void SearchDlg::slotOpenDir()
{
    HitWidget* item = static_cast<HitWidget*>(sender()->parent());
    if (item)
      KRun::runUrl(KUrl(item->uri()).directory(), "inode/directory", false, true);
}

void SearchDlg::slotMailTo(const QString &address)
{
    KToolInvocation::invokeMailer(address, QString::null);
}

void SearchDlg::slotOpenEvolution(const QString &address)
{
    KProcess *proc = new KProcess;
    *proc << "evolution";
    *proc << address;
    if (!proc->startDetached()) {
      KMessageBox::error(0,i18n("Could not start Evolution."));
      return;
    }
}

void SearchDlg::slotOpenThunderbird(const QString &address)
{
    KProcess *proc = new KProcess;
    *proc << "thunderbird";
    *proc << "-mail";
    *proc << address;
    if (!proc->startDetached()) {
      KMessageBox::error(0,i18n("Could not start Thunderbird."));
      return;
    }
}

void SearchDlg::slotOpenKAddressBook(const QString &uid)
{
    KProcess *proc = new KProcess;
    *proc << "kaddressbook";
    *proc << "--uid" << uid;
    if (!proc->startDetached()) {
      KMessageBox::error(0,i18n("Could not start KAddressBook."));
      return;
    }
}

void SearchDlg::slotOpenKOrganizer(const QString &/*uri*/)
{
    HitWidget* item = static_cast<HitWidget*>(sender()->parent());
    if (item) {
/*       if (ensureServiceRunning("korganizer")) {
         QString mimetype = item->mimetype();
         QByteArray data;
         QDataStream arg(data, QIODevice::WriteOnly);

         if (mimetype=="text/x-korganizer-event") {
            kapp->dcopClient()->send("korganizer","CalendarIface","showEventView()", data);

            arg << item->date();
            kapp->dcopClient()->send("korganizer","CalendarIface","goDate(QDate)", data);
         }
         else
            kapp->dcopClient()->send("korganizer","CalendarIface","showTodoView()", data);
      }
*/
   }
}

void SearchDlg::slotOpenKNotes(const QString &noteid)
{
	Q_UNUSED(noteid);
/*    if (ensureServiceRunning("knotes")) {
       QByteArray data;
       QDataStream arg(data, QIODevice::WriteOnly);
       arg << noteid;

       kapp->dcopClient()->send("knotes","KNotesIface","showNote(QString)", data);
    }*/
}

void SearchDlg::slotOpenURL(const QString& url)
{
    (void) new KRun( url, parentWidget());
}

QString SearchDlg::formatBytes(QString& bytesStr) const
{
        static double kilobyte = 1024.0;
        static double megabyte = 1024.0*1024.0;
	double bytes = KGlobal::locale()->readNumber(bytesStr);
        if (bytes < megabyte)
                return KGlobal::locale()->formatNumber(bytes/kilobyte, 2) + "K";
        return KGlobal::locale()->formatNumber(bytes/megabyte, 2) + "M";
}

void SearchDlg::slotStartBeagle()
{
    beagleJustStarted = true;
    if (cb_beagleStart->isChecked()) {
      KConfigGroup config = KGlobal::config()->group("Beagle");
      config.writeEntry("AutoStart", true);
      config.sync();
    }

    KProcess *proc = new KProcess;
    *proc << "beagled";
    *proc << "--indexing-delay 2";
    if (!proc->startDetached()) {
      KMessageBox::error(0,i18n("Could not start Beagle daemon."));
      return;
    }
    slotClear();
    QTimer::singleShot(5000, this, SLOT(search()));
}

void SearchDlg::searchLostOutput(BeagleSearch::VanishedURIList &items)
{
    bool rebuildDisplay = false;
    for (BeagleSearch::VanishedURIList::ConstIterator it = items.begin(); it != items.end(); ++it) {
      int i;
      for(i = 0; i < (int)displayed_results.count(); ++i)
      {
         BeagleSearch::beagle_result_struct *result = displayed_results.at(i);
         if (*(result->uri)==(*it)) {
           displayed_results.remove(i);
           if (displayed_results.count()==0)
              searchFinished();
           else if (displayAmount==1)
              tableHits->removeItem(i);
           else if (i<=displayOffset+displayAmount) {
             rebuildDisplay = true;
             if (displayOffset>=(int)displayed_results.count())
               displayOffset-=displayAmount;
           }
           break;
        }
      }
      for(i = 0; i < (int)results.count(); ++i)
      {
         BeagleSearch::beagle_result_struct *result = results.at(i);
         if (*(result->uri)==(*it)) {
           results.remove(i);
           break;
        }
      }
    }

    if (rebuildDisplay) {
      tableHits->setUpdatesEnabled(false);
      fillTableHits();
      tableHits->setUpdatesEnabled(true);
    }

    updateStatus();
}

void SearchDlg::searchFinished()
{
    m_searchPixmap->setPixmap( BarIcon( "edit-find", 32 ) );

    still_searching = false;

    if (displayed_results.count()) {
       updateStatus();
       return;
    }

    if (editSearch->lineEdit()->text().isEmpty()) {
       showQuickTips();
       return;
    }

    tableHits->clear();
    HitWidget* item = new HitWidget(QString::null, QString::null);
    QLabel *headerLabel = new QLabel(item);
    headerLabel->setText(i18n("No results for \"%1\" were found.").arg(current_query.get()));
    item->insertHeaderWidget(0,headerLabel);

    item->setIcon("dialog-warning");

    QString text = "<qt>";
    if (showMode)
	text += i18n("- A broader search scope might produce more results.")+"<br>";
    text += i18n("- You should check the spelling of your search words.");
    if (beagleJustStarted) {
        text += "<br>"+i18n("- The Beagle daemon was just started. Please be patient until it has finished its indexing.");
        beagleJustStarted = false;
    }
    item->setDescriptionText(text+"</qt>");
    labelStatus->setText("");

    tableHits->insertItem(item);
}

void SearchDlg::searchError(const QString& error)
{
     kDebug() << "SearchDlg::searchError() " << error << endl;
}

bool SearchDlg::canPreview( KFileItem* item )
{
    if ( !KGlobalSettings::showFilePreview( item->url() ) )
        return false;

    if ( pPreviewMimeTypes == 0L )
        updatePreviewMimeTypes();

    return mimeTypeMatch( item->mimetype(), *( pPreviewMimeTypes ) );
}

void SearchDlg::updatePreviewMimeTypes()
{
    if ( pPreviewMimeTypes == 0L )
        pPreviewMimeTypes = new QStringList;
    else
        pPreviewMimeTypes->clear();

    // Load the list of plugins to determine which mimetypes are supported
    const KService::List plugins = KServiceTypeTrader::self()->query("ThumbCreator");
    KService::List::ConstIterator it;

    for ( it = plugins.constBegin(); it != plugins.constEnd(); ++it ) {
        const QStringList mimeTypes = (*it)->property("MimeTypes").toStringList();
        for (QStringList::ConstIterator mt = mimeTypes.constBegin(); mt != mimeTypes.constEnd(); ++mt)
           pPreviewMimeTypes->append(*mt);
    }
}

bool SearchDlg::mimeTypeMatch( const QString& mimeType, const QStringList& mimeList ) const
{
    for (QStringList::ConstIterator mt = mimeList.begin(); mt != mimeList.end(); ++mt)
    {
        if ( mimeType == *mt )
            return true;
        // Support for *mt == "image/*"
        QString tmp( mimeType );
        if ( (*mt).endsWith("*") && tmp.replace(QRegExp("/.*"), "/*") == (*mt) )
            return true;
    }
    return false;
}

void SearchDlg::startPreview( const KFileItemList& items )
{
    stopPreview(); // just in case
    int iconSize = KIconLoader::global()->currentSize( KIconLoader::Desktop );

    pPreviewJob = KIO::filePreview( items, KIconLoader::SizeHuge, KIconLoader::SizeHuge, iconSize,
        true /*m_pSettings->textPreviewIconTransparency()*/, true /* scale */,
        true /* save */, 0); //&(d->previewSettings) );
    connect( pPreviewJob, SIGNAL( gotPreview( const KFileItem& , const QPixmap & ) ),
             this, SLOT( slotPreview( const KFileItem& , const QPixmap & ) ) );
    connect( pPreviewJob, SIGNAL( result( KIO::Job * ) ),
             this, SLOT( slotPreviewResult() ) );
}


void SearchDlg::stopPreview()
{
    if (pPreviewJob)
    {
        pPreviewJob->kill();
        pPreviewJob = 0;
    }
}

void SearchDlg::slotPreview(const KFileItem& item, const QPixmap &pix)
{
  for(uint i=0; i < tableHits->count(); ++i)
  {
    HitWidget* w = static_cast<HitWidget*>(tableHits->item(i));
    if (w && KUrl(w->uri()).prettyUrl() == item.url().prettyUrl() ) {
      w->hiticon->setPixmap(pix);
      break;
    }
  }
}

void SearchDlg::slotPreviewResult()
{
    pPreviewJob = 0;
    previewItems.clear();
}

void SearchDlg::keyPressEvent(QKeyEvent *e)
{
    if (e->key()==Qt::Key_PageDown && displayAmount!=1) {
      if (e->state()==Qt::ControlModifier) {
        if (displayOffset+displayAmount>=(int)displayed_results.count())
          return;

        displayOffset=((displayed_results.count() -1) / displayAmount) * displayAmount;
        tableHits->setUpdatesEnabled(false);
        fillTableHits();
        tableHits->setUpdatesEnabled(true);
        updateStatus();
      }
      else
        slotNext();
    }
    else if (e->key()==Qt::Key_PageUp && displayAmount!=1) {
      if (e->state()==Qt::ControlModifier) {
        if (displayOffset==0)
          return;

        displayOffset=0;
        tableHits->setUpdatesEnabled(false);
        fillTableHits();
        tableHits->setUpdatesEnabled(true);
        updateStatus();
      }
      else
        slotPrevious();
    }
    else
      QWidget::keyPressEvent(e);
}

void SearchDlg::showEvent(QShowEvent *e )
{
    QWidget::showEvent( e );
    if (pending_showQuickTips) {
      showQuickTips();
      pending_showQuickTips=false;
    }
}

void SearchDlg::slotContextMenu( int /*row*/, int /*col*/, const QPoint & pos )
{
    KMenu *popup = new KMenu(this);
    popup->addTitle(i18n("Collapse") + " / " + i18n("Expand"));
    QAction *collapse = popup->addAction(i18n("Collapse All"));
    QAction *expand = popup->addAction(i18n("Expand All"));
    QAction *selected = popup->exec(pos);
    if (selected==collapse || selected==expand)
      for(uint i=0; i < tableHits->count(); ++i) {
         HitWidget* w = static_cast<HitWidget*>(tableHits->item(i));
         w->setCollapsed(selected==collapse);
      }
    delete popup;
}


void SearchDlg::showSearchDialog()
{
    show();
    KWindowSystem::setOnDesktop( winId(), KWindowSystem::currentDesktop() );
    kapp->updateUserTimestamp();
    KWindowSystem::forceActiveWindow( winId() );
    editSearch->setFocus();
    editSearch->lineEdit()->selectAll();
}

void SearchDlg::configChanged()
{
    KConfigGroup config = KGlobal::config()->group("General");

    showBigTiles=config.readEntry("ShowBigTiles", false);
    searchAsYouType=config.readEntry("SearchAsYouType", true);
    setDisplayAmount(config.readEntry("DisplayAmount", 20));
    setSortOrder(config.readEntry("DefaultSortOrder", 0));
}

void SearchDlg::searchProgramList(QString relPath)
{
    KServiceGroup::Ptr group = KServiceGroup::group(relPath);
    if (!group || !group->isValid())
      return;

    KServiceGroup::List list = group->entries();
    if (list.isEmpty())
      return;

    KServiceGroup::List::ConstIterator it = list.constBegin();
    for(; it != list.constEnd(); ++it) {
	KSycocaEntry::Ptr e = (*it);

	if(e) {
		if(e->isType(KST_KServiceGroup)) {
			KServiceGroup::Ptr g = KServiceGroup::Ptr::staticCast(e);
			if(!g->noDisplay())
				searchProgramList(g->relPath());
		} else if(e->isType(KST_KService)) {
			KService::Ptr s = KService::Ptr::staticCast(e);
			if(s->type() == "Application" && !s->noDisplay() && !checkUriInResults(KStandardDirs::locate("apps", s->desktopEntryPath()))) {
				if (!current_query.matches(s->name().lower()+' '+s->genericName()+' '+
                                    s->exec()+' '+s->keywords().join(",")+' '+s->comment()+' ' +
                                    group->caption()+' '+s->categories().join(",")))
					continue;

				BeagleSearch::beagle_result_struct *result = new BeagleSearch::beagle_result_struct;
				result->mime_type=new QString("application/x-desktop");
                                result->tilegroup = BeagleSearch::Application;
				result->uri=new QString("file://"+KStandardDirs::locate("apps", s->desktopEntryPath()));
				result->properties.append("fixme:Name="+s->name());
				result->tilegroup = BeagleSearch::Application;
				result->score = 0.0;
				result->show_expanded=showBigTiles;
				results.append(result);
				new_results.append(result);
			}
		}
	}
    }
}

bool SearchDlg::checkUriInResults(const QString& path) const
{
    for (BeagleSearch::BeagleResultList::ConstIterator it = results.begin(); it != results.end(); ++it) {
        BeagleSearch::beagle_result_struct *result = *it;
        if (*(result->uri) == path)
           return true;
    }
    return false;
}

void SearchDlg::searchBookmarks(KBookmarkGroup group)
{
	KBookmark bookmark = group.first();
	while(!bookmark.isNull()) {
		if (bookmark.isGroup()) {
			searchBookmarks(bookmark.toGroup());
		} else if (!bookmark.isSeparator() && !bookmark.isNull()) {
				if (!current_query.matches(bookmark.fullText()+' '+bookmark.url().url())) {
                                        bookmark = group.next(bookmark);
	    				continue;
                                }

                                if (checkUriInResults(bookmark.url().prettyUrl())) {
                                        bookmark = group.next(bookmark);
                                        continue;
                                }

				BeagleSearch::beagle_result_struct *result = new BeagleSearch::beagle_result_struct;
				result->mime_type=new QString("text/html");
				result->uri=new QString(bookmark.url().prettyUrl());
				result->properties.append("dc:title="+bookmark.fullText());
				result->tilegroup = BeagleSearch::Website;
				result->score = 0.0;
				result->show_expanded=showBigTiles;
				results.append(result);
				new_results.append(result);
		}
		bookmark = group.next(bookmark);
	}
}

void SearchDlg::searchAddressbook()
{
    if (!m_addressBook)
      m_addressBook = KABC::StdAddressBook::self( false );

    KABC::AddressBook::ConstIterator it = m_addressBook->constBegin();
    while (it!=m_addressBook->constEnd()) {
        if (!current_query.matches((*it).assembledName()+' '+(*it).fullEmail())) {
            it++;
            continue;
        }

        if (checkUriInResults("kabc:///"+(*it).uid())) {
             it++;
             continue;
        }

        QString realName = (*it).realName();
        if (realName.isEmpty())
            realName=(*it).preferredEmail();

	BeagleSearch::beagle_result_struct *result = new BeagleSearch::beagle_result_struct;
	result->mime_type=new QString("text/html");
        result->uri=new QString("kabc:///"+(*it).uid());
	result->properties.append("vCard:FN="+realName);
        result->properties.append("vCard:EMAIL="+(*it).preferredEmail());

	// Add phone numbers
	QString number;
        number = (*it).phoneNumber(KABC::PhoneNumber::Work).number();
        if (!number.isEmpty())
	   result->properties.append(i18n(I18N_NOOP("Business phone: %1")"<br>").arg(number));

        number = (*it).phoneNumber(KABC::PhoneNumber::Cell).number();
        if (!number.isEmpty())
	   result->properties.append(i18n(I18N_NOOP("Mobile phone: %1")"<br>").arg(number));

        number = (*it).phoneNumber(KABC::PhoneNumber::Home).number();
        if (!number.isEmpty())
	   result->properties.append(i18n(I18N_NOOP("Home phone: %1")"<br>").arg(number));

	result->tilegroup = BeagleSearch::Contact;
	result->score = 0.0;
	result->show_expanded=showBigTiles;
	results.append(result);
	new_results.append(result);

       it++;
    }
}


bool SearchDlg::eventFilter(QObject *obj, QEvent *e)
{
#define showSwitchesCount 9
static QLabel* showSwitches[showSwitchesCount] = {showEverything, showApplications, showContacts, showDocuments,
                                   showConversations, showImages, showMedia, showWebPages, showFilePathName};

#define sortSwitchesCount 4
static QLabel* sortSwitches[sortSwitchesCount] = {sortByType, sortByDate, sortByName, sortByRelevance};

#define dateSwitchesCount 6
static QLabel* dateSwitches[dateSwitchesCount] = {showAnyDate, showToday, showSinceYesterday, showThisWeek, 
                                  showThisMonth, showThisYear};

    if (e->type()==QEvent::Enter) {
       QApplication::setOverrideCursor( QCursor(Qt::PointingHandCursor) );

       for (int i=0; i<showSwitchesCount; ++i)
          if (obj ==showSwitches[i]) {
             ((QLabel*)obj)->setBackgroundRole(QPalette::AlternateBase);
             return true;
          }

       for (int i=0; i<sortSwitchesCount; ++i)
          if (obj ==sortSwitches[i]) {
             ((QLabel*)obj)->setBackgroundRole(QPalette::AlternateBase);
             return true;
          }

       for (int i=0; i<dateSwitchesCount; ++i)
          if (obj ==dateSwitches[i]) {
             ((QLabel*)obj)->setBackgroundRole(QPalette::AlternateBase);
             return true;
          }
    } else if (e->type()==QEvent::Leave) {
       QApplication::restoreOverrideCursor();

       for (int i=0; i<showSwitchesCount; ++i)
          if (obj ==showSwitches[i]) {
             ((QLabel*)obj)->setBackgroundRole(QPalette::Base);
             return true;
          }

       for (int i=0; i<sortSwitchesCount; ++i)
          if (obj ==sortSwitches[i]) {
             ((QLabel*)obj)->setBackgroundRole(QPalette::Base);
             return true;
          }

       for (int i=0; i<dateSwitchesCount; ++i)
          if (obj ==dateSwitches[i]) {
             ((QLabel*)obj)->setBackgroundRole(QPalette::Base);
             return true;
          }
    } else if (e->type()==QEvent::MouseButtonPress) {
       if (obj == buttonClear && QApplication::mouseButtons() & Qt::MidButton) {
           search( QApplication::clipboard()->text( QClipboard::Selection ) );
           return true;
       }

       for (int i=0; i<showSwitchesCount; ++i)
	  if (obj ==showSwitches[i]) {
             if (i!=showMode) {
                QFont f= showSwitches[showMode]->font();
                f.setBold(false);
                showSwitches[showMode]->setFont(f);
                showMode = (ScopeType)i;
                f.setBold(true);
                showSwitches[showMode]->setFont(f);
                sortFilterResults();
             }
             return true;
          }

       for (int i=0; i<sortSwitchesCount; ++i)
	  if (obj ==sortSwitches[i]) {
             setSortOrder(i);
             return true;
          }

       for (int i=0; i<dateSwitchesCount; ++i)
	  if (obj ==dateSwitches[i]) {
             if (i!=dateRange) {
                QFont f= dateSwitches[dateRange]->font();
                f.setBold(false);
                dateSwitches[dateRange]->setFont(f);
                dateRange = (DateRange)i;
                f.setBold(true);
                dateSwitches[dateRange]->setFont(f);
                sortFilterResults();
             }
             return true;
          }
    }

    return false;
}

bool SearchDlg::ensureServiceRunning(const QString & name)
{
	Q_UNUSED(name);
/*    QStringList URLs;
    QByteArray data, replyData;
    QByteArray replyType;
    QDataStream arg(data, QIODevice::WriteOnly);
    arg << name << URLs;

    if ( !kapp->dcopClient()->call( "klauncher", "klauncher", "start_service_by_desktop_name(QString,QStringList)",
                      data, replyType, replyData) ) {
        qWarning( "call to klauncher failed.");
        return false;
    }
    QDataStream reply(replyData, QIODevice::ReadOnly);

    if ( replyType != "serviceResult" )
    {
        qWarning( "unexpected result '%s' from klauncher.", replyType.data());
        return false;
    }
    int result;
    QByteArray dcopName;
    QString error;
//  reply >> result >> dcopName >> error;
    if (result != 0)
    {
        qWarning("Error starting: %s", error.local8Bit().data());
        return false;
    }
*/
    return true;
}

#include "searchdlg.moc"
