QGIS API Documentation  3.13.0-Master (788156190c)
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 }
QgsSublayersDialog::mShowType
bool mShowType
Whether to show type in the table.
Definition: qgssublayersdialog.h:111
QgsSublayersDialog::QgsSublayersDialog
QgsSublayersDialog(ProviderType providerType, const QString &name, QWidget *parent=nullptr, Qt::WindowFlags fl=nullptr)
Constructor for QgsSublayersDialog.
Definition: qgssublayersdialog.cpp:45
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsSublayersDialog::mShowCount
bool mShowCount
Whether to show number of features in the table.
Definition: qgssublayersdialog.h:110
qgsgui.h
QgsSettings
Definition: qgssettings.h:61
QgsSublayersDialog::exec
int exec() override
Definition: qgssublayersdialog.cpp:168
QgsSublayersDialog::ProviderType
ProviderType
Definition: qgssublayersdialog.h:34
QgsSublayersDialog::LayerDefinition::layerName
QString layerName
Name of the layer (not necessarily unique)
Definition: qgssublayersdialog.h:48
QgsSublayersDialog::populateLayerTable
void populateLayerTable(const LayerDefinitionList &list)
Populate the table with layers.
Definition: qgssublayersdialog.cpp:133
QgsSublayersDialog::mName
QString mName
Definition: qgssublayersdialog.h:108
QgsSublayersDialog::Ogr
@ Ogr
Definition: qgssublayersdialog.h:36
QgsGui::enableAutoGeometryRestore
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:133
QgsSublayersDialog::mShowDescription
bool mShowDescription
Whether to show description in the table.
Definition: qgssublayersdialog.h:112
QgsSublayersDialog::countColumn
int countColumn() const
Returns column with count or -1.
Definition: qgssublayersdialog.h:102
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:289
QgsSublayersDialog::selection
LayerDefinitionList selection()
Returns list of selected layers.
Definition: qgssublayersdialog.cpp:109
QgsSublayersDialog
Definition: qgssublayersdialog.h:29
QgsSublayersDialog::LayerDefinitionList
QList< QgsSublayersDialog::LayerDefinition > LayerDefinitionList
List of layer definitions for the purpose of this dialog.
Definition: qgssublayersdialog.h:58
qgssublayersdialog.h
qgssettings.h
QgsSublayersDialog::LayerDefinition::type
QString type
Extra type depending on the use (e.g. geometry type for vector sublayers)
Definition: qgssublayersdialog.h:50
QgsSublayersDialog::LayerDefinition::layerId
int layerId
Identifier of the layer (one unique layer id may have multiple types though)
Definition: qgssublayersdialog.h:47
QgsSublayersDialog::Gdal
@ Gdal
Definition: qgssublayersdialog.h:37
qgslogger.h
QgsSublayersDialog::~QgsSublayersDialog
~QgsSublayersDialog() override
Definition: qgssublayersdialog.cpp:87
QgsSublayersDialog::LayerDefinition
A structure that defines layers for the purpose of this dialog.
Definition: qgssublayersdialog.h:45