36#include <QAbstractTextDocumentLayout>
37#include <QActionGroup>
41#include <QPlainTextDocumentLayout>
42#include <QSortFilterProxyModel>
46#include "moc_qgsbrowserwidget.cpp"
52#include <QDragEnterEvent>
57 , mModel( browserModel )
61 layout()->setContentsMargins( 0, 0, 0, 0 );
62 qgis::down_cast<QVBoxLayout *>( layout() )->setSpacing( 0 );
64 mBrowserView =
new QgsDockBrowserTreeView(
this );
65 mLayoutBrowser->addWidget( mBrowserView );
67 mWidgetFilter->hide();
68 mLeFilter->setPlaceholderText( tr(
"Type here to filter visible items…" ) );
71 QMenu *menu =
new QMenu(
this );
72 menu->setSeparatorsCollapsible(
false );
73 mBtnFilterOptions->setMenu( menu );
74 QAction *action =
new QAction( tr(
"Case Sensitive" ), menu );
75 action->setData(
"case" );
76 action->setCheckable(
true );
77 action->setChecked(
false );
78 connect( action, &QAction::toggled,
this, &QgsBrowserWidget::setCaseSensitive );
79 menu->addAction( action );
80 QActionGroup *group =
new QActionGroup( menu );
81 action =
new QAction( tr(
"Filter Pattern Syntax" ), group );
82 action->setSeparator(
true );
83 menu->addAction( action );
84 action =
new QAction( tr(
"Normal" ), group );
86 action->setCheckable(
true );
87 action->setChecked(
true );
88 menu->addAction( action );
89 action =
new QAction( tr(
"Wildcard(s)" ), group );
91 action->setCheckable(
true );
92 menu->addAction( action );
93 action =
new QAction( tr(
"Regular Expression" ), group );
95 action->setCheckable(
true );
96 menu->addAction( action );
98 mBrowserView->setExpandsOnDoubleClick(
false );
101 connect( mActionAddLayers, &QAction::triggered,
this, &QgsBrowserWidget::addSelectedLayers );
102 connect( mActionCollapse, &QAction::triggered, mBrowserView, &QgsDockBrowserTreeView::collapseAll );
103 connect( mActionShowFilter, &QAction::triggered,
this, &QgsBrowserWidget::showFilterWidget );
104 connect( mActionPropertiesWidget, &QAction::triggered,
this, &QgsBrowserWidget::propertiesWidgetToggled );
105 connect( mLeFilter, &QgsFilterLineEdit::returnPressed,
this, &QgsBrowserWidget::setFilter );
107 connect( mLeFilter, &QgsFilterLineEdit::textChanged,
this, &QgsBrowserWidget::setFilter );
108 connect( group, &QActionGroup::triggered,
this, &QgsBrowserWidget::setFilterSyntax );
109 connect( mBrowserView, &QgsDockBrowserTreeView::customContextMenuRequested,
this, &QgsBrowserWidget::showContextMenu );
110 connect( mBrowserView, &QgsDockBrowserTreeView::doubleClicked,
this, &QgsBrowserWidget::itemDoubleClicked );
111 connect( mSplitter, &QSplitter::splitterMoved,
this, &QgsBrowserWidget::splitterMoved );
121 if ( !mModel->initialized() )
123 mModel->initialize();
128 mProxyModel->setBrowserModel( mModel );
129 mProxyModel->setHiddenDataItemProviderKeyFilter( mDisabledDataItemsKeys );
130 mBrowserView->setSettingsSection( objectName().toLower() );
131 mBrowserView->setBrowserModel( mModel );
132 mBrowserView->setModel( mProxyModel );
133 mBrowserView->setSortingEnabled(
true );
134 mBrowserView->sortByColumn( 0, Qt::AscendingOrder );
136 mBrowserView->setTextElideMode( Qt::ElideNone );
137 mBrowserView->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
138 mBrowserView->header()->setStretchLastSection(
false );
141 connect( mBrowserView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &QgsBrowserWidget::selectionChanged );
148 mActionPropertiesWidget->setChecked( settings.
value( settingsSection() +
"/propertiesWidgetEnabled",
false ).toBool() );
149 mPropertiesWidget->setVisible(
false );
151 mSplitter->restoreState( settings.
value( QStringLiteral(
"%1/splitterState" ).arg( settingsSection() ) ).toByteArray() );
154 QWidget::showEvent( e );
157void QgsBrowserWidget::itemDoubleClicked(
const QModelIndex &index )
168 if ( provider->handleDoubleClick( item, context ) )
176 if ( mBrowserView->isExpanded( index ) )
177 mBrowserView->collapse( index );
179 mBrowserView->expand( index );
183void QgsBrowserWidget::onOptionsChanged()
185 std::function<void(
const QModelIndex &index )> updateItem;
186 updateItem = [
this, &updateItem](
const QModelIndex &index ) {
187 if ( QgsDirectoryItem *dirItem = qobject_cast<QgsDirectoryItem *>( mModel->dataItem( index ) ) )
189 dirItem->reevaluateMonitoring();
192 const int rowCount = mModel->rowCount( index );
193 for (
int i = 0; i < rowCount; ++i )
195 const QModelIndex child = mModel->index( i, 0, index );
200 for (
int i = 0; i < mModel->rowCount(); ++i )
202 updateItem( mModel->index( i, 0 ) );
206void QgsBrowserWidget::showContextMenu( QPoint pt )
208 QModelIndex index = mProxyModel->mapToSource( mBrowserView->indexAt( pt ) );
209 QgsDataItem *item = mModel->dataItem( index );
213 const QModelIndexList selection = mBrowserView->selectionModel()->selectedIndexes();
214 QList<QgsDataItem *> selectedItems;
215 selectedItems.reserve( selection.size() );
216 for (
const QModelIndex &selectedIndex : selection )
218 QgsDataItem *selectedItem = mProxyModel->dataItem( selectedIndex );
220 selectedItems << selectedItem;
223 QMenu *menu =
new QMenu(
this );
225 const QList<QMenu *> menus = item->
menus( menu );
226 QList<QAction *> actions = item->
actions( menu );
228 if ( !menus.isEmpty() )
230 for ( QMenu *mn : menus )
236 if ( !actions.isEmpty() )
238 if ( !menu->actions().isEmpty() )
239 menu->addSeparator();
241 menu->addActions( actions );
244 QgsDataItemGuiContext context = createContext();
247 std::sort( providers.begin(), providers.end(), []( QgsDataItemGuiProvider *a, QgsDataItemGuiProvider *b ) {
248 return a->precedenceWhenPopulatingMenus() < b->precedenceWhenPopulatingMenus();
250 for ( QgsDataItemGuiProvider *provider : std::as_const( providers ) )
252 provider->populateContextMenu( item, menu, selectedItems, context );
255 if ( menu->actions().isEmpty() )
261 menu->popup( mBrowserView->mapToGlobal( pt ) );
267 mModel->setMessageBar( bar );
278 mModel->setMapCanvas( canvas );
288 mDisabledDataItemsKeys = filter;
293 mProxyModel->setHiddenDataItemProviderKeyFilter( mDisabledDataItemsKeys );
298 refreshModel( QModelIndex() );
301void QgsBrowserWidget::refreshModel(
const QModelIndex &index )
303 if ( mModel && mProxyModel )
317 mModel->refresh( index );
320 for (
int i = 0; i < mModel->rowCount( index ); i++ )
322 QModelIndex idx = mModel->index( i, 0, index );
323 QModelIndex proxyIdx = mProxyModel->mapFromSource( idx );
324 QgsDataItem *child = mModel->dataItem( idx );
343void QgsBrowserWidget::addLayer(
QgsLayerItem *layerItem )
351void QgsBrowserWidget::addSelectedLayers()
353 QApplication::setOverrideCursor( Qt::WaitCursor );
356 QModelIndexList list = mBrowserView->selectionModel()->selectedIndexes();
357 std::sort( list.begin(), list.end() );
360 const auto constList = list;
361 for (
const QModelIndex &index : constList )
363 QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( index ) );
366 QgsProjectItem *projectItem = qobject_cast<QgsProjectItem *>( item );
368 emit
openFile( projectItem->
path(), QStringLiteral(
"project" ) );
370 QApplication::restoreOverrideCursor();
376 for (
int i = list.size() - 1; i >= 0; i-- )
378 QgsDataItem *item = mModel->dataItem( mProxyModel->mapToSource( list[i] ) );
381 QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
383 addLayer( layerItem );
387 QApplication::restoreOverrideCursor();
390void QgsBrowserWidget::hideItem()
392 QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
393 QgsDataItem *item = mModel->dataItem( index );
399 mModel->hidePath( item );
403void QgsBrowserWidget::showProperties()
405 QModelIndex index = mProxyModel->mapToSource( mBrowserView->currentIndex() );
406 QgsDataItem *item = mModel->dataItem( index );
412 QgsBrowserPropertiesDialog *dialog =
new QgsBrowserPropertiesDialog( settingsSection(),
this );
413 dialog->setAttribute( Qt::WA_DeleteOnClose );
414 dialog->setItem( item, createContext() );
419void QgsBrowserWidget::showFilterWidget(
bool visible )
421 mWidgetFilter->setVisible( visible );
424 mLeFilter->setText( QString() );
429 mLeFilter->setFocus();
433void QgsBrowserWidget::setFilter()
435 QString filter = mLeFilter->text();
437 mProxyModel->setFilterString( filter );
443 mModel->updateProjectHome();
446void QgsBrowserWidget::setFilterSyntax( QAction *action )
448 if ( !action || !mProxyModel )
454void QgsBrowserWidget::setCaseSensitive(
bool caseSensitive )
458 mProxyModel->setFilterCaseSensitivity( caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
461int QgsBrowserWidget::selectedItemsCount()
463 QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
464 if ( selectionModel )
466 return selectionModel->selectedIndexes().size();
473 QgsDataItemGuiContext context;
476 context.
setView( mBrowserView );
480void QgsBrowserWidget::selectionChanged(
const QItemSelection &selected,
const QItemSelection &deselected )
483 Q_UNUSED( deselected )
484 if ( mActionPropertiesWidget->isChecked() )
486 setPropertiesWidget();
490void QgsBrowserWidget::clearPropertiesWidget()
492 while ( mPropertiesLayout->count() > 0 )
494 delete mPropertiesLayout->itemAt( 0 )->widget();
496 mPropertiesWidget->setVisible(
false );
499void QgsBrowserWidget::setPropertiesWidget()
501 clearPropertiesWidget();
502 QItemSelectionModel *selectionModel = mBrowserView->selectionModel();
503 if ( selectionModel )
505 QModelIndexList indexes = selectionModel->selectedIndexes();
506 if ( indexes.size() == 1 )
508 QModelIndex index = mProxyModel->mapToSource( indexes.value( 0 ) );
509 QgsDataItem *item = mModel->dataItem( index );
510 QgsDataItemGuiContext context = createContext();
511 QgsBrowserPropertiesWidget *propertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, mPropertiesWidget );
512 if ( propertiesWidget )
514 propertiesWidget->setCondensedMode(
true );
515 mPropertiesLayout->addWidget( propertiesWidget );
519 mPropertiesWidget->setVisible( mPropertiesLayout->count() > 0 );
522void QgsBrowserWidget::enablePropertiesWidget(
bool enable )
524 mActionPropertiesWidget->setChecked( enable );
525 propertiesWidgetToggled( enable );
528void QgsBrowserWidget::propertiesWidgetToggled(
bool enabled )
530 if ( enabled && selectedItemsCount() == 1 )
532 setPropertiesWidget();
536 clearPropertiesWidget();
539 QgsSettings settings;
540 settings.
setValue( settingsSection() +
"/propertiesWidgetEnabled", enabled );
545 if ( index.isValid() )
547 QModelIndex proxyIndex = mProxyModel->mapFromSource( index );
548 mBrowserView->expand( proxyIndex );
549 mBrowserView->setCurrentIndex( proxyIndex );
553void QgsBrowserWidget::splitterMoved()
556 settings.
setValue( QStringLiteral(
"%1/splitterState" ).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)