diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/searchbar.cpp | 477 | ||||
-rw-r--r-- | src/searchbar.h | 104 |
2 files changed, 581 insertions, 0 deletions
diff --git a/src/searchbar.cpp b/src/searchbar.cpp new file mode 100644 index 00000000..f1f6ef80 --- /dev/null +++ b/src/searchbar.cpp @@ -0,0 +1,477 @@ +/* ============================================================ + * + * This file is a part of the reKonq project + * + * Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot 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, 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. + * + * ============================================================ */ + +#include "searchbar.h" + + +#include <unistd.h> +#include <QLineEdit> +#include <QApplication> +#include <kaction.h> +#include <kconfig.h> +#include <ksharedconfig.h> +#include <kdebug.h> +#include <kdesktopfile.h> +#include <kgenericfactory.h> +#include <kglobal.h> +#include <khtml_part.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmimetype.h> +#include <kprotocolmanager.h> +#include <kstandarddirs.h> +#include <kurifilter.h> +#include <kservice.h> +#include <kactioncollection.h> + +#include <qpainter.h> +#include <qmenu.h> +#include <qtimer.h> +#include <qstyle.h> +#include <QPixmap> +#include <QMouseEvent> + + + + +SearchBar::SearchBar() : + m_searchCombo(0), + m_searchMode(UseSearchProvider), + m_urlEnterLock(false), + m_process(0) +{ + m_searchCombo = new SearchBarCombo(0); + m_searchCombo->lineEdit()->installEventFilter(this); + connect(m_searchCombo, SIGNAL(activated(const QString &)), SLOT(startSearch(const QString &))); + connect(m_searchCombo, SIGNAL(iconClicked()), SLOT(showSelectionMenu())); + m_searchCombo->setWhatsThis(i18n("Search Bar<p>" + "Enter a search term. Click on the icon to change search mode or provider.</p>")); + + m_popupMenu = 0; + + m_searchComboAction = actionCollection()->addAction("toolbar_search_bar"); + m_searchComboAction->setText(i18n("Search Bar")); + m_searchComboAction->setDefaultWidget(m_searchCombo); + m_searchComboAction->setShortcutConfigurable(false); + + + KAction *a = actionCollection()->addAction("focus_search_bar"); + a->setText(i18n("Focus Searchbar")); + a->setShortcut(Qt::CTRL+Qt::Key_S); + connect(a, SIGNAL(triggered()), this, SLOT(focusSearchbar())); + + configurationChanged(); + + // parent is the KonqMainWindow and we want to listen to PartActivateEvent events. + parent->installEventFilter(this); +} + + + +SearchBar::~SearchBar() +{ + KConfigGroup config(KGlobal::config(), "SearchBar"); + config.writeEntry("Mode", (int) m_searchMode); + config.writeEntry("CurrentEngine", m_currentEngine); + + delete m_searchCombo; + m_searchCombo = 0L; + delete m_process; + m_process=0L; +} + +static QChar delimiter() +{ + static QChar s_delimiter = 0; + if (s_delimiter == 0) { + KConfig _config("kuriikwsfilterrc", KConfig::NoGlobals); + KConfigGroup config(&_config, "General"); + s_delimiter = config.readEntry("KeywordDelimiter", int(':')); + } + return s_delimiter; +} + + + +void SearchBar::nextSearchEntry() +{ + if (m_searchMode == FindInThisPage) { + m_searchMode = UseSearchProvider; + if (!m_searchEngines.isEmpty()) { + m_currentEngine = m_searchEngines.first(); + } else { + m_currentEngine = "google"; + } + } else { + int index = m_searchEngines.indexOf(m_currentEngine); + ++index; + if (index >= m_searchEngines.count()) { + m_searchMode = FindInThisPage; + } else { + m_currentEngine = m_searchEngines.at(index); + } + } + setIcon(); +} + +void SearchBar::previousSearchEntry() +{ + if (m_searchMode == FindInThisPage) { + m_searchMode = UseSearchProvider; + if (!m_searchEngines.isEmpty()) { + m_currentEngine = m_searchEngines.last(); + } else { + m_currentEngine = "google"; + } + } else { + int index = m_searchEngines.indexOf(m_currentEngine); + if (index == 0) { + m_searchMode = FindInThisPage; + } else { + --index; + m_currentEngine = m_searchEngines.at(index); + } + } + setIcon(); +} + +void SearchBar::startSearch(const QString &search) +{ + if ( m_urlEnterLock || search.isEmpty() ) + return; + if (m_searchMode == UseSearchProvider) { + m_urlEnterLock = true; + KService::Ptr service; + KUriFilterData data; + QStringList list; + list << "kurisearchfilter" << "kuriikwsfilter"; + + service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(m_currentEngine)); + if (service) { + const QString searchProviderPrefix = service->property("Keys").toStringList().first() + delimiter(); + data.setData(searchProviderPrefix + search); + } + + if (!service || !KUriFilter::self()->filterUri(data, list)) { + data.setData(QLatin1String("google") + delimiter() + search); + KUriFilter::self()->filterUri(data, list); + } + + if (QApplication::keyboardModifiers() & Qt::ControlModifier) { + KParts::OpenUrlArguments arguments; + KParts::BrowserArguments browserArguments; + browserArguments.setNewTab(true); + if (ext) + emit ext->createNewWindow(data.uri(), arguments, browserArguments); + } else { + if (ext) { + emit ext->openUrlRequest(data.uri()); + m_part->widget()->setFocus(); // #152923 + } + } + } + + m_searchCombo->addToHistory(search); + m_searchCombo->setItemIcon(0, m_searchIcon); + + m_urlEnterLock = false; +} + +void SearchBarPlugin::setIcon() +{ + if (m_searchMode == FindInThisPage) { + m_searchIcon = SmallIcon("edit-find"); + } else { + KService::Ptr service; + KUriFilterData data; + QStringList list; + list << "kurisearchfilter" << "kuriikwsfilter"; + + service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(m_currentEngine)); + if (service) { + const QString searchProviderPrefix = service->property("Keys").toStringList().first() + delimiter(); + data.setData(searchProviderPrefix + "some keyword"); + } + + if (service && KUriFilter::self()->filterUri(data, list)) + { + QString iconPath = KStandardDirs::locate("cache", KMimeType::favIconForUrl(data.uri()) + ".png"); + if (iconPath.isEmpty()) { + m_searchIcon = SmallIcon("unknown"); + } else { + m_searchIcon = QPixmap(iconPath); + } + } + else + { + m_searchIcon = SmallIcon("google"); + } + } + + // Create a bit wider icon with arrow + QPixmap arrowmap = QPixmap(m_searchIcon.width()+5,m_searchIcon.height()+5); + arrowmap.fill(m_searchCombo->lineEdit()->palette().color(m_searchCombo->lineEdit()->backgroundRole())); + QPainter p(&arrowmap); + p.drawPixmap(0, 2, m_searchIcon); + QStyleOption opt; + opt.state = QStyle::State_None; + opt.rect = QRect(arrowmap.width()-6, arrowmap.height()-5, 6, 5); + m_searchCombo->style()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &opt, &p, m_searchCombo); + p.end(); + m_searchIcon = arrowmap; + + m_searchCombo->setIcon(m_searchIcon); +} + +void SearchBar::showSelectionMenu() +{ + if (!m_popupMenu) { + KUriFilterData data; + QStringList list; + list << "kurisearchfilter" << "kuriikwsfilter"; + + m_popupMenu = new QMenu(m_searchCombo); + m_popupMenu->setObjectName("search selection menu"); + m_popupMenu->addAction(KIcon("edit-find"), i18n("Find in This Page"), this, SLOT(useFindInThisPage())); + m_popupMenu->addSeparator(); + + int i=-1; + for (QStringList::ConstIterator it = m_searchEngines.begin(); it != m_searchEngines.end(); ++it) { + i++; + KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(*it)); + if (!service) { + continue; + } + const QString searchProviderPrefix = service->property("Keys").toStringList().first() + delimiter(); + data.setData(searchProviderPrefix + "some keyword"); + + if (KUriFilter::self()->filterUri(data, list)) + { + QIcon icon; + QString iconPath = KStandardDirs::locate("cache", KMimeType::favIconForUrl(data.uri()) + ".png"); + if (iconPath.isEmpty()) { + icon = KIcon("unknown"); + } else { + icon = QPixmap(iconPath); + } + QAction* action = m_popupMenu->addAction(icon, service->name()); + action->setData(qVariantFromValue(i)); + } + } + + m_popupMenu->addSeparator(); + m_popupMenu->addAction(KIcon("preferences-web-browser-shortcuts"), i18n("Select Search Engines..."), + this, SLOT(selectSearchEngines())); + connect(m_popupMenu, SIGNAL(triggered(QAction *)), SLOT(useSearchProvider(QAction *))); + } + m_popupMenu->popup(m_searchCombo->mapToGlobal(QPoint(0, m_searchCombo->height() + 1))); +} + +void SearchBar::useFindInThisPage() +{ + m_searchMode = FindInThisPage; + setIcon(); +} + +void SearchBar::useSearchProvider(QAction *action) +{ + bool ok = false; + const int id = action->data().toInt(&ok); + if(!ok) { + // Not a search engine entry selected + return; + } + m_searchMode = UseSearchProvider; + m_currentEngine = m_searchEngines.at(id); + setIcon(); + m_searchCombo->lineEdit()->selectAll(); +} + +void SearchBar::selectSearchEngines() +{ + m_process = new KProcess; + + *m_process << "kcmshell4" << "ebrowsing"; + + connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(searchEnginesSelected(int,QProcess::ExitStatus))); + + m_process->start(); + if(!m_process->waitForStarted()) + { + kDebug(1202) << "Couldn't invoke kcmshell"; + delete m_process; + m_process = 0; + } +} + +void SearchBar::searchEnginesSelected(int exitCode, QProcess::ExitStatus exitStatus) +{ + Q_UNUSED(exitCode); + if(exitStatus == QProcess::NormalExit) { + KConfigGroup config(KGlobal::config(), "SearchBar"); + config.writeEntry("CurrentEngine", m_currentEngine); + config.sync(); + configurationChanged(); + } + delete m_process; + m_process = 0; +} + +void SearchBar::configurationChanged() +{ + KConfigGroup config(KSharedConfig::openConfig("kuriikwsfilterrc"), "General"); + const QString engine = config.readEntry("DefaultSearchEngine", "google"); + + QStringList favoriteEngines; + favoriteEngines << "google" << "google_groups" << "google_news" << "webster" << "dmoz" << "wikipedia"; + favoriteEngines = config.readEntry("FavoriteSearchEngines", favoriteEngines); + + delete m_popupMenu; + m_popupMenu = 0; + m_searchEngines.clear(); + m_searchEngines << engine; + for (QStringList::ConstIterator it = favoriteEngines.begin(); it != favoriteEngines.end(); ++it) + if(*it!=engine) + m_searchEngines << *it; + + if(engine.isEmpty()) { + m_providerName = "Google"; + } else { + KDesktopFile file("services", "searchproviders/" + engine + ".desktop"); + m_providerName = file.readName(); + } + + config = KConfigGroup(KGlobal::config(), "SearchBar"); + m_searchMode = (SearchModes) config.readEntry("Mode", (int) UseSearchProvider); + m_currentEngine = config.readEntry("CurrentEngine", engine); + + if (m_currentEngine.isEmpty()) + m_currentEngine = "google"; + + setIcon(); +} + + + +void SearchBar::updateComboVisibility() +{ + if (!m_part|| m_searchComboAction->associatedWidgets().isEmpty()) + { + m_searchCombo->setPluginActive(false); + m_searchCombo->hide(); + } else { + m_searchCombo->setPluginActive(true); + m_searchCombo->show(); + } +} + + + +void SearchBar::focusSearchbar() +{ + m_searchCombo->setFocus(Qt::ShortcutFocusReason); +} + + + +SearchBarCombo::SearchBarCombo(QWidget *parent) : + KHistoryComboBox(parent), + m_pluginActive(true) +{ + setDuplicatesEnabled(false); + setFixedWidth(180); + connect(this, SIGNAL(cleared()), SLOT(historyCleared())); + + Q_ASSERT(useCompletion()); + + KConfigGroup config(KGlobal::config(), "SearchBar"); + QStringList list = config.readEntry( "History list", QStringList() ); + list.prepend(QString()); // empty item + setHistoryItems(list, true); + Q_ASSERT(currentText().isEmpty()); // KHistoryComboBox calls clearEditText +} + +const QPixmap &SearchBarCombo::icon() const +{ + return m_icon; +} + +void SearchBarCombo::setIcon(const QPixmap &icon) +{ + m_icon = icon; + const QString editText = currentText(); + if (count() == 0) { + insertItem(0, m_icon, 0); + } else { + for(int i = 0; i < count(); i++) { + setItemIcon(i, m_icon); + } + } + setEditText(editText); +} + +int SearchBarCombo::findHistoryItem(const QString &searchText) +{ + for(int i = 0; i < count(); i++) { + if (itemText(i) == searchText) { + return i; + } + } + + return -1; +} + +void SearchBarCombo::mousePressEvent(QMouseEvent *e) +{ + QStyleOptionComplex opt; + int x0 = QStyle::visualRect(layoutDirection(), style()->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this), rect()).x(); + + if (e->x() > x0 + 2 && e->x() < lineEdit()->x()) { + emit iconClicked(); + + e->accept(); + } else { + KHistoryComboBox::mousePressEvent(e); + } +} + +void SearchBarCombo::historyCleared() +{ + setIcon(m_icon); +} + +void SearchBarCombo::setPluginActive(bool pluginActive) +{ + m_pluginActive = pluginActive; +} + +void SearchBarCombo::show() +{ + if (m_pluginActive) { + KHistoryComboBox::show(); + } +} + +SearchBarCombo::~SearchBarCombo() +{ + KConfigGroup config(KGlobal::config(), "SearchBar"); + config.writeEntry( "History list", historyItems() ); +} + +#include "searchbar.moc" diff --git a/src/searchbar.h b/src/searchbar.h new file mode 100644 index 00000000..222b97e4 --- /dev/null +++ b/src/searchbar.h @@ -0,0 +1,104 @@ +/* ============================================================ + * + * This file is a part of the reKonq project + * + * Copyright (C) 2008 by Andrea Diamantini <adjam7 at gmail dot 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, 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. + * + * ============================================================ */ + +#ifndef SEARCHBAR_H +#define SEARCHBAR_H + +#include <KHistoryComboBox> +#include <KProcess> +#include <KAction> +#include <KDialog> + +#include <QPixmap> +#include <QString> +#include <QMenu> + +class KHTMLPart; + + +class SearchBarCombo : public KHistoryComboBox +{ + Q_OBJECT + +public: + SearchBarCombo(QWidget *parent); + ~SearchBarCombo(); + const QPixmap &icon() const; + void setIcon(const QPixmap &icon); + int findHistoryItem(const QString &text); + +public slots: + virtual void show(); + +signals: + void iconClicked(); + +protected: + virtual void mousePressEvent(QMouseEvent *e); + +private slots: + void historyCleared(); + +private: + QPixmap m_icon; +}; + + +class SearchBar : public KDialog +{ + Q_OBJECT + +public: + enum SearchModes { FindInThisPage = 0, UseSearchProvider }; + + SearchBar(); + virtual ~SearchBar(); + +private slots: + void startSearch(const QString &search); + void setIcon(); + void showSelectionMenu(); + + void useFindInThisPage(); + void useSearchProvider(QAction *); + void selectSearchEngines(); + void searchEnginesSelected(int, QProcess::ExitStatus); + void configurationChanged(); + + void updateComboVisibility(); + + void focusSearchbar(); +private: + void nextSearchEntry(); + void previousSearchEntry(); + + + SearchBarCombo *m_searchCombo; + KAction *m_searchComboAction; + QMenu *m_popupMenu; + QPixmap m_searchIcon; + SearchModes m_searchMode; + QString m_providerName; + bool m_urlEnterLock; + QString m_currentEngine; + QStringList m_searchEngines; + KProcess *m_process; +}; + +#endif |