QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
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
18#include "qgsgui.h"
19#include "qgslogger.h"
20#include "qgsproviderregistry.h"
21#include "qgssettings.h"
22
23#include <QPushButton>
24#include <QString>
25#include <QTableWidgetItem>
26
27#include "moc_qgssublayersdialog.cpp"
28
29using namespace Qt::StringLiterals;
30
32class SubLayerItem : public QTreeWidgetItem
33{
34 public:
35 SubLayerItem( const QStringList &strings, int type = QTreeWidgetItem::Type )
36 : QTreeWidgetItem( strings, type )
37 {}
38
39 bool operator<( const QTreeWidgetItem &other ) const override
40 {
41 QgsSublayersDialog *d = qobject_cast<QgsSublayersDialog *>( treeWidget()->parent() );
42 const int col = treeWidget()->sortColumn();
43
44 if ( col == 0 || ( col > 0 && d->countColumn() == col ) )
45 return text( col ).toInt() < other.text( col ).toInt();
46 else
47 return text( col ) < other.text( col );
48 }
49};
51
52QgsSublayersDialog::QgsSublayersDialog( ProviderType providerType, const QString &name, QWidget *parent, Qt::WindowFlags fl, const QString &dataSourceUri )
53 : QDialog( parent, fl )
54 , mName( name )
55{
56 setupUi( this );
58
59 QString title;
60 switch ( providerType )
61 {
63 title = tr( "Select Vector Layers to Add…" );
64 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) << tr( "Number of features" ) << tr( "Geometry type" ) << tr( "Description" ) );
65 mShowCount = true;
66 mShowType = true;
67 mShowDescription = true;
68 break;
70 title = tr( "Select Raster Layers to Add…" );
71 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) );
72 break;
74 title = tr( "Select Mesh Layers to Add…" );
75 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Mesh name" ) );
76 break;
77 default:
78 title = tr( "Select Layers to Add…" );
79 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) << tr( "Type" ) );
80 mShowType = true;
81 }
82
83 const QVariantMap dataSourceUriParsed = QgsProviderRegistry::instance()->decodeUri( name, dataSourceUri );
84 const QString dataSourceFilePath = dataSourceUriParsed.value( u"path"_s ).toString();
85 const QString filePath = dataSourceFilePath.isEmpty() ? dataSourceUri : dataSourceFilePath;
86 const QString fileName = QFileInfo( filePath ).fileName();
87
88 setWindowTitle( fileName.isEmpty() ? title : u"%1 | %2"_s.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", layersTable->columnCount() );
104 settings.setValue( "/Windows/" + mName + "SubLayers/headerState", layersTable->header()->saveState() );
105}
106
107static bool _isLayerIdUnique( int layerId, QTreeWidget *layersTable )
108{
109 int count = 0;
110 for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
111 {
112 if ( layersTable->topLevelItem( j )->text( 0 ).toInt() == layerId )
113 {
114 count++;
115 }
116 }
117 return count == 1;
118}
119
121{
123 for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
124 {
125 QTreeWidgetItem *item = layersTable->selectedItems().at( i );
126
127 LayerDefinition def;
128 def.layerId = item->text( 0 ).toInt();
129 def.layerName = item->text( 1 );
130 if ( mShowType )
131 {
132 // If there are more sub layers of the same name (virtual for geometry types),
133 // add geometry type
134 if ( !_isLayerIdUnique( def.layerId, layersTable ) )
135 def.type = item->text( mShowCount ? 3 : 2 );
136 }
137
138 list << def;
139 }
140 return list;
141}
142
143
145{
146 const auto constList = list;
147 for ( const LayerDefinition &item : constList )
148 {
149 QStringList elements;
150 elements << QString::number( item.layerId ) << item.layerName;
151 if ( mShowCount )
152 elements
153 << ( item.count == static_cast<int>( Qgis::FeatureCountState::Uncounted ) || item.count == static_cast<int>( Qgis::FeatureCountState::UnknownCount ) ? tr( "Unknown" )
154 : 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 const QgsSettings settings;
164 const QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
165 const 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 const Qgis::SublayerPromptMode promptLayers = settings.enumValue( u"qgis/promptForSublayers"_s, Qgis::SublayerPromptMode::AlwaysAsk );
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 == Qgis::SublayerPromptMode::NeverAskSkip )
194 return QDialog::Rejected;
195 else if ( promptLayers == Qgis::SublayerPromptMode::NeverAskLoadAll )
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 const 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 const bool addToGroup = settings.value( u"/qgis/openSublayersInGroup"_s, false ).toBool();
220 mCbxAddToGroup->setChecked( addToGroup );
221 }
222
223 const int ret = QDialog::exec();
224 if ( overrideCursor )
225 QApplication::setOverrideCursor( cursor );
226
227 if ( mShowAddToGroupCheckbox )
228 settings.setValue( u"/qgis/openSublayersInGroup"_s, mCbxAddToGroup->isChecked() );
229 return ret;
230}
231
232void QgsSublayersDialog::layersTable_selectionChanged( const QItemSelection &, const QItemSelection & )
233{
234 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( layersTable->selectedItems().length() > 0 );
235}
236
237void QgsSublayersDialog::mBtnDeselectAll_pressed()
238{
239 layersTable->selectionModel()->clear();
240}
SublayerPromptMode
Specifies how to handle layer sources with multiple sublayers.
Definition qgis.h:1767
@ AlwaysAsk
Always ask users to select from available sublayers, if sublayers are present.
Definition qgis.h:1768
@ NeverAskLoadAll
Never ask users to select sublayers, instead automatically load all available sublayers.
Definition qgis.h:1771
@ NeverAskSkip
Never ask users to select sublayers, instead don't load anything.
Definition qgis.h:1770
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:224
QVariantMap decodeUri(const QString &providerKey, const QString &uri)
Breaks a provider data source URI into its component paths (e.g.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
Stores settings for use within QGIS.
Definition qgssettings.h:68
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
bool mShowType
Whether to show type in the table.
QList< QgsSublayersDialog::LayerDefinition > LayerDefinitionList
List of layer definitions for the purpose of this dialog.
Q_DECL_DEPRECATED QgsSublayersDialog(ProviderType providerType, const QString &name, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags(), const QString &dataSourceUri=QString())
Constructor for QgsSublayersDialog.
LayerDefinitionList selection()
Returns list of selected layers.
bool mShowCount
Whether to show number of features in the table.
bool mShowDescription
Whether to show description in the table.
void populateLayerTable(const LayerDefinitionList &list)
Populate the table with layers.
int countColumn() const
Returns column with count or -1.
QString mName
Provider type name.
@ Uncounted
Feature count not yet computed.
Definition qgis.h:572
@ UnknownCount
Provider returned an unknown feature count.
Definition qgis.h:573
bool operator<(const QVariant &v1, const QVariant &v2)
Compares two QVariant values and returns whether the first is less than the second.
Definition qgis.h:7396
A structure that defines layers for the purpose of this dialog.
QString layerName
Name of the layer (not necessarily unique).
QString type
Extra type depending on the use (e.g. geometry type for vector sublayers).
int layerId
Identifier of the layer (one unique layer id may have multiple types though).