QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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" ) );
58  mShowCount = true;
59  mShowType = true;
60  }
61  else if ( providerType == QgsSublayersDialog::Gdal )
62  {
63  setWindowTitle( tr( "Select Raster Layers to Add…" ) );
64  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) );
65  }
66  else
67  {
68  setWindowTitle( tr( "Select Layers to Add…" ) );
69  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
70  << tr( "Type" ) );
71  mShowType = true;
72  }
73 
74  // add a "Select All" button - would be nicer with an icon
75  QPushButton *button = new QPushButton( tr( "Select All" ) );
76  buttonBox->addButton( button, QDialogButtonBox::ActionRole );
77  connect( button, &QAbstractButton::pressed, layersTable, &QTreeView::selectAll );
78  // connect( pbnSelectNone, SIGNAL( pressed() ), SLOT( layersTable->selectNone() ) );
79 
80  // Checkbox about adding sublayers to a group
81  mCheckboxAddToGroup = new QCheckBox( tr( "Add layers to a group" ), this );
82  buttonBox->addButton( mCheckboxAddToGroup, QDialogButtonBox::ActionRole );
83  mCheckboxAddToGroup->setVisible( false );
84 }
85 
87 {
88  QgsSettings settings;
89  settings.setValue( "/Windows/" + mName + "SubLayers/headerState",
90  layersTable->header()->saveState() );
91 }
92 
93 static bool _isLayerIdUnique( int layerId, QTreeWidget *layersTable )
94 {
95  int count = 0;
96  for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
97  {
98  if ( layersTable->topLevelItem( j )->text( 0 ).toInt() == layerId )
99  {
100  count++;
101  }
102  }
103  return count == 1;
104 }
105 
107 {
108  LayerDefinitionList list;
109  for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
110  {
111  QTreeWidgetItem *item = layersTable->selectedItems().at( i );
112 
113  LayerDefinition def;
114  def.layerId = item->text( 0 ).toInt();
115  def.layerName = item->text( 1 );
116  if ( mShowType )
117  {
118  // If there are more sub layers of the same name (virtual for geometry types),
119  // add geometry type
120  if ( !_isLayerIdUnique( def.layerId, layersTable ) )
121  def.type = item->text( mShowCount ? 3 : 2 );
122  }
123 
124  list << def;
125  }
126  return list;
127 }
128 
129 
131 {
132  const auto constList = list;
133  for ( const LayerDefinition &item : constList )
134  {
135  QStringList elements;
136  elements << QString::number( item.layerId ) << item.layerName;
137  if ( mShowCount )
138  elements << ( item.count == -1 ? tr( "Unknown" ) : QString::number( item.count ) );
139  if ( mShowType )
140  elements << item.type;
141  layersTable->addTopLevelItem( new SubLayerItem( elements ) );
142  }
143 
144  // resize columns
145  QgsSettings settings;
146  QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
147  if ( ! ba.isNull() )
148  {
149  layersTable->header()->restoreState( ba );
150  }
151  else
152  {
153  for ( int i = 0; i < layersTable->columnCount(); i++ )
154  layersTable->resizeColumnToContents( i );
155  layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
156  }
157 }
158 
159 // override exec() instead of using showEvent()
160 // because in some case we don't want the dialog to appear (depending on user settings)
161 // TODO alert the user when dialog is not opened
163 {
164  QgsSettings settings;
165  QString promptLayers = settings.value( QStringLiteral( "qgis/promptForSublayers" ), 1 ).toString();
166 
167  // make sure three are sublayers to choose
168  if ( layersTable->topLevelItemCount() == 0 )
169  return QDialog::Rejected;
170 
171  // check promptForSublayers settings - perhaps this should be in QgsDataSource instead?
172  if ( promptLayers == QLatin1String( "no" ) )
173  return QDialog::Rejected;
174  else if ( promptLayers == QLatin1String( "all" ) )
175  {
176  layersTable->selectAll();
177  return QDialog::Accepted;
178  }
179 
180  // if there is only 1 sublayer (probably the main layer), just select that one and return
181  if ( layersTable->topLevelItemCount() == 1 )
182  {
183  layersTable->selectAll();
184  return QDialog::Accepted;
185  }
186 
187  layersTable->sortByColumn( 1, Qt::AscendingOrder );
188  layersTable->setSortingEnabled( true );
189 
190  // if we got here, disable override cursor, open dialog and return result
191  // TODO add override cursor where it is missing (e.g. when opening via "Add Raster")
192  QCursor cursor;
193  bool overrideCursor = nullptr != QApplication::overrideCursor();
194  if ( overrideCursor )
195  {
196  cursor = QCursor( * QApplication::overrideCursor() );
197  QApplication::restoreOverrideCursor();
198  }
199 
200  // Checkbox about adding sublayers to a group
201  if ( mShowAddToGroupCheckbox )
202  {
203  mCheckboxAddToGroup->setVisible( true );
204  bool addToGroup = settings.value( QStringLiteral( "/qgis/openSublayersInGroup" ), false ).toBool();
205  mCheckboxAddToGroup->setChecked( addToGroup );
206  }
207 
208  int ret = QDialog::exec();
209  if ( overrideCursor )
210  QApplication::setOverrideCursor( cursor );
211 
212  if ( mShowAddToGroupCheckbox )
213  settings.setValue( QStringLiteral( "/qgis/openSublayersInGroup" ), mCheckboxAddToGroup->isChecked() );
214  return ret;
215 }
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:104
A structure that defines layers for the purpose of this dialog.