QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 
18 #include "qgslogger.h"
19 
20 #include <QSettings>
21 #include <QTableWidgetItem>
22 #include <QPushButton>
23 
24 
26  QWidget* parent, const Qt::WindowFlags& fl )
27  : QDialog( parent, fl )
28  , mName( name )
29  , mShowCount( false )
30  , mShowType( false )
31 {
32  setupUi( this );
33 
34  if ( providerType == QgsSublayersDialog::Ogr )
35  {
36  setWindowTitle( tr( "Select vector layers to add..." ) );
37  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
38  << tr( "Number of features" ) << tr( "Geometry type" ) );
39  mShowCount = true;
40  mShowType = true;
41  }
42  else if ( providerType == QgsSublayersDialog::Gdal )
43  {
44  setWindowTitle( tr( "Select raster layers to add..." ) );
45  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" ) );
46  }
47  else
48  {
49  setWindowTitle( tr( "Select layers to add..." ) );
50  layersTable->setHeaderLabels( QStringList() << tr( "Layer ID" ) << tr( "Layer name" )
51  << tr( "Type" ) );
52  mShowType = true;
53  }
54 
55  // add a "Select All" button - would be nicer with an icon
56  QPushButton* button = new QPushButton( tr( "Select All" ) );
57  buttonBox->addButton( button, QDialogButtonBox::ActionRole );
58  connect( button, SIGNAL( pressed() ), layersTable, SLOT( selectAll() ) );
59  // connect( pbnSelectNone, SIGNAL( pressed() ), SLOT( layersTable->selectNone() ) );
60 
61  QSettings settings;
62  restoreGeometry( settings.value( "/Windows/" + mName + "SubLayers/geometry" ).toByteArray() );
63 }
64 
66 {
67  QSettings settings;
68  settings.setValue( "/Windows/" + mName + "SubLayers/geometry", saveGeometry() );
69  settings.setValue( "/Windows/" + mName + "SubLayers/headerState",
70  layersTable->header()->saveState() );
71 }
72 
73 static bool _isLayerIdUnique( int layerId, QTreeWidget* layersTable )
74 {
75  int count = 0;
76  for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
77  {
78  if ( layersTable->topLevelItem( j )->text( 0 ).toInt() == layerId )
79  {
80  count++;
81  }
82  }
83  return count == 1;
84 }
85 
87 {
89  for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
90  {
91  QTreeWidgetItem* item = layersTable->selectedItems().at( i );
92 
93  LayerDefinition def;
94  def.layerId = item->text( 0 ).toInt();
95  def.layerName = item->text( 1 );
96  if ( mShowType )
97  {
98  // If there are more sub layers of the same name (virtual for geometry types),
99  // add geometry type
100  if ( !_isLayerIdUnique( def.layerId, layersTable ) )
101  def.type = item->text( mShowCount ? 3 : 2 );
102  }
103 
104  list << def;
105  }
106  return list;
107 }
108 
109 
111 {
112  Q_FOREACH ( const LayerDefinition& item, list )
113  {
114  QStringList elements;
115  elements << QString::number( item.layerId ) << item.layerName;
116  if ( mShowCount )
117  elements << QString::number( item.count );
118  if ( mShowType )
119  elements << item.type;
120  layersTable->addTopLevelItem( new QTreeWidgetItem( elements ) );
121  }
122 
123  // resize columns
124  QSettings settings;
125  QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
126  if ( ! ba.isNull() )
127  {
128  layersTable->header()->restoreState( ba );
129  }
130  else
131  {
132  for ( int i = 0; i < layersTable->columnCount(); i++ )
133  layersTable->resizeColumnToContents( i );
134  layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
135  }
136 }
137 
138 
140 {
141  QStringList list;
142  for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
143  {
144  // If there are more sub layers of the same name (virtual for geometry types),
145  // add geometry type
146 
147  QString name = layersTable->selectedItems().at( i )->text( 1 );
148  int count = 0;
149  for ( int j = 0; j < layersTable->topLevelItemCount(); j++ )
150  {
151  if ( layersTable->topLevelItem( j )->text( 1 ) == name )
152  {
153  count++;
154  }
155  }
156 
157  if ( count > 1 )
158  {
159  name += ':' + layersTable->selectedItems().at( i )->text( 3 );
160  }
161  else
162  {
163  name += ":any";
164  }
165 
166  list << name;
167  }
168  return list;
169 }
170 
172 {
173  QList<int> list;
174  for ( int i = 0; i < layersTable->selectedItems().size(); i++ )
175  {
176  list << layersTable->selectedItems().at( i )->text( 0 ).toInt();
177  }
178  return list;
179 }
180 
181 void QgsSublayersDialog::populateLayerTable( const QStringList& theList, const QString& delim )
182 {
183  Q_FOREACH ( const QString& item, theList )
184  {
185  QStringList elements = item.split( delim );
186  while ( elements.size() > 4 )
187  {
188  elements[1] += delim + elements[2];
189  elements.removeAt( 2 );
190  }
191  layersTable->addTopLevelItem( new QTreeWidgetItem( elements ) );
192  }
193 
194  // resize columns
195  QSettings settings;
196  QByteArray ba = settings.value( "/Windows/" + mName + "SubLayers/headerState" ).toByteArray();
197  if ( ! ba.isNull() )
198  {
199  layersTable->header()->restoreState( ba );
200  }
201  else
202  {
203  for ( int i = 0; i < layersTable->columnCount(); i++ )
204  layersTable->resizeColumnToContents( i );
205  layersTable->setColumnWidth( 1, layersTable->columnWidth( 1 ) + 10 );
206  }
207 }
208 
209 // override exec() instead of using showEvent()
210 // because in some case we don't want the dialog to appear (depending on user settings)
211 // TODO alert the user when dialog is not opened
213 {
214  QSettings settings;
215  QString promptLayers = settings.value( "/qgis/promptForSublayers", 1 ).toString();
216 
217  // make sure three are sublayers to choose
218  if ( layersTable->topLevelItemCount() == 0 )
219  return QDialog::Rejected;
220 
221  // check promptForSublayers settings - perhaps this should be in QgsDataSource instead?
222  if ( promptLayers == "no" )
223  return QDialog::Rejected;
224  else if ( promptLayers == "all" )
225  {
226  layersTable->selectAll();
227  return QDialog::Accepted;
228  }
229 
230  // if there is only 1 sublayer (probably the main layer), just select that one and return
231  if ( layersTable->topLevelItemCount() == 1 )
232  {
233  layersTable->selectAll();
234  return QDialog::Accepted;
235  }
236 
237  layersTable->sortByColumn( 1, Qt::AscendingOrder );
238  layersTable->setSortingEnabled( true );
239 
240  // if we got here, disable override cursor, open dialog and return result
241  // TODO add override cursor where it is missing (e.g. when opening via "Add Raster")
242  QCursor cursor;
243  bool overrideCursor = nullptr != QApplication::overrideCursor();
244  if ( overrideCursor )
245  {
246  cursor = QCursor( * QApplication::overrideCursor() );
248  }
249  int ret = QDialog::exec();
250  if ( overrideCursor )
252  return ret;
253 }
QByteArray toByteArray() const
QString layerName
name of the layer (not necessarily unique)
int layerId
identifier of the layer (one unique layer id may have multiple types though)
void setupUi(QWidget *widget)
QCursor cursor() const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
const T & at(int i) const
bool isNull() const
void removeAt(int i)
Q_DECL_DEPRECATED QStringList selectionNames()
int exec()
bool mShowType
whether to show type in the table
QString tr(const char *sourceText, const char *disambiguation, int n)
bool mShowCount
whether to show number of features in the table
int size() const
void setValue(const QString &key, const QVariant &value)
const char * name() const
QString number(int n, int base)
int count
number of features (might be unused)
bool restoreGeometry(const QByteArray &geometry)
int toInt(bool *ok, int base) const
void populateLayerTable(const LayerDefinitionList &list)
Populate the table with layers.
QgsSublayersDialog(ProviderType providerType, const QString &name, QWidget *parent=nullptr, const Qt::WindowFlags &fl=nullptr)
void setOverrideCursor(const QCursor &cursor)
void restoreOverrideCursor()
Q_DECL_DEPRECATED QList< int > selectionIndexes()
QString type
extra type depending on the use (e.g. geometry type for vector sublayers)
QVariant value(const QString &key, const QVariant &defaultValue) const
QByteArray saveGeometry() const
LayerDefinitionList selection()
Returns list of selected layers.
const QChar at(int position) const
void setWindowTitle(const QString &)
typedef WindowFlags
QTreeWidgetItem * topLevelItem(int index) const
static bool _isLayerIdUnique(int layerId, QTreeWidget *layersTable)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString toString() const
A structure that defines layers for the purpose of this dialog.
QString text(int column) const
QCursor * overrideCursor()