QGIS API Documentation 3.99.0-Master (d270888f95f)
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 <QString>
55#include <QToolButton>
56#include <QTreeView>
57
58#include "moc_qgsbrowserdockwidget_p.cpp"
59
60using namespace Qt::StringLiterals;
61
63
64
65QgsBrowserPropertiesWrapLabel::QgsBrowserPropertiesWrapLabel( const QString &text, QWidget *parent )
66 : QTextEdit( text, parent )
67{
68 setReadOnly( true );
69 setFrameStyle( QFrame::NoFrame );
70 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
71 QPalette pal = palette();
72 pal.setColor( QPalette::Base, Qt::transparent );
73 setPalette( pal );
74 setLineWrapMode( QTextEdit::WidgetWidth );
75 setWordWrapMode( QTextOption::WrapAnywhere );
76 connect( document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged, this, &QgsBrowserPropertiesWrapLabel::adjustHeight );
77 setMaximumHeight( 20 );
78}
79
80void QgsBrowserPropertiesWrapLabel::adjustHeight( QSizeF size )
81{
82 const int height = static_cast<int>( size.height() ) + 2 * frameWidth();
83 setMinimumHeight( height );
84 setMaximumHeight( height );
85}
86
87QgsBrowserPropertiesWidget::QgsBrowserPropertiesWidget( QWidget *parent )
88 : QWidget( parent )
89{
90}
91
92void QgsBrowserPropertiesWidget::setWidget( QWidget *paramWidget )
93{
94 QVBoxLayout *layout = new QVBoxLayout( this );
95 layout->setContentsMargins( 0, 0, 0, 0 );
96 paramWidget->setParent( this );
97 layout->addWidget( paramWidget );
98}
99
100QgsBrowserPropertiesWidget *QgsBrowserPropertiesWidget::createWidget( QgsDataItem *item, const QgsDataItemGuiContext &context, QWidget *parent )
101{
102 QgsBrowserPropertiesWidget *propertiesWidget = nullptr;
103 // In general, we would like to show all items' paramWidget, but top level items like
104 // WMS etc. have currently too large widgets which do not fit well to browser properties widget
105 if ( item->type() == Qgis::BrowserItemType::Directory )
106 {
107 propertiesWidget = new QgsBrowserDirectoryProperties( parent );
108 propertiesWidget->setItem( item );
109 }
110 else if ( item->type() == Qgis::BrowserItemType::Layer
113 || item->type() == Qgis::BrowserItemType::Field )
114 {
115 // try new infrastructure of creation of layer widgets
116 QWidget *paramWidget = nullptr;
117 const QList<QgsDataItemGuiProvider *> providers = QgsGui::dataItemGuiProviderRegistry()->providers();
118 for ( QgsDataItemGuiProvider *provider : providers )
119 {
120 paramWidget = provider->createParamWidget( item, context );
121 if ( paramWidget )
122 break;
123 }
124 if ( !paramWidget )
125 {
126 // try old infrastructure
128 paramWidget = item->paramWidget();
130 }
131
132 // prefer item's widget over standard layer widget
133 if ( paramWidget )
134 {
135 propertiesWidget = new QgsBrowserPropertiesWidget( parent );
136 propertiesWidget->setWidget( paramWidget );
137 }
138 else if ( item->type() == Qgis::BrowserItemType::Layer )
139 {
140 propertiesWidget = new QgsBrowserLayerProperties( parent );
141 propertiesWidget->setItem( item );
142 }
143 }
144 return propertiesWidget;
145}
146
147QgsBrowserLayerProperties::QgsBrowserLayerProperties( QWidget *parent )
148 : QgsBrowserPropertiesWidget( parent )
149{
150 setupUi( this );
151
152 // we don't want links to open in the little widget, open them externally instead
153 mMetadataTextBrowser->setOpenLinks( false );
154 connect( mMetadataTextBrowser, &QTextBrowser::anchorClicked, this, &QgsBrowserLayerProperties::urlClicked );
155
156 mMapCanvas->setProperty( "browser_canvas", true );
157 mMapCanvas->setLayers( QList<QgsMapLayer *>() );
158 mMapCanvas->setMapTool( new QgsMapToolPan( mMapCanvas ) );
159 mMapCanvas->freeze( true );
160
161 connect( mTabWidget, &QTabWidget::currentChanged, this, [this] {
162 if ( mTabWidget->currentWidget() == mPreviewTab && mMapCanvas->isFrozen() )
163 {
164 mMapCanvas->freeze( false );
165 mMapCanvas->refresh();
166 }
167 else if ( mTabWidget->currentWidget() == mAttributesTab )
168 {
169 if ( !mAttributeTableFilterModel )
170 loadAttributeTable();
171 }
172 } );
173}
174
175void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
176{
177 QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
178 if ( !layerItem )
179 return;
180
181 mNoticeLabel->clear();
182
183 const Qgis::LayerType type = layerItem->mapLayerType();
184 QString layerMetadata = tr( "Error" );
185
186 mLayer.reset();
187
188 // find root item
189 // we need to create a temporary layer to get metadata
190 // we could use a provider but the metadata is not as complete and "pretty" and this is easier
191 QgsDebugMsgLevel( u"creating temporary layer using path %1"_s.arg( layerItem->path() ), 2 );
192 switch ( type )
193 {
195 {
196 QgsDebugMsgLevel( u"creating raster layer"_s, 2 );
197 // should copy code from addLayer() to split uri ?
199 options.skipCrsValidation = true;
200 mLayer = std::make_unique<QgsRasterLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
201 break;
202 }
203
205 {
206 QgsDebugMsgLevel( u"creating mesh layer"_s, 2 );
208 options.skipCrsValidation = true;
209 mLayer = std::make_unique<QgsMeshLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
210 break;
211 }
212
214 {
215 QgsDebugMsgLevel( u"creating vector layer"_s, 2 );
217 options.skipCrsValidation = true;
218 mLayer = std::make_unique<QgsVectorLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
219 break;
220 }
221
223 {
224 QgsDebugMsgLevel( u"creating vector tile layer"_s, 2 );
225 mLayer = std::make_unique<QgsVectorTileLayer>( layerItem->uri(), layerItem->name() );
226 break;
227 }
228
230 {
231 QgsDebugMsgLevel( u"creating point cloud layer"_s, 2 );
233 options.skipCrsValidation = true;
234 mLayer = std::make_unique<QgsPointCloudLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
235 break;
236 }
237
239 {
240 QgsDebugMsgLevel( u"creating tiled scene layer"_s, 2 );
242 options.skipCrsValidation = true;
243 mLayer = std::make_unique<QgsTiledSceneLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
244 break;
245 }
246
250 {
251 // TODO: support display of properties for plugin layers
252 return;
253 }
254 }
255
256 mAttributeTable->setModel( nullptr );
257 if ( mAttributeTableFilterModel )
258 {
259 // Cleanup
260 mAttributeTableFilterModel->deleteLater();
261 mAttributeTableFilterModel = nullptr;
262 }
263 if ( mLayer && mLayer->isValid() )
264 {
265 bool ok = false;
266 mLayer->loadDefaultMetadata( ok );
267 layerMetadata = mLayer->htmlMetadata();
268
269 mMapCanvas->setDestinationCrs( mLayer->crs() );
270 mMapCanvas->setLayers( QList<QgsMapLayer *>() << mLayer.get() );
271 mMapCanvas->zoomToFullExtent();
272
273 if ( mAttributesTab && mLayer->type() != Qgis::LayerType::Vector )
274 {
275 mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
276 mAttributesTab = nullptr;
277 }
278
279 // Remove Preview Tab if layer has no geometry
280 if ( QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( mLayer.get() ) )
281 {
282 if ( vLayer->geometryType() == Qgis::GeometryType::Null )
283 {
284 mTabWidget->removeTab( mTabWidget->indexOf( mPreviewTab ) );
285 mPreviewTab = nullptr;
286 }
287 }
288 }
289
290 const QString myStyle = QgsApplication::reportStyleSheet();
291 mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
292 mMetadataTextBrowser->setHtml( layerMetadata );
293
294 if ( mNoticeLabel->text().isEmpty() )
295 {
296 mNoticeLabel->hide();
297 }
298}
299
300void QgsBrowserLayerProperties::setCondensedMode( bool )
301{
302}
303
304void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
305{
306 if ( !url.fragment().isEmpty() && url.toString().startsWith( '#'_L1 ) )
307 {
308 mMetadataTextBrowser->scrollToAnchor( url.fragment() );
309 return;
310 }
311 const QFileInfo file( url.toLocalFile() );
312 if ( file.exists() && !file.isDir() )
313 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
314 else
315 QDesktopServices::openUrl( url );
316}
317
318void QgsBrowserLayerProperties::loadAttributeTable()
319{
320 if ( !mLayer || !mLayer->isValid() || mLayer->type() != Qgis::LayerType::Vector )
321 return;
322
323 // Initialize the cache
324 QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast<QgsVectorLayer *>( mLayer.get() ), 1000, this );
325 layerCache->setCacheGeometry( false );
326 QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
327 mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
328 tableModel->setRequest( QgsFeatureRequest().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setLimit( 100 ) );
329 layerCache->setParent( tableModel );
330 tableModel->setParent( mAttributeTableFilterModel );
331
332 mAttributeTable->setModel( mAttributeTableFilterModel );
333 tableModel->loadLayer();
334 QFont font = mAttributeTable->font();
335 int fontSize = font.pointSize();
336#ifdef Q_OS_WIN
337 fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
338#else
339 fontSize = std::max( fontSize - 2, 6 );
340#endif
341 font.setPointSize( fontSize );
342 mAttributeTable->setFont( font );
343
344 // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
345 mAttributeTable->resizeColumnsToContents();
346 mAttributeTable->resizeRowsToContents();
347 mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
348 mAttributeTable->setAlternatingRowColors( true );
349}
350
351QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
352 : QgsBrowserPropertiesWidget( parent )
353
354{
355 setupUi( this );
356
357 mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
358 mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
359}
360
361void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
362{
363 QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
364 if ( !item )
365 return;
366
367 mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
368 mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
369 mLayout->addWidget( mDirectoryWidget );
370}
371
372QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
373 : QDialog( parent )
374 , mSettingsSection( settingsSection )
375{
376 setupUi( this );
378}
379
380void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
381{
382 if ( !item )
383 return;
384
385 mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
386 mLayout->addWidget( mPropertiesWidget );
387 setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
388}
389
390
391//
392// QgsDockBrowserTreeView
393//
394
395QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent )
396 : QgsBrowserTreeView( parent )
397{
398 setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
399 setSelectionMode( QAbstractItemView::ExtendedSelection );
400 setContextMenuPolicy( Qt::CustomContextMenu );
401 setHeaderHidden( true );
402 setDropIndicatorShown( true );
403}
404
405void QgsDockBrowserTreeView::setAction( QDropEvent *e )
406{
407 // if this mime data come from layer tree, the proposed action will be MoveAction
408 // but for browser we really need CopyAction
409 if ( e->mimeData()->hasFormat( u"application/qgis.layertreemodeldata"_s ) && e->mimeData()->hasFormat( u"application/x-vnd.qgis.qgis.uri"_s ) )
410 {
411 e->setDropAction( Qt::CopyAction );
412 }
413}
414
415void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
416{
417 setAction( e );
418
419 // accept drag enter so that our widget will not get ignored
420 // and drag events will not get passed to QgisApp
421 e->accept();
422}
423
424void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
425{
426 // do not accept drops above/below items
427 /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
428 {
429 QgsDebugMsgLevel("drag not on item", 2);
430 e->ignore();
431 return;
432 }*/
433
434 setAction( e );
435 QTreeView::dragMoveEvent( e );
436 // reset action because QTreeView::dragMoveEvent() accepts proposed action
437 setAction( e );
438
439 if ( !e->mimeData()->hasFormat( u"application/x-vnd.qgis.qgis.uri"_s ) )
440 {
441 e->ignore();
442 return;
443 }
444}
445
446void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
447{
448 setAction( e );
449 QTreeView::dropEvent( e );
450 // reset action because QTreeView::dropEvent() accepts proposed action
451 setAction( e );
452}
453
454
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2254
@ Layer
Represents a map layer.
Definition qgis.h:941
@ Field
Vector layer field.
Definition qgis.h:947
@ Custom
Custom item type.
Definition qgis.h:945
@ Fields
Collection of fields.
Definition qgis.h:946
@ Directory
Represents a file directory.
Definition qgis.h:940
@ Null
No geometry.
Definition qgis.h:370
LayerType
Types of layers that can be added to a map.
Definition qgis.h:193
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:201
@ Plugin
Plugin based layer.
Definition qgis.h:196
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:202
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:199
@ Vector
Vector layer.
Definition qgis.h:194
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:198
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:197
@ Raster
Raster layer.
Definition qgis.h:195
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:200
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:50
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:224
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition qgsgui.cpp:99
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition qgsgui.cpp:194
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:119
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:7451
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7450
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:63
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.