36#include <QAbstractTextDocumentLayout>
37#include <QActionGroup>
41#include <QPlainTextDocumentLayout>
42#include <QSortFilterProxyModel>
47#include "moc_qgsbrowserwidget.cpp"
49using namespace Qt::StringLiterals;
55#include <QDragEnterEvent>
60 , mModel( browserModel )
64 layout()->setContentsMargins( 0, 0, 0, 0 );
65 qgis::down_cast<QVBoxLayout *>( layout() )->setSpacing( 0 );
67 mBrowserView =
new QgsDockBrowserTreeView(
this );
68 mLayoutBrowser->addWidget( mBrowserView );
70 mWidgetFilter->hide();
71 mLeFilter->setPlaceholderText( tr(
"Type here to filter visible items…" ) );
74 QMenu *menu =
new QMenu(
this );
75 menu->setSeparatorsCollapsible(
false );
76 mBtnFilterOptions->setMenu( menu );
77 QAction *action =
new QAction( tr(
"Case Sensitive" ), menu );
78 action->setData(
"case" );
79 action->setCheckable(
true );
80 action->setChecked(
false );
81 connect( action, &QAction::toggled,
this, &QgsBrowserWidget::setCaseSensitive );
82 menu->addAction( action );
83 QActionGroup *group =
new QActionGroup( menu );
84 action =
new QAction( tr(
"Filter Pattern Syntax" ), group );
85 action->setSeparator(
true );
86 menu->addAction( action );
87 action =
new QAction( tr(
"Normal" ), group );
89 action->setCheckable(
true );
90 action->setChecked(
true );
91 menu->addAction( action );
92 action =
new QAction( tr(
"Wildcard(s)" ), group );
94 action->setCheckable(
true );
95 menu->addAction( action );
96 action =
new QAction( tr(
"Regular Expression" ), group );
98 action->setCheckable(
true );
99 menu->addAction( action );
101 mBrowserView->setExpandsOnDoubleClick(
false );
104 connect( mActionAddLayers, &QAction::triggered,
this, &QgsBrowserWidget::addSelectedLayers );
105 connect( mActionCollapse, &QAction::triggered, mBrowserView, &QgsDockBrowserTreeView::collapseAll );
106 connect( mActionShowFilter, &QAction::triggered,
this, &QgsBrowserWidget::showFilterWidget );
107 connect( mActionPropertiesWidget, &QAction::triggered,
this, &QgsBrowserWidget::propertiesWidgetToggled );
108 connect( mLeFilter, &QgsFilterLineEdit::returnPressed,
this, &QgsBrowserWidget::setFilter );
110 connect( mLeFilter, &QgsFilterLineEdit::textChanged,
this, &QgsBrowserWidget::setFilter );
111 connect( group, &QActionGroup::triggered,
this, &QgsBrowserWidget::setFilterSyntax );
112 connect( mBrowserView, &QgsDockBrowserTreeView::customContextMenuRequested,
this, &QgsBrowserWidget::showContextMenu );
113 connect( mBrowserView, &QgsDockBrowserTreeView::doubleClicked,
this, &QgsBrowserWidget::itemDoubleClicked );
114 connect( mSplitter, &QSplitter::splitterMoved,
this, &QgsBrowserWidget::splitterMoved );
124 if ( !mModel->initialized() )
126 mModel->initialize();
131 mProxyModel->setBrowserModel( mModel );
132 mProxyModel->setHiddenDataItemProviderKeyFilter( mDisabledDataItemsKeys );
133 mBrowserView->setSettingsSection( objectName().toLower() );
134 mBrowserView->setBrowserModel( mModel );
135 mBrowserView->setModel( mProxyModel );
136 mBrowserView->setSortingEnabled(
true );
137 mBrowserView->sortByColumn( 0, Qt::AscendingOrder );
139 mBrowserView->setTextElideMode( Qt::ElideNone );
140 mBrowserView->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
141 mBrowserView->header()->setStretchLastSection(
false );
144 connect( mBrowserView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsBrowserWidget::selectionChanged );
151 mActionPropertiesWidget->setChecked( settings.
value( settingsSection() +
"/propertiesWidgetEnabled",
false ).toBool() );
152 mPropertiesWidget->setVisible(
false );
154 mSplitter->restoreState( settings.
value( u
"%1/splitterState"_s.arg( settingsSection() ) ).toByteArray() );
157 QWidget::showEvent( e );
160void QgsBrowserWidget::itemDoubleClicked(
const QModelIndex &index )
171 if ( provider->handleDoubleClick( item, context ) )
179 if ( mBrowserView->isExpanded( index ) )
180 mBrowserView->collapse( index );
182 mBrowserView->expand( index );
186void QgsBrowserWidget::onOptionsChanged()
188 std::function<void(
const QModelIndex &index )> updateItem;
189 updateItem = [
this, &updateItem](
const QModelIndex &index ) {
190 if ( QgsDirectoryItem *dirItem = qobject_cast<QgsDirectoryItem *>( mModel->dataItem( index ) ) )
192 dirItem->reevaluateMonitoring();
195 const int rowCount = mModel->rowCount( index );
196 for (
int i = 0; i < rowCount; ++i )
198 const QModelIndex child = mModel->index( i, 0, index );
203 for (
int i = 0; i < mModel->rowCount(); ++i )
205 updateItem( mModel->index( i, 0 ) );
209void QgsBrowserWidget::showContextMenu( QPoint pt )
211 QModelIndex index = mProxyModel->mapToSource( mBrowserView->indexAt( pt ) );
212 QgsDataItem *item = mModel->dataItem( index );
216 const QModelIndexList selection = mBrowserView->selectionModel()->selectedIndexes();
217 QList<QgsDataItem *> selectedItems;
218 selectedItems.reserve( selection.size() );
219 for (
const QModelIndex &selectedIndex : selection )
221 QgsDataItem *selectedItem = mProxyModel->dataItem( selectedIndex );
223 selectedItems << selectedItem;
226 QMenu *menu =
new QMenu(
this );
228 const QList<QMenu *> menus = item->
menus( menu );
229 QList<QAction *> actions = item->
actions( menu );
231 if ( !menus.isEmpty() )
233 for ( QMenu *mn : menus )
239 if ( !actions.isEmpty() )
241 if ( !menu->actions().isEmpty() )
242 menu->addSeparator();
244 menu->addActions( actions );
247 QgsDataItemGuiContext context = createContext();
250 std::sort( providers.begin(), providers.end(), []( QgsDataItemGuiProvider *a, QgsDataItemGuiProvider *b ) { return a->precedenceWhenPopulatingMenus() < b->precedenceWhenPopulatingMenus(); } );
251 for ( QgsDataItemGuiProvider *provider : std::as_const( providers ) )
253 provider->populateContextMenu( item, menu, selectedItems, context );
256 if ( menu->actions().isEmpty() )
262 menu->popup( mBrowserView->mapToGlobal( pt ) );
268 mModel->setMessageBar( bar );
279 mModel->setMapCanvas( canvas );
289 mDisabledDataItemsKeys = filter;
294 mProxyModel->setHiddenDataItemProviderKeyFilter( mDisabledDataItemsKeys );
299 refreshModel( QModelIndex() );
302void QgsBrowserWidget::refreshModel(
const QModelIndex &index )
304 if ( mModel && mProxyModel )
318 mModel->refresh( index );
321 for (
int i = 0; i < mModel->rowCount( index ); i++ )
323 QModelIndex idx = mModel->index( i, 0, index );
324 QModelIndex proxyIdx = mProxyModel->mapFromSource( idx );
325 QgsDataItem *child = mModel->dataItem( idx );
344void QgsBrowserWidget::addLayer(
QgsLayerItem *layerItem )
352void QgsBrowserWidget::addSelectedLayers()
354 QApplication::setOverrideCursor( Qt::WaitCursor );
357 QModelIndexList list = mBrowserView->selectionModel()->selectedIndexes();
358 std::sort( list.begin(), list.end() );
361 const auto constList = list;
362 for (
const QModelIndex &index : constList )
364 QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
367 QgsProjectItem *projectItem = qobject_cast<QgsProjectItem *>( item );
371 QApplication::restoreOverrideCursor();
377 for (
int i = list.size() - 1; i >= 0; i-- )
379 QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( list[i] ) );
382 QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
384 addLayer( layerItem );
388 QApplication::restoreOverrideCursor();
391void QgsBrowserWidget::hideItem()
393 QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
394 QgsDataItem *item = mModel->dataItem( index );
400 mModel->hidePath( item );
404void QgsBrowserWidget::showProperties()
406 QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
407 QgsDataItem *item = mModel->dataItem( index );
413 QgsBrowserPropertiesDialog *dialog =
new QgsBrowserPropertiesDialog( settingsSection(),
this );
414 dialog->setAttribute( Qt::WA_DeleteOnClose );
415 dialog->setItem( item, createContext() );
420void QgsBrowserWidget::showFilterWidget(
bool visible )
422 mWidgetFilter->setVisible( visible );
425 mLeFilter->setText( QString() );
430 mLeFilter->setFocus();
434void QgsBrowserWidget::setFilter()
436 QString filter = mLeFilter->text();
438 mProxyModel->setFilterString( filter );
444 mModel->updateProjectHome();
447void QgsBrowserWidget::setFilterSyntax( QAction *action )
449 if ( !action || !mProxyModel )
455void QgsBrowserWidget::setCaseSensitive(
bool caseSensitive )
459 mProxyModel->setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
462int QgsBrowserWidget::selectedItemsCount()
464 QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
465 if ( selectionModel )
467 return selectionModel->selectedIndexes().size();
474 QgsDataItemGuiContext context;
477 context.
setView( mBrowserView );
481void QgsBrowserWidget::selectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected )
484 Q_UNUSED( deselected )
485 if ( mActionPropertiesWidget->isChecked() )
487 setPropertiesWidget();
491void QgsBrowserWidget::clearPropertiesWidget()
493 while ( mPropertiesLayout->count() > 0 )
495 delete mPropertiesLayout->itemAt( 0 )->widget();
497 mPropertiesWidget->setVisible(
false );
500void QgsBrowserWidget::setPropertiesWidget()
502 clearPropertiesWidget();
503 QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
504 if ( selectionModel )
506 QModelIndexList indexes = selectionModel->selectedIndexes();
507 if ( indexes.size() == 1 )
509 QModelIndex index = mProxyModel->mapToSource( indexes.value( 0 ) );
510 QgsDataItem *item = mModel->dataItem( index );
511 QgsDataItemGuiContext context = createContext();
512 QgsBrowserPropertiesWidget *propertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, mPropertiesWidget );
513 if ( propertiesWidget )
515 propertiesWidget->setCondensedMode(
true );
516 mPropertiesLayout->addWidget( propertiesWidget );
520 mPropertiesWidget->setVisible( mPropertiesLayout->count() > 0 );
523void QgsBrowserWidget::enablePropertiesWidget(
bool enable )
525 mActionPropertiesWidget->setChecked( enable );
526 propertiesWidgetToggled( enable );
529void QgsBrowserWidget::propertiesWidgetToggled(
bool enabled )
531 if ( enabled && selectedItemsCount() == 1 )
533 setPropertiesWidget();
537 clearPropertiesWidget();
540 QgsSettings settings;
541 settings.
setValue( settingsSection() +
"/propertiesWidgetEnabled", enabled );
546 if ( index.isValid() )
548 QModelIndex proxyIndex = mProxyModel->mapFromSource( index );
549 mBrowserView->expand( proxyIndex );
550 mBrowserView->setCurrentIndex( proxyIndex );
554void QgsBrowserWidget::splitterMoved()
557 settings.
setValue( u
"%1/splitterState"_s.arg( settingsSection() ), mSplitter->saveState() );
@ Fertile
Can create children. Even items without this capability may have children, but cannot create them,...
@ Fast
CreateChildren() is fast enough to be run in main thread when refreshing items, most root items (wms,...
@ Layer
Represents a map layer.
@ Project
Represents a QGIS project.
@ Directory
Represents a file directory.
A model for showing available data sources and other items in a structured tree.
void connectionsChanged(const QString &providerKey)
Emitted when connections for the specified providerKey have changed in the browser.
QgsDataItem * dataItem(const QModelIndex &idx) const
Returns the data item at the specified index, or nullptr if no item exists at the index.
A QSortFilterProxyModel subclass for filtering and sorting browser model items.
FilterSyntax
Filter syntax options.
@ RegularExpression
Regular expression filtering.
@ Wildcards
Wildcard filtering.
@ Normal
Standard string filtering.
void setFilterSyntax(FilterSyntax syntax)
Sets the filter syntax.
Encapsulates the context in which a QgsDataItem is shown within the application GUI.
void setView(QgsBrowserTreeView *view)
Sets the associated view.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the data item.
void setMessageBar(QgsMessageBar *bar)
Sets the associated message bar.
QList< QgsDataItemGuiProvider * > providers() const
Returns the list of available providers.
Abstract base class for providers which affect how QgsDataItem items behave within the application GU...
Base class for all items in the model.
virtual QList< QMenu * > menus(QWidget *parent)
Returns the list of menus available for this item.
virtual bool handleDoubleClick()
Called when a user double clicks on the item.
Qgis::BrowserItemType type() const
virtual QList< QAction * > actions(QWidget *parent)
Returns the list of actions available for this item.
virtual Qgis::BrowserItemCapabilities capabilities2() const
Returns the capabilities for the data item.
virtual void depopulate()
Remove children recursively and set as not populated. This is used when refreshing collapsed items.
void cleared()
Emitted when the widget is cleared.
void optionsChanged()
This signal is emitted whenever the application options have been changed.
static QgsGui * instance()
Returns a pointer to the singleton instance.
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
A browser item that represents a layer that can be opened with one of the providers.
QgsMimeDataUtils::UriList mimeUris() const override
Returns mime URIs for the data item, most data providers will only return a single URI but some data ...
Map canvas is a class for displaying all GIS data types on a canvas.
A bar for displaying non-blocking messages to the user.
Stores settings for use within QGIS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
#define QgsDebugMsgLevel(str, level)