QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
21 #include <QTableWidgetItem>
22 #include <QPushButton>
23 
25 class SubLayerItem : public QTreeWidgetItem
26 {
27  public:
28  SubLayerItem( const QStringList &strings, int type = QTreeWidgetItem::Type )
29  : QTreeWidgetItem( strings, type )
30  {}
31 
32  bool operator <( const QTreeWidgetItem &other ) const override
33  {
34  QgsSublayersDialog *d = qobject_cast<QgsSublayersDialog *>( treeWidget()->parent() );
35  int col = treeWidget()->sortColumn();
36 
37  if ( col == 0 || ( col > 0 && d->countColumn() == col ) )
38  return text( col ).toInt() < other.text( col ).toInt();
39  else
40  return text( col ) < other.text( col );
41  }
42 };
44 
45 QgsSublayersDialog::QgsSublayersDialog( ProviderType providerType, const QString &name,
46  QWidget *parent, Qt::WindowFlags fl )
47  : QDialog( parent, fl )
48  , mName( name )
49 {
50  setupUi( this );
52 
53  if ( providerType == QgsSublayersDialog::Ogr )
54  {
55  setWindowTitle( tr( "Select Vector Layers to Add…" ) );
56  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
57  << tr( "Number of features" ) << tr( "Geometry type" ) << tr( "Description" ) );
58  mShowCount = true;
59  mShowType = true;
60  mShowDescription = true;
61  }
62  else if ( providerType == QgsSublayersDialog::Gdal )
63  {
64  setWindowTitle( tr( "Select Raster Layers to Add…" ) );
65  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) );
66  }
67  else
68  {
69  setWindowTitle( tr( "Select Layers to Add…" ) );
70  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
71  << tr( "Type" ) );
72  mShowType = true;
73  }
74 
75  // add a "Select All" button - would be nicer with an icon
76  QPushButton *button = new QPushButton( tr( "Select All" ) );
77  buttonBox->addButton( button, QDialogButtonBox::ActionRole );
78  connect( button, &QAbstractButton::pressed, layersTable, &QTreeView::selectAll );
79  // connect( pbnSelectNone, SIGNAL( pressed() ), SLOT( layersTable->selectNone() ) );
80 
81  // Checkbox about adding sublayers to a group
82  mCheckboxAddToGroup = new QCheckBox( tr( "Add layers to a group" ), this );
83  buttonBox->addButton( mCheckboxAddToGroup, QDialogButtonBox::ActionRole );
84  mCheckboxAddToGroup->setVisible( false );
85 }
86 
88 {
89  QgsSettings settings;
90  settings.setValue( "/Windows/" + mName + "SubLayers/headerColumnCount",
91  layersTable->columnCount() );
92  settings.setValue( "/Windows/" + mName + "SubLayers/headerState",
93  layersTable->header()->saveState() );
94 }
95 
96 static bool _isLayerIdUnique( int layerId, QTreeWidget *layersTable )
97 {
98  int count = 0;
99  for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
100  {
101  if ( layersTable->topLevelItem( j )->text( 0 ).toInt() == layerId )
102  {
103  count++;
104  }
105  }
106  return count == 1;
107 }
108 
110 {
111  LayerDefinitionList list;
112  for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
113  {
114  QTreeWidgetItem *item = layersTable->selectedItems().at( i );
115 
116  LayerDefinition def;
117  def.layerId = item->text( 0 ).toInt();
118  def.layerName = item->text( 1 );
119  if ( mShowType )
120  {
121  // If there are more sub layers of the same name (virtual for geometry types),
122  // add geometry type
123  if ( !_isLayerIdUnique( def.layerId, layersTable ) )
124  def.type = item->text( mShowCount ? 3 : 2 );
125  }
126 
127  list << def;
128  }
129  return list;
130 }
131 
132 
134 {
135  const auto constList = list;
136  for ( const LayerDefinition &item : constList )
137  {
138  QStringList elements;
139  elements << QString::number( item.layerId ) << item.layerName;
140  if ( mShowCount )
141  elements << ( item.count == -1 ? tr( "Unknown" ) : QString::number( item.count ) );
142  if ( mShowType )
143  elements << item.type;
144  if ( mShowDescription )
145  elements << item.description;
146  layersTable->addTopLevelItem( new SubLayerItem( elements ) );
147  }
148 
149  // resize columns
150  QgsSettings settings;
151  QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
152  int savedColumnCount = settings.value( "/Windows/" + mName + "SubLayers/headerColumnCount" ).toInt();
153  if ( ! ba.isNull() && savedColumnCount == layersTable->columnCount() )
154  {
155  layersTable->header()->restoreState( ba );
156  }
157  else
158  {
159  for ( int i = 0; i < layersTable->columnCount(); i++ )
160  layersTable->resizeColumnToContents( i );
161  layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
162  }
163 }
164 
165 // override exec() instead of using showEvent()
166 // because in some case we don't want the dialog to appear (depending on user settings)
167 // TODO alert the user when dialog is not opened
169 {
170  QgsSettings settings;
171  QString promptLayers = settings.value( QStringLiteral( "qgis/promptForSublayers" ), 1 ).toString();
172 
173  // make sure three are sublayers to choose
174  if ( layersTable->topLevelItemCount() == 0 )
175  return QDialog::Rejected;
176 
177  // check promptForSublayers settings - perhaps this should be in QgsDataSource instead?
178  if ( promptLayers == QLatin1String( "no" ) )
179  return QDialog::Rejected;
180  else if ( promptLayers == QLatin1String( "all" ) )
181  {
182  layersTable->selectAll();
183  return QDialog::Accepted;
184  }
185 
186  // if there is only 1 sublayer (probably the main layer), just select that one and return
187  if ( layersTable->topLevelItemCount() == 1 )
188  {
189  layersTable->selectAll();
190  return QDialog::Accepted;
191  }
192 
193  layersTable->sortByColumn( 1, Qt::AscendingOrder );
194  layersTable->setSortingEnabled( true );
195 
196  // if we got here, disable override cursor, open dialog and return result
197  // TODO add override cursor where it is missing (e.g. when opening via "Add Raster")
198  QCursor cursor;
199  bool overrideCursor = nullptr != QApplication::overrideCursor();
200  if ( overrideCursor )
201  {
202  cursor = QCursor( * QApplication::overrideCursor() );
203  QApplication::restoreOverrideCursor();
204  }
205 
206  // Checkbox about adding sublayers to a group
207  if ( mShowAddToGroupCheckbox )
208  {
209  mCheckboxAddToGroup->setVisible( true );
210  bool addToGroup = settings.value( QStringLiteral( "/qgis/openSublayersInGroup" ), false ).toBool();
211  mCheckboxAddToGroup->setChecked( addToGroup );
212  }
213 
214  int ret = QDialog::exec();
215  if ( overrideCursor )
216  QApplication::setOverrideCursor( cursor );
217 
218  if ( mShowAddToGroupCheckbox )
219  settings.setValue( QStringLiteral( "/qgis/openSublayersInGroup" ), mCheckboxAddToGroup->isChecked() );
220  return ret;
221 }
QString layerName
Name of the layer (not necessarily unique)
int layerId
Identifier of the layer (one unique layer id may have multiple types though)
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
QList< QgsSublayersDialog::LayerDefinition > LayerDefinitionList
List of layer definitions for the purpose of this dialog.
bool mShowType
Whether to show type in the table.
bool mShowCount
Whether to show number of features in the table.
void populateLayerTable(const LayerDefinitionList &list)
Populate the table with layers.
QString type
Extra type depending on the use (e.g. geometry type for vector sublayers)
QgsSublayersDialog(ProviderType providerType, const QString &name, QWidget *parent=nullptr, Qt::WindowFlags fl=nullptr)
Constructor for QgsSublayersDialog.
int countColumn() const
Returns column with count or -1.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
LayerDefinitionList selection()
Returns list of selected layers.
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:127
bool mShowDescription
Whether to show description in the table.
A structure that defines layers for the purpose of this dialog.