QGIS API Documentation  3.21.0-Master (909859188c)
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::instance()->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 
234  {
235  // TODO: support display of properties for plugin layers
236  return;
237  }
238  }
239 
240  mAttributeTable->setModel( nullptr );
241  if ( mAttributeTableFilterModel )
242  {
243  // Cleanup
244  mAttributeTableFilterModel->deleteLater();
245  mAttributeTableFilterModel = nullptr;
246  }
247  if ( mLayer && mLayer->isValid() )
248  {
249  bool ok = false;
250  mLayer->loadDefaultMetadata( ok );
251  layerMetadata = mLayer->htmlMetadata();
252 
253  mMapCanvas->setDestinationCrs( mLayer->crs() );
254  mMapCanvas->setLayers( QList< QgsMapLayer * >() << mLayer.get() );
255  mMapCanvas->zoomToFullExtent();
256 
257  if ( mAttributesTab && mLayer->type() != QgsMapLayerType::VectorLayer )
258  {
259  mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
260  mAttributesTab = nullptr;
261  }
262  }
263 
264  const QString myStyle = QgsApplication::reportStyleSheet();
265  mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
266  mMetadataTextBrowser->setHtml( layerMetadata );
267 
268  if ( mNoticeLabel->text().isEmpty() )
269  {
270  mNoticeLabel->hide();
271  }
272 }
273 
274 void QgsBrowserLayerProperties::setCondensedMode( bool )
275 {
276 
277 }
278 
279 void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
280 {
281  const QFileInfo file( url.toLocalFile() );
282  if ( file.exists() && !file.isDir() )
283  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
284  else
285  QDesktopServices::openUrl( url );
286 }
287 
288 void QgsBrowserLayerProperties::loadAttributeTable()
289 {
290  if ( !mLayer || !mLayer->isValid() || mLayer->type() != QgsMapLayerType::VectorLayer )
291  return;
292 
293  // Initialize the cache
294  QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
295  layerCache->setCacheGeometry( false );
296  QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
297  mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
298  tableModel->setRequest( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setLimit( 100 ) );
299  layerCache->setParent( tableModel );
300  tableModel->setParent( mAttributeTableFilterModel );
301 
302  mAttributeTable->setModel( mAttributeTableFilterModel );
303  tableModel->loadLayer();
304  QFont font = mAttributeTable->font();
305  int fontSize = font.pointSize();
306 #ifdef Q_OS_WIN
307  fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
308 #else
309  fontSize = std::max( fontSize - 2, 6 );
310 #endif
311  font.setPointSize( fontSize );
312  mAttributeTable->setFont( font );
313 
314  // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
315  mAttributeTable->resizeColumnsToContents();
316  mAttributeTable->resizeRowsToContents();
317  mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
318  mAttributeTable->setAlternatingRowColors( true );
319 }
320 
321 QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
322  : QgsBrowserPropertiesWidget( parent )
323 
324 {
325  setupUi( this );
326 
327  mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
328  mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
329 }
330 
331 void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
332 {
333  QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
334  if ( !item )
335  return;
336 
337  mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
338  mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
339  mLayout->addWidget( mDirectoryWidget );
340 }
341 
342 QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
343  : QDialog( parent )
344  , mSettingsSection( settingsSection )
345 {
346  setupUi( this );
348 }
349 
350 void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
351 {
352  if ( !item )
353  return;
354 
355  mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
356  mLayout->addWidget( mPropertiesWidget );
357  setWindowTitle( item->type() == Qgis::BrowserItemType::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
358 }
359 
360 
361 //
362 // QgsDockBrowserTreeView
363 //
364 
365 QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
366 {
367  setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
368  setSelectionMode( QAbstractItemView::ExtendedSelection );
369  setContextMenuPolicy( Qt::CustomContextMenu );
370  setHeaderHidden( true );
371  setDropIndicatorShown( true );
372 
373 }
374 
375 void QgsDockBrowserTreeView::setAction( QDropEvent *e )
376 {
377  // if this mime data come from layer tree, the proposed action will be MoveAction
378  // but for browser we really need CopyAction
379  if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
380  e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
381  {
382  e->setDropAction( Qt::CopyAction );
383  }
384 }
385 
386 void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
387 {
388  setAction( e );
389 
390  // accept drag enter so that our widget will not get ignored
391  // and drag events will not get passed to QgisApp
392  e->accept();
393 }
394 
395 void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
396 {
397  // do not accept drops above/below items
398  /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
399  {
400  QgsDebugMsg("drag not on item");
401  e->ignore();
402  return;
403  }*/
404 
405  setAction( e );
406  QTreeView::dragMoveEvent( e );
407  // reset action because QTreeView::dragMoveEvent() accepts proposed action
408  setAction( e );
409 
410  if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
411  {
412  e->ignore();
413  return;
414  }
415 }
416 
417 void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
418 {
419  setAction( e );
420  QTreeView::dropEvent( e );
421  // reset action because QTreeView::dropEvent() accepts proposed action
422  setAction( e );
423 }
424 
425 
@ 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 QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:67
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:168
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:73
static QgsDataItemGuiProviderRegistry * dataItemGuiProviderRegistry()
Returns the global data item GUI provider registry, used for tracking providers which affect the brow...
Definition: qgsgui.cpp:153
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:467
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
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:1604
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:1603
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:104
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.