QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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
QList< QgsSublayersDialog::LayerDefinition > LayerDefinitionList
List of layer definitions for the purpose of this dialog.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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.