QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 
221  {
222  // TODO: support display of properties for plugin layers
223  return;
224  }
225  }
226 
227  mAttributeTable->setModel( nullptr );
228  if ( mAttributeTableFilterModel )
229  {
230  // Cleanup
231  mAttributeTableFilterModel->deleteLater();
232  mAttributeTableFilterModel = nullptr;
233  }
234  if ( mLayer && mLayer->isValid() )
235  {
236  bool ok = false;
237  mLayer->loadDefaultMetadata( ok );
238  layerMetadata = mLayer->htmlMetadata();
239 
240  mMapCanvas->setDestinationCrs( mLayer->crs() );
241  mMapCanvas->setLayers( QList< QgsMapLayer * >() << mLayer.get() );
242  mMapCanvas->zoomToFullExtent();
243 
244  if ( mAttributesTab && mLayer->type() != QgsMapLayerType::VectorLayer )
245  {
246  mTabWidget->removeTab( mTabWidget->indexOf( mAttributesTab ) );
247  mAttributesTab = nullptr;
248  }
249  }
250 
251  QString myStyle = QgsApplication::reportStyleSheet();
252  mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
253  mMetadataTextBrowser->setHtml( layerMetadata );
254 
255  if ( mNoticeLabel->text().isEmpty() )
256  {
257  mNoticeLabel->hide();
258  }
259 }
260 
261 void QgsBrowserLayerProperties::setCondensedMode( bool )
262 {
263 
264 }
265 
266 void QgsBrowserLayerProperties::urlClicked( const QUrl &url )
267 {
268  QFileInfo file( url.toLocalFile() );
269  if ( file.exists() && !file.isDir() )
270  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
271  else
272  QDesktopServices::openUrl( url );
273 }
274 
275 void QgsBrowserLayerProperties::loadAttributeTable()
276 {
277  if ( !mLayer || !mLayer->isValid() || mLayer->type() != QgsMapLayerType::VectorLayer )
278  return;
279 
280  // Initialize the cache
281  QgsVectorLayerCache *layerCache = new QgsVectorLayerCache( qobject_cast< QgsVectorLayer * >( mLayer.get() ), 1000, this );
282  layerCache->setCacheGeometry( false );
283  QgsAttributeTableModel *tableModel = new QgsAttributeTableModel( layerCache, this );
284  mAttributeTableFilterModel = new QgsAttributeTableFilterModel( nullptr, tableModel, this );
285  tableModel->setRequest( QgsFeatureRequest().setFlags( QgsFeatureRequest::NoGeometry ).setLimit( 100 ) );
286  layerCache->setParent( tableModel );
287  tableModel->setParent( mAttributeTableFilterModel );
288 
289  mAttributeTable->setModel( mAttributeTableFilterModel );
290  tableModel->loadLayer();
291  QFont font = mAttributeTable->font();
292  int fontSize = font.pointSize();
293 #ifdef Q_OS_WIN
294  fontSize = std::max( fontSize - 1, 8 ); // bit less on windows, due to poor rendering of small point sizes
295 #else
296  fontSize = std::max( fontSize - 2, 6 );
297 #endif
298  font.setPointSize( fontSize );
299  mAttributeTable->setFont( font );
300 
301  // we can safely do this expensive operation here (unlike in the main attribute table), because at most we have only 100 rows...
302  mAttributeTable->resizeColumnsToContents();
303  mAttributeTable->resizeRowsToContents();
304  mAttributeTable->verticalHeader()->setVisible( false ); // maximize valuable table space
305  mAttributeTable->setAlternatingRowColors( true );
306 }
307 
308 QgsBrowserDirectoryProperties::QgsBrowserDirectoryProperties( QWidget *parent )
309  : QgsBrowserPropertiesWidget( parent )
310 
311 {
312  setupUi( this );
313 
314  mPathLabel = new QgsBrowserPropertiesWrapLabel( QString(), mHeaderWidget );
315  mHeaderGridLayout->addItem( new QWidgetItem( mPathLabel ), 0, 1 );
316 }
317 
318 void QgsBrowserDirectoryProperties::setItem( QgsDataItem *item )
319 {
320  QgsDirectoryItem *directoryItem = qobject_cast<QgsDirectoryItem *>( item );
321  if ( !item )
322  return;
323 
324  mPathLabel->setText( QDir::toNativeSeparators( directoryItem->dirPath() ) );
325  mDirectoryWidget = new QgsDirectoryParamWidget( directoryItem->dirPath(), this );
326  mLayout->addWidget( mDirectoryWidget );
327 }
328 
329 QgsBrowserPropertiesDialog::QgsBrowserPropertiesDialog( const QString &settingsSection, QWidget *parent )
330  : QDialog( parent )
331  , mSettingsSection( settingsSection )
332 {
333  setupUi( this );
335 }
336 
337 void QgsBrowserPropertiesDialog::setItem( QgsDataItem *item, const QgsDataItemGuiContext &context )
338 {
339  if ( !item )
340  return;
341 
342  mPropertiesWidget = QgsBrowserPropertiesWidget::createWidget( item, context, this );
343  mLayout->addWidget( mPropertiesWidget );
344  setWindowTitle( item->type() == QgsDataItem::Layer ? tr( "Layer Properties" ) : tr( "Directory Properties" ) );
345 }
346 
347 
348 //
349 // QgsDockBrowserTreeView
350 //
351 
352 QgsDockBrowserTreeView::QgsDockBrowserTreeView( QWidget *parent ) : QgsBrowserTreeView( parent )
353 {
354  setDragDropMode( QTreeView::DragDrop ); // sets also acceptDrops + dragEnabled
355  setSelectionMode( QAbstractItemView::ExtendedSelection );
356  setContextMenuPolicy( Qt::CustomContextMenu );
357  setHeaderHidden( true );
358  setDropIndicatorShown( true );
359 
360 }
361 
362 void QgsDockBrowserTreeView::setAction( QDropEvent *e )
363 {
364  // if this mime data come from layer tree, the proposed action will be MoveAction
365  // but for browser we really need CopyAction
366  if ( e->mimeData()->hasFormat( QStringLiteral( "application/qgis.layertreemodeldata" ) ) &&
367  e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
368  {
369  e->setDropAction( Qt::CopyAction );
370  }
371 }
372 
373 void QgsDockBrowserTreeView::dragEnterEvent( QDragEnterEvent *e )
374 {
375  setAction( e );
376 
377  // accept drag enter so that our widget will not get ignored
378  // and drag events will not get passed to QgisApp
379  e->accept();
380 }
381 
382 void QgsDockBrowserTreeView::dragMoveEvent( QDragMoveEvent *e )
383 {
384  // do not accept drops above/below items
385  /*if ( dropIndicatorPosition() != QAbstractItemView::OnItem )
386  {
387  QgsDebugMsg("drag not on item");
388  e->ignore();
389  return;
390  }*/
391 
392  setAction( e );
393  QTreeView::dragMoveEvent( e );
394  // reset action because QTreeView::dragMoveEvent() accepts proposed action
395  setAction( e );
396 
397  if ( !e->mimeData()->hasFormat( QStringLiteral( "application/x-vnd.qgis.qgis.uri" ) ) )
398  {
399  e->ignore();
400  return;
401  }
402 }
403 
404 void QgsDockBrowserTreeView::dropEvent( QDropEvent *e )
405 {
406  setAction( e );
407  QTreeView::dropEvent( e );
408  // reset action because QTreeView::dropEvent() accepts proposed action
409  setAction( e );
410 }
411 
412 
QgsLayerItem::mapLayerType
QgsMapLayerType mapLayerType() const
Returns QgsMapLayerType.
Definition: qgsdataitem.cpp:642
QgsFeatureRequest::NoGeometry
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition: qgsfeaturerequest.h:107
qgsdataitemguiproviderregistry.h
QgsDataItemGuiProvider
Definition: qgsdataitemguiprovider.h:84
qgsrasterlayer.h
qgsvectorlayercache.h
qgsbrowsertreeview.h
QgsDataItem::path
QString path() const
Definition: qgsdataitem.h:327
QgsVectorLayerCache
The cached features can be indexed by QgsAbstractCacheIndex.
Definition: qgsvectorlayercache.h:45
QgsBrowserTreeView
Definition: qgsbrowsertreeview.h:32
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:139
QgsMapLayerType
QgsMapLayerType
Definition: qgsmaplayer.h:67
QgsDataItemGuiProviderRegistry::providers
QList< QgsDataItemGuiProvider * > providers() const
Returns the list of available providers.
Definition: qgsdataitemguiproviderregistry.h:51
QgsProject::transformContext
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:99
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsDataItem::name
QString name() const
Returns the name of the item (the displayed text for the item).
Definition: qgsdataitem.h:318
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsDataItem::Directory
@ Directory
Definition: qgsdataitem.h:79
pal
Definition: qgsdiagramrenderer.h:49
QgsMeshLayer::LayerOptions
Setting options for loading mesh layers.
Definition: qgsmeshlayer.h:102
QgsDirectoryItem::dirPath
QString dirPath() const
Returns the full path to the directory the item represents.
Definition: qgsdataitem.h:717
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:133
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:752
QgsDataItem::type
Type type() const
Definition: qgsdataitem.h:299
QgsFeatureRequest
Definition: qgsfeaturerequest.h:75
qgsmaptoolpan.h
QgsDirectoryItem
Definition: qgsdataitem.h:671
QgsAttributeTableModel::setRequest
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
Definition: qgsattributetablemodel.cpp:965
QgsAttributeTableModel
Is able to generate editor widgets for its QModelIndexes as well. Is mostly referred to as "master mo...
Definition: qgsattributetablemodel.h:49
QgsDataItem::paramWidget
virtual Q_DECL_DEPRECATED QWidget * paramWidget()
Returns source widget from data item for QgsBrowserPropertiesWidget.
Definition: qgsdataitem.h:172
QgsMapLayerType::RasterLayer
@ RasterLayer
qgsattributetablefiltermodel.h
QgsMapToolPan
Definition: qgsmaptoolpan.h:32
QgsDataItemGuiContext
Definition: qgsdataitemguiprovider.h:39
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:68
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:118
qgsbrowsermodel.h
QgsAttributeTableFilterModel
Definition: qgsattributetablefiltermodel.h:35
QgsVectorLayer::LayerOptions
Setting options for loading vector layers.
Definition: qgsvectorlayer.h:423
QgsRasterLayer::LayerOptions
Setting options for loading raster layers.
Definition: qgsrasterlayer.h:105
QgsGui::instance
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:62
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:80
QgsLayerItem
Definition: qgsdataitem.h:499
QgsDirectoryParamWidget
Definition: qgsdataitem.h:789
QgsDataItem::Custom
@ Custom
Custom item type.
Definition: qgsdataitem.h:84
QgsLayerItem::providerKey
QString providerKey() const
Returns provider key.
Definition: qgsdataitem.h:547
qgslogger.h
QgsDataItem
Definition: qgsdataitem.h:49
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:751
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:1344
qgsproject.h
QgsMapLayerType::PluginLayer
@ PluginLayer
QgsLayerItem::uri
QString uri() const
Returns layer uri or empty string if layer cannot be created.
Definition: qgsdataitem.h:544