QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 || item->type() == Qgis::BrowserItemType::Custom )
107  {
108  // try new infrastructure of creation of layer widgets
109  QWidget *paramWidget = nullptr;
110  const QList< QgsDataItemGuiProvider * > providers = QgsGui::dataItemGuiProviderRegistry()->providers();
111  for ( QgsDataItemGuiProvider *provider : providers )
112  {
113  paramWidget = provider->createParamWidget( item, context );
114  if ( paramWidget )
115  break;
116  }
117  if ( !paramWidget )
118  {
119  // try old infrastructure
121  paramWidget = item->paramWidget();
123  }
124 
125  // prefer item's widget over standard layer widget
126  if ( paramWidget )
127  {
128  propertiesWidget = new QgsBrowserPropertiesWidget( parent );
129  propertiesWidget->setWidget( paramWidget );
130  }
131  else if ( item->type() == Qgis::BrowserItemType::Layer )
132  {
133  propertiesWidget = new QgsBrowserLayerProperties( parent );
134  propertiesWidget->setItem( item );
135  }
136  }
137  return propertiesWidget;
138 }
139 
140 QgsBrowserLayerProperties::QgsBrowserLayerProperties( QWidget *parent )
141  : QgsBrowserPropertiesWidget( parent )
142 {
143  setupUi( this );
144 
145  // we don't want links to open in the little widget, open them externally instead
146  mMetadataTextBrowser->setOpenLinks( false );
147  connect( mMetadataTextBrowser, &QTextBrowser::anchorClicked, this, &QgsBrowserLayerProperties::urlClicked );
148 
149  mMapCanvas->setProperty( "browser_canvas", true );
150  mMapCanvas->setLayers( QList< QgsMapLayer * >() );
151  mMapCanvas->setMapTool( new QgsMapToolPan( mMapCanvas ) );
152  mMapCanvas->freeze( true );
153 
154  connect( mTabWidget, &QTabWidget::currentChanged, this, [ = ]
155  {
156  if ( mTabWidget->currentWidget() == mPreviewTab && mMapCanvas->isFrozen() )
157  {
158  mMapCanvas->freeze( false );
159  mMapCanvas->refresh();
160  }
161  else if ( mTabWidget->currentWidget() == mAttributesTab )
162  {
163  if ( ! mAttributeTableFilterModel )
164  loadAttributeTable();
165  }
166  } );
167 }
168 
169 void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
170 {
171  QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
172  if ( !layerItem )
173  return;
174 
175  mNoticeLabel->clear();
176 
177  const QgsMapLayerType type = layerItem->mapLayerType();
178  QString layerMetadata = tr( "Error" );
179 
180  mLayer.reset();
181 
182  // find root item
183  // we need to create a temporary layer to get metadata
184  // we could use a provider but the metadata is not as complete and "pretty" and this is easier
185  QgsDebugMsg( QStringLiteral( "creating temporary layer using path %1" ).arg( layerItem->path() ) );
186  switch ( type )
187  {
189  {
190  QgsDebugMsg( QStringLiteral( "creating raster layer" ) );
191  // should copy code from addLayer() to split uri ?
193  options.skipCrsValidation = true;
194  mLayer = std::make_unique< QgsRasterLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
195  break;
196  }
197 
199  {
200  QgsDebugMsg( QStringLiteral( "creating mesh layer" ) );
202  options.skipCrsValidation = true;
203  mLayer = std::make_unique < QgsMeshLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
204  break;
205  }
206 
208  {
209  QgsDebugMsg( QStringLiteral( "creating vector layer" ) );
211  options.skipCrsValidation = true;
212  mLayer = std::make_unique < QgsVectorLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
213  break;
214  }
215 
217  {
218  QgsDebugMsgLevel( QStringLiteral( "creating vector tile layer" ), 2 );
219  mLayer = std::make_unique< QgsVectorTileLayer >( layerItem->uri(), layerItem->name() );
220  break;
221  }
222 
224  {
225  QgsDebugMsgLevel( QStringLiteral( "creating point cloud layer" ), 2 );
227  options.skipCrsValidation = true;
228  mLayer = std::make_unique< QgsPointCloudLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
229  break;
230  }
231 
235  {
236  // TODO: support display of properties for plugin layers
237  return;
238  }
239  }
240 
241  mAttributeTable->setModel( nullptr );
242  if ( mAttributeTableFilterModel )
243  {
244  // Cleanup
245  mAttributeTableFilterModel->deleteLater();
246  mAttributeTableFilterModel = nullptr;
247  }
248  if ( mLayer && mLayer->isValid() )
249  {
250  bool ok = false;
251  mLayer->loadDefaultMetadata( ok );
252  layerMetadata = mLayer->htmlMetadata();
253 
254  mMapCanvas->setDestinationCrs( mLayer->crs() );
255  mMapCanvas->setLayers( QList< QgsMapLayer * >() << mLayer.get() );
256  mMapCanvas->zoomToFullExtent();
257 
258  if ( mAttributesTab && mLayer->type() != QgsMapLayerType::VectorLayer )
259  {
260  mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
261  mAttributesTab = nullptr;
262  }
263  }
264 
265  const QString myStyle = QgsApplication::reportStyleSheet();
266  mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
267  mMetadataTextBrowser->setHtml( layerMetadata );
268 
269  if ( mNoticeLabel->text().isEmpty() )
270  {
271  mNoticeLabel->hide();
272  }
273 }
274 
275 void QgsBrowserLayerProperties::setCondensedMode( bool )
276 {
277 
278 }
279 
280 void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
281 {
282  const QFileInfo file( url.toLocalFile() );
283  if ( file.exists() && !file.isDir() )
284  QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
285  else
286  QDesktopServices::openUrl( url );
287 }
288 
289 void QgsBrowserLayerProperties::loadAttributeTable()
290 {
291  if ( !mLayer || !mLayer->isValid() || mLayer->type() != QgsMapLayerType::VectorLayer )
292  return;
293 
294  // Initialize the cache
295  QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
296  layerCache->setCacheGeometry( false );
297  QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
298  mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
299  tableModel->setRequest( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setLimit( 100 ) );
300  layerCache->setParent( tableModel );
301  tableModel->setParent( mAttributeTableFilterModel );
302 
303  mAttributeTable->setModel( mAttributeTableFilterModel );
304  tableModel->loadLayer();
305  QFont font = mAttributeTable->font();
306  int fontSize = font.pointSize();
307 #ifdef Q_OS_WIN
308  fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
309 #else
310  fontSize = std::max( fontSize - 2, 6 );
311 #endif
312  font.setPointSize( fontSize );
313  mAttributeTable->setFont( font );
314 
315  // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
316  mAttributeTable->resizeColumnsToContents();
317  mAttributeTable->resizeRowsToContents();
318  mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
319  mAttributeTable->setAlternatingRowColors( true );
320 }
321 
322 QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
323  : QgsBrowserPropertiesWidget( parent )
324 
325 {
326  setupUi( this );
327 
328  mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
329  mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
330 }
331 
332 void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
333 {
334  QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
335  if ( !item )
336  return;
337 
338  mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
339  mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
340  mLayout->addWidget( mDirectoryWidget );
341 }
342 
343 QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
344  : QDialog( parent )
345  , mSettingsSection( settingsSection )
346 {
347  setupUi( this );
349 }
350 
351 void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
352 {
353  if ( !item )
354  return;
355 
356  mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
357  mLayout->addWidget( mPropertiesWidget );
358  setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
359 }
360 
361 
362 //
363 // QgsDockBrowserTreeView
364 //
365 
366 QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
367 {
368  setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
369  setSelectionMode( QAbstractItemView::ExtendedSelection );
370  setContextMenuPolicy( Qt::CustomContextMenu );
371  setHeaderHidden( true );
372  setDropIndicatorShown( true );
373 
374 }
375 
376 void QgsDockBrowserTreeView::setAction( QDropEvent *e )
377 {
378  // if this mime data come from layer tree, the proposed action will be MoveAction
379  // but for browser we really need CopyAction
380  if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
381  e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
382  {
383  e->setDropAction( Qt::CopyAction );
384  }
385 }
386 
387 void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
388 {
389  setAction( e );
390 
391  // accept drag enter so that our widget will not get ignored
392  // and drag events will not get passed to QgisApp
393  e->accept();
394 }
395 
396 void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
397 {
398  // do not accept drops above/below items
399  /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
400  {
401  QgsDebugMsg("drag not on item");
402  e->ignore();
403  return;
404  }*/
405 
406  setAction( e );
407  QTreeView::dragMoveEvent( e );
408  // reset action because QTreeView::dragMoveEvent() accepts proposed action
409  setAction( e );
410 
411  if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
412  {
413  e->ignore();
414  return;
415  }
416 }
417 
418 void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
419 {
420  setAction( e );
421  QTreeView::dropEvent( e );
422  // reset action because QTreeView::dropEvent() accepts proposed action
423  setAction( e );
424 }
425 
426 
@ Layer
Represents a map layer.
@ Custom
Custom item type.
@ 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:174
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:74
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition: qgsgui.cpp:154
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:470
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:107
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:2065
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2064
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:105
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.