QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsbrowserdockwidget_p.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsbrowserdockwidget_p.cpp
3
4 Private classes for QgsBrowserDockWidget
5
6 ---------------------
7 begin : May 2017
8 copyright : (C) 2017 by Alessandro Pasotti
9 real work done by : (C) 2011 by Martin Dobias
10 email : a dot pasotti at itopen dot it
11 ---------------------
12 ***************************************************************************
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 ***************************************************************************/
21
22#include <memory>
23
24#include "qgsapplication.h"
27#include "qgsbrowsermodel.h"
28#include "qgsbrowsertreeview.h"
31#include "qgsdirectoryitem.h"
32#include "qgsgui.h"
33#include "qgslayeritem.h"
34#include "qgslogger.h"
35#include "qgsmaptoolpan.h"
36#include "qgsmeshlayer.h"
37#include "qgsnative.h"
38#include "qgspointcloudlayer.h"
39#include "qgsproject.h"
40#include "qgsrasterlayer.h"
41#include "qgstiledscenelayer.h"
42#include "qgsvectorlayer.h"
43#include "qgsvectorlayercache.h"
44#include "qgsvectortilelayer.h"
45
46#include <QAbstractTextDocumentLayout>
47#include <QDesktopServices>
48#include <QDragEnterEvent>
49#include <QFileDialog>
50#include <QHeaderView>
51#include <QMenu>
52#include <QPlainTextDocumentLayout>
53#include <QSortFilterProxyModel>
54#include <QToolButton>
55#include <QTreeView>
56
57#include "moc_qgsbrowserdockwidget_p.cpp"
58
60
61
62QgsBrowserPropertiesWrapLabel::QgsBrowserPropertiesWrapLabel( const QString &text, QWidget *parent )
63 : QTextEdit( text, parent )
64{
65 setReadOnly( true );
66 setFrameStyle( QFrame::NoFrame );
67 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
68 QPalette pal = palette();
69 pal.setColor( QPalette::Base, Qt::transparent );
70 setPalette( pal );
71 setLineWrapMode( QTextEdit::WidgetWidth );
72 setWordWrapMode( QTextOption::WrapAnywhere );
73 connect( document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged, this, &QgsBrowserPropertiesWrapLabel::adjustHeight );
74 setMaximumHeight( 20 );
75}
76
77void QgsBrowserPropertiesWrapLabel::adjustHeight( QSizeF size )
78{
79 const int height = static_cast<int>( size.height() ) + 2 * frameWidth();
80 setMinimumHeight( height );
81 setMaximumHeight( height );
82}
83
84QgsBrowserPropertiesWidget::QgsBrowserPropertiesWidget( QWidget *parent )
85 : QWidget( parent )
86{
87}
88
89void QgsBrowserPropertiesWidget::setWidget( QWidget *paramWidget )
90{
91 QVBoxLayout *layout = new QVBoxLayout( this );
92 layout->setContentsMargins( 0, 0, 0, 0 );
93 paramWidget->setParent( this );
94 layout->addWidget( paramWidget );
95}
96
97QgsBrowserPropertiesWidget *QgsBrowserPropertiesWidget::createWidget( QgsDataItem *item, const QgsDataItemGuiContext &context, QWidget *parent )
98{
99 QgsBrowserPropertiesWidget *propertiesWidget = nullptr;
100 // In general, we would like to show all items' paramWidget, but top level items like
101 // WMS etc. have currently too large widgets which do not fit well to browser properties widget
102 if ( item->type() == Qgis::BrowserItemType::Directory )
103 {
104 propertiesWidget = new QgsBrowserDirectoryProperties( parent );
105 propertiesWidget->setItem( item );
106 }
107 else if ( item->type() == Qgis::BrowserItemType::Layer
110 || item->type() == Qgis::BrowserItemType::Field )
111 {
112 // try new infrastructure of creation of layer widgets
113 QWidget *paramWidget = nullptr;
114 const QList<QgsDataItemGuiProvider *> providers = QgsGui::dataItemGuiProviderRegistry()->providers();
115 for ( QgsDataItemGuiProvider *provider : providers )
116 {
117 paramWidget = provider->createParamWidget( item, context );
118 if ( paramWidget )
119 break;
120 }
121 if ( !paramWidget )
122 {
123 // try old infrastructure
125 paramWidget = item->paramWidget();
127 }
128
129 // prefer item's widget over standard layer widget
130 if ( paramWidget )
131 {
132 propertiesWidget = new QgsBrowserPropertiesWidget( parent );
133 propertiesWidget->setWidget( paramWidget );
134 }
135 else if ( item->type() == Qgis::BrowserItemType::Layer )
136 {
137 propertiesWidget = new QgsBrowserLayerProperties( parent );
138 propertiesWidget->setItem( item );
139 }
140 }
141 return propertiesWidget;
142}
143
144QgsBrowserLayerProperties::QgsBrowserLayerProperties( QWidget *parent )
145 : QgsBrowserPropertiesWidget( parent )
146{
147 setupUi( this );
148
149 // we don't want links to open in the little widget, open them externally instead
150 mMetadataTextBrowser->setOpenLinks( false );
151 connect( mMetadataTextBrowser, &QTextBrowser::anchorClicked, this, &QgsBrowserLayerProperties::urlClicked );
152
153 mMapCanvas->setProperty( "browser_canvas", true );
154 mMapCanvas->setLayers( QList<QgsMapLayer *>() );
155 mMapCanvas->setMapTool( new QgsMapToolPan( mMapCanvas ) );
156 mMapCanvas->freeze( true );
157
158 connect( mTabWidget, &QTabWidget::currentChanged, this, [this] {
159 if ( mTabWidget->currentWidget() == mPreviewTab && mMapCanvas->isFrozen() )
160 {
161 mMapCanvas->freeze( false );
162 mMapCanvas->refresh();
163 }
164 else if ( mTabWidget->currentWidget() == mAttributesTab )
165 {
166 if ( !mAttributeTableFilterModel )
167 loadAttributeTable();
168 }
169 } );
170}
171
172void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
173{
174 QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
175 if ( !layerItem )
176 return;
177
178 mNoticeLabel->clear();
179
180 const Qgis::LayerType type = layerItem->mapLayerType();
181 QString layerMetadata = tr( "Error" );
182
183 mLayer.reset();
184
185 // find root item
186 // we need to create a temporary layer to get metadata
187 // we could use a provider but the metadata is not as complete and "pretty" and this is easier
188 QgsDebugMsgLevel( QStringLiteral( "creating temporary layer using path %1" ).arg( layerItem->path() ), 2 );
189 switch ( type )
190 {
192 {
193 QgsDebugMsgLevel( QStringLiteral( "creating raster layer" ), 2 );
194 // should copy code from addLayer() to split uri ?
196 options.skipCrsValidation = true;
197 mLayer = std::make_unique<QgsRasterLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
198 break;
199 }
200
202 {
203 QgsDebugMsgLevel( QStringLiteral( "creating mesh layer" ), 2 );
205 options.skipCrsValidation = true;
206 mLayer = std::make_unique<QgsMeshLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
207 break;
208 }
209
211 {
212 QgsDebugMsgLevel( QStringLiteral( "creating vector layer" ), 2 );
214 options.skipCrsValidation = true;
215 mLayer = std::make_unique<QgsVectorLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
216 break;
217 }
218
220 {
221 QgsDebugMsgLevel( QStringLiteral( "creating vector tile layer" ), 2 );
222 mLayer = std::make_unique<QgsVectorTileLayer>( layerItem->uri(), layerItem->name() );
223 break;
224 }
225
227 {
228 QgsDebugMsgLevel( QStringLiteral( "creating point cloud layer" ), 2 );
230 options.skipCrsValidation = true;
231 mLayer = std::make_unique<QgsPointCloudLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
232 break;
233 }
234
236 {
237 QgsDebugMsgLevel( QStringLiteral( "creating tiled scene layer" ), 2 );
239 options.skipCrsValidation = true;
240 mLayer = std::make_unique<QgsTiledSceneLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
241 break;
242 }
243
247 {
248 // TODO: support display of properties for plugin layers
249 return;
250 }
251 }
252
253 mAttributeTable->setModel( nullptr );
254 if ( mAttributeTableFilterModel )
255 {
256 // Cleanup
257 mAttributeTableFilterModel->deleteLater();
258 mAttributeTableFilterModel = nullptr;
259 }
260 if ( mLayer && mLayer->isValid() )
261 {
262 bool ok = false;
263 mLayer->loadDefaultMetadata( ok );
264 layerMetadata = mLayer->htmlMetadata();
265
266 mMapCanvas->setDestinationCrs( mLayer->crs() );
267 mMapCanvas->setLayers( QList<QgsMapLayer *>() << mLayer.get() );
268 mMapCanvas->zoomToFullExtent();
269
270 if ( mAttributesTab && mLayer->type() != Qgis::LayerType::Vector )
271 {
272 mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
273 mAttributesTab = nullptr;
274 }
275
276 // Remove Preview Tab if layer has no geometry
277 if ( QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer.get() ) )
278 {
279 if ( vLayer->geometryType() == Qgis::GeometryType::Null )
280 {
281 mTabWidget->removeTab( mTabWidget->indexOf( mPreviewTab ) );
282 mPreviewTab = nullptr;
283 }
284 }
285 }
286
287 const QString myStyle = QgsApplication::reportStyleSheet();
288 mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
289 mMetadataTextBrowser->setHtml( layerMetadata );
290
291 if ( mNoticeLabel->text().isEmpty() )
292 {
293 mNoticeLabel->hide();
294 }
295}
296
297void QgsBrowserLayerProperties::setCondensedMode( bool )
298{
299}
300
301void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
302{
303 if ( !url.fragment().isEmpty() && url.toString().startsWith( QLatin1Char( '#' ) ) )
304 {
305 mMetadataTextBrowser->scrollToAnchor( url.fragment() );
306 return;
307 }
308 const QFileInfo file( url.toLocalFile() );
309 if ( file.exists() && !file.isDir() )
310 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
311 else
312 QDesktopServices::openUrl( url );
313}
314
315void QgsBrowserLayerProperties::loadAttributeTable()
316{
317 if ( !mLayer || !mLayer->isValid() || mLayer->type() != Qgis::LayerType::Vector )
318 return;
319
320 // Initialize the cache
321 QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast<QgsVectorLayer *>( mLayer.get() ), 1000, this );
322 layerCache->setCacheGeometry( false );
323 QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
324 mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
325 tableModel->setRequest( QgsFeatureRequest().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setLimit( 100 ) );
326 layerCache->setParent( tableModel );
327 tableModel->setParent( mAttributeTableFilterModel );
328
329 mAttributeTable->setModel( mAttributeTableFilterModel );
330 tableModel->loadLayer();
331 QFont font = mAttributeTable->font();
332 int fontSize = font.pointSize();
333#ifdef Q_OS_WIN
334 fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
335#else
336 fontSize = std::max( fontSize - 2, 6 );
337#endif
338 font.setPointSize( fontSize );
339 mAttributeTable->setFont( font );
340
341 // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
342 mAttributeTable->resizeColumnsToContents();
343 mAttributeTable->resizeRowsToContents();
344 mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
345 mAttributeTable->setAlternatingRowColors( true );
346}
347
348QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
349 : QgsBrowserPropertiesWidget( parent )
350
351{
352 setupUi( this );
353
354 mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
355 mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
356}
357
358void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
359{
360 QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
361 if ( !item )
362 return;
363
364 mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
365 mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
366 mLayout->addWidget( mDirectoryWidget );
367}
368
369QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
370 : QDialog( parent )
371 , mSettingsSection( settingsSection )
372{
373 setupUi( this );
375}
376
377void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
378{
379 if ( !item )
380 return;
381
382 mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
383 mLayout->addWidget( mPropertiesWidget );
384 setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
385}
386
387
388//
389// QgsDockBrowserTreeView
390//
391
392QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent )
393 : QgsBrowserTreeView( parent )
394{
395 setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
396 setSelectionMode( QAbstractItemView::ExtendedSelection );
397 setContextMenuPolicy( Qt::CustomContextMenu );
398 setHeaderHidden( true );
399 setDropIndicatorShown( true );
400}
401
402void QgsDockBrowserTreeView::setAction( QDropEvent *e )
403{
404 // if this mime data come from layer tree, the proposed action will be MoveAction
405 // but for browser we really need CopyAction
406 if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) && e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
407 {
408 e->setDropAction( Qt::CopyAction );
409 }
410}
411
412void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
413{
414 setAction( e );
415
416 // accept drag enter so that our widget will not get ignored
417 // and drag events will not get passed to QgisApp
418 e->accept();
419}
420
421void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
422{
423 // do not accept drops above/below items
424 /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
425 {
426 QgsDebugMsgLevel("drag not on item", 2);
427 e->ignore();
428 return;
429 }*/
430
431 setAction( e );
432 QTreeView::dragMoveEvent( e );
433 // reset action because QTreeView::dragMoveEvent() accepts proposed action
434 setAction( e );
435
436 if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
437 {
438 e->ignore();
439 return;
440 }
441}
442
443void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
444{
445 setAction( e );
446 QTreeView::dropEvent( e );
447 // reset action because QTreeView::dropEvent() accepts proposed action
448 setAction( e );
449}
450
451
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2196
@ Layer
Represents a map layer.
Definition qgis.h:922
@ Field
Vector layer field.
Definition qgis.h:928
@ Custom
Custom item type.
Definition qgis.h:926
@ Fields
Collection of fields.
Definition qgis.h:927
@ Directory
Represents a file directory.
Definition qgis.h:921
@ Null
No geometry.
Definition qgis.h:363
LayerType
Types of layers that can be added to a map.
Definition qgis.h:190
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:198
@ Plugin
Plugin based layer.
Definition qgis.h:193
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:199
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:196
@ Vector
Vector layer.
Definition qgis.h:191
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:195
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:194
@ Raster
Raster layer.
Definition qgis.h:192
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:197
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
A proxy model for filtering an attribute table model.
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
Extends QTreeView with save/restore tree state and other browser-specific functionality.
Encapsulates the context in which a QgsDataItem is shown within the application GUI.
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.
Definition qgsdataitem.h:47
Qgis::BrowserItemType type() const
QString name() const
Returns the name of the item (the displayed text for the item).
QString path() const
virtual Q_DECL_DEPRECATED QWidget * paramWidget()
Returns source widget from data item for QgsBrowserPropertiesWidget.
QString providerKey() const
Returns the provider key that created this item (e.g.
A browser item for directories: contains subdirectories and layers.
QString dirPath() const
Returns the full path to the directory the item represents.
Browser parameter widget implementation for directory items.
Wraps a request for features to a vector layer (or directly its vector data provider).
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:221
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition qgsgui.cpp:96
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition qgsgui.cpp:191
A browser item that represents a layer that can be opened with one of the providers.
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Qgis::LayerType mapLayerType() const
Returns the associated map layer type.
A map tool for panning the map.
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:116
Caches features for a given QgsVectorLayer.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
Represents a vector layer which manages a vector based dataset.
#define Q_NOWARN_DEPRECATED_POP
Definition qgis.h:7170
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7169
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
Setting options for loading mesh layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Setting options for loading point cloud layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Setting options for loading raster layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Setting options for loading tiled scene layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Setting options for loading vector layers.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.