From: Matthias Fuchs Date: Mon, 5 Oct 2009 18:46:35 +0000 (+0000) Subject: Adds autocompletition to the dolphin-search-box. So far existing tags and commands... X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/commitdiff_plain/b6310bf521ebb42ef5b4a4adc39c75fe2d2a545a Adds autocompletition to the dolphin-search-box. So far existing tags and commands like "and", "or" and "-" (for not) are offered as completition-suggestions. svn path=/trunk/KDE/kdebase/apps/; revision=1031685 --- diff --git a/src/dolphinsearchbox.cpp b/src/dolphinsearchbox.cpp index d27b08014..134fce9c7 100644 --- a/src/dolphinsearchbox.cpp +++ b/src/dolphinsearchbox.cpp @@ -18,22 +18,225 @@ ***************************************************************************/ #include "dolphinsearchbox.h" +#include + #include #include #include #include -#include #include #include #include #include +#include +#include +#include #include +#ifdef HAVE_NEPOMUK +#include +#include +#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 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 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) diff --git a/src/dolphinsearchbox.h b/src/dolphinsearchbox.h index 949c0b547..2f1c6e172 100644 --- a/src/dolphinsearchbox.h +++ b/src/dolphinsearchbox.h @@ -21,10 +21,45 @@ #include +#include + 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