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