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
This commit is contained in:
Matthias Fuchs 2009-10-05 18:46:35 +00:00
parent 647e1469b5
commit b6310bf521
2 changed files with 249 additions and 2 deletions

View file

@ -18,22 +18,225 @@
***************************************************************************/
#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)

View file

@ -21,10 +21,45 @@
#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