diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,15 +52,18 @@ Concurrent DBus PrintSupport + QuickWidgets Widgets ) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED CoreAddons Config I18n + Declarative KIO Notifications + Plasma Wayland WidgetsAddons WindowSystem diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,7 +8,6 @@ accessdialog.cpp appchooser.cpp appchooserdialog.cpp - appchooserdialogitem.cpp desktopportal.cpp email.cpp filechooser.cpp @@ -41,6 +40,7 @@ ki18n_wrap_ui(xdg_desktop_portal_kde_SRCS accessdialog.ui + appchooserdialog.ui screenshotdialog.ui ) @@ -51,10 +51,12 @@ Qt5::DBus Qt5::Concurrent Qt5::PrintSupport + Qt5::QuickWidgets Qt5::Widgets KF5::CoreAddons KF5::ConfigCore KF5::I18n + KF5::Declarative KF5::KIOFileWidgets KF5::Notifications KF5::WaylandClient @@ -70,3 +72,7 @@ endif() install(TARGETS xdg-desktop-portal-kde DESTINATION ${KDE_INSTALL_LIBEXECDIR}) + +install(FILES + qml/AppChooserDialog.qml + DESTINATION ${KDE_INSTALL_DATADIR}/xdg-desktop-portal-kde/qml) diff --git a/src/appchooserdialog.h b/src/appchooserdialog.h --- a/src/appchooserdialog.h +++ b/src/appchooserdialog.h @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Red Hat, Inc + * Copyright © 2016-2019 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,30 +23,109 @@ #include -class QGridLayout; +#include +#include + +namespace Ui +{ +class AppChooserDialog; +} + +class ApplicationItem +{ +public: + enum ApplicationCategory { + PreferredApplication, + AllApplications + }; + + explicit ApplicationItem(const QString &name, const QString &icon, const QString &desktopFileName); + + QString applicationName() const; + QString applicationIcon() const; + QString applicationDesktopFile() const; + + void setApplicationCategory(ApplicationCategory category); + ApplicationCategory applicationCategory() const; + + bool operator==(const ApplicationItem &item) const; +private: + QString m_applicationName; + QString m_applicationIcon; + QString m_applicationDesktopFile; + ApplicationCategory m_applicationCategory; +}; + +class AppFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT + Q_PROPERTY(bool showOnlyPreferredApps READ showOnlyPreferredApps WRITE setShowOnlyPrefferedApps) + Q_PROPERTY(QString filter READ filter WRITE setFilter) +public: + explicit AppFilterModel(QObject *parent = nullptr); + ~AppFilterModel() override; + + void setShowOnlyPrefferedApps(bool show); + bool showOnlyPreferredApps() const; + + void setFilter(const QString &text); + QString filter() const; + +protected: + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + +private: + bool m_showOnlyPreferredApps = true; + QString m_filter; +}; + +class AppModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum ItemRoles { + ApplicationNameRole = Qt::UserRole + 1, + ApplicationIconRole, + ApplicationDesktopFileRole, + ApplicationCategoryRole + }; + + explicit AppModel(QObject *parent = nullptr); + ~AppModel() override; + + void setPreferredApps(const QStringList &list); + + QVariant data(const QModelIndex &index, int role) const override; + int rowCount(const QModelIndex &parent) const override; + QHash roleNames() const override; + +private: + void loadApplications(); + + QList m_list; +}; class AppChooserDialog : public QDialog { Q_OBJECT public: - AppChooserDialog(const QStringList &choices, const QString &defaultApp, const QString &fileName, QDialog *parent = nullptr, Qt::WindowFlags flags = {}); + explicit AppChooserDialog(const QStringList &choices, const QString &defaultApp, const QString &fileName, QDialog *parent = nullptr, Qt::WindowFlags flags = {}); ~AppChooserDialog(); void updateChoices(const QStringList &choices); QString selectedApplication() const; - private Q_SLOTS: - void addDialogItems(); - + void onApplicationSelected(const QString &desktopFile); + void onOpenDiscover(); private: + Ui::AppChooserDialog *m_dialog; - QStringList m_choices; + AppModel *m_model; + QStringList m_defaultChoices; QString m_defaultApp; QString m_selectedApplication; - QGridLayout *m_gridLayout; }; #endif // XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_DIALOG_H - - diff --git a/src/appchooserdialog.cpp b/src/appchooserdialog.cpp --- a/src/appchooserdialog.cpp +++ b/src/appchooserdialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright © 2017-2018 Red Hat, Inc + * Copyright © 2017-2019 Red Hat, Inc * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,161 +19,292 @@ */ #include "appchooserdialog.h" -#include "appchooserdialogitem.h" - -#include -#include -#include -#include -#include -#include -#include +#include "ui_appchooserdialog.h" + +#include +#include +#include +#include + +#include #include -#include -#include +#include #include - -Q_LOGGING_CATEGORY(XdgDesktopPortalKdeAppChooserDialog, "xdp-kde-app-chooser-dialog") +#include AppChooserDialog::AppChooserDialog(const QStringList &choices, const QString &defaultApp, const QString &fileName, QDialog *parent, Qt::WindowFlags flags) : QDialog(parent, flags) - , m_choices(choices) + , m_dialog(new Ui::AppChooserDialog) + , m_defaultChoices(choices) , m_defaultApp(defaultApp) { - setMinimumWidth(640); - setMaximumHeight(480); - - QVBoxLayout *vboxLayout = new QVBoxLayout(this); - vboxLayout->setSpacing(20); - vboxLayout->setContentsMargins(20, 20, 20, 20); + m_dialog->setupUi(this); - QLabel *label = new QLabel(this); - label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - label->setScaledContents(true); - label->setWordWrap(true); - label->setText(i18n("Select application to open \"%1\". Other applications are available in Discover.", fileName)); - label->setOpenExternalLinks(false); + KDeclarative::KDeclarative kdeclarative; + kdeclarative.setDeclarativeEngine(m_dialog->quickWidget->engine()); + kdeclarative.setTranslationDomain(QStringLiteral(TRANSLATION_DOMAIN)); + kdeclarative.setupEngine(m_dialog->quickWidget->engine()); + kdeclarative.setupContext(); - connect(label, &QLabel::linkActivated, this, [] () { - KProcess::startDetached(QStringLiteral("plasma-discover")); - }); + m_model = new AppModel(this); + m_model->setPreferredApps(choices); - vboxLayout->addWidget(label); + AppFilterModel *filterModel = new AppFilterModel(this); + filterModel->setSourceModel(m_model); - QWidget *appsWidget = new QWidget(this); - QScrollArea *scrollArea = new QScrollArea(this); - scrollArea->setFrameShape(QFrame::NoFrame); - scrollArea->setWidget(appsWidget); - scrollArea->setWidgetResizable(true); + m_dialog->quickWidget->rootContext()->setContextProperty(QStringLiteral("myModel"), filterModel); + m_dialog->quickWidget->rootContext()->setContextProperty(QStringLiteral("fileName"), fileName); + m_dialog->quickWidget->rootContext()->setContextProperty(QStringLiteral("defaultApp"), defaultApp); + m_dialog->quickWidget->rootContext()->setContextProperty(QStringLiteral("backgroundColor"), palette().color(QPalette::Active, QPalette::Window)); + m_dialog->quickWidget->rootContext()->setContextProperty(QStringLiteral("highlightColor"), palette().color(QPalette::Active, QPalette::Highlight)); + m_dialog->quickWidget->setClearColor(Qt::transparent); + m_dialog->quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_dialog->quickWidget->setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("xdg-desktop-portal-kde/qml/AppChooserDialog.qml")))); - // FIXME: workaround scrollarea sizing, set minimum height to make sure at least two rows are visible - if (choices.count() > 3) { - scrollArea->setMinimumHeight(200); - } + QObject *rootItem = m_dialog->quickWidget->rootObject(); + connect(rootItem, SIGNAL(openDiscover()), this, SLOT(onOpenDiscover())); + connect(rootItem, SIGNAL(applicationSelected(QString)), this, SLOT(onApplicationSelected(QString))); - m_gridLayout = new QGridLayout; - appsWidget->setLayout(m_gridLayout); + setWindowTitle(i18n("Open with...")); +} - QTimer::singleShot(0, this, &AppChooserDialog::addDialogItems); +AppChooserDialog::~AppChooserDialog() +{ + delete m_dialog; +} - vboxLayout->addWidget(scrollArea); +QString AppChooserDialog::selectedApplication() const +{ + return m_selectedApplication; +} - setLayout(vboxLayout); - setWindowTitle(i18n("Open with")); +void AppChooserDialog::onApplicationSelected(const QString& desktopFile) +{ + m_selectedApplication = desktopFile; + QDialog::accept(); } -AppChooserDialog::~AppChooserDialog() +void AppChooserDialog::onOpenDiscover() { - delete m_gridLayout; + KProcess::startDetached(QStringLiteral("plasma-discover")); } void AppChooserDialog::updateChoices(const QStringList &choices) { - bool changed = false; + m_model->setPreferredApps(choices); +} + +ApplicationItem::ApplicationItem(const QString &name, const QString &icon, const QString &desktopFileName) + : m_applicationName(name) + , m_applicationIcon(icon) + , m_applicationDesktopFile(desktopFileName) + , m_applicationCategory(AllApplications) +{ +} + +QString ApplicationItem::applicationName() const +{ + return m_applicationName; +} + +QString ApplicationItem::applicationIcon() const +{ + return m_applicationIcon; +} + +QString ApplicationItem::applicationDesktopFile() const +{ + return m_applicationDesktopFile; +} + +void ApplicationItem::setApplicationCategory(ApplicationItem::ApplicationCategory category) +{ + m_applicationCategory = category; +} + +ApplicationItem::ApplicationCategory ApplicationItem::applicationCategory() const +{ + return m_applicationCategory; +} + +bool ApplicationItem::operator==(const ApplicationItem &item) const +{ + return item.applicationDesktopFile() == applicationDesktopFile(); +} + +AppFilterModel::AppFilterModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ + setDynamicSortFilter(true); + setFilterCaseSensitivity(Qt::CaseInsensitive); + sort(0, Qt::DescendingOrder); +} + +AppFilterModel::~AppFilterModel() +{ +} + +void AppFilterModel::setShowOnlyPrefferedApps(bool show) +{ + m_showOnlyPreferredApps = show; + + invalidate(); +} + +bool AppFilterModel::showOnlyPreferredApps() const +{ + return m_showOnlyPreferredApps; +} + +void AppFilterModel::setFilter(const QString &text) +{ + m_filter = text; + + invalidate(); +} + +QString AppFilterModel::filter() const +{ + return m_filter; +} + +bool AppFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const +{ + const QModelIndex index = sourceModel()->index(source_row, 0, source_parent); + + ApplicationItem::ApplicationCategory category = static_cast(sourceModel()->data(index, AppModel::ApplicationCategoryRole).toInt()); + QString appName = sourceModel()->data(index, AppModel::ApplicationNameRole).toString(); + + if (m_showOnlyPreferredApps) + return category == ApplicationItem::PreferredApplication; + + if (category == ApplicationItem::PreferredApplication) + return true; + + if (m_filter.isEmpty()) + return true; + + return appName.toLower().contains(m_filter); +} + +bool AppFilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + ApplicationItem::ApplicationCategory leftCategory = static_cast(sourceModel()->data(left, AppModel::ApplicationCategoryRole).toInt()); + ApplicationItem::ApplicationCategory rightCategory = static_cast(sourceModel()->data(right, AppModel::ApplicationCategoryRole).toInt()); + QString leftName = sourceModel()->data(left, AppModel::ApplicationNameRole).toString(); + QString rightName = sourceModel()->data(right, AppModel::ApplicationNameRole).toString(); + + if (leftCategory < rightCategory) { + return false; + } else if (leftCategory > rightCategory) { + return true; + } + + return QString::localeAwareCompare(leftName, rightName) > 0; +} + +AppModel::AppModel(QObject *parent) + : QAbstractListModel(parent) +{ + loadApplications(); +} + +AppModel::~AppModel() +{ +} - // Check if we will be adding something - for (const QString &choice : choices) { - if (!m_choices.contains(choice)) { +void AppModel::setPreferredApps(const QStringList &list) +{ + for (ApplicationItem &item : m_list) { + bool changed = false; + + // First reset to initial type + if (item.applicationCategory() != ApplicationItem::AllApplications) { + item.setApplicationCategory(ApplicationItem::AllApplications); changed = true; - m_choices << choice; } - } - // Check if we will be removing something - for (const QString &choice : m_choices) { - if (!choices.contains(choice)) { + if (list.contains(item.applicationDesktopFile())) { + item.setApplicationCategory(ApplicationItem::PreferredApplication); changed = true; - m_choices.removeAll(choice); } - } - // If something changed, clear the layout and add the items again - if (changed) { - int rowCount = m_gridLayout->rowCount(); - int columnCount = m_gridLayout->columnCount(); - - for (int i = 0; i < rowCount; ++i) { - for (int j = 0; j < columnCount; ++j) { - QLayoutItem *item = m_gridLayout->itemAtPosition(i, j); - if (item) { - QWidget *widget = item->widget(); - if (widget) { - m_gridLayout->removeWidget(widget); - widget->deleteLater(); - } - } + if (changed) { + const int row = m_list.indexOf(item); + if (row >= 0) { + QModelIndex index = createIndex(row, 0, AppModel::ApplicationCategoryRole); + Q_EMIT dataChanged(index, index); } } - - addDialogItems(); } } -QString AppChooserDialog::selectedApplication() const +QVariant AppModel::data(const QModelIndex &index, int role) const { - if (m_selectedApplication.isEmpty()) { - return m_defaultApp; + const int row = index.row(); + + if (row >= 0 && row < m_list.count()) { + ApplicationItem item = m_list.at(row); + + switch (role) { + case ApplicationNameRole: + return item.applicationName(); + case ApplicationIconRole: + return item.applicationIcon(); + case ApplicationDesktopFileRole: + return item.applicationDesktopFile(); + case ApplicationCategoryRole: + return static_cast(item.applicationCategory()); + default: + break; + } } - return m_selectedApplication; + return QVariant(); +} + +int AppModel::rowCount(const QModelIndex &parent) const +{ + return parent.isValid() ? 0 : m_list.count(); +} + +QHash AppModel::roleNames() const +{ + QHash roles = QAbstractListModel::roleNames(); + roles[ApplicationNameRole] = "ApplicationName"; + roles[ApplicationIconRole] = "ApplicationIcon"; + roles[ApplicationDesktopFileRole] = "ApplicationDesktopFile"; + roles[ApplicationCategoryRole] = "ApplicationCategory"; + + return roles; } -void AppChooserDialog::addDialogItems() +void AppModel::loadApplications() { - int i = 0, j = 0; - for (const QString &choice : m_choices) { - const QString desktopFile = choice + QStringLiteral(".desktop"); - const QStringList desktopFilesLocations = QStandardPaths::locateAll(QStandardPaths::ApplicationsLocation, desktopFile, QStandardPaths::LocateFile); - for (const QString &desktopFile : desktopFilesLocations) { + for (const QString &location : QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation)) { + QDir dir(location); + for (QString &entry : dir.entryList(QStringList({QStringLiteral("*.desktop")}), QDir::Files, QDir::Name)) { QString applicationIcon; QString applicationName; - QSettings settings(desktopFile, QSettings::IniFormat); + + QSettings settings(QStringLiteral("%1/%2").arg(dir.path()).arg(entry), QSettings::IniFormat); settings.beginGroup(QStringLiteral("Desktop Entry")); if (settings.contains(QStringLiteral("X-GNOME-FullName"))) { applicationName = settings.value(QStringLiteral("X-GNOME-FullName")).toString(); } else { applicationName = settings.value(QStringLiteral("Name")).toString(); } applicationIcon = settings.value(QStringLiteral("Icon")).toString(); - AppChooserDialogItem *item = new AppChooserDialogItem(applicationName, applicationIcon, choice, this); - m_gridLayout->addWidget(item, i, j++, Qt::AlignHCenter); + const QString desktopFileWithoutSuffix = entry.remove(QStringLiteral(".desktop")); + if (applicationName.isEmpty() || applicationIcon.isEmpty()) + continue; - connect(item, &AppChooserDialogItem::clicked, this, [this] (const QString &selectedApplication) { - m_selectedApplication = selectedApplication; - QDialog::accept(); - }); + ApplicationItem appItem(applicationName, applicationIcon, desktopFileWithoutSuffix); - if (choice == m_defaultApp) { - item->setDown(true); - item->setChecked(true); - } - - if (j == 3) { - i++; - j = 0; - } + if (!m_list.contains(appItem)) + m_list.append(appItem); } } } diff --git a/src/appchooserdialog.ui b/src/appchooserdialog.ui new file mode 100644 --- /dev/null +++ b/src/appchooserdialog.ui @@ -0,0 +1,47 @@ + + + AppChooserDialog + + + + 0 + 0 + 640 + 400 + + + + + 0 + 0 + + + + Dialog + + + + + + + 0 + 0 + + + + QQuickWidget::SizeRootObjectToView + + + + + + + + QQuickWidget + QWidget +
QtQuickWidgets/QQuickWidget
+
+
+ + +
diff --git a/src/appchooserdialogitem.h b/src/appchooserdialogitem.h deleted file mode 100644 --- a/src/appchooserdialogitem.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright © 2018 Red Hat, Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * Authors: - * Jan Grulich - */ - -#ifndef XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_DIALOG_ITEM_H -#define XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_DIALOG_ITEM_H - -class QMouseEvent; - -#include - -class AppChooserDialogItem : public QToolButton -{ - Q_OBJECT -public: - explicit AppChooserDialogItem(const QString &applicationName, const QString &icon, const QString &applicationExec, QWidget *parent = nullptr); - ~AppChooserDialogItem() override; - - QString applicationName() const; - - void mousePressEvent(QMouseEvent * event) override; -Q_SIGNALS: - void clicked(const QString &applicationName); - -private: - QString m_applicationName; -}; - -#endif // XDG_DESKTOP_PORTAL_KDE_APPCHOOSER_DIALOG_ITEM_H - - - diff --git a/src/appchooserdialogitem.cpp b/src/appchooserdialogitem.cpp deleted file mode 100644 --- a/src/appchooserdialogitem.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2018 Red Hat, Inc - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see . - * - * Authors: - * Jan Grulich - */ - -#include "appchooserdialogitem.h" - -#include -#include - - -AppChooserDialogItem::AppChooserDialogItem(const QString &applicationName, const QString &icon, const QString &applicationExec, QWidget *parent) - : QToolButton(parent) - , m_applicationName(applicationExec) -{ - setAutoRaise(true); - setAutoExclusive(true); - setStyleSheet(QStringLiteral("text-align: center")); - setIcon(QIcon::fromTheme(icon)); - setIconSize(QSize(64, 64)); - setCheckable(true); - setFixedHeight(100); - setFixedWidth(150); - setToolButtonStyle(Qt::ToolButtonTextUnderIcon); - - QFontMetrics metrics(font()); - QString elidedText = metrics.elidedText(applicationName, Qt::ElideRight, 128); - setText(elidedText); - - connect(this, &QToolButton::toggled, this, [this] (bool toggled) { - if (!toggled) { - setDown(false); - } - }); -} - -AppChooserDialogItem::~AppChooserDialogItem() -{ -} - -QString AppChooserDialogItem::applicationName() const -{ - return m_applicationName; -} - -void AppChooserDialogItem::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) { - Q_EMIT clicked(m_applicationName); - } -} diff --git a/src/qml/AppChooserDialog.qml b/src/qml/AppChooserDialog.qml new file mode 100644 --- /dev/null +++ b/src/qml/AppChooserDialog.qml @@ -0,0 +1,153 @@ +/* + * Copyright © 2019 Red Hat, Inc + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: + * Jan Grulich + */ + + +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.12 +import org.kde.plasma.core 2.0 + +Item { + id: root + + signal applicationSelected(string name) + signal openDiscover() + + Rectangle { + id: background + anchors.fill: parent + focus: true + color: backgroundColor + } + + Label { + id: topLabel + anchors { + left: parent.left + right: parent.right + top: parent.top + } + horizontalAlignment: Text.AlignHCenter + text: i18n("Select application to open %1. Other applications are available in Discover.", fileName) + textFormat: Text.RichText + wrapMode: Text.WordWrap + + onLinkActivated: { + openDiscover() + } + } + + ScrollView { + id: scrollView + + anchors { + bottom: showAllAppsButton.top + bottomMargin: units.gridUnit / 2 + left: parent.left + right: parent.right + top: topLabel.bottom + topMargin: units.gridUnit / 2 + } + + GridView { + id: grid + anchors.fill: parent + cellHeight: 100 + cellWidth: 150 + model: myModel + delegate: appDelegate + } + } + + Button { + id: showAllAppsButton + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + icon.name: "view-more-symbolic" + text: i18n("Show more") + + + onClicked: { + visible = false + myModel.showOnlyPreferredApps = false + } + } + + TextField { + id: searchField + + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + visible: !showAllAppsButton.visible + opacity: visible + placeholderText: i18n("search..."); + + onTextChanged: myModel.filter = text + } + + Component { + id: appDelegate + + Item { + height: grid.cellHeight + width: grid.cellWidth + + Rectangle { + anchors.fill: parent + color: highlightColor + radius: 5 + visible: ApplicationDesktopFile == defaultApp + } + + MouseArea { + id: mouseArea + anchors.fill: parent + onClicked: applicationSelected(ApplicationDesktopFile) + } + + Column { + anchors.fill: parent + anchors.margins: units.gridUnit / 2 + spacing: units.gridUnit / 3 + + IconItem { + anchors.horizontalCenter: parent.horizontalCenter + implicitHeight: units.iconSizes.huge + implicitWidth: units.iconSizes.huge + source: ApplicationIcon + } + + Label { + anchors { + left: parent.left + right: parent.right + } + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + text: ApplicationName + } + } + } + } +} +