QGIS API Documentation 3.41.0-Master (45a0abf3bec)
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#include "moc_qgsbrowserdockwidget_p.cpp"
22
23#include <memory>
24
25#include <QAbstractTextDocumentLayout>
26#include <QHeaderView>
27#include <QTreeView>
28#include <QMenu>
29#include <QToolButton>
30#include <QFileDialog>
31#include <QPlainTextDocumentLayout>
32#include <QSortFilterProxyModel>
33#include <QDesktopServices>
34#include <QDragEnterEvent>
35
36#include "qgsbrowsermodel.h"
37#include "qgsbrowsertreeview.h"
38#include "qgslogger.h"
39#include "qgsrasterlayer.h"
40#include "qgsvectorlayer.h"
41#include "qgsproject.h"
42#include "qgsmeshlayer.h"
43#include "qgsgui.h"
44#include "qgsnative.h"
45#include "qgsmaptoolpan.h"
46#include "qgsvectorlayercache.h"
47#include "qgsvectortilelayer.h"
50#include "qgsapplication.h"
53#include "qgspointcloudlayer.h"
54#include "qgslayeritem.h"
55#include "qgsdirectoryitem.h"
56#include "qgstiledscenelayer.h"
57
59
60
61QgsBrowserPropertiesWrapLabel::QgsBrowserPropertiesWrapLabel( const QString &text, QWidget *parent )
62 : QTextEdit( text, parent )
63{
64 setReadOnly( true );
65 setFrameStyle( QFrame::NoFrame );
66 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
67 QPalette pal = palette();
68 pal.setColor( QPalette::Base, Qt::transparent );
69 setPalette( pal );
70 setLineWrapMode( QTextEdit::WidgetWidth );
71 setWordWrapMode( QTextOption::WrapAnywhere );
72 connect( document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
73 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, [ = ]
159 {
160 if ( mTabWidget->currentWidget() == mPreviewTab && mMapCanvas->isFrozen() )
161 {
162 mMapCanvas->freeze( false );
163 mMapCanvas->refresh();
164 }
165 else if ( mTabWidget->currentWidget() == mAttributesTab )
166 {
167 if ( ! mAttributeTableFilterModel )
168 loadAttributeTable();
169 }
170 } );
171}
172
173void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
174{
175 QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
176 if ( !layerItem )
177 return;
178
179 mNoticeLabel->clear();
180
181 const Qgis::LayerType type = layerItem->mapLayerType();
182 QString layerMetadata = tr( "Error" );
183
184 mLayer.reset();
185
186 // find root item
187 // we need to create a temporary layer to get metadata
188 // we could use a provider but the metadata is not as complete and "pretty" and this is easier
189 QgsDebugMsgLevel( QStringLiteral( "creating temporary layer using path %1" ).arg( layerItem->path() ), 2 );
190 switch ( type )
191 {
193 {
194 QgsDebugMsgLevel( QStringLiteral( "creating raster layer" ), 2 );
195 // should copy code from addLayer() to split uri ?
197 options.skipCrsValidation = true;
198 mLayer = std::make_unique< QgsRasterLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
199 break;
200 }
201
203 {
204 QgsDebugMsgLevel( QStringLiteral( "creating mesh layer" ), 2 );
206 options.skipCrsValidation = true;
207 mLayer = std::make_unique < QgsMeshLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
208 break;
209 }
210
212 {
213 QgsDebugMsgLevel( QStringLiteral( "creating vector layer" ), 2 );
215 options.skipCrsValidation = true;
216 mLayer = std::make_unique < QgsVectorLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
217 break;
218 }
219
221 {
222 QgsDebugMsgLevel( QStringLiteral( "creating vector tile layer" ), 2 );
223 mLayer = std::make_unique< QgsVectorTileLayer >( layerItem->uri(), layerItem->name() );
224 break;
225 }
226
228 {
229 QgsDebugMsgLevel( QStringLiteral( "creating point cloud layer" ), 2 );
231 options.skipCrsValidation = true;
232 mLayer = std::make_unique< QgsPointCloudLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
233 break;
234 }
235
237 {
238 QgsDebugMsgLevel( QStringLiteral( "creating tiled scene layer" ), 2 );
240 options.skipCrsValidation = true;
241 mLayer = std::make_unique< QgsTiledSceneLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
242 break;
243 }
244
248 {
249 // TODO: support display of properties for plugin layers
250 return;
251 }
252 }
253
254 mAttributeTable->setModel( nullptr );
255 if ( mAttributeTableFilterModel )
256 {
257 // Cleanup
258 mAttributeTableFilterModel->deleteLater();
259 mAttributeTableFilterModel = nullptr;
260 }
261 if ( mLayer && mLayer->isValid() )
262 {
263 bool ok = false;
264 mLayer->loadDefaultMetadata( ok );
265 layerMetadata = mLayer->htmlMetadata();
266
267 mMapCanvas->setDestinationCrs( mLayer->crs() );
268 mMapCanvas->setLayers( QList< QgsMapLayer * >() << mLayer.get() );
269 mMapCanvas->zoomToFullExtent();
270
271 if ( mAttributesTab && mLayer->type() != Qgis::LayerType::Vector )
272 {
273 mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
274 mAttributesTab = nullptr;
275 }
276 }
277
278 const QString myStyle = QgsApplication::reportStyleSheet();
279 mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
280 mMetadataTextBrowser->setHtml( layerMetadata );
281
282 if ( mNoticeLabel->text().isEmpty() )
283 {
284 mNoticeLabel->hide();
285 }
286}
287
288void QgsBrowserLayerProperties::setCondensedMode( bool )
289{
290
291}
292
293void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
294{
295 if ( !url.fragment().isEmpty() && url.toString().startsWith( QLatin1Char( '#' ) ) )
296 {
297 mMetadataTextBrowser->scrollToAnchor( url.fragment() );
298 return;
299 }
300 const QFileInfo file( url.toLocalFile() );
301 if ( file.exists() && !file.isDir() )
302 QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
303 else
304 QDesktopServices::openUrl( url );
305}
306
307void QgsBrowserLayerProperties::loadAttributeTable()
308{
309 if ( !mLayer || !mLayer->isValid() || mLayer->type() != Qgis::LayerType::Vector )
310 return;
311
312 // Initialize the cache
313 QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
314 layerCache->setCacheGeometry( false );
315 QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
316 mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
317 tableModel->setRequest( QgsFeatureRequest().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setLimit( 100 ) );
318 layerCache->setParent( tableModel );
319 tableModel->setParent( mAttributeTableFilterModel );
320
321 mAttributeTable->setModel( mAttributeTableFilterModel );
322 tableModel->loadLayer();
323 QFont font = mAttributeTable->font();
324 int fontSize = font.pointSize();
325#ifdef Q_OS_WIN
326 fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
327#else
328 fontSize = std::max( fontSize - 2, 6 );
329#endif
330 font.setPointSize( fontSize );
331 mAttributeTable->setFont( font );
332
333 // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
334 mAttributeTable->resizeColumnsToContents();
335 mAttributeTable->resizeRowsToContents();
336 mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
337 mAttributeTable->setAlternatingRowColors( true );
338}
339
340QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
341 : QgsBrowserPropertiesWidget( parent )
342
343{
344 setupUi( this );
345
346 mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
347 mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
348}
349
350void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
351{
352 QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
353 if ( !item )
354 return;
355
356 mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
357 mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
358 mLayout->addWidget( mDirectoryWidget );
359}
360
361QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
362 : QDialog( parent )
363 , mSettingsSection( settingsSection )
364{
365 setupUi( this );
367}
368
369void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
370{
371 if ( !item )
372 return;
373
374 mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
375 mLayout->addWidget( mPropertiesWidget );
376 setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
377}
378
379
380//
381// QgsDockBrowserTreeView
382//
383
384QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
385{
386 setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
387 setSelectionMode( QAbstractItemView::ExtendedSelection );
388 setContextMenuPolicy( Qt::CustomContextMenu );
389 setHeaderHidden( true );
390 setDropIndicatorShown( true );
391
392}
393
394void QgsDockBrowserTreeView::setAction( QDropEvent *e )
395{
396 // if this mime data come from layer tree, the proposed action will be MoveAction
397 // but for browser we really need CopyAction
398 if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
399 e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
400 {
401 e->setDropAction( Qt::CopyAction );
402 }
403}
404
405void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
406{
407 setAction( e );
408
409 // accept drag enter so that our widget will not get ignored
410 // and drag events will not get passed to QgisApp
411 e->accept();
412}
413
414void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
415{
416 // do not accept drops above/below items
417 /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
418 {
419 QgsDebugMsgLevel("drag not on item", 2);
420 e->ignore();
421 return;
422 }*/
423
424 setAction( e );
425 QTreeView::dragMoveEvent( e );
426 // reset action because QTreeView::dragMoveEvent() accepts proposed action
427 setAction( e );
428
429 if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
430 {
431 e->ignore();
432 return;
433 }
434}
435
436void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
437{
438 setAction( e );
439 QTreeView::dropEvent( e );
440 // reset action because QTreeView::dropEvent() accepts proposed action
441 setAction( e );
442}
443
444
@ 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:169
@ 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
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 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:209
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition qgsgui.cpp:84
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition qgsgui.cpp:179
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: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:6535
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6534
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
Setting options for loading mesh layers.
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.