]> cloud.milkyroute.net Git - dolphin.git/commitdiff
Adds autocompletition to the dolphin-search-box. So far existing tags and commands...
authorMatthias Fuchs <mat69@gmx.net>
Mon, 5 Oct 2009 18:46:35 +0000 (18:46 +0000)
committerMatthias Fuchs <mat69@gmx.net>
Mon, 5 Oct 2009 18:46:35 +0000 (18:46 +0000)
svn path=/trunk/KDE/kdebase/apps/; revision=1031685

src/dolphinsearchbox.cpp
src/dolphinsearchbox.h

index d27b080148e1e3138e00f2e70823a87e9c7cb66b..134fce9c72598db401ed6e6f5764def4d2b5e5b5 100644 (file)
  ***************************************************************************/
 #include "dolphinsearchbox.h"
 
+#include <config-nepomuk.h>
+
 #include <kdialog.h>
 #include <kglobalsettings.h>
 #include <klineedit.h>
 #include <klocale.h>
-#include <kicon.h>
 #include <kiconloader.h>
 
 #include <QEvent>
 #include <QKeyEvent>
 #include <QHBoxLayout>
+#include <QStandardItemModel>
+#include <QtGui/QCompleter>
+#include <QtGui/QTreeView>
 #include <QToolButton>
 
+#ifdef HAVE_NEPOMUK
+#include <Nepomuk/ResourceManager>
+#include <Nepomuk/Tag>
+#endif //HAVE_NEPOMUK
+
+
+DolphinSearchCompleter::DolphinSearchCompleter(KLineEdit* linedit) :
+    QObject(0),
+    q(linedit),
+    m_completer(0),
+    m_completionModel(0),
+    m_wordStart(-1),
+    m_wordEnd(-1)
+{
+}
+
+void DolphinSearchCompleter::init()
+{
+    m_completionModel = new QStandardItemModel(this);
+
+#ifdef HAVE_NEPOMUK
+    if (!Nepomuk::ResourceManager::instance()->init()) {
+        //read all currently set tags
+        //NOTE if the user changes tags elsewhere they won't get updated here
+        QList<Nepomuk::Tag> tags = Nepomuk::Tag::allTags();
+        foreach (const Nepomuk::Tag& tag, tags) {
+            const QString tagText = tag.label();
+            addCompletionItem(tagText,
+                                "tag:\"" + tagText + '\"',
+                                i18nc("Tag as in Nepomuk::Tag", "Tag"),
+                                KIcon("mail-tagged"));
+        }
+    }
+#endif //HAVE_NEPOMUK
+
+    //add "and", "or" and "-" (not) logic operators
+    addCompletionItem(i18nc("and ss in a logic operator to connect search terms", "and"),
+                        "and",
+                        "logic operator and");
+    addCompletionItem(i18nc("or as in a logic operator to connect search terms", "or"),
+                        "or",
+                        "logic operator or");
+    addCompletionItem(i18nc("not as in a logic operator to connect search terms", "not"),
+                        "-",
+                        "logic operator not");
+
+    m_completionModel->sort(0, Qt::AscendingOrder);
+
+    m_completer = new QCompleter(m_completionModel, this);
+    m_completer->setWidget(q);
+    m_completer->setCaseSensitivity(Qt::CaseInsensitive);
+    QTreeView *view = new QTreeView;
+    m_completer->setPopup(view);
+    view->setRootIsDecorated(false);
+    view->setHeaderHidden(true);
+
+    connect(q, SIGNAL(textEdited(QString)), this, SLOT(slotTextEdited(QString)));
+    connect(m_completer, SIGNAL(activated(QModelIndex)), this, SLOT(completionActivated(QModelIndex)));
+    connect(m_completer, SIGNAL(highlighted(QModelIndex)), this, SLOT(highlighted(QModelIndex)));
+}
+
+void DolphinSearchCompleter::addCompletionItem(const QString& displayed, const QString& usedForCompletition, const QString& description, const KIcon& icon)
+{
+    QList<QStandardItem*> items;
+    QStandardItem *item = new QStandardItem();
+    item->setData(QVariant(displayed), Qt::DisplayRole);
+    item->setData(QVariant(usedForCompletition), Qt::UserRole);
+    items << item;
+
+    item = new QStandardItem(description);
+    item->setIcon(icon);
+    items << item;
+
+    m_completionModel->insertRow(m_completionModel->rowCount(), items);
+}
+
+void DolphinSearchCompleter::findText(int* wordStart, int* wordEnd, QString* newWord, int cursorPos, const QString &input)
+{
+    --cursorPos;//decrease to get a useful position (not the end of the word e.g.)
+
+    if (!wordStart || !wordEnd) {
+        return;
+    }
+
+    *wordStart = -1;
+    *wordEnd = -1;
+
+    //the word might contain "" and thus maybe spaces
+    if (input.contains('\"')) {
+        int tempStart = -1;
+        int tempEnd = -1;
+
+        do {
+            tempStart = input.indexOf('\"', tempEnd + 1);
+            tempEnd = input.indexOf('\"', tempStart + 1);
+            if ((cursorPos >= tempStart) && (cursorPos <= tempEnd)) {
+                *wordStart = tempStart;
+                *wordEnd = tempEnd;
+                break;
+            } else if ((tempEnd == -1) && (cursorPos >= tempStart)) {
+                //one " found, so probably the beginning of the new word
+                *wordStart = tempStart;
+                break;
+            }
+        } while ((tempStart != -1) && (tempEnd != -1));
+    }
+
+    if (*wordEnd > -1) {
+        *wordEnd = input.indexOf(' ', *wordEnd) - 1;
+    } else {
+        *wordEnd = input.indexOf(' ', cursorPos) - 1;
+    }
+    if (*wordEnd < 0) {
+        *wordEnd = input.length() - 1;
+    }
+
+    if (*wordStart > -1) {
+        *wordStart = input.lastIndexOf(' ', *wordStart + 1) + 1;
+    } else {
+        *wordStart = input.lastIndexOf(' ', cursorPos) + 1;
+    }
+    if (*wordStart < 0) {
+        *wordStart = 0;
+    }
+
+
+    QString word = input.mid(*wordStart, *wordEnd - *wordStart + 1);
+
+    //remove opening braces or negations ('-' = not) at the beginning
+    while (word.count() && ((word[0] == '(') || (word[0] == '-'))) {
+        word.remove(0, 1);
+        ++(*wordStart);
+    }
+
+    //remove ending braces at the end
+    while (word.count() && (word[word.count() - 1] == ')')) {
+        word.remove(word.count() - 1, 1);
+        --(*wordEnd);
+    }
+
+    if (newWord) {
+        *newWord = word;
+    }
+}
+
+void DolphinSearchCompleter::slotTextEdited(const QString& text)
+{
+    findText(&m_wordStart, &m_wordEnd, &m_userText, q->cursorPosition(), text);
+
+    if (!m_userText.isEmpty()) {
+        const int role = m_completer->completionRole();
+
+        //change the role used for comparison depending on what the user entered
+        if (m_userText.contains(':') || m_userText.contains('\"')) {
+            //assume that m_userText contains searchinformation like 'tag:"..."'
+            if (role != Qt::UserRole) {
+                m_completer->setCompletionRole(Qt::UserRole);
+            }
+        } else if (role != Qt::EditRole) {
+            m_completer->setCompletionRole(Qt::EditRole);
+        }
+
+        m_completer->setCompletionPrefix(m_userText);
+        m_completer->complete();
+    }
+}
+
+void DolphinSearchCompleter::highlighted(const QModelIndex& index)
+{
+    QString text = q->text();
+    int wordStart;
+    int wordEnd;
+
+    findText(&wordStart, &wordEnd, 0, q->cursorPosition(), text);
+
+    QString replace = index.sibling(index.row(), 0).data(Qt::UserRole).toString();
+    //show the originally entered text
+    if (replace.isEmpty()) {
+        replace = m_userText;
+    }
+
+    text.replace(wordStart, wordEnd - wordStart + 1, replace);
+    q->setText(text);
+    q->setCursorPosition(wordStart + replace.length());
+}
+
+void DolphinSearchCompleter::activated(const QModelIndex& index)
+{
+    if ((m_wordStart == -1) || (m_wordStart == -1)) {
+        return;
+    }
+
+    const QString replace = index.sibling(index.row(), 0).data(Qt::UserRole).toString();
+    QString newText = q->text();
+    newText.replace(m_wordStart, m_wordEnd - m_wordStart + 1, replace);
+    q->setText(newText);
+}
+
 DolphinSearchBox::DolphinSearchBox(QWidget* parent) :
     QWidget(parent),
     m_searchInput(0),
-    m_searchButton(0)
+    m_searchButton(0),
+    m_completer(0)
 {
     QHBoxLayout* hLayout = new QHBoxLayout(this);
     hLayout->setMargin(0);
@@ -47,6 +250,9 @@ DolphinSearchBox::DolphinSearchBox(QWidget* parent) :
     connect(m_searchInput, SIGNAL(returnPressed()),
             this, SLOT(emitSearchSignal()));
 
+    m_completer = new DolphinSearchCompleter(m_searchInput);
+    m_completer->init();
+
     m_searchButton = new QToolButton(this);
     m_searchButton->setAutoRaise(true);
     m_searchButton->setIcon(KIcon("edit-find"));
@@ -58,6 +264,7 @@ DolphinSearchBox::DolphinSearchBox(QWidget* parent) :
 
 DolphinSearchBox::~DolphinSearchBox()
 {
+    delete m_completer;
 }
 
 bool DolphinSearchBox::event(QEvent* event)
index 949c0b5478895e96359e4b8ee40749e4b3ed0d9e..2f1c6e1721a8f7f8320eb620035d9571c7206977 100644 (file)
 
 #include <QWidget>
 
+#include <KIcon>
+
 class KLineEdit;
 class KUrl;
+class QCompleter;
+class QModelIndex;
+class QStandardItemModel;
 class QToolButton;
 
+/**
+ * @brief used for completition for the DolphinSearchBox
+ */
+class DolphinSearchCompleter : public QObject
+{
+    Q_OBJECT
+    public:
+        DolphinSearchCompleter(KLineEdit *linedit);
+
+        void init();
+
+    public slots:
+        void highlighted(const QModelIndex& index);
+        void activated(const QModelIndex& index);
+        void slotTextEdited(const QString &text);
+
+    private:
+        void addCompletionItem(const QString& displayed, const QString& usedForCompletition, const QString& description = QString(), const KIcon& icon = KIcon());
+
+        void findText(int* wordStart, int* wordEnd, QString* newWord, int cursorPos, const QString &input);
+
+    private:
+        KLineEdit* q;
+        QCompleter* m_completer;
+        QStandardItemModel* m_completionModel;
+        QString m_userText;
+        int m_wordStart;
+        int m_wordEnd;
+};
+
 /**
  * @brief Input box for searching files with Nepomuk.
  */
@@ -50,9 +85,14 @@ signals:
 private slots:
     void emitSearchSignal();
 
+
+
+
 private:
     KLineEdit* m_searchInput;
     QToolButton* m_searchButton;
+
+    DolphinSearchCompleter* m_completer;
 };
 
 #endif