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 | 
