QGIS API Documentation 3.99.0-Master (2fe06baccd8)
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 <QTableWidgetItem>
25
26#include "moc_qgssublayersdialog.cpp"
27
29class SubLayerItem : public QTreeWidgetItem
30{
31 public:
32 SubLayerItem( const QStringList &strings, int type = QTreeWidgetItem::Type )
33 : QTreeWidgetItem( strings, type )
34 {}
35
36 bool operator<( const QTreeWidgetItem &other ) const override
37 {
38 QgsSublayersDialog *d = qobject_cast<QgsSublayersDialog *>( treeWidget()->parent() );
39 const int col = treeWidget()->sortColumn();
40
41 if ( col == 0 || ( col > 0 && d->countColumn() == col ) )
42 return text( col ).toInt() < other.text( col ).toInt();
43 else
44 return text( col ) < other.text( col );
45 }
46};
48
49QgsSublayersDialog::QgsSublayersDialog( ProviderType providerType, const QString &name, QWidget *parent, Qt::WindowFlags fl, const QString &dataSourceUri )
50 : QDialog( parent, fl )
51 , mName( name )
52{
53 setupUi( this );
55
56 QString title;
57 switch ( providerType )
58 {
60 title = tr( "Select Vector Layers to Add…" );
61 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) << tr( "Number of features" ) << tr( "Geometry type" ) << tr( "Description" ) );
62 mShowCount = true;
63 mShowType = true;
64 mShowDescription = true;
65 break;
67 title = tr( "Select Raster Layers to Add…" );
68 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) );
69 break;
71 title = tr( "Select Mesh Layers to Add…" );
72 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Mesh name" ) );
73 break;
74 default:
75 title = tr( "Select Layers to Add…" );
76 layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) << tr( "Type" ) );
77 mShowType = true;
78 }
79
80 const QVariantMap dataSourceUriParsed = QgsProviderRegistry::instance()->decodeUri( name, dataSourceUri );
81 const QString dataSourceFilePath = dataSourceUriParsed.value( QStringLiteral( "path" ) ).toString();
82 const QString filePath = dataSourceFilePath.isEmpty() ? dataSourceUri : dataSourceFilePath;
83 const QString fileName = QFileInfo( filePath ).fileName();
84
85 setWindowTitle( fileName.isEmpty() ? title : QStringLiteral( "%1 | %2" ).arg( title, fileName ) );
86 mLblFilePath->setText( QDir::toNativeSeparators( QFileInfo( filePath ).canonicalFilePath() ) );
87 mLblFilePath->setVisible( !fileName.isEmpty() );
88
89 // add a "Select All" button - would be nicer with an icon
90 connect( mBtnSelectAll, &QAbstractButton::pressed, layersTable, &QTreeView::selectAll );
91 connect( mBtnDeselectAll, &QAbstractButton::pressed, this, &QgsSublayersDialog::mBtnDeselectAll_pressed );
92 connect( layersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsSublayersDialog::layersTable_selectionChanged );
93
94 mCbxAddToGroup->setVisible( false );
95}
96
98{
99 QgsSettings settings;
100 settings.setValue( "/Windows/" + mName + "SubLayers/headerColumnCount", layersTable->columnCount() );
101 settings.setValue( "/Windows/" + mName + "SubLayers/headerState", layersTable->header()->saveState() );
102}
103
104static bool _isLayerIdUnique( int layerId, QTreeWidget *layersTable )
105{
106 int count = 0;
107 for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
108 {
109 if ( layersTable->topLevelItem( j )->text( 0 ).toInt() == layerId )
110 {
111 count++;
112 }
113 }
114 return count == 1;
115}
116
118{
120 for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
121 {
122 QTreeWidgetItem *item = layersTable->selectedItems().at( i );
123
124 LayerDefinition def;
125 def.layerId = item->text( 0 ).toInt();
126 def.layerName = item->text( 1 );
127 if ( mShowType )
128 {
129 // If there are more sub layers of the same name (virtual for geometry types),
130 // add geometry type
131 if ( !_isLayerIdUnique( def.layerId, layersTable ) )
132 def.type = item->text( mShowCount ? 3 : 2 );
133 }
134
135 list << def;
136 }
137 return list;
138}
139
140
142{
143 const auto constList = list;
144 for ( const LayerDefinition &item : constList )
145 {
146 QStringList elements;
147 elements << QString::number( item.layerId ) << item.layerName;
148 if ( mShowCount )
149 elements << ( item.count == static_cast<int>( Qgis::FeatureCountState::Uncounted ) || item.count == static_cast<int>( Qgis::FeatureCountState::UnknownCount ) ? tr( "Unknown" ) : QString::number( item.count ) );
150 if ( mShowType )
151 elements << item.type;
152 if ( mShowDescription )
153 elements << item.description;
154 layersTable->addTopLevelItem( new SubLayerItem( elements ) );
155 }
156
157 // resize columns
158 const QgsSettings settings;
159 const QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
160 const int savedColumnCount = settings.value( "/Windows/" + mName + "SubLayers/headerColumnCount" ).toInt();
161 if ( !ba.isNull() && savedColumnCount == layersTable->columnCount() )
162 {
163 layersTable->header()->restoreState( ba );
164 }
165 else
166 {
167 for ( int i = 0; i < layersTable->columnCount(); i++ )
168 layersTable->resizeColumnToContents( i );
169 layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
170 }
171}
172
173// override exec() instead of using showEvent()
174// because in some case we don't want the dialog to appear (depending on user settings)
175// TODO alert the user when dialog is not opened
177{
178 QgsSettings settings;
179 const Qgis::SublayerPromptMode promptLayers = settings.enumValue( QStringLiteral( "qgis/promptForSublayers" ), Qgis::SublayerPromptMode::AlwaysAsk );
180
181 // make sure three are sublayers to choose
182 if ( layersTable->topLevelItemCount() == 0 )
183 return QDialog::Rejected;
184
185 layersTable->selectAll();
186
187 // check promptForSublayers settings - perhaps this should be in QgsDataSource instead?
188 if ( promptLayers == Qgis::SublayerPromptMode::NeverAskSkip )
189 return QDialog::Rejected;
190 else if ( promptLayers == Qgis::SublayerPromptMode::NeverAskLoadAll )
191 return QDialog::Accepted;
192
193 // if there is only 1 sublayer (probably the main layer), just select that one and return
194 if ( layersTable->topLevelItemCount() == 1 )
195 return QDialog::Accepted;
196
197 layersTable->sortByColumn( 1, Qt::AscendingOrder );
198 layersTable->setSortingEnabled( true );
199
200 // if we got here, disable override cursor, open dialog and return result
201 // TODO add override cursor where it is missing (e.g. when opening via "Add Raster")
202 QCursor cursor;
203 const bool overrideCursor = nullptr != QApplication::overrideCursor();
204 if ( overrideCursor )
205 {
206 cursor = QCursor( *QApplication::overrideCursor() );
207 QApplication::restoreOverrideCursor();
208 }
209
210 // Checkbox about adding sublayers to a group
211 if ( mShowAddToGroupCheckbox )
212 {
213 mCbxAddToGroup->setVisible( true );
214 const bool addToGroup = settings.value( QStringLiteral( "/qgis/openSublayersInGroup" ), false ).toBool();
215 mCbxAddToGroup->setChecked( addToGroup );
216 }
217
218 const int ret = QDialog::exec();
219 if ( overrideCursor )
220 QApplication::setOverrideCursor( cursor );
221
222 if ( mShowAddToGroupCheckbox )
223 settings.setValue( QStringLiteral( "/qgis/openSublayersInGroup" ), mCbxAddToGroup->isChecked() );
224 return ret;
225}
226
227void QgsSublayersDialog::layersTable_selectionChanged( const QItemSelection &, const QItemSelection & )
228{
229 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( layersTable->selectedItems().length() > 0 );
230}
231
232void QgsSublayersDialog::mBtnDeselectAll_pressed()
233{
234 layersTable->selectionModel()->clear();
235}
SublayerPromptMode
Specifies how to handle layer sources with multiple sublayers.
Definition qgis.h:1688
@ AlwaysAsk
Always ask users to select from available sublayers, if sublayers are present.
Definition qgis.h:1689
@ NeverAskLoadAll
Never ask users to select sublayers, instead automatically load all available sublayers.
Definition qgis.h:1692
@ NeverAskSkip
Never ask users to select sublayers, instead don't load anything.
Definition qgis.h:1691
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:221
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:65
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:546
@ UnknownCount
Provider returned an unknown feature count.
Definition qgis.h:547
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:7039
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).