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 ) {
251 return a->precedenceWhenPopulatingMenus() < b->precedenceWhenPopulatingMenus();
253 for ( QgsDataItemGuiProvider *provider : std::as_const( providers ) )
255 provider->populateContextMenu( item, menu, selectedItems, context );
258 if ( menu->actions().isEmpty() )
264 menu->popup( mBrowserView->mapToGlobal( pt ) );
270 mModel->setMessageBar( bar );
281 mModel->setMapCanvas( canvas );
291 mDisabledDataItemsKeys = filter;
296 mProxyModel->setHiddenDataItemProviderKeyFilter( mDisabledDataItemsKeys );
301 refreshModel( QModelIndex() );
304void QgsBrowserWidget::refreshModel(
const QModelIndex &index )
306 if ( mModel && mProxyModel )
320 mModel->refresh( index );
323 for (
int i = 0; i < mModel->rowCount( index ); i++ )
325 QModelIndex idx = mModel->index( i, 0, index );
326 QModelIndex proxyIdx = mProxyModel->mapFromSource( idx );
327 QgsDataItem *child = mModel->dataItem( idx );
346void QgsBrowserWidget::addLayer(
QgsLayerItem *layerItem )
354void QgsBrowserWidget::addSelectedLayers()
356 QApplication::setOverrideCursor( Qt::WaitCursor );
359 QModelIndexList list = mBrowserView->selectionModel()->selectedIndexes();
360 std::sort( list.begin(), list.end() );
363 const auto constList = list;
364 for (
const QModelIndex &index : constList )
366 QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
369 QgsProjectItem *projectItem = qobject_cast<QgsProjectItem *>( item );
373 QApplication::restoreOverrideCursor();
379 for (
int i = list.size() - 1; i >= 0; i-- )
381 QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( list[i] ) );
384 QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
386 addLayer( layerItem );
390 QApplication::restoreOverrideCursor();
393void QgsBrowserWidget::hideItem()
395 QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
396 QgsDataItem *item = mModel->dataItem( index );
402 mModel->hidePath( item );
406void QgsBrowserWidget::showProperties()
408 QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
409 QgsDataItem *item = mModel->dataItem( index );
415 QgsBrowserPropertiesDialog *dialog =
new QgsBrowserPropertiesDialog( settingsSection(),
this );
416 dialog->setAttribute( Qt::WA_DeleteOnClose );
417 dialog->setItem( item, createContext() );
422void QgsBrowserWidget::showFilterWidget(
bool visible )
424 mWidgetFilter->setVisible( visible );
427 mLeFilter->setText( QString() );
432 mLeFilter->setFocus();
436void QgsBrowserWidget::setFilter()
438 QString filter = mLeFilter->text();
440 mProxyModel->setFilterString( filter );
446 mModel->updateProjectHome();
449void QgsBrowserWidget::setFilterSyntax( QAction *action )
451 if ( !action || !mProxyModel )
457void QgsBrowserWidget::setCaseSensitive(
bool caseSensitive )
461 mProxyModel->setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
464int QgsBrowserWidget::selectedItemsCount()
466 QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
467 if ( selectionModel )
469 return selectionModel->selectedIndexes().size();
476 QgsDataItemGuiContext context;
479 context.
setView( mBrowserView );
483void QgsBrowserWidget::selectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected )
486 Q_UNUSED( deselected )
487 if ( mActionPropertiesWidget->isChecked() )
489 setPropertiesWidget();
493void QgsBrowserWidget::clearPropertiesWidget()
495 while ( mPropertiesLayout->count() > 0 )
497 delete mPropertiesLayout->itemAt( 0 )->widget();
499 mPropertiesWidget->setVisible(
false );
502void QgsBrowserWidget::setPropertiesWidget()
504 clearPropertiesWidget();
505 QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
506 if ( selectionModel )
508 QModelIndexList indexes = selectionModel->selectedIndexes();
509 if ( indexes.size() == 1 )
511 QModelIndex index = mProxyModel->mapToSource( indexes.value( 0 ) );
512 QgsDataItem *item = mModel->dataItem( index );
513 QgsDataItemGuiContext context = createContext();
514 QgsBrowserPropertiesWidget *propertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, mPropertiesWidget );
515 if ( propertiesWidget )
517 propertiesWidget->setCondensedMode(
true );
518 mPropertiesLayout->addWidget( propertiesWidget );
522 mPropertiesWidget->setVisible( mPropertiesLayout->count() > 0 );
525void QgsBrowserWidget::enablePropertiesWidget(
bool enable )
527 mActionPropertiesWidget->setChecked( enable );
528 propertiesWidgetToggled( enable );
531void QgsBrowserWidget::propertiesWidgetToggled(
bool enabled )
533 if ( enabled && selectedItemsCount() == 1 )
535 setPropertiesWidget();
539 clearPropertiesWidget();
542 QgsSettings settings;
543 settings.
setValue( settingsSection() +
"/propertiesWidgetEnabled", enabled );
548 if ( index.isValid() )
550 QModelIndex proxyIndex = mProxyModel->mapFromSource( index );
551 mBrowserView->expand( proxyIndex );
552 mBrowserView->setCurrentIndex( proxyIndex );
556void QgsBrowserWidget::splitterMoved()
559 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)