[FEATURE] Allow customization of the items shown in browser (#33679)

* [FEATURE] Allow customization of the items show is browser. User can select in Interface Customization dialog to hide some of the items in the browser panel

Funded by Limerick City and County Council
This commit is contained in:
Peter Petrik 2020-01-15 10:08:58 +01:00 committed by GitHub
parent a9ed83f1a6
commit ecd90c6ecb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 338 additions and 53 deletions

View File

@ -55,6 +55,7 @@ Constructor for QgsBrowserModel, with the specified ``parent`` object.
PathRole,
CommentRole,
SortRole,
ProviderKeyRole,
};
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
@ -161,7 +162,6 @@ and on Linux the "/" root directory.
.. versionadded:: 3.6
%End
signals:
void stateChanged( const QModelIndex &index, QgsDataItem::State oldState );
@ -232,7 +232,6 @@ Delayed initialization, needed because the provider registry must be already pop
.. seealso:: :py:func:`initialized`
%End
protected:
void addRootItems();
%Docstring

View File

@ -131,6 +131,21 @@ filterByLayerType() is ``True``.
.. seealso:: :py:func:`layerType`
.. seealso:: :py:func:`setFilterByLayerType`
%End
void setDataItemProviderKeyFilter( const QStringList &filter );
%Docstring
Sets the customization filters for data items based on item's data provider key
By default browser model shows all items from all available data items provider and few special
items (e.g. Favourites). To customize the behavious, set the filter to not load certain data items.
The items that are not based on data item providers have prefix "special:", for example
"special:Favourites", "special:Home", "PostGIS", "MSSQL"
All items created by the providers listed in filter are hidden from the layer tree.
This filter is always evaluated.
.. versionadded:: 3.12
%End
protected:

View File

@ -52,9 +52,10 @@ Parent/children hierarchy is not based on QObject.
};
QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent /TransferThis/, const QString &name, const QString &path );
QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent /TransferThis/, const QString &name, const QString &path, const QString &providerKey = QString() );
%Docstring
Create new data item.
Creates new data item
``providerKey`` added in QGIS 3.12
%End
~QgsDataItem();
@ -300,6 +301,27 @@ Sets the ``name`` of the item (the displayed text for the item).
QString path() const;
void setPath( const QString &path );
QString providerKey() const;
%Docstring
Returns the provider key that created this item (e.g. "PostGIS")
If key has a prefix "special:", it marks that the item was not created with a provider,
but manually. For example "special:Favorites", "special:Home"
.. versionadded:: 3.12
%End
void setProviderKey( const QString &value );
%Docstring
Sets the provider key that created this item (e.g. "PostGIS")
If key has a prefix "special:", it marks that the item was not created with a provider,
but manually. For example "special:Favorites"
.. versionadded:: 3.12
%End
static QString pathComponent( const QString &component );
%Docstring
Create path component replacing path separators
@ -525,7 +547,6 @@ Use QgsDataItemGuiProvider.deleteLayer instead
protected:
public:
static QIcon iconPoint();
static QIcon iconLine();
@ -556,7 +577,10 @@ A Collection: logical collection of layers or subcollections, e.g. GRASS locatio
#include "qgsdataitem.h"
%End
public:
QgsDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path = QString() );
QgsDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path = QString(), const QString &providerKey = QString() );
%Docstring
Constructor
%End
~QgsDataCollectionItem();
void addChild( QgsDataItem *item /Transfer/ );
@ -605,14 +629,15 @@ A directory: contains subdirectories and layers
QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &path );
QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path );
QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path, const QString &providerKey = QString() );
%Docstring
Constructor.
:param parent:
:param name: directory name
:param dirPath: path to directory in file system
:param path: item path in the tree, it may be dirPath or dirPath with some prefix, e.g. favorites: *
:param path: item path in the tree, it may be dirPath or dirPath with some prefix, e.g. favorites:
:param providerKey: key of the provider that created this item
%End
virtual void setState( State state );
@ -662,13 +687,14 @@ Data item that can be used to represent QGIS projects.
%End
public:
QgsProjectItem( QgsDataItem *parent, const QString &name, const QString &path );
QgsProjectItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey = QString() );
%Docstring
A data item holding a reference to a QGIS project file.
:param parent: The parent data item.
:param name: The name of the of the project. Displayed to the user.
:param path: The full path to the project.
:param providerKey: key of the provider that created this item
%End
virtual bool hasDragEnabled() const;
@ -782,7 +808,14 @@ A zip file: contains layers, using GDAL/OGR VSIFILE mechanism
public:
QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path );
QgsZipItem( QgsDataItem *parent, const QString &name, const QString &filePath, const QString &path );
%Docstring
Constructor
%End
QgsZipItem( QgsDataItem *parent, const QString &name, const QString &filePath, const QString &path, const QString &providerKey = QString() );
%Docstring
Constructor
%End
virtual QVector<QgsDataItem *> createChildren();

View File

@ -58,6 +58,20 @@ Returns the message bar associated with the dock.
.. seealso:: :py:func:`setMessageBar`
.. versionadded:: 3.6
%End
void setDisabledDataItemsKeys( const QStringList &filter );
%Docstring
Sets the customization for data items based on item's data provider key
By default browser model shows all items from all available data items provider and few special
items (e.g. Favourites). To customize the behavior, set the filter to not load certain data items.
The items that are not based on data item providers (e.g. Favourites, Home) have
prefix "special:"
Used in the proxy browser model to hide items
.. versionadded:: 3.12
%End
public slots:
@ -190,8 +204,6 @@ Show event override
};
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -1300,6 +1300,10 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
QgsApplication::dataItemProviderRegistry()->addProvider( new QgsProjectDataItemProvider() );
// now when all data item providers are registered, customize both browsers
QgsCustomization::instance()->updateBrowserWidget( mBrowserWidget );
QgsCustomization::instance()->updateBrowserWidget( mBrowserWidget2 );
// Create the plugin registry and load plugins
// load any plugins that were running in the last session
mSplash->showMessage( tr( "Restoring loaded plugins" ), Qt::AlignHCenter | Qt::AlignBottom );

View File

@ -19,6 +19,9 @@
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsstatusbar.h"
#include "qgsbrowserdockwidget.h"
#include "qgsdataitemprovider.h"
#include "qgsdataitemproviderregistry.h"
#include "qgsgui.h"
#include <QAction>
@ -359,6 +362,7 @@ void QgsCustomizationDialog::init()
}
treeWidget->insertTopLevelItems( 0, QgsCustomization::instance()->mMainWindowItems );
treeWidget->addTopLevelItem( QgsCustomization::instance()->mBrowserItem );
for ( int i = 0; i < treeWidget->topLevelItemCount(); i++ )
treeWidget->expandItem( treeWidget->topLevelItem( i ) );
@ -696,6 +700,42 @@ void QgsCustomization::createTreeItemStatus()
mMainWindowItems << topItem;
}
void QgsCustomization::createTreeItemBrowser()
{
if ( mBrowserItem )
return;
QStringList data;
data << QStringLiteral( "Browser" );
mBrowserItem = new QTreeWidgetItem( data );
QVector<QStringList> items;
items << QStringList( {QStringLiteral( "special:Home" ), tr( "Home Folder" )} );
items << QStringList( {QStringLiteral( "special:ProjectHome" ), tr( "Project tHome Folder" )} );
items << QStringList( {QStringLiteral( "special:Favorites" ), tr( "Favorites Folder" )} );
items << QStringList( {QStringLiteral( "special:Drives" ), tr( "Drive Folders (e.g. C:\\)" )} );
items << QStringList( {QStringLiteral( "special:Volumes" ), tr( "Volume Folder (MacOS only)" )} );
const auto constProviders = QgsApplication::dataItemProviderRegistry()->providers();
for ( QgsDataItemProvider *pr : constProviders )
{
int capabilities = pr->capabilities();
if ( capabilities != QgsDataProvider::NoDataCapabilities )
{
QStringList item;
item << QStringLiteral( "%1" ).arg( pr->name() ) << QObject::tr( "Data Item Provider: %1" ).arg( pr->name() );
items << item;
}
}
for ( const QStringList &strs : items )
{
QTreeWidgetItem *item = new QTreeWidgetItem( mBrowserItem, strs );
item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
item->setCheckState( 0, Qt::Checked );
}
}
QgsCustomization *QgsCustomization::sInstance = nullptr;
QgsCustomization *QgsCustomization::instance()
{
@ -975,6 +1015,34 @@ void QgsCustomization::removeFromLayout( QLayout *layout, QWidget *widget )
}
}
void QgsCustomization::updateBrowserWidget( QgsBrowserDockWidget *widget )
{
createTreeItemBrowser();
if ( !widget )
return;
if ( !mEnabled )
return;
if ( !mBrowserItem )
return;
QStringList disabledDataItems;
mSettings->beginGroup( QStringLiteral( "Customization/Browser" ) );
for ( int i = 0; i < mBrowserItem->childCount(); ++i )
{
const QTreeWidgetItem *item = mBrowserItem->child( i );
if ( item && !mSettings->value( item->text( 0 ), true ).toBool() )
{
disabledDataItems << item->text( 0 );
}
}
mSettings->endGroup();
widget->setDisabledDataItemsKeys( disabledDataItems );
}
void QgsCustomization::preNotify( QObject *receiver, QEvent *event, bool *done )
{
if ( event->type() == QEvent::Show || event->type() == QEvent::MouseButtonPress )

View File

@ -31,6 +31,7 @@ class QTreeWidgetItem;
class QEvent;
class QMouseEvent;
class QSettings;
class QgsBrowserDockWidget;
class APP_EXPORT QgsCustomizationDialog : public QMainWindow, private Ui::QgsCustomizationDialogBase
{
@ -129,6 +130,7 @@ class APP_EXPORT QgsCustomization : public QObject
static void customizeWidget( const QString &path, QWidget *widget, QSettings *settings );
static void removeFromLayout( QLayout *layout, QWidget *widget );
void updateBrowserWidget( QgsBrowserDockWidget *model );
void updateMainWindow( QMenu *toolBarMenu );
// make sure to enable/disable before creating QgisApp in order to get it customized (or not)
@ -162,10 +164,12 @@ class APP_EXPORT QgsCustomization : public QObject
void createTreeItemToolbars();
void createTreeItemDocks();
void createTreeItemStatus();
void createTreeItemBrowser();
void addTreeItemMenu( QTreeWidgetItem *parentItem, const QMenu *menu, const QAction *action = nullptr );
void addTreeItemActions( QTreeWidgetItem *parentItem, const QList<QAction *> &actions );
QList<QTreeWidgetItem *> mMainWindowItems;
friend class QgsCustomizationDialog; // in order to access mMainWindowItems
QTreeWidgetItem *mBrowserItem = nullptr;
friend class QgsCustomizationDialog; // in order to access mMainWindowItems and mBrowserItem
private:
static QgsCustomization *sInstance;

View File

@ -88,7 +88,9 @@ void QgsBrowserModel::addRootItems()
updateProjectHome();
// give the home directory a prominent third place
QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, tr( "Home" ), QDir::homePath(), QStringLiteral( HOME_PREFIX ) + QDir::homePath() );
QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, tr( "Home" ), QDir::homePath(),
QStringLiteral( HOME_PREFIX ) + QDir::homePath(),
QStringLiteral( "special:Home" ) );
item->setSortKey( QStringLiteral( " 2" ) );
setupItemConnections( item );
mRootItems << item;
@ -110,7 +112,7 @@ void QgsBrowserModel::addRootItems()
if ( QgsDirectoryItem::hiddenPath( path ) )
continue;
QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, path, path );
QgsDirectoryItem *item = new QgsDirectoryItem( nullptr, path, QString(), path, QStringLiteral( "special:Drives" ) );
item->setSortKey( QStringLiteral( " 3 %1" ).arg( path ) );
mDriveItems.insert( path, item );
@ -120,7 +122,7 @@ void QgsBrowserModel::addRootItems()
#ifdef Q_OS_MAC
QString path = QString( "/Volumes" );
QgsDirectoryItem *vols = new QgsDirectoryItem( nullptr, path, path );
QgsDirectoryItem *vols = new QgsDirectoryItem( nullptr, path, QString(), path, QStringLiteral( "special:Volumes" ) );
mRootItems << vols;
#endif
@ -140,6 +142,8 @@ void QgsBrowserModel::addRootItems()
QgsDataItem *item = pr->createDataItem( QString(), nullptr ); // empty path -> top level
if ( item )
{
// make sure the top level key is set always
item->setProviderKey( pr->name() );
// Forward the signal from the root items to the model (and then to the app)
connect( item, &QgsDataItem::connectionsChanged, this, &QgsBrowserModel::connectionsChanged );
QgsDebugMsgLevel( "Add new top level item : " + item->name(), 4 );
@ -194,7 +198,6 @@ void QgsBrowserModel::initialize()
}
}
Qt::ItemFlags QgsBrowserModel::flags( const QModelIndex &index ) const
{
if ( !index.isValid() )
@ -263,6 +266,10 @@ QVariant QgsBrowserModel::data( const QModelIndex &index, int role ) const
}
return QVariant();
}
else if ( role == QgsBrowserModel::ProviderKeyRole )
{
return item->providerKey();
}
else
{
// unsupported role

View File

@ -90,6 +90,7 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel
PathRole = Qt::UserRole, //!< Item path used to access path in the tree, see QgsDataItem::mPath
CommentRole = Qt::UserRole + 1, //!< Item comment
SortRole, //!< Custom sort role, see QgsDataItem::sortKey()
ProviderKeyRole, //!< Data item provider key that created the item, \since QGIS 3.12
};
// implemented methods from QAbstractItemModel for read-only access
@ -175,7 +176,6 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel
* \since QGIS 3.6
*/
QMap<QString, QgsDirectoryItem *> driveItems() const;
signals:
//! Emitted when item children fetch was finished
@ -243,7 +243,6 @@ class CORE_EXPORT QgsBrowserModel : public QAbstractItemModel
*/
void initialize();
protected:
//! Populates the model
void addRootItems();

View File

@ -146,10 +146,13 @@ bool QgsBrowserProxyModel::filterAcceptsString( const QString &value ) const
bool QgsBrowserProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
{
if ( ( mFilter.isEmpty() && !mFilterByLayerType ) || !mModel )
if ( ( mFilter.isEmpty() && !mFilterByLayerType && mHiddenDataItemsKeys.empty() ) || !mModel )
return true;
QModelIndex sourceIndex = mModel->index( sourceRow, 0, sourceParent );
if ( !filterAcceptsProviderKey( sourceIndex ) || !filterRootAcceptsProviderKey( sourceIndex ) )
return false;
return filterAcceptsItem( sourceIndex ) || filterAcceptsAncestor( sourceIndex ) || filterAcceptsDescendant( sourceIndex );
}
@ -230,3 +233,35 @@ bool QgsBrowserProxyModel::filterAcceptsItem( const QModelIndex &sourceIndex ) c
return true;
}
bool QgsBrowserProxyModel::filterAcceptsProviderKey( const QModelIndex &sourceIndex ) const
{
if ( !mModel )
return true;
const QString providerKey = mModel->data( sourceIndex, QgsBrowserModel::ProviderKeyRole ).toString();
if ( providerKey.isEmpty() )
return true;
return !mHiddenDataItemsKeys.contains( providerKey );
}
bool QgsBrowserProxyModel::filterRootAcceptsProviderKey( const QModelIndex &sourceIndex ) const
{
if ( !mModel )
return true;
QModelIndex sourceParentIndex = mModel->parent( sourceIndex );
if ( !sourceParentIndex.isValid() )
{
return filterAcceptsProviderKey( sourceIndex );
}
return filterRootAcceptsProviderKey( sourceParentIndex );
}
void QgsBrowserProxyModel::setDataItemProviderKeyFilter( const QStringList &filter )
{
mHiddenDataItemsKeys = filter;
invalidateFilter();
}

View File

@ -143,13 +143,28 @@ class CORE_EXPORT QgsBrowserProxyModel : public QSortFilterProxyModel
*/
void setLayerType( QgsMapLayerType type );
/**
* Sets the customization filters for data items based on item's data provider key
*
* By default browser model shows all items from all available data items provider and few special
* items (e.g. Favourites). To customize the behavious, set the filter to not load certain data items.
* The items that are not based on data item providers have prefix "special:", for example
* "special:Favourites", "special:Home", "PostGIS", "MSSQL"
*
* All items created by the providers listed in filter are hidden from the layer tree.
* This filter is always evaluated.
*
* \since QGIS 3.12
*/
void setDataItemProviderKeyFilter( const QStringList &filter );
protected:
// It would be better to apply the filer only to expanded (visible) items, but using mapFromSource() + view here was causing strange errors
bool filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const override;
private:
QStringList mHiddenDataItemsKeys;
QgsBrowserModel *mModel = nullptr;
QString mFilter; //filter string provided
QVector<QRegExp> mREList; //list of filters, separated by "|"
@ -173,6 +188,12 @@ class CORE_EXPORT QgsBrowserProxyModel : public QSortFilterProxyModel
//! Filter accepts item name
bool filterAcceptsItem( const QModelIndex &sourceIndex ) const;
//! Filter accepts provider key.
bool filterAcceptsProviderKey( const QModelIndex &sourceIndex ) const;
//! Root item accepts provider key.
bool filterRootAcceptsProviderKey( const QModelIndex &sourceIndex ) const;
};
#endif // QGSBROWSERPROXYMODEL_H

View File

@ -121,13 +121,14 @@ QIcon QgsZipItem::iconZip()
QgsAnimatedIcon *QgsDataItem::sPopulatingIcon = nullptr;
QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent, const QString &name, const QString &path )
QgsDataItem::QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey )
// Do not pass parent to QObject, Qt would delete this when parent is deleted
: mType( type )
, mCapabilities( NoCapabilities )
, mParent( parent )
, mState( NotPopulated )
, mName( name )
, mProviderKey( providerKey )
, mPath( path )
, mDeferredDelete( false )
, mFutureWatcher( nullptr )
@ -438,6 +439,16 @@ void QgsDataItem::refresh( const QVector<QgsDataItem *> &children )
setState( Populated );
}
QString QgsDataItem::providerKey() const
{
return mProviderKey;
}
void QgsDataItem::setProviderKey( const QString &value )
{
mProviderKey = value;
}
int QgsDataItem::rowCount()
{
return mChildren.size();
@ -607,9 +618,9 @@ QList<QMenu *> QgsDataItem::menus( QWidget *parent )
// ---------------------------------------------------------------------
QgsLayerItem::QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri, LayerType layerType, const QString &providerKey )
: QgsDataItem( Layer, parent, name, path )
, mProviderKey( providerKey )
QgsLayerItem::QgsLayerItem( QgsDataItem *parent, const QString &name, const QString &path,
const QString &uri, LayerType layerType, const QString &providerKey )
: QgsDataItem( Layer, parent, name, path, providerKey )
, mUri( uri )
, mLayerType( layerType )
{
@ -784,8 +795,11 @@ QgsMimeDataUtils::Uri QgsLayerItem::mimeUri() const
}
// ---------------------------------------------------------------------
QgsDataCollectionItem::QgsDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataItem( Collection, parent, name, path )
QgsDataCollectionItem::QgsDataCollectionItem( QgsDataItem *parent,
const QString &name,
const QString &path,
const QString &providerKey )
: QgsDataItem( Collection, parent, name, path, providerKey )
{
mCapabilities = Fertile;
mIconName = QStringLiteral( "/mIconDbSchema.svg" );
@ -817,8 +831,10 @@ QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name, co
init();
}
QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path )
: QgsDataCollectionItem( parent, QDir::toNativeSeparators( name ), path )
QgsDirectoryItem::QgsDirectoryItem( QgsDataItem *parent, const QString &name,
const QString &dirPath, const QString &path,
const QString &providerKey )
: QgsDataCollectionItem( parent, QDir::toNativeSeparators( name ), path, providerKey )
, mDirPath( dirPath )
, mRefreshLater( false )
{
@ -1207,8 +1223,9 @@ void QgsDirectoryParamWidget::showHideColumn()
settings.setValue( QStringLiteral( "dataitem/directoryHiddenColumns" ), lst );
}
QgsProjectItem::QgsProjectItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataItem( QgsDataItem::Project, parent, name, path )
QgsProjectItem::QgsProjectItem( QgsDataItem *parent, const QString &name,
const QString &path, const QString &providerKey )
: QgsDataItem( QgsDataItem::Project, parent, name, path, providerKey )
{
mIconName = QStringLiteral( ":/images/icons/qgis_icon.svg" );
setToolTip( QDir::toNativeSeparators( path ) );
@ -1233,7 +1250,7 @@ QgsErrorItem::QgsErrorItem( QgsDataItem *parent, const QString &error, const QSt
}
QgsFavoritesItem::QgsFavoritesItem( QgsDataItem *parent, const QString &name, const QString &path )
: QgsDataCollectionItem( parent, name, QStringLiteral( "favorites:" ) )
: QgsDataCollectionItem( parent, name, QStringLiteral( "favorites:" ), QStringLiteral( "special:Favorites" ) )
{
Q_UNUSED( path )
mCapabilities |= Fast;
@ -1392,8 +1409,10 @@ QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString
init();
}
QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name, const QString &filePath, const QString &path )
: QgsDataCollectionItem( parent, name, path )
QgsZipItem::QgsZipItem( QgsDataItem *parent, const QString &name,
const QString &filePath, const QString &path,
const QString &providerKey )
: QgsDataCollectionItem( parent, name, path, providerKey )
, mFilePath( filePath )
{
init();
@ -1584,7 +1603,7 @@ QStringList QgsZipItem::getZipFileList()
///@cond PRIVATE
QgsProjectHomeItem::QgsProjectHomeItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path )
: QgsDirectoryItem( parent, name, dirPath, path )
: QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral( "special:ProjectHome" ) )
{
}
@ -1602,7 +1621,7 @@ QVariant QgsProjectHomeItem::sortKey() const
QgsFavoriteItem::QgsFavoriteItem( QgsFavoritesItem *parent, const QString &name, const QString &dirPath, const QString &path )
: QgsDirectoryItem( parent, name, dirPath, path )
: QgsDirectoryItem( parent, name, dirPath, path, QStringLiteral( "special:Favorites" ) )
, mFavorites( parent )
{
mCapabilities |= Rename;

View File

@ -86,8 +86,11 @@ class CORE_EXPORT QgsDataItem : public QObject
Q_ENUM( Type )
//! Create new data item.
QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent SIP_TRANSFERTHIS, const QString &name, const QString &path );
/**
* Creates new data item
* \a providerKey added in QGIS 3.12
*/
QgsDataItem( QgsDataItem::Type type, QgsDataItem *parent SIP_TRANSFERTHIS, const QString &name, const QString &path, const QString &providerKey = QString() );
~QgsDataItem() override;
bool hasChildren();
@ -308,6 +311,27 @@ class CORE_EXPORT QgsDataItem : public QObject
QString path() const { return mPath; }
void setPath( const QString &path ) { mPath = path; }
/**
* Returns the provider key that created this item (e.g. "PostGIS")
*
* If key has a prefix "special:", it marks that the item was not created with a provider,
* but manually. For example "special:Favorites", "special:Home"
*
* \since QGIS 3.12
*/
QString providerKey() const;
/**
* Sets the provider key that created this item (e.g. "PostGIS")
*
* If key has a prefix "special:", it marks that the item was not created with a provider,
* but manually. For example "special:Favorites"
*
* \since QGIS 3.12
*/
void setProviderKey( const QString &value );
//! Create path component replacing path separators
static QString pathComponent( const QString &component );
@ -369,6 +393,7 @@ class CORE_EXPORT QgsDataItem : public QObject
QVector<QgsDataItem *> mChildren; // easier to have it always
State mState;
QString mName;
QString mProviderKey;
// Path is slash ('/') separated chain of item identifiers which are usually item names, but may be different if it is
// necessary to distinguish paths of two providers to the same source (e.g GRASS location and standard directory have the same
// name but different paths). Identifiers in path must not contain '/' characters.
@ -537,9 +562,6 @@ class CORE_EXPORT QgsLayerItem : public QgsDataItem
Q_DECL_DEPRECATED virtual bool deleteLayer() SIP_DEPRECATED;
protected:
//! The provider key
QString mProviderKey;
//! The URI
QString mUri;
//! The layer type
@ -572,7 +594,8 @@ class CORE_EXPORT QgsDataCollectionItem : public QgsDataItem
{
Q_OBJECT
public:
QgsDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path = QString() );
//! Constructor
QgsDataCollectionItem( QgsDataItem *parent, const QString &name, const QString &path = QString(), const QString &providerKey = QString() );
~QgsDataCollectionItem() override;
void addChild( QgsDataItem *item SIP_TRANSFER ) { mChildren.append( item ); }
@ -620,8 +643,10 @@ class CORE_EXPORT QgsDirectoryItem : public QgsDataCollectionItem
* \param parent
* \param name directory name
* \param dirPath path to directory in file system
* \param path item path in the tree, it may be dirPath or dirPath with some prefix, e.g. favorites: */
QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path );
* \param path item path in the tree, it may be dirPath or dirPath with some prefix, e.g. favorites:
* \param providerKey key of the provider that created this item
*/
QgsDirectoryItem( QgsDataItem *parent, const QString &name, const QString &dirPath, const QString &path, const QString &providerKey = QString() );
void setState( State state ) override;
@ -669,8 +694,9 @@ class CORE_EXPORT QgsProjectItem : public QgsDataItem
* \param parent The parent data item.
* \param name The name of the of the project. Displayed to the user.
* \param path The full path to the project.
* \param providerKey key of the provider that created this item
*/
QgsProjectItem( QgsDataItem *parent, const QString &name, const QString &path );
QgsProjectItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &providerKey = QString() );
bool hasDragEnabled() const override { return true; }
@ -775,8 +801,11 @@ class CORE_EXPORT QgsZipItem : public QgsDataCollectionItem
QStringList mZipFileList;
public:
//! Constructor
QgsZipItem( QgsDataItem *parent, const QString &name, const QString &path );
QgsZipItem( QgsDataItem *parent, const QString &name, const QString &filePath, const QString &path );
//! Constructor
QgsZipItem( QgsDataItem *parent, const QString &name, const QString &filePath, const QString &path, const QString &providerKey = QString() );
QVector<QgsDataItem *> createChildren() override;
QStringList getZipFileList();

View File

@ -128,6 +128,7 @@ void QgsBrowserDockWidget::showEvent( QShowEvent *e )
{
mProxyModel = new QgsBrowserProxyModel( this );
mProxyModel->setBrowserModel( mModel );
mProxyModel->setDataItemProviderKeyFilter( mDisabledDataItemsKeys );
mBrowserView->setSettingsSection( objectName().toLower() ); // to distinguish 2 or more instances of the browser
mBrowserView->setBrowserModel( mModel );
mBrowserView->setModel( mProxyModel );
@ -289,6 +290,16 @@ QgsMessageBar *QgsBrowserDockWidget::messageBar()
return mMessageBar;
}
void QgsBrowserDockWidget::setDisabledDataItemsKeys( const QStringList &filter )
{
mDisabledDataItemsKeys = filter;
if ( !mProxyModel )
return;
mProxyModel->setDataItemProviderKeyFilter( mDisabledDataItemsKeys );
}
void QgsBrowserDockWidget::removeFavorite()
{
mModel->removeFavorite( mProxyModel->mapToSource( mBrowserView->currentIndex() ) );

View File

@ -80,6 +80,20 @@ class GUI_EXPORT QgsBrowserDockWidget : public QgsDockWidget, private Ui::QgsBro
*/
QgsMessageBar *messageBar();
/**
* Sets the customization for data items based on item's data provider key
*
* By default browser model shows all items from all available data items provider and few special
* items (e.g. Favourites). To customize the behavior, set the filter to not load certain data items.
* The items that are not based on data item providers (e.g. Favourites, Home) have
* prefix "special:"
*
* Used in the proxy browser model to hide items
*
* \since QGIS 3.12
*/
void setDisabledDataItemsKeys( const QStringList &filter );
public slots:
/**
@ -192,9 +206,7 @@ class GUI_EXPORT QgsBrowserDockWidget : public QgsDockWidget, private Ui::QgsBro
float mPropertiesWidgetHeight;
QgsMessageBar *mMessageBar = nullptr;
QStringList mDisabledDataItemsKeys;
};
#endif // QGSBROWSERDOCKWIDGET_H

View File

@ -75,7 +75,7 @@ void TestQgsBrowserModel::testModel()
QVERIFY( !model.dataItem( QModelIndex() ) );
// add a root child
QgsDataCollectionItem *rootItem1 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Test" ), QStringLiteral( "root1" ) );
QgsDataCollectionItem *rootItem1 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Test" ), QStringLiteral( "root1" ), QStringLiteral( "providerKeyRoot1" ) );
QVERIFY( !model.findItem( rootItem1 ).isValid() );
model.setupItemConnections( rootItem1 );
model.mRootItems.append( rootItem1 );
@ -95,6 +95,7 @@ void TestQgsBrowserModel::testModel()
QVERIFY( !model.hasChildren( root1Index ) );
QCOMPARE( model.data( root1Index ).toString(), QStringLiteral( "Test" ) );
QCOMPARE( model.data( root1Index, QgsBrowserModel::PathRole ).toString(), QStringLiteral( "root1" ) );
QCOMPARE( model.data( root1Index, QgsBrowserModel::ProviderKeyRole ).toString(), QStringLiteral( "providerKeyRoot1" ) );
QCOMPARE( model.dataItem( root1Index ), rootItem1 );
QCOMPARE( model.findItem( rootItem1 ), root1Index );
@ -111,11 +112,12 @@ void TestQgsBrowserModel::testModel()
QCOMPARE( model.columnCount( root2Index ), 1 );
QCOMPARE( model.data( root2Index ).toString(), QStringLiteral( "Test2" ) );
QCOMPARE( model.data( root2Index, QgsBrowserModel::PathRole ).toString(), QStringLiteral( "root2" ) );
QVERIFY( model.data( root2Index, QgsBrowserModel::ProviderKeyRole ).toString().isEmpty() );
QCOMPARE( model.dataItem( root2Index ), rootItem2 );
QCOMPARE( model.findItem( rootItem2 ), root2Index );
// child item
QgsDataCollectionItem *childItem1 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Child1" ), QStringLiteral( "child1" ) );
QgsDataCollectionItem *childItem1 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Child1" ), QStringLiteral( "child1" ), QStringLiteral( "providerKeyChild1" ) );
model.setupItemConnections( childItem1 );
rootItem1->addChild( childItem1 );
@ -127,6 +129,7 @@ void TestQgsBrowserModel::testModel()
QModelIndex child1Index = model.index( 0, 0, root1Index );
QCOMPARE( model.data( child1Index ).toString(), QStringLiteral( "Child1" ) );
QCOMPARE( model.data( child1Index, QgsBrowserModel::PathRole ).toString(), QStringLiteral( "child1" ) );
QCOMPARE( model.data( child1Index, QgsBrowserModel::ProviderKeyRole ).toString(), QStringLiteral( "providerKeyChild1" ) );
QCOMPARE( model.dataItem( child1Index ), childItem1 );
QCOMPARE( model.findItem( childItem1 ), child1Index );
QCOMPARE( model.findItem( childItem1, rootItem1 ), child1Index );

View File

@ -99,7 +99,7 @@ void TestQgsBrowserProxyModel::testModel()
QCOMPARE( proxy.dataItem( root1Index ), rootItem1 );
// second root item
QgsDataCollectionItem *rootItem2 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Test2" ), QStringLiteral( "root2" ) );
QgsDataCollectionItem *rootItem2 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Test2" ), QStringLiteral( "root2" ), QStringLiteral( "provider2" ) );
model.setupItemConnections( rootItem2 );
model.beginInsertRows( QModelIndex(), 1, 1 );
model.mRootItems.append( rootItem2 );
@ -116,7 +116,7 @@ void TestQgsBrowserProxyModel::testModel()
QCOMPARE( proxy.dataItem( root2Index ), rootItem2 );
// child item
QgsDataCollectionItem *childItem1 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Child1" ), QStringLiteral( "child1" ) );
QgsDataCollectionItem *childItem1 = new QgsDataCollectionItem( nullptr, QStringLiteral( "Child1" ), QStringLiteral( "child1" ), QStringLiteral( "provider1" ) );
rootItem1->addChildItem( childItem1, true );
QCOMPARE( proxy.rowCount(), 2 );
@ -250,6 +250,20 @@ void TestQgsBrowserProxyModel::testModel()
QCOMPARE( proxy.rowCount( child2Index ), 0 );
QCOMPARE( proxy.rowCount( root2Index ), 1 );
QCOMPARE( proxy.data( proxy.index( 0, 0, root2Index ) ).toString(), QStringLiteral( "Child4" ) );
proxy.setFilterByLayerType( false );
// provider filtering
proxy.setDataItemProviderKeyFilter( QStringList( {QStringLiteral( "provider1" )} ) );
QCOMPARE( proxy.rowCount(), 2 );
root1Index = proxy.index( 0, 0 );
QCOMPARE( proxy.rowCount( root1Index ), 1 );
proxy.setDataItemProviderKeyFilter( QStringList( {QStringLiteral( "provider2" )} ) );
QCOMPARE( proxy.rowCount(), 1 );
root1Index = proxy.index( 0, 0 );
QCOMPARE( proxy.rowCount( root1Index ), 2 );
proxy.setDataItemProviderKeyFilter( QStringList() );
QCOMPARE( proxy.rowCount(), 2 );
}
QGSTEST_MAIN( TestQgsBrowserProxyModel )