QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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  ***************************************************************************/
20 #include "qgsbrowserdockwidget_p.h"
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 "qgssettings.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"
48 #include "qgsattributetablemodel.h"
50 #include "qgsapplication.h"
52 #include "qgsdataitemguiprovider.h"
53 #include "qgspointcloudlayer.h"
54 #include "qgslayeritem.h"
55 #include "qgsdirectoryitem.h"
56 
58 
59 
60 QgsBrowserPropertiesWrapLabel::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 
76 void QgsBrowserPropertiesWrapLabel::adjustHeight( QSizeF size )
77 {
78  const int height = static_cast<int>( size.height() ) + 2 * frameWidth();
79  setMinimumHeight( height );
80  setMaximumHeight( height );
81 }
82 
83 QgsBrowserPropertiesWidget::QgsBrowserPropertiesWidget( QWidget *parent )
84  : QWidget( parent )
85 {
86 }
87 
88 void 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 
96 QgsBrowserPropertiesWidget *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
107  || item->type() == Qgis::BrowserItemType::Custom
108  || item->type() == Qgis::BrowserItemType::Fields
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 
143 QgsBrowserLayerProperties::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 
172 void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
173 {
174  QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
175  if ( !layerItem )
176  return;
177 
178  mNoticeLabel->clear();
179 
180  const QgsMapLayerType 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 
238  {
239  // TODO: support display of properties for plugin layers
240  return;
241  }
242  }
243 
244  mAttributeTable->setModel( nullptr );
245  if ( mAttributeTableFilterModel )
246  {
247  // Cleanup
248  mAttributeTableFilterModel->deleteLater();
249  mAttributeTableFilterModel = nullptr;
250  }
251  if ( mLayer && mLayer->isValid() )
252  {
253  bool ok = false;
254  mLayer->loadDefaultMetadata( ok );
255  layerMetadata = mLayer->htmlMetadata();
256 
257  mMapCanvas->setDestinationCrs( mLayer->crs() );
258  mMapCanvas->setLayers( QList< QgsMapLayer * >() << mLayer.get() );
259  mMapCanvas->zoomToFullExtent();
260 
261  if ( mAttributesTab && mLayer->type() != QgsMapLayerType::VectorLayer )
262  {
263  mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
264  mAttributesTab = nullptr;
265  }
266  }
267 
268  const QString myStyle = QgsApplication::reportStyleSheet();
269  mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
270  mMetadataTextBrowser->setHtml( layerMetadata );
271 
272  if ( mNoticeLabel->text().isEmpty() )
273  {
274  mNoticeLabel->hide();
275  }
276 }
277 
278 void QgsBrowserLayerProperties::setCondensedMode( bool )
279 {
280 
281 }
282 
283 void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
284 {
285  const QFileInfo file( url.toLocalFile() );
286  if ( file.exists() && !file.isDir() )
287  QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
288  else
289  QDesktopServices::openUrl( url );
290 }
291 
292 void QgsBrowserLayerProperties::loadAttributeTable()
293 {
294  if ( !mLayer || !mLayer->isValid() || mLayer->type() != QgsMapLayerType::VectorLayer )
295  return;
296 
297  // Initialize the cache
298  QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
299  layerCache->setCacheGeometry( false );
300  QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
301  mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
302  tableModel->setRequest( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setLimit( 100 ) );
303  layerCache->setParent( tableModel );
304  tableModel->setParent( mAttributeTableFilterModel );
305 
306  mAttributeTable->setModel( mAttributeTableFilterModel );
307  tableModel->loadLayer();
308  QFont font = mAttributeTable->font();
309  int fontSize = font.pointSize();
310 #ifdef Q_OS_WIN
311  fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
312 #else
313  fontSize = std::max( fontSize - 2, 6 );
314 #endif
315  font.setPointSize( fontSize );
316  mAttributeTable->setFont( font );
317 
318  // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
319  mAttributeTable->resizeColumnsToContents();
320  mAttributeTable->resizeRowsToContents();
321  mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
322  mAttributeTable->setAlternatingRowColors( true );
323 }
324 
325 QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
326  : QgsBrowserPropertiesWidget( parent )
327 
328 {
329  setupUi( this );
330 
331  mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
332  mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
333 }
334 
335 void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
336 {
337  QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
338  if ( !item )
339  return;
340 
341  mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
342  mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
343  mLayout->addWidget( mDirectoryWidget );
344 }
345 
346 QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
347  : QDialog( parent )
348  , mSettingsSection( settingsSection )
349 {
350  setupUi( this );
352 }
353 
354 void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
355 {
356  if ( !item )
357  return;
358 
359  mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
360  mLayout->addWidget( mPropertiesWidget );
361  setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
362 }
363 
364 
365 //
366 // QgsDockBrowserTreeView
367 //
368 
369 QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
370 {
371  setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
372  setSelectionMode( QAbstractItemView::ExtendedSelection );
373  setContextMenuPolicy( Qt::CustomContextMenu );
374  setHeaderHidden( true );
375  setDropIndicatorShown( true );
376 
377 }
378 
379 void QgsDockBrowserTreeView::setAction( QDropEvent *e )
380 {
381  // if this mime data come from layer tree, the proposed action will be MoveAction
382  // but for browser we really need CopyAction
383  if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
384  e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
385  {
386  e->setDropAction( Qt::CopyAction );
387  }
388 }
389 
390 void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
391 {
392  setAction( e );
393 
394  // accept drag enter so that our widget will not get ignored
395  // and drag events will not get passed to QgisApp
396  e->accept();
397 }
398 
399 void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
400 {
401  // do not accept drops above/below items
402  /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
403  {
404  QgsDebugMsg("drag not on item");
405  e->ignore();
406  return;
407  }*/
408 
409  setAction( e );
410  QTreeView::dragMoveEvent( e );
411  // reset action because QTreeView::dragMoveEvent() accepts proposed action
412  setAction( e );
413 
414  if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
415  {
416  e->ignore();
417  return;
418  }
419 }
420 
421 void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
422 {
423  setAction( e );
424  QTreeView::dropEvent( e );
425  // reset action because QTreeView::dropEvent() accepts proposed action
426  setAction( e );
427 }
428 
429 
QgsLayerItem::mapLayerType
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
Definition: qgslayeritem.cpp:92
QgsFeatureRequest::NoGeometry
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition: qgsfeaturerequest.h:115
qgsdataitemguiproviderregistry.h
QgsDataItemGuiProvider
Abstract base class for providers which affect how QgsDataItem items behave within the application GU...
Definition: qgsdataitemguiprovider.h:85
Qgis::BrowserItemType::Fields
@ Fields
Collection of fields.
qgsrasterlayer.h
qgsvectorlayercache.h
qgsbrowsertreeview.h
qgsdirectoryitem.h
QgsDataItem::path
QString path() const
Definition: qgsdataitem.h:354
QgsVectorLayerCache
This class caches features of a given QgsVectorLayer.
Definition: qgsvectorlayercache.h:46
QgsBrowserTreeView
The QgsBrowserTreeView class extends QTreeView with save/restore tree state functionality.
Definition: qgsbrowsertreeview.h:32
QgsMapLayerType::MeshLayer
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
QgsMapLayerType::VectorLayer
@ VectorLayer
Vector layer.
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsgui.h
qgsdataitemguiprovider.h
QgsRasterLayer::LayerOptions::skipCrsValidation
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
Definition: qgsrasterlayer.h:143
QgsMapLayerType::AnnotationLayer
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
QgsMapLayerType
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:46
QgsDataItemGuiProviderRegistry::providers
QList< QgsDataItemGuiProvider * > providers() const
Returns the list of available providers.
Definition: qgsdataitemguiproviderregistry.h:51
QgsProject::transformContext
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:110
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
Qgis::BrowserItemType::Layer
@ Layer
Represents a map layer.
QgsDataItem::name
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:345
pal
Definition: qgsdiagramrenderer.h:50
QgsMeshLayer::LayerOptions
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:106
QgsDirectoryItem::dirPath
QString dirPath() const
Returns the full path to the directory the item represents.
Definition: qgsdirectoryitem.h:86
qgsapplication.h
qgsvectortilelayer.h
QgsGui::enableAutoGeometryRestore
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:180
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
qgslayeritem.h
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
qgsmaptoolpan.h
qgspointcloudlayer.h
Qgis::BrowserItemType::Field
@ Field
Vector layer field.
QgsDirectoryItem
A directory: contains subdirectories and layers.
Definition: qgsdirectoryitem.h:33
QgsMapLayerType::GroupLayer
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
QgsAttributeTableModel::setRequest
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
Definition: qgsattributetablemodel.cpp:1044
QgsAttributeTableModel
A model backed by a QgsVectorLayerCache which is able to provide feature/attribute information to a Q...
Definition: qgsattributetablemodel.h:49
QgsDataItem::paramWidget
virtual Q_DECL_DEPRECATED QWidget * paramWidget()
Returns source widget from data item for QgsBrowserPropertiesWidget.
Definition: qgsdataitem.h:189
QgsMapLayerType::RasterLayer
@ RasterLayer
Raster layer.
qgsattributetablefiltermodel.h
QgsMapToolPan
A map tool for panning the map.
Definition: qgsmaptoolpan.h:32
QgsDataItemGuiContext
Encapsulates the context in which a QgsDataItem is shown within the application GUI.
Definition: qgsdataitemguiprovider.h:40
qgsattributetablemodel.h
QgsAttributeTableModel::loadLayer
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
Definition: qgsattributetablemodel.cpp:460
QgsGui::nativePlatformInterface
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:75
qgsmeshlayer.h
qgsvectorlayer.h
QgsGui::dataItemGuiProviderRegistry
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition: qgsgui.cpp:160
qgsbrowsermodel.h
QgsAttributeTableFilterModel
Definition: qgsattributetablefiltermodel.h:36
QgsVectorLayer::LayerOptions
Setting options for loading vector layers.
Definition: qgsvectorlayer.h:408
QgsRasterLayer::LayerOptions
Setting options for loading raster layers.
Definition: qgsrasterlayer.h:109
qgsbrowserdockwidget_p.h
qgssettings.h
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
QgsVectorLayerCache::setCacheGeometry
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
Definition: qgsvectorlayercache.cpp:65
QgsLayerItem
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:29
QgsDirectoryParamWidget
Browser parameter widget implementation for directory items.
Definition: qgsdirectoryitem.h:231
QgsPointCloudLayer::LayerOptions
Setting options for loading point cloud layers.
Definition: qgspointcloudlayer.h:53
QgsLayerItem::providerKey
QString providerKey() const
Returns provider key.
Definition: qgslayeritem.h:84
qgslogger.h
QgsDataItem
Base class for all items in the model.
Definition: qgsdataitem.h:45
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsMapLayerType::PointCloudLayer
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
QgsDataItem::type
Qgis::BrowserItemType type() const
Definition: qgsdataitem.h:324
QgsApplication::reportStyleSheet
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
Definition: qgsapplication.cpp:1517
qgsproject.h
Qgis::BrowserItemType::Custom
@ Custom
Custom item type.
QgsMapLayerType::PluginLayer
@ PluginLayer
Plugin based layer.
Qgis::BrowserItemType::Directory
@ Directory
Represents a file directory.
QgsLayerItem::uri
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgslayeritem.h:81