QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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 
56 
57 
58 QgsBrowserPropertiesWrapLabel::QgsBrowserPropertiesWrapLabel( const QString &text, QWidget *parent )
59  : QTextEdit( text, parent )
60 {
61  setReadOnly( true );
62  setFrameStyle( QFrame::NoFrame );
63  setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum );
64  QPalette pal = palette();
65  pal.setColor( QPalette::Base, Qt::transparent );
66  setPalette( pal );
67  setLineWrapMode( QTextEdit::WidgetWidth );
68  setWordWrapMode( QTextOption::WrapAnywhere );
69  connect( document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged,
70  this, &QgsBrowserPropertiesWrapLabel::adjustHeight );
71  setMaximumHeight( 20 );
72 }
73 
74 void QgsBrowserPropertiesWrapLabel::adjustHeight( QSizeF size )
75 {
76  int height = static_cast<int>( size.height() ) + 2 * frameWidth();
77  setMinimumHeight( height );
78  setMaximumHeight( height );
79 }
80 
81 QgsBrowserPropertiesWidget::QgsBrowserPropertiesWidget( QWidget *parent )
82  : QWidget( parent )
83 {
84 }
85 
86 void QgsBrowserPropertiesWidget::setWidget( QWidget *paramWidget )
87 {
88  QVBoxLayout *layout = new QVBoxLayout( this );
89  layout->setContentsMargins( 0, 0, 0, 0 );
90  paramWidget->setParent( this );
91  layout->addWidget( paramWidget );
92 }
93 
94 QgsBrowserPropertiesWidget *QgsBrowserPropertiesWidget::createWidget( QgsDataItem *item, const QgsDataItemGuiContext &context, QWidget *parent )
95 {
96  QgsBrowserPropertiesWidget *propertiesWidget = nullptr;
97  // In general, we would like to show all items' paramWidget, but top level items like
98  // WMS etc. have currently too large widgets which do not fit well to browser properties widget
99  if ( item->type() == QgsDataItem::Directory )
100  {
101  propertiesWidget = new QgsBrowserDirectoryProperties( parent );
102  propertiesWidget->setItem( item );
103  }
104  else if ( item->type() == QgsDataItem::Layer || item->type() == QgsDataItem::Custom )
105  {
106  // try new infrastructure of creation of layer widgets
107  QWidget *paramWidget = nullptr;
108  const QList< QgsDataItemGuiProvider * > providers = QgsGui::instance()->dataItemGuiProviderRegistry()->providers();
109  for ( QgsDataItemGuiProvider *provider : providers )
110  {
111  paramWidget = provider->createParamWidget( item, context );
112  if ( paramWidget )
113  break;
114  }
115  if ( !paramWidget )
116  {
117  // try old infrastructure
119  paramWidget = item->paramWidget();
121  }
122 
123  // prefer item's widget over standard layer widget
124  if ( paramWidget )
125  {
126  propertiesWidget = new QgsBrowserPropertiesWidget( parent );
127  propertiesWidget->setWidget( paramWidget );
128  }
129  else if ( item->type() == QgsDataItem::Layer )
130  {
131  propertiesWidget = new QgsBrowserLayerProperties( parent );
132  propertiesWidget->setItem( item );
133  }
134  }
135  return propertiesWidget;
136 }
137 
138 QgsBrowserLayerProperties::QgsBrowserLayerProperties( QWidget *parent )
139  : QgsBrowserPropertiesWidget( parent )
140 {
141  setupUi( this );
142 
143  // we don't want links to open in the little widget, open them externally instead
144  mMetadataTextBrowser->setOpenLinks( false );
145  connect( mMetadataTextBrowser, &QTextBrowser::anchorClicked, this, &QgsBrowserLayerProperties::urlClicked );
146 
147  mMapCanvas->setProperty( "browser_canvas", true );
148  mMapCanvas->setLayers( QList< QgsMapLayer * >() );
149  mMapCanvas->setMapTool( new QgsMapToolPan( mMapCanvas ) );
150  mMapCanvas->freeze( true );
151 
152  connect( mTabWidget, &QTabWidget::currentChanged, this, [ = ]
153  {
154  if ( mTabWidget->currentWidget() == mPreviewTab && mMapCanvas->isFrozen() )
155  {
156  mMapCanvas->freeze( false );
157  mMapCanvas->refresh();
158  }
159  else if ( mTabWidget->currentWidget() == mAttributesTab )
160  {
161  if ( ! mAttributeTableFilterModel )
162  loadAttributeTable();
163  }
164  } );
165 }
166 
167 void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
168 {
169  QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
170  if ( !layerItem )
171  return;
172 
173  mNoticeLabel->clear();
174 
175  QgsMapLayerType type = layerItem->mapLayerType();
176  QString layerMetadata = tr( "Error" );
177 
178  mLayer.reset();
179 
180  // find root item
181  // we need to create a temporary layer to get metadata
182  // we could use a provider but the metadata is not as complete and "pretty" and this is easier
183  QgsDebugMsg( QStringLiteral( "creating temporary layer using path %1" ).arg( layerItem->path() ) );
184  switch ( type )
185  {
187  {
188  QgsDebugMsg( QStringLiteral( "creating raster layer" ) );
189  // should copy code from addLayer() to split uri ?
191  options.skipCrsValidation = true;
192  mLayer = qgis::make_unique< QgsRasterLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
193  break;
194  }
195 
197  {
198  QgsDebugMsg( QStringLiteral( "creating mesh layer" ) );
200  options.skipCrsValidation = true;
201  mLayer = qgis::make_unique < QgsMeshLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
202  break;
203  }
204 
206  {
207  QgsDebugMsg( QStringLiteral( "creating vector layer" ) );
209  options.skipCrsValidation = true;
210  mLayer = qgis::make_unique < QgsVectorLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
211  break;
212  }
213 
215  {
216  QgsDebugMsgLevel( QStringLiteral( "creating vector tile layer" ), 2 );
217  mLayer = qgis::make_unique< QgsVectorTileLayer >( layerItem->uri(), layerItem->name() );
218  break;
219  }
220 
222  {
223  QgsDebugMsgLevel( QStringLiteral( "creating point cloud layer" ), 2 );
225  options.skipCrsValidation = true;
226  mLayer = qgis::make_unique< QgsPointCloudLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
227  break;
228  }
229 
232  {
233  // TODO: support display of properties for plugin layers
234  return;
235  }
236  }
237 
238  mAttributeTable->setModel( nullptr );
239  if ( mAttributeTableFilterModel )
240  {
241  // Cleanup
242  mAttributeTableFilterModel->deleteLater();
243  mAttributeTableFilterModel = nullptr;
244  }
245  if ( mLayer && mLayer->isValid() )
246  {
247  bool ok = false;
248  mLayer->loadDefaultMetadata( ok );
249  layerMetadata = mLayer->htmlMetadata();
250 
251  mMapCanvas->setDestinationCrs( mLayer->crs() );
252  mMapCanvas->setLayers( QList< QgsMapLayer * >() << mLayer.get() );
253  mMapCanvas->zoomToFullExtent();
254 
255  if ( mAttributesTab && mLayer->type() != QgsMapLayerType::VectorLayer )
256  {
257  mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
258  mAttributesTab = nullptr;
259  }
260  }
261 
262  QString myStyle = QgsApplication::reportStyleSheet();
263  mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
264  mMetadataTextBrowser->setHtml( layerMetadata );
265 
266  if ( mNoticeLabel->text().isEmpty() )
267  {
268  mNoticeLabel->hide();
269  }
270 }
271 
272 void QgsBrowserLayerProperties::setCondensedMode( bool )
273 {
274 
275 }
276 
277 void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
278 {
279  QFileInfo file( url.toLocalFile() );
280  if ( file.exists() && !file.isDir() )
281  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
282  else
283  QDesktopServices::openUrl( url );
284 }
285 
286 void QgsBrowserLayerProperties::loadAttributeTable()
287 {
288  if ( !mLayer || !mLayer->isValid() || mLayer->type() != QgsMapLayerType::VectorLayer )
289  return;
290 
291  // Initialize the cache
292  QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
293  layerCache->setCacheGeometry( false );
294  QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
295  mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
296  tableModel->setRequest( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setLimit( 100 ) );
297  layerCache->setParent( tableModel );
298  tableModel->setParent( mAttributeTableFilterModel );
299 
300  mAttributeTable->setModel( mAttributeTableFilterModel );
301  tableModel->loadLayer();
302  QFont font = mAttributeTable->font();
303  int fontSize = font.pointSize();
304 #ifdef Q_OS_WIN
305  fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
306 #else
307  fontSize = std::max( fontSize - 2, 6 );
308 #endif
309  font.setPointSize( fontSize );
310  mAttributeTable->setFont( font );
311 
312  // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
313  mAttributeTable->resizeColumnsToContents();
314  mAttributeTable->resizeRowsToContents();
315  mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
316  mAttributeTable->setAlternatingRowColors( true );
317 }
318 
319 QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
320  : QgsBrowserPropertiesWidget( parent )
321 
322 {
323  setupUi( this );
324 
325  mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
326  mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
327 }
328 
329 void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
330 {
331  QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
332  if ( !item )
333  return;
334 
335  mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
336  mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
337  mLayout->addWidget( mDirectoryWidget );
338 }
339 
340 QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
341  : QDialog( parent )
342  , mSettingsSection( settingsSection )
343 {
344  setupUi( this );
346 }
347 
348 void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
349 {
350  if ( !item )
351  return;
352 
353  mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
354  mLayout->addWidget( mPropertiesWidget );
355  setWindowTitle( item->type() == QgsDataItem::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
356 }
357 
358 
359 //
360 // QgsDockBrowserTreeView
361 //
362 
363 QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
364 {
365  setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
366  setSelectionMode( QAbstractItemView::ExtendedSelection );
367  setContextMenuPolicy( Qt::CustomContextMenu );
368  setHeaderHidden( true );
369  setDropIndicatorShown( true );
370 
371 }
372 
373 void QgsDockBrowserTreeView::setAction( QDropEvent *e )
374 {
375  // if this mime data come from layer tree, the proposed action will be MoveAction
376  // but for browser we really need CopyAction
377  if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
378  e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
379  {
380  e->setDropAction( Qt::CopyAction );
381  }
382 }
383 
384 void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
385 {
386  setAction( e );
387 
388  // accept drag enter so that our widget will not get ignored
389  // and drag events will not get passed to QgisApp
390  e->accept();
391 }
392 
393 void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
394 {
395  // do not accept drops above/below items
396  /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
397  {
398  QgsDebugMsg("drag not on item");
399  e->ignore();
400  return;
401  }*/
402 
403  setAction( e );
404  QTreeView::dragMoveEvent( e );
405  // reset action because QTreeView::dragMoveEvent() accepts proposed action
406  setAction( e );
407 
408  if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
409  {
410  e->ignore();
411  return;
412  }
413 }
414 
415 void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
416 {
417  setAction( e );
418  QTreeView::dropEvent( e );
419  // reset action because QTreeView::dropEvent() accepts proposed action
420  setAction( e );
421 }
422 
423 
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:52
Type type() const
Definition: qgsdataitem.h:339
@ Custom
Custom item type.
Definition: qgsdataitem.h:86
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:360
QString path() const
Definition: qgsdataitem.h:369
virtual Q_DECL_DEPRECATED QWidget * paramWidget()
Returns source widget from data item for QgsBrowserPropertiesWidget.
Definition: qgsdataitem.h:201
A directory: contains subdirectories and layers.
Definition: qgsdataitem.h:804
QString dirPath() const
Returns the full path to the directory the item represents.
Definition: qgsdataitem.h:849
Browser parameter widget implementation for directory items.
Definition: qgsdataitem.h:922
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:65
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:156
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:71
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition: qgsgui.cpp:141
Item that represents a layer that can be opened with one of the providers.
Definition: qgsdataitem.h:554
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgsdataitem.h:599
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
QString providerKey() const
Returns provider key.
Definition: qgsdataitem.h:602
A map tool for panning the map.
Definition: qgsmaptoolpan.h:33
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:105
This class caches features of a given QgsVectorLayer.
void setCacheGeometry(bool cacheGeometry)
Enable or disable the caching of geometries.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgsmaplayer.h:69
@ PointCloudLayer
Added in 3.18.
@ MeshLayer
Added in 3.2.
@ VectorTileLayer
Added in 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:798
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:797
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:103
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 vector layers.