QGIS API Documentation 3.99.0-Master (d270888f95f)
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 << ( item.count == static_cast<int>( Qgis::FeatureCountState::Uncounted ) || item.count == static_cast<int>( Qgis::FeatureCountState::UnknownCount ) ? tr( "Unknown" ) : QString::number( item.count ) );
153 if ( mShowType )
154 elements << item.type;
155 if ( mShowDescription )
156 elements << item.description;
157 layersTable->addTopLevelItem( new SubLayerItem( elements ) );
158 }
159
160 // resize columns
161 const QgsSettings settings;
162 const QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
163 const int savedColumnCount = settings.value( "/Windows/" + mName + "SubLayers/headerColumnCount" ).toInt();
164 if ( !ba.isNull() && savedColumnCount == layersTable->columnCount() )
165 {
166 layersTable->header()->restoreState( ba );
167 }
168 else
169 {
170 for ( int i = 0; i < layersTable->columnCount(); i++ )
171 layersTable->resizeColumnToContents( i );
172 layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
173 }
174}
175
176// override exec() instead of using showEvent()
177// because in some case we don't want the dialog to appear (depending on user settings)
178// TODO alert the user when dialog is not opened
180{
181 QgsSettings settings;
182 const Qgis::SublayerPromptMode promptLayers = settings.enumValue( u"qgis/promptForSublayers"_s, Qgis::SublayerPromptMode::AlwaysAsk );
183
184 // make sure three are sublayers to choose
185 if ( layersTable->topLevelItemCount() == 0 )
186 return QDialog::Rejected;
187
188 layersTable->selectAll();
189
190 // check promptForSublayers settings - perhaps this should be in QgsDataSource instead?
191 if ( promptLayers == Qgis::SublayerPromptMode::NeverAskSkip )
192 return QDialog::Rejected;
193 else if ( promptLayers == Qgis::SublayerPromptMode::NeverAskLoadAll )
194 return QDialog::Accepted;
195
196 // if there is only 1 sublayer (probably the main layer), just select that one and return
197 if ( layersTable->topLevelItemCount() == 1 )
198 return QDialog::Accepted;
199
200 layersTable->sortByColumn( 1, Qt::AscendingOrder );
201 layersTable->setSortingEnabled( true );
202
203 // if we got here, disable override cursor, open dialog and return result
204 // TODO add override cursor where it is missing (e.g. when opening via "Add Raster")
205 QCursor cursor;
206 const bool overrideCursor = nullptr != QApplication::overrideCursor();
207 if ( overrideCursor )
208 {
209 cursor = QCursor( *QApplication::overrideCursor() );
210 QApplication::restoreOverrideCursor();
211 }
212
213 // Checkbox about adding sublayers to a group
214 if ( mShowAddToGroupCheckbox )
215 {
216 mCbxAddToGroup->setVisible( true );
217 const bool addToGroup = settings.value( u"/qgis/openSublayersInGroup"_s, false ).toBool();
218 mCbxAddToGroup->setChecked( addToGroup );
219 }
220
221 const int ret = QDialog::exec();
222 if ( overrideCursor )
223 QApplication::setOverrideCursor( cursor );
224
225 if ( mShowAddToGroupCheckbox )
226 settings.setValue( u"/qgis/openSublayersInGroup"_s, mCbxAddToGroup->isChecked() );
227 return ret;
228}
229
230void QgsSublayersDialog::layersTable_selectionChanged( const QItemSelection &, const QItemSelection & )
231{
232 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( layersTable->selectedItems().length() > 0 );
233}
234
235void QgsSublayersDialog::mBtnDeselectAll_pressed()
236{
237 layersTable->selectionModel()->clear();
238}
SublayerPromptMode
Specifies how to handle layer sources with multiple sublayers.
Definition qgis.h:1746
@ AlwaysAsk
Always ask users to select from available sublayers, if sublayers are present.
Definition qgis.h:1747
@ NeverAskLoadAll
Never ask users to select sublayers, instead automatically load all available sublayers.
Definition qgis.h:1750
@ NeverAskSkip
Never ask users to select sublayers, instead don't load anything.
Definition qgis.h:1749
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:565
@ UnknownCount
Provider returned an unknown feature count.
Definition qgis.h:566
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:7330
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).