Support 'hidden' plugins

Plugins can be hidden in the "About Plugins" view by default. Users can
still make them all visible, but the default view can be made less noisy
by hiding plugins that only exist as a base for other plugins.
Plugins that can not run on the current platform are hidden by default
as well.

Change-Id: Iaf2f751c4ea4b3afc605bbbea6611eea042e62c7
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Eike Ziller
2017-01-04 06:23:32 +01:00
parent b29513aa5b
commit 284fa63be2
8 changed files with 91 additions and 11 deletions

View File

@@ -81,6 +81,13 @@
If set, the respective plugin is not loaded by default but must be explicitly If set, the respective plugin is not loaded by default but must be explicitly
enabled by the user. This should be done for plugins which are not expected enabled by the user. This should be done for plugins which are not expected
to be used by so many people as to justify the additional resource consumption. to be used by so many people as to justify the additional resource consumption.
\row
\li HiddenByDefault
\li Boolean
\li Optional. Defaults to \c false.
If set, the plugin is not shown in the default view in the
\uicontrol {About Plugins...} dialog, but only if the user requests seeing all
plugins. It is still shown with the \c{-version} command line option.
\row \row
\li Required \li Required
\li Boolean \li Boolean

View File

@@ -277,6 +277,11 @@ bool PluginSpec::isRequired() const
return d->required; return d->required;
} }
bool PluginSpec::isHiddenByDefault() const
{
return d->hiddenByDefault;
}
/*! /*!
Returns whether the plugin has its experimental flag set. Returns whether the plugin has its experimental flag set.
*/ */
@@ -482,6 +487,7 @@ namespace {
const char PLUGIN_VERSION[] = "Version"; const char PLUGIN_VERSION[] = "Version";
const char PLUGIN_COMPATVERSION[] = "CompatVersion"; const char PLUGIN_COMPATVERSION[] = "CompatVersion";
const char PLUGIN_REQUIRED[] = "Required"; const char PLUGIN_REQUIRED[] = "Required";
const char PLUGIN_HIDDEN_BY_DEFAULT[] = "HiddenByDefault";
const char PLUGIN_EXPERIMENTAL[] = "Experimental"; const char PLUGIN_EXPERIMENTAL[] = "Experimental";
const char PLUGIN_DISABLED_BY_DEFAULT[] = "DisabledByDefault"; const char PLUGIN_DISABLED_BY_DEFAULT[] = "DisabledByDefault";
const char VENDOR[] = "Vendor"; const char VENDOR[] = "Vendor";
@@ -692,6 +698,12 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &metaData)
required = value.toBool(false); required = value.toBool(false);
qCDebug(pluginLog) << "required =" << required; qCDebug(pluginLog) << "required =" << required;
value = pluginInfo.value(QLatin1String(PLUGIN_HIDDEN_BY_DEFAULT));
if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_HIDDEN_BY_DEFAULT));
hiddenByDefault = value.toBool(false);
qCDebug(pluginLog) << "hiddenByDefault =" << hiddenByDefault;
value = pluginInfo.value(QLatin1String(PLUGIN_EXPERIMENTAL)); value = pluginInfo.value(QLatin1String(PLUGIN_EXPERIMENTAL));
if (!value.isUndefined() && !value.isBool()) if (!value.isUndefined() && !value.isBool())
return reportError(msgValueIsNotABool(PLUGIN_EXPERIMENTAL)); return reportError(msgValueIsNotABool(PLUGIN_EXPERIMENTAL));

View File

@@ -95,6 +95,7 @@ public:
QRegExp platformSpecification() const; QRegExp platformSpecification() const;
bool isAvailableForHostPlatform() const; bool isAvailableForHostPlatform() const;
bool isRequired() const; bool isRequired() const;
bool isHiddenByDefault() const;
bool isExperimental() const; bool isExperimental() const;
bool isEnabledByDefault() const; bool isEnabledByDefault() const;
bool isEnabledBySettings() const; bool isEnabledBySettings() const;

View File

@@ -71,6 +71,7 @@ public:
QString version; QString version;
QString compatVersion; QString compatVersion;
bool required = false; bool required = false;
bool hiddenByDefault = false;
bool experimental = false; bool experimental = false;
bool enabledByDefault = true; bool enabledByDefault = true;
QString vendor; QString vendor;

View File

@@ -82,6 +82,7 @@ enum Columns { NameColumn, LoadedColumn, VersionColumn, VendorColumn, };
enum IconIndex { OkIcon, ErrorIcon, NotLoadedIcon }; enum IconIndex { OkIcon, ErrorIcon, NotLoadedIcon };
static const int SortRole = Qt::UserRole + 1; static const int SortRole = Qt::UserRole + 1;
static const int HiddenByDefaultRole = Qt::UserRole + 2;
static const QIcon &icon(IconIndex icon) static const QIcon &icon(IconIndex icon)
{ {
@@ -114,6 +115,8 @@ public:
QVariant data(int column, int role) const QVariant data(int column, int role) const
{ {
if (role == HiddenByDefaultRole)
return m_spec->isHiddenByDefault() || !m_spec->isAvailableForHostPlatform();
switch (column) { switch (column) {
case NameColumn: case NameColumn:
if (role == Qt::DisplayRole) if (role == Qt::DisplayRole)
@@ -223,6 +226,8 @@ public:
QVariant data(int column, int role) const QVariant data(int column, int role) const
{ {
if (role == HiddenByDefaultRole)
return false;
if (column == NameColumn) { if (column == NameColumn) {
if (role == Qt::DisplayRole || role == SortRole) if (role == Qt::DisplayRole || role == SortRole)
return m_name; return m_name;
@@ -285,6 +290,40 @@ public:
PluginView *m_view; // Not owned. PluginView *m_view; // Not owned.
}; };
class PluginFilterModel : public CategorySortFilterModel
{
public:
PluginFilterModel(QObject *parent = 0) : CategorySortFilterModel(parent) {}
void setShowHidden(bool show)
{
if (show == m_showHidden)
return;
m_showHidden = show;
invalidateFilter();
}
bool isShowingHidden() const
{
return m_showHidden;
}
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
{
if (CategorySortFilterModel::filterAcceptsRow(source_row, source_parent)) {
if (m_showHidden)
return true;
const QModelIndex &index = sourceModel()->index(source_row, 0, source_parent);
return !sourceModel()->data(index, HiddenByDefaultRole).toBool();
}
return false;
}
private:
bool m_showHidden = true;
};
} // Internal } // Internal
using namespace ExtensionSystem::Internal; using namespace ExtensionSystem::Internal;
@@ -312,7 +351,7 @@ PluginView::PluginView(QWidget *parent)
m_model = new TreeModel<TreeItem, CollectionItem, PluginItem>(this); m_model = new TreeModel<TreeItem, CollectionItem, PluginItem>(this);
m_model->setHeader({ tr("Name"), tr("Load"), tr("Version"), tr("Vendor") }); m_model->setHeader({ tr("Name"), tr("Load"), tr("Version"), tr("Vendor") });
m_sortModel = new CategorySortFilterModel(this); m_sortModel = new PluginFilterModel(this);
m_sortModel->setSourceModel(m_model); m_sortModel->setSourceModel(m_model);
m_sortModel->setSortRole(SortRole); m_sortModel->setSortRole(SortRole);
m_sortModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_sortModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
@@ -360,6 +399,17 @@ void PluginView::setFilter(const QString &filter)
m_categoryView->expandAll(); m_categoryView->expandAll();
} }
void PluginView::setShowHidden(bool showHidden)
{
m_sortModel->setShowHidden(showHidden);
m_categoryView->expandAll();
}
bool PluginView::isShowingHidden() const
{
return m_sortModel->isShowingHidden();
}
PluginSpec *PluginView::pluginForIndex(const QModelIndex &index) const PluginSpec *PluginView::pluginForIndex(const QModelIndex &index) const
{ {
const QModelIndex &sourceIndex = m_sortModel->mapToSource(index); const QModelIndex &sourceIndex = m_sortModel->mapToSource(index);

View File

@@ -45,8 +45,9 @@ class PluginManager;
class PluginSpec; class PluginSpec;
namespace Internal { namespace Internal {
class PluginItem;
class CollectionItem; class CollectionItem;
class PluginFilterModel;
class PluginItem;
} // Internal } // Internal
class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget
@@ -59,6 +60,8 @@ public:
PluginSpec *currentPlugin() const; PluginSpec *currentPlugin() const;
void setFilter(const QString &filter); void setFilter(const QString &filter);
void setShowHidden(bool showHidden);
bool isShowingHidden() const;
signals: signals:
void currentPluginChanged(ExtensionSystem::PluginSpec *spec); void currentPluginChanged(ExtensionSystem::PluginSpec *spec);
@@ -72,7 +75,7 @@ private:
Utils::TreeView *m_categoryView; Utils::TreeView *m_categoryView;
Utils::TreeModel<Utils::TreeItem, Internal::CollectionItem, Internal::PluginItem> *m_model; Utils::TreeModel<Utils::TreeItem, Internal::CollectionItem, Internal::PluginItem> *m_model;
QSortFilterProxyModel *m_sortModel; Internal::PluginFilterModel *m_sortModel;
friend class Internal::CollectionItem; friend class Internal::CollectionItem;
friend class Internal::PluginItem; friend class Internal::PluginItem;

View File

@@ -42,15 +42,10 @@ bool CategorySortFilterModel::filterAcceptsRow(int source_row,
if (regexp.indexIn(sourceModel()->data(categoryIndex, filterRole()).toString()) != -1) if (regexp.indexIn(sourceModel()->data(categoryIndex, filterRole()).toString()) != -1)
return true; return true;
const int rowCount = sourceModel()->rowCount(categoryIndex); const int rowCount = sourceModel()->rowCount(categoryIndex);
const int columnCount = sourceModel()->columnCount(categoryIndex);
for (int row = 0; row < rowCount; ++row) { for (int row = 0; row < rowCount; ++row) {
for (int column = 0; column < columnCount; ++column) { if (filterAcceptsRow(row, categoryIndex))
if (regexp.indexIn(sourceModel()->data(
sourceModel()->index(row, column, categoryIndex),
filterRole()).toString()) != -1)
return true; return true;
} }
}
return false; return false;
} }
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);

View File

@@ -35,6 +35,7 @@
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QCheckBox>
#include <QDialog> #include <QDialog>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QPushButton> #include <QPushButton>
@@ -52,11 +53,21 @@ PluginDialog::PluginDialog(QWidget *parent)
{ {
QVBoxLayout *vl = new QVBoxLayout(this); QVBoxLayout *vl = new QVBoxLayout(this);
auto filterLayout = new QHBoxLayout;
vl->addLayout(filterLayout);
auto filterEdit = new Utils::FancyLineEdit(this); auto filterEdit = new Utils::FancyLineEdit(this);
filterEdit->setFiltering(true); filterEdit->setFiltering(true);
connect(filterEdit, &Utils::FancyLineEdit::filterChanged, connect(filterEdit, &Utils::FancyLineEdit::filterChanged,
m_view, &ExtensionSystem::PluginView::setFilter); m_view, &ExtensionSystem::PluginView::setFilter);
vl->addWidget(filterEdit); filterLayout->addWidget(filterEdit);
m_view->setShowHidden(false);
auto showHidden = new QCheckBox(tr("Show All"));
showHidden->setToolTip(tr("Show all installed plugins, including base plugins "
"and plugins that are not available on this platform."));
showHidden->setChecked(m_view->isShowingHidden());
connect(showHidden, &QCheckBox::stateChanged,
m_view, &ExtensionSystem::PluginView::setShowHidden);
filterLayout->addWidget(showHidden);
vl->addWidget(m_view); vl->addWidget(m_view);