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