QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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 <QAbstractTextDocumentLayout>
25#include <QHeaderView>
26#include <QTreeView>
27#include <QMenu>
28#include <QToolButton>
29#include <QFileDialog>
30#include <QPlainTextDocumentLayout>
31#include <QSortFilterProxyModel>
32#include <QDesktopServices>
33#include <QDragEnterEvent>
34
35#include "qgsbrowsermodel.h"
36#include "qgsbrowsertreeview.h"
37#include "qgslogger.h"
38#include "qgsrasterlayer.h"
39#include "qgsvectorlayer.h"
40#include "qgsproject.h"
41#include "qgsmeshlayer.h"
42#include "qgsgui.h"
43#include "qgsnative.h"
44#include "qgsmaptoolpan.h"
45#include "qgsvectorlayercache.h"
46#include "qgsvectortilelayer.h"
49#include "qgsapplication.h"
52#include "qgspointcloudlayer.h"
53#include "qgslayeritem.h"
54#include "qgsdirectoryitem.h"
55#include "qgstiledscenelayer.h"
56
58
59
60QgsBrowserPropertiesWrapLabel::QgsBrowserPropertiesWrapLabel( const QString &text, QWidget *parent )
61 : QTextEdit( text, parent )
62{
63 setReadOnly( true );
64 setFrameStyle( QFrame::NoFrame );
65 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
66 QPalette pal = palette();
67 pal.setColor( QPalette::Base, Qt::transparent );
68 setPalette( pal );
69 setLineWrapMode( QTextEdit::WidgetWidth );
70 setWordWrapMode( QTextOption::WrapAnywhere );
71 connect( document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
72 this, &QgsBrowserPropertiesWrapLabel::adjustHeight );
73 setMaximumHeight( 20 );
74}
75
76void QgsBrowserPropertiesWrapLabel::adjustHeight( QSizeF size )
77{
78 const int height = static_cast<int>( size.height() ) + 2 * frameWidth();
79 setMinimumHeight( height );
80 setMaximumHeight( height );
81}
82
83QgsBrowserPropertiesWidget::QgsBrowserPropertiesWidget( QWidget *parent )
84 : QWidget( parent )
85{
86}
87
88void QgsBrowserPropertiesWidget::setWidget( QWidget *paramWidget )
89{
90 QVBoxLayout *layout = new QVBoxLayout( this );
91 layout->setContentsMargins( 0, 0, 0, 0 );
92 paramWidget->setParent( this );
93 layout->addWidget( paramWidget );
94}
95
96QgsBrowserPropertiesWidget *QgsBrowserPropertiesWidget::createWidget( QgsDataItem *item, const QgsDataItemGuiContext &context, QWidget *parent )
97{
98 QgsBrowserPropertiesWidget *propertiesWidget = nullptr;
99 // In general, we would like to show all items' paramWidget, but top level items like
100 // WMS etc. have currently too large widgets which do not fit well to browser properties widget
101 if ( item->type() == Qgis::BrowserItemType::Directory )
102 {
103 propertiesWidget = new QgsBrowserDirectoryProperties( parent );
104 propertiesWidget->setItem( item );
105 }
106 else if ( item->type() == Qgis::BrowserItemType::Layer
109 || item->type() == Qgis::BrowserItemType::Field )
110 {
111 // try new infrastructure of creation of layer widgets
112 QWidget *paramWidget = nullptr;
113 const QList< QgsDataItemGuiProvider * > providers = QgsGui::dataItemGuiProviderRegistry()->providers();
114 for ( QgsDataItemGuiProvider *provider : providers )
115 {
116 paramWidget = provider->createParamWidget( item, context );
117 if ( paramWidget )
118 break;
119 }
120 if ( !paramWidget )
121 {
122 // try old infrastructure
124 paramWidget = item->paramWidget();
126 }
127
128 // prefer item's widget over standard layer widget
129 if ( paramWidget )
130 {
131 propertiesWidget = new QgsBrowserPropertiesWidget( parent );
132 propertiesWidget->setWidget( paramWidget );
133 }
134 else if ( item->type() == Qgis::BrowserItemType::Layer )
135 {
136 propertiesWidget = new QgsBrowserLayerProperties( parent );
137 propertiesWidget->setItem( item );
138 }
139 }
140 return propertiesWidget;
141}
142
143QgsBrowserLayerProperties::QgsBrowserLayerProperties( QWidget *parent )
144 : QgsBrowserPropertiesWidget( parent )
145{
146 setupUi( this );
147
148 // we don't want links to open in the little widget, open them externally instead
149 mMetadataTextBrowser->setOpenLinks( false );
150 connect( mMetadataTextBrowser, &QTextBrowser::anchorClicked, this, &QgsBrowserLayerProperties::urlClicked );
151
152 mMapCanvas->setProperty( "browser_canvas", true );
153 mMapCanvas->setLayers( QList< QgsMapLayer * >() );
154 mMapCanvas->setMapTool( new QgsMapToolPan( mMapCanvas ) );
155 mMapCanvas->freeze( true );
156
157 connect( mTabWidget, &QTabWidget::currentChanged, this, [ = ]
158 {
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
277 const QString myStyle = QgsApplication::reportStyleSheet();
278 mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
279 mMetadataTextBrowser->setHtml( layerMetadata );
280
281 if ( mNoticeLabel->text().isEmpty() )
282 {
283 mNoticeLabel->hide();
284 }
285}
286
287void QgsBrowserLayerProperties::setCondensedMode( bool )
288{
289
290}
291
292void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
293{
294 const QFileInfo file( url.toLocalFile() );
295 if ( file.exists() && !file.isDir() )
296 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
297 else
298 QDesktopServices::openUrl( url );
299}
300
301void QgsBrowserLayerProperties::loadAttributeTable()
302{
303 if ( !mLayer || !mLayer->isValid() || mLayer->type() != Qgis::LayerType::Vector )
304 return;
305
306 // Initialize the cache
307 QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
308 layerCache->setCacheGeometry( false );
309 QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
310 mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
311 tableModel->setRequest( QgsFeatureRequest().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setLimit( 100 ) );
312 layerCache->setParent( tableModel );
313 tableModel->setParent( mAttributeTableFilterModel );
314
315 mAttributeTable->setModel( mAttributeTableFilterModel );
316 tableModel->loadLayer();
317 QFont font = mAttributeTable->font();
318 int fontSize = font.pointSize();
319#ifdef Q_OS_WIN
320 fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
321#else
322 fontSize = std::max( fontSize - 2, 6 );
323#endif
324 font.setPointSize( fontSize );
325 mAttributeTable->setFont( font );
326
327 // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
328 mAttributeTable->resizeColumnsToContents();
329 mAttributeTable->resizeRowsToContents();
330 mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
331 mAttributeTable->setAlternatingRowColors( true );
332}
333
334QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
335 : QgsBrowserPropertiesWidget( parent )
336
337{
338 setupUi( this );
339
340 mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
341 mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
342}
343
344void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
345{
346 QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
347 if ( !item )
348 return;
349
350 mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
351 mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
352 mLayout->addWidget( mDirectoryWidget );
353}
354
355QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
356 : QDialog( parent )
357 , mSettingsSection( settingsSection )
358{
359 setupUi( this );
361}
362
363void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
364{
365 if ( !item )
366 return;
367
368 mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
369 mLayout->addWidget( mPropertiesWidget );
370 setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
371}
372
373
374//
375// QgsDockBrowserTreeView
376//
377
378QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
379{
380 setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
381 setSelectionMode( QAbstractItemView::ExtendedSelection );
382 setContextMenuPolicy( Qt::CustomContextMenu );
383 setHeaderHidden( true );
384 setDropIndicatorShown( true );
385
386}
387
388void QgsDockBrowserTreeView::setAction( QDropEvent *e )
389{
390 // if this mime data come from layer tree, the proposed action will be MoveAction
391 // but for browser we really need CopyAction
392 if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
393 e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
394 {
395 e->setDropAction( Qt::CopyAction );
396 }
397}
398
399void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
400{
401 setAction( e );
402
403 // accept drag enter so that our widget will not get ignored
404 // and drag events will not get passed to QgisApp
405 e->accept();
406}
407
408void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
409{
410 // do not accept drops above/below items
411 /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
412 {
413 QgsDebugMsgLevel("drag not on item", 2);
414 e->ignore();
415 return;
416 }*/
417
418 setAction( e );
419 QTreeView::dragMoveEvent( e );
420 // reset action because QTreeView::dragMoveEvent() accepts proposed action
421 setAction( e );
422
423 if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
424 {
425 e->ignore();
426 return;
427 }
428}
429
430void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
431{
432 setAction( e );
433 QTreeView::dropEvent( e );
434 // reset action because QTreeView::dropEvent() accepts proposed action
435 setAction( e );
436}
437
438
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ Layer
Represents a map layer.
@ Field
Vector layer field.
@ Custom
Custom item type.
@ Fields
Collection of fields.
@ Directory
Represents a file directory.
LayerType
Types of layers that can be added to a map.
Definition: qgis.h:114
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
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 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...
The QgsBrowserTreeView class extends QTreeView with save/restore tree state 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:46
Qgis::BrowserItemType type() const
Definition: qgsdataitem.h:318
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:339
QString path() const
Definition: qgsdataitem.h:348
virtual Q_DECL_DEPRECATED QWidget * paramWidget()
Returns source widget from data item for QgsBrowserPropertiesWidget.
Definition: qgsdataitem.h:187
A directory: contains subdirectories and layers.
QString dirPath() const
Returns the full path to the directory the item represents.
Browser parameter widget implementation for directory items.
This class 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:194
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:79
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition: qgsgui.cpp:164
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:31
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgslayeritem.h:71
QString providerKey() const
Returns provider key.
Definition: qgslayeritem.h:74
Qgis::LayerType mapLayerType() const
Returns the associated map layer type.
A map tool for panning the map.
Definition: qgsmaptoolpan.h:31
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:113
This class caches features of a given QgsVectorLayer.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:109
Setting options for loading point cloud layers.
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.
Setting options for loading vector layers.