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