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