QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgssublayersdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssublayersdialog.cpp - dialog for selecting sublayers
3  ---------------------
4  begin : January 2009
5  copyright : (C) 2009 by Florian El Ahdab
6  email : felahdab at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgssublayersdialog.h"
17 #include "qgslogger.h"
18 #include "qgssettings.h"
19 #include "qgsgui.h"
20 #include "qgsproviderregistry.h"
21 
22 #include <QTableWidgetItem>
23 #include <QPushButton>
24 
26 class SubLayerItem : public QTreeWidgetItem
27 {
28  public:
29  SubLayerItem( const QStringList &strings, int type = QTreeWidgetItem::Type )
30  : QTreeWidgetItem( strings, type )
31  {}
32 
33  bool operator <( const QTreeWidgetItem &other ) const override
34  {
35  QgsSublayersDialog *d = qobject_cast<QgsSublayersDialog *>( treeWidget()->parent() );
36  int col = treeWidget()->sortColumn();
37 
38  if ( col == 0 || ( col > 0 && d->countColumn() == col ) )
39  return text( col ).toInt() < other.text( col ).toInt();
40  else
41  return text( col ) < other.text( col );
42  }
43 };
45 
47  const QString &name,
48  QWidget *parent,
49  Qt::WindowFlags fl,
50  const QString &dataSourceUri )
51  : QDialog( parent, fl )
52  , mName( name )
53 {
54  setupUi( this );
56 
57  QString title;
58  switch ( providerType )
59  {
61  title = tr( "Select Vector Layers to Add…" );
62  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
63  << tr( "Number of features" ) << tr( "Geometry type" ) << tr( "Description" ) );
64  mShowCount = true;
65  mShowType = true;
66  mShowDescription = true;
67  break;
69  title = tr( "Select Raster Layers to Add…" );
70  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) );
71  break;
73  title = tr( "Select Mesh Layers to Add…" );
74  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Mesh name" ) );
75  break;
76  default:
77  title = tr( "Select Layers to Add…" );
78  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
79  << tr( "Type" ) );
80  mShowType = true;
81  }
82 
83  const QVariantMap dataSourceUriParsed = QgsProviderRegistry::instance()->decodeUri( name, dataSourceUri );
84  const QString dataSourceFilePath = dataSourceUriParsed.value( QStringLiteral( "path" ) ).toString();
85  const QString filePath = dataSourceFilePath.isEmpty() ? dataSourceUri : dataSourceFilePath;
86  const QString fileName = QFileInfo( filePath ).fileName();
87 
88  setWindowTitle( fileName.isEmpty() ? title : QStringLiteral( "%1 | %2" ).arg( title, fileName ) );
89  mLblFilePath->setText( QDir::toNativeSeparators( QFileInfo( filePath ).canonicalFilePath() ) );
90  mLblFilePath->setVisible( ! fileName.isEmpty() );
91 
92  // add a "Select All" button - would be nicer with an icon
93  connect( mBtnSelectAll, &QAbstractButton::pressed, layersTable, &QTreeView::selectAll );
94  connect( mBtnDeselectAll, &QAbstractButton::pressed, this, &QgsSublayersDialog::mBtnDeselectAll_pressed );
95  connect( layersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsSublayersDialog::layersTable_selectionChanged );
96 
97  mCbxAddToGroup->setVisible( false );
98 }
99 
101 {
102  QgsSettings settings;
103  settings.setValue( "/Windows/" + mName + "SubLayers/headerColumnCount",
104  layersTable->columnCount() );
105  settings.setValue( "/Windows/" + mName + "SubLayers/headerState",
106  layersTable->header()->saveState() );
107 }
108 
109 static bool _isLayerIdUnique( int layerId, QTreeWidget *layersTable )
110 {
111  int count = 0;
112  for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
113  {
114  if ( layersTable->topLevelItem( j )->text( 0 ).toInt() == layerId )
115  {
116  count++;
117  }
118  }
119  return count == 1;
120 }
121 
123 {
124  LayerDefinitionList list;
125  for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
126  {
127  QTreeWidgetItem *item = layersTable->selectedItems().at( i );
128 
129  LayerDefinition def;
130  def.layerId = item->text( 0 ).toInt();
131  def.layerName = item->text( 1 );
132  if ( mShowType )
133  {
134  // If there are more sub layers of the same name (virtual for geometry types),
135  // add geometry type
136  if ( !_isLayerIdUnique( def.layerId, layersTable ) )
137  def.type = item->text( mShowCount ? 3 : 2 );
138  }
139 
140  list << def;
141  }
142  return list;
143 }
144 
145 
147 {
148  const auto constList = list;
149  for ( const LayerDefinition &item : constList )
150  {
151  QStringList elements;
152  elements << QString::number( item.layerId ) << item.layerName;
153  if ( mShowCount )
154  elements << ( item.count == -1 ? tr( "Unknown" ) : QString::number( item.count ) );
155  if ( mShowType )
156  elements << item.type;
157  if ( mShowDescription )
158  elements << item.description;
159  layersTable->addTopLevelItem( new SubLayerItem( elements ) );
160  }
161 
162  // resize columns
163  QgsSettings settings;
164  QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
165  int savedColumnCount = settings.value( "/Windows/" + mName + "SubLayers/headerColumnCount" ).toInt();
166  if ( ! ba.isNull() && savedColumnCount == layersTable->columnCount() )
167  {
168  layersTable->header()->restoreState( ba );
169  }
170  else
171  {
172  for ( int i = 0; i < layersTable->columnCount(); i++ )
173  layersTable->resizeColumnToContents( i );
174  layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
175  }
176 }
177 
178 // override exec() instead of using showEvent()
179 // because in some case we don't want the dialog to appear (depending on user settings)
180 // TODO alert the user when dialog is not opened
182 {
183  QgsSettings settings;
184  PromptMode promptLayers = settings.enumValue( QStringLiteral( "qgis/promptForSublayers" ), PromptAlways );
185 
186  // make sure three are sublayers to choose
187  if ( layersTable->topLevelItemCount() == 0 )
188  return QDialog::Rejected;
189 
190  layersTable->selectAll();
191 
192  // check promptForSublayers settings - perhaps this should be in QgsDataSource instead?
193  if ( promptLayers == PromptNever )
194  return QDialog::Rejected;
195  else if ( promptLayers == PromptLoadAll )
196  return QDialog::Accepted;
197 
198  // if there is only 1 sublayer (probably the main layer), just select that one and return
199  if ( layersTable->topLevelItemCount() == 1 )
200  return QDialog::Accepted;
201 
202  layersTable->sortByColumn( 1, Qt::AscendingOrder );
203  layersTable->setSortingEnabled( true );
204 
205  // if we got here, disable override cursor, open dialog and return result
206  // TODO add override cursor where it is missing (e.g. when opening via "Add Raster")
207  QCursor cursor;
208  bool overrideCursor = nullptr != QApplication::overrideCursor();
209  if ( overrideCursor )
210  {
211  cursor = QCursor( * QApplication::overrideCursor() );
212  QApplication::restoreOverrideCursor();
213  }
214 
215  // Checkbox about adding sublayers to a group
216  if ( mShowAddToGroupCheckbox )
217  {
218  mCbxAddToGroup->setVisible( true );
219  bool addToGroup = settings.value( QStringLiteral( "/qgis/openSublayersInGroup" ), false ).toBool();
220  mCbxAddToGroup->setChecked( addToGroup );
221  }
222 
223  int ret = QDialog::exec();
224  if ( overrideCursor )
225  QApplication::setOverrideCursor( cursor );
226 
227  if ( mShowAddToGroupCheckbox )
228  settings.setValue( QStringLiteral( "/qgis/openSublayersInGroup" ), mCbxAddToGroup->isChecked() );
229  return ret;
230 }
231 
232 void QgsSublayersDialog::layersTable_selectionChanged( const QItemSelection &, const QItemSelection & )
233 {
234  buttonBox->button( QDialogButtonBox::Ok )->setEnabled( layersTable->selectedItems().length() > 0 );
235 }
236 
237 void QgsSublayersDialog::mBtnDeselectAll_pressed()
238 {
239  layersTable->selectionModel()->clear();
240 }
QgsSublayersDialog::mShowType
bool mShowType
Whether to show type in the table.
Definition: qgssublayersdialog.h:160
QgsSublayersDialog::PromptNever
@ PromptNever
never prompt, will not load anything
Definition: qgssublayersdialog.h:54
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsSublayersDialog::mShowCount
bool mShowCount
Whether to show number of features in the table.
Definition: qgssublayersdialog.h:159
QgsSublayersDialog::PromptMode
PromptMode
Prompt behavior of the QgsSublayersDialog.
Definition: qgssublayersdialog.h:39
qgsgui.h
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsSublayersDialog::PromptAlways
@ PromptAlways
always ask if there are existing sublayers
Definition: qgssublayersdialog.h:44
QgsSublayersDialog::exec
int exec() override
Definition: qgssublayersdialog.cpp:181
QgsSublayersDialog::ProviderType
ProviderType
Definition: qgssublayersdialog.h:64
QgsSublayersDialog::LayerDefinition::layerName
QString layerName
Name of the layer (not necessarily unique)
Definition: qgssublayersdialog.h:78
QgsSublayersDialog::populateLayerTable
void populateLayerTable(const LayerDefinitionList &list)
Populate the table with layers.
Definition: qgssublayersdialog.cpp:146
QgsSublayersDialog::mName
QString mName
Provider type name.
Definition: qgssublayersdialog.h:157
QgsSublayersDialog::Ogr
@ Ogr
Definition: qgssublayersdialog.h:65
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
qgsproviderregistry.h
QgsSublayersDialog::mShowDescription
bool mShowDescription
Whether to show description in the table.
Definition: qgssublayersdialog.h:161
QgsSublayersDialog::countColumn
int countColumn() const
Returns column with count or -1.
Definition: qgssublayersdialog.h:143
QgsProviderRegistry::decodeUri
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
Definition: qgsproviderregistry.cpp:433
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsSublayersDialog::selection
LayerDefinitionList selection()
Returns list of selected layers.
Definition: qgssublayersdialog.cpp:122
QgsSublayersDialog::Mdal
@ Mdal
Definition: qgssublayersdialog.h:68
QgsSublayersDialog
Definition: qgssublayersdialog.h:30
QgsSublayersDialog::LayerDefinitionList
QList< QgsSublayersDialog::LayerDefinition > LayerDefinitionList
List of layer definitions for the purpose of this dialog.
Definition: qgssublayersdialog.h:88
qgssublayersdialog.h
qgssettings.h
QgsSublayersDialog::LayerDefinition::type
QString type
Extra type depending on the use (e.g. geometry type for vector sublayers)
Definition: qgssublayersdialog.h:80
QgsSublayersDialog::QgsSublayersDialog
QgsSublayersDialog(ProviderType providerType, const QString &name, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags(), const QString &dataSourceUri=QString())
Constructor for QgsSublayersDialog.
Definition: qgssublayersdialog.cpp:46
QgsSublayersDialog::PromptLoadAll
@ PromptLoadAll
never prompt, but load all sublayers
Definition: qgssublayersdialog.h:59
QgsSublayersDialog::LayerDefinition::layerId
int layerId
Identifier of the layer (one unique layer id may have multiple types though)
Definition: qgssublayersdialog.h:77
QgsSublayersDialog::Gdal
@ Gdal
Definition: qgssublayersdialog.h:66
QgsSettings::enumValue
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
Definition: qgssettings.h:252
qgslogger.h
QgsProviderRegistry::instance
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Definition: qgsproviderregistry.cpp:48
QgsSublayersDialog::~QgsSublayersDialog
~QgsSublayersDialog() override
Definition: qgssublayersdialog.cpp:100
QgsSublayersDialog::LayerDefinition
A structure that defines layers for the purpose of this dialog.
Definition: qgssublayersdialog.h:76