QGIS API Documentation  3.25.0-Master (6b426f5f8a)
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 
@ Layer
Represents a map layer.
@ Field
Vector layer field.
@ Custom
Custom item type.
@ Fields
Collection of fields.
@ Directory
Represents a file directory.
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:324
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:345
QString path() const
Definition: qgsdataitem.h:354
virtual Q_DECL_DEPRECATED QWidget * paramWidget()
Returns source widget from data item for QgsBrowserPropertiesWidget.
Definition: qgsdataitem.h:189
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).
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:75
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition: qgsgui.cpp:160
Item that represents a layer that can be opened with one of the providers.
Definition: qgslayeritem.h:30
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgslayeritem.h:68
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
QString providerKey() const
Returns provider key.
Definition: qgslayeritem.h:71
A map tool for panning the map.
Definition: qgsmaptoolpan.h:33
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:472
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:109
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: qgis.h:47
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2533
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2532
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:107
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.