diff --git a/razorqt-runner/commanditemmodel.cpp b/razorqt-runner/commanditemmodel.cpp index 13c28b1a..d3fc79d0 100644 --- a/razorqt-runner/commanditemmodel.cpp +++ b/razorqt-runner/commanditemmodel.cpp @@ -32,6 +32,7 @@ #include #include #include +#include /************************************************ @@ -110,6 +111,12 @@ bool CommandItemModel::filterAcceptsRow(int sourceRow, const QModelIndex &/*sour ************************************************/ bool CommandItemModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { + if (left == mSourceModel->customCommandIndex()) + return true; + + if (right == mSourceModel->customCommandIndex()) + return false; + if (mOnlyHistory) return left.row() < right.row(); else @@ -123,25 +130,29 @@ bool CommandItemModel::lessThan(const QModelIndex &left, const QModelIndex &righ QModelIndex CommandItemModel::appropriateItem(const QString &pattern) const { QModelIndex res; - int delta = 0xFFFF; + unsigned int rank = 0; int cnt = rowCount(); + for (int i=0; icustomCommandIndex()) + continue; + const CommandProviderItem *item = mSourceModel->command(srcIndex); if (!item) continue; - int d = item->tile().indexOf(pattern, 0, Qt::CaseInsensitive); - if (drank(pattern); + if (r > rank) { res = ind; - delta = d; + rank = r; } - if (delta==0) + if (rank >= MAX_RANK) break; } @@ -169,8 +180,14 @@ void CommandItemModel::rebuild() CommandSourceItemModel::CommandSourceItemModel(QObject *parent) : QAbstractListModel(parent) { + mCustomCommandProvider = new CustomCommandProvider; + mProviders.append(mCustomCommandProvider); + rebuild(); + mCustomCommandIndex = index(0, 0); + mHistoryProvider = new HistoryProvider(); mProviders.append(mHistoryProvider); + mProviders.append(new AppLinkProvider()); #ifdef MATH_ENABLED mProviders.append(new MathProvider()); @@ -230,7 +247,7 @@ QVariant CommandSourceItemModel::data(const QModelIndex &index, int role) const switch (role) { case Qt::DisplayRole: - return QString("%1
\n%2\n").arg(item->tile(), item->comment()); + return QString("%1
\n%2\n").arg(item->title(), item->comment()); case Qt::DecorationRole: return item->icon(); diff --git a/razorqt-runner/commanditemmodel.h b/razorqt-runner/commanditemmodel.h index 82db7640..482f9ddb 100644 --- a/razorqt-runner/commanditemmodel.h +++ b/razorqt-runner/commanditemmodel.h @@ -50,12 +50,18 @@ class CommandSourceItemModel: public QAbstractListModel void addHistoryCommand(const QString &command); + QString command() const { return mCustomCommandProvider->command(); } + void setCommand(const QString &command) { mCustomCommandProvider->setCommand(command); } + + QPersistentModelIndex customCommandIndex() const { return mCustomCommandIndex; } public slots: void rebuild(); private: QList mProviders; HistoryProvider *mHistoryProvider; + CustomCommandProvider *mCustomCommandProvider; + QPersistentModelIndex mCustomCommandIndex; }; @@ -76,6 +82,9 @@ class CommandItemModel: public QSortFilterProxyModel bool isShowOnlyHistory() const { return mOnlyHistory; } void showOnlyHistory(bool onlyHistory) { mOnlyHistory = onlyHistory; } + QString command() const { return mSourceModel->command(); } + void setCommand(const QString &command) { mSourceModel->setCommand(command); } + public slots: void rebuild(); diff --git a/razorqt-runner/dialog.cpp b/razorqt-runner/dialog.cpp index 9a289090..f86c2f5f 100644 --- a/razorqt-runner/dialog.cpp +++ b/razorqt-runner/dialog.cpp @@ -68,13 +68,10 @@ Dialog::Dialog(QWidget *parent) : connect(mSettings, SIGNAL(settingsChanged()), this, SLOT(applySettings())); - ui->commandEd->installEventFilter(this); - ui->commandEd->setInsertPolicy(QComboBox::NoInsert); - ui->commandEd->setCompleter(0); connect(ui->commandEd, SIGNAL(textChanged(QString)), this, SLOT(setFilter(QString))); - connect(ui->commandEd->lineEdit(), SIGNAL(returnPressed()), this, SLOT(runCommand())); + connect(ui->commandEd, SIGNAL(returnPressed()), this, SLOT(runCommand())); mCommandItemModel = new CommandItemModel(this); @@ -168,7 +165,7 @@ bool Dialog::editKeyPressEvent(QKeyEvent *event) { case Qt::Key_Up: case Qt::Key_PageUp: - if (ui->commandEd->currentText().isEmpty() && + if (ui->commandEd->text().isEmpty() && ui->commandList->isVisible() && ui->commandList->currentIndex().row() == 0 ) @@ -181,7 +178,7 @@ bool Dialog::editKeyPressEvent(QKeyEvent *event) case Qt::Key_Down: case Qt::Key_PageDown: - if (ui->commandEd->currentText().isEmpty() && + if (ui->commandEd->text().isEmpty() && ui->commandList->isHidden() ) { @@ -313,6 +310,7 @@ void Dialog::setFilter(const QString &text, bool onlyHistory) if (mCommandItemModel->isOutDated()) mCommandItemModel->rebuild(); + mCommandItemModel->setCommand(text); mCommandItemModel->showOnlyHistory(onlyHistory); mCommandItemModel->setFilterWildcard(text); @@ -346,7 +344,7 @@ void Dialog::runCommand() } else { - QString command = ui->commandEd->currentText(); + QString command = ui->commandEd->text(); res = QProcess::startDetached(command); if (res) { @@ -357,7 +355,7 @@ void Dialog::runCommand() if (res) { hide(); - ui->commandEd->clearEditText(); + ui->commandEd->clear(); } } diff --git a/razorqt-runner/dialog.ui b/razorqt-runner/dialog.ui index eaf2fa69..aeea267b 100644 --- a/razorqt-runner/dialog.ui +++ b/razorqt-runner/dialog.ui @@ -79,11 +79,7 @@ - - - true - - + @@ -146,11 +142,6 @@
widgets.h
1 - - CommandComboBox - QComboBox -
widgets.h
-
closeButton diff --git a/razorqt-runner/providers.cpp b/razorqt-runner/providers.cpp index 2662a28a..109dab3a 100644 --- a/razorqt-runner/providers.cpp +++ b/razorqt-runner/providers.cpp @@ -37,7 +37,10 @@ #include #include #include +#include +#include #include +#include #define MAX_HISORTY 100 @@ -45,39 +48,16 @@ /************************************************ ************************************************/ -CommandProviderItem::CommandProviderItem() +unsigned int CommandProviderItem::stringRank(const QString str, const QString pattern) const { -} - - -/************************************************ - - ************************************************/ -CommandProviderItem::~CommandProviderItem() -{ -} - - -/************************************************ - - ************************************************/ -void CommandProviderItem::setTile(const QString &title) -{ - mTitle = title; -} + int n = str.indexOf(pattern, 0, Qt::CaseInsensitive); + if (n<0) + return 0; - -/************************************************ - - ************************************************/ -void CommandProviderItem::setComment(const QString &comment) -{ - mComment = comment; + return MAX_RANK - ((str.length() - pattern.length()) + n * 5); } - - /************************************************ ************************************************/ @@ -104,11 +84,10 @@ AppLinkItem::AppLinkItem(const QDomElement &element): CommandProviderItem() { mIconName = element.attribute("icon"); - setTile(element.attribute("title")); - setComment(element.attribute("genericName")); - setToolTip(element.attribute("comment")); + mTitle = element.attribute("title"); + mComment = element.attribute("genericName"); + mToolTip = element.attribute("comment"); mCommand = QFileInfo(element.attribute("exec")).baseName().section(" ", 0, 0); - mSearchText = element.attribute("title") + " " + mCommand; mDesktopFile = element.attribute("desktopFile"); } @@ -118,8 +97,8 @@ AppLinkItem::AppLinkItem(const QDomElement &element): ************************************************/ void AppLinkItem::updateIcon() { - if (icon().isNull()) - setIcon(XdgIcon::fromTheme(mIconName)); + if (mIcon.isNull()) + mIcon = XdgIcon::fromTheme(mIconName); } @@ -128,16 +107,26 @@ void AppLinkItem::updateIcon() ************************************************/ void AppLinkItem::operator=(const AppLinkItem &other) { - setTile(other.tile()); - setComment(other.comment()); - setToolTip(other.toolTip()); + mTitle = other.title(); + mComment = other.comment(); + mToolTip = other.toolTip(); mCommand = other.mCommand; - mSearchText = other.mSearchText; mDesktopFile = other.mDesktopFile; mIconName = other.mIconName; - setIcon(other.icon()); + mIcon = other.icon(); +} + + +/************************************************ + + ************************************************/ +unsigned int AppLinkItem::rank(const QString &pattern) const +{ + return qMax(stringRank(mCommand, pattern), + stringRank(mTitle, pattern) + ); } @@ -162,7 +151,8 @@ bool AppLinkItem::compare(const QRegExp ®Exp) const QRegExp re(regExp); re.setCaseSensitivity(Qt::CaseInsensitive); - return mSearchText.contains(re); + return mCommand.contains(re) || + mTitle.contains(re) ; } @@ -264,9 +254,9 @@ void AppLinkProvider::update() HistoryItem::HistoryItem(const QString &command): CommandProviderItem() { - setIcon(XdgIcon::defaultApplicationIcon()); - setTile(command); - setComment(QObject::tr("History")); + mIcon = XdgIcon::defaultApplicationIcon(); + mTitle = command; + mComment = QObject::tr("History"); mCommand = command; } @@ -292,7 +282,13 @@ bool HistoryItem::compare(const QRegExp ®Exp) const } +/************************************************ + ************************************************/ +unsigned int HistoryItem::rank(const QString &pattern) const +{ + return stringRank(mCommand, pattern); +} /************************************************ @@ -341,18 +337,142 @@ void HistoryProvider::AddCommand(const QString &command) } } + + +/************************************************ + + ************************************************/ +CustomCommandItem::CustomCommandItem(): + CommandProviderItem() +{ + mIcon = XdgIcon::fromTheme("utilities-terminal"); +} + + +/************************************************ + + ************************************************/ +QString which(const QString &progName) +{ + if (progName.isEmpty()) + return ""; + + if (progName.startsWith(QDir::separator())) + { + if (QFileInfo(progName).isExecutable()) + QFileInfo(progName).absoluteFilePath(); + } + + QStringList dirs = QString(getenv("PATH")).split(":"); + + foreach (QString dir, dirs) + { + if (QFileInfo(QDir(dir), progName).isExecutable()) + return QFileInfo(QDir(dir), progName).absoluteFilePath(); + } + + return ""; +} + + +/************************************************ + + ************************************************/ +QString expandCommand(const QString &command, QStringList *arguments=0) +{ + QString program; + wordexp_t words; + + if (wordexp(command.toLocal8Bit().data(), &words, 0) != 0) + return ""; + + char **w; + w = words.we_wordv; + program = QString::fromLocal8Bit(w[0]); + + if (arguments) + { + for (size_t i = 1; i < words.we_wordc; i++) + *arguments << w[i]; + } + + wordfree(&words); + return program; +} + + +/************************************************ + + ************************************************/ +void CustomCommandItem::setCommand(const QString &command) +{ + mCommand = command; + mTitle = mCommand; + + QString program = which(expandCommand(command)); + + if (!program.isEmpty()) + mComment = QString("%1 %2").arg(program, command.section(' ', 1)); + else + mComment = ""; + +} + + +/************************************************ + + ************************************************/ +bool CustomCommandItem::run() const +{ + QStringList args; + QString program = expandCommand(mCommand, &args); + if (program.isEmpty()) + return false; + + return QProcess::startDetached(program, args); +} + + +/************************************************ + + ************************************************/ +bool CustomCommandItem::compare(const QRegExp ®Exp) const +{ + return !mComment.isEmpty(); +} + + +/************************************************ + + ************************************************/ +unsigned int CustomCommandItem::rank(const QString &pattern) const +{ + return 0; +} + + +/************************************************ + + ************************************************/ +CustomCommandProvider::CustomCommandProvider(): + CommandProvider() +{ + mItem = new CustomCommandItem(); + append(mItem); +} + #ifdef VBOX_ENABLED VirtualBoxItem::VirtualBoxItem(const QString & MachineName , const QIcon & Icon): CommandProviderItem() { - setTile (MachineName); - setIcon (Icon); + mTitle = MachineName; + mIcon = Icon; } bool VirtualBoxItem::run() const { QStringList arguments; - arguments << "startvm" << tile(); + arguments << "startvm" << title(); return QProcess::startDetached ("VBoxManage" , arguments); } @@ -360,8 +480,13 @@ bool VirtualBoxItem::compare(const QRegExp ®Exp) const { QRegExp re(regExp); re.setCaseSensitivity(Qt::CaseInsensitive); - //qDebug() << "Title: " << re.indexIn (tile ()); - return (-1 != re.indexIn (tile ())); + //qDebug() << "Title: " << re.indexIn (title ()); + return (-1 != re.indexIn (title ())); +} + +unsigned int VirtualBoxItem::rank(const QString &pattern) const +{ + return stringRank(mTitle, pattern); } /////// @@ -508,8 +633,8 @@ bool VirtualBoxProvider::isOutDated() const MathItem::MathItem(): CommandProviderItem() { - setToolTip(QObject::tr("Mathematics")); - setIcon(XdgIcon::fromTheme("accessories-calculator")); + mToolTip =QObject::tr("Mathematics"); + mIcon = XdgIcon::fromTheme("accessories-calculator"); } @@ -537,7 +662,7 @@ bool MathItem::compare(const QRegExp ®Exp) const if (res.isNumber()) { MathItem *self=const_cast(this); - self->setTile(s + " = " + res.toString()); + self->mTitle = s + " = " + res.toString(); return true; } } @@ -545,6 +670,13 @@ bool MathItem::compare(const QRegExp ®Exp) const return false; } +/************************************************ + + ************************************************/ +unsigned int MathItem::rank(const QString &pattern) const +{ + return stringRank(mTitle, pattern); +} /************************************************ diff --git a/razorqt-runner/providers.h b/razorqt-runner/providers.h index a85f2ee4..b9dae68e 100644 --- a/razorqt-runner/providers.h +++ b/razorqt-runner/providers.h @@ -35,28 +35,44 @@ #include #include +#define MAX_RANK 0xFFFF + +/*! The CommandProviderItem class provides an item for use with CommandProvider. + Items usually contain title, comment, toolTip and icon. + */ class CommandProviderItem { public: - CommandProviderItem(); - virtual ~CommandProviderItem(); + CommandProviderItem() {} + virtual ~CommandProviderItem() {} virtual bool run() const = 0; virtual bool compare(const QRegExp ®Exp) const = 0; + /// Returns the item's icon. QIcon icon() const { return mIcon; } - QString tile() const { return mTitle; } + + /// Returns the item's title. + QString title() const { return mTitle; } + + /// Returns the item's comment. QString comment() const { return mComment; } - QString toolTip() const { return mToolTip; } -protected: - void setIcon(const QIcon &icon) { mIcon = icon; } - void setTile(const QString &title); - void setComment(const QString &comment); - void setToolTip(const QString &toolTip) { mToolTip = toolTip; } + /// Returns the item's tooltip. + QString toolTip() const { return mToolTip; } + /*! The result of this function is used when searching for a apropriate item. + The item with the highest rank will be highlighted. + 0 - not suitable. + MAX_RANK - an exact match. + In the most cases you can yse something like: + return stringRank(mTitle, pattern); + */ + virtual unsigned int rank(const QString &pattern) const = 0; -private: +protected: + /// Helper function for the CommandProviderItem::rank + unsigned int stringRank(const QString str, const QString pattern) const; QIcon mIcon; QString mTitle; QString mComment; @@ -64,7 +80,8 @@ class CommandProviderItem }; - +/*! The CommandProvider class provides task for the razor-runner. + */ class CommandProvider: public QObject, public QList { Q_OBJECT @@ -96,9 +113,9 @@ class AppLinkItem: public CommandProviderItem QString command() const { return mCommand; } void operator=(const AppLinkItem &other); + + virtual unsigned int rank(const QString &pattern) const; private: -public: - QString mSearchText; QString mDesktopFile; QString mIconName; QString mCommand; @@ -134,6 +151,7 @@ class HistoryItem: public CommandProviderItem bool compare(const QRegExp ®Exp) const; QString command() const { return mCommand; } + virtual unsigned int rank(const QString &pattern) const; private: QString mCommand; @@ -156,6 +174,43 @@ class HistoryProvider: public CommandProvider +/************************************************ + * Custom command + ************************************************/ + +class CustomCommandItem: public CommandProviderItem +{ +public: + CustomCommandItem(); + + bool run() const; + bool compare(const QRegExp ®Exp) const; + + QString command() const { return mCommand; } + void setCommand(const QString &command); + + virtual unsigned int rank(const QString &pattern) const; +private: + QString mCommand; +}; + + + +class QSettings; +class CustomCommandProvider: public CommandProvider +{ +public: + CustomCommandProvider(); + + QString command() const { return mItem->command(); } + void setCommand(const QString &command) { mItem->setCommand(command); } + +private: + CustomCommandItem *mItem; +}; + + + /************************************************ * Mathematics ************************************************/ @@ -166,6 +221,7 @@ class MathItem: public CommandProviderItem bool run() const; bool compare(const QRegExp ®Exp) const; + virtual unsigned int rank(const QString &pattern) const; }; @@ -189,6 +245,7 @@ class VirtualBoxItem: public CommandProviderItem bool run() const; bool compare(const QRegExp ®Exp) const; + virtual unsigned int rank(const QString &pattern) const; }; class VirtualBoxProvider: public CommandProvider