QGIS API Documentation  3.24.2-Tisler (13c1a02865)
qgsnewmemorylayerdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsnewmemorylayerdialog.cpp
3  -------------------
4  begin : September 2014
5  copyright : (C) 2014 by Nyall Dawson, Marco Hugentobler
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgsapplication.h"
20 #include "qgis.h"
22 #include "qgsproviderregistry.h"
23 #include "qgsvectordataprovider.h"
24 #include "qgsvectorlayer.h"
25 #include "qgsfield.h"
26 #include "qgsfields.h"
27 #include "qgssettings.h"
28 #include "qgsmemoryproviderutils.h"
29 #include "qgsgui.h"
30 #include "qgsiconutils.h"
31 #include "qgsvariantutils.h"
32 
33 #include <QPushButton>
34 #include <QComboBox>
35 #include <QUuid>
36 #include <QFileDialog>
37 
39 {
40  QgsNewMemoryLayerDialog dialog( parent );
41  dialog.setCrs( defaultCrs );
42  if ( dialog.exec() == QDialog::Rejected )
43  {
44  return nullptr;
45  }
46 
47  const QgsWkbTypes::Type geometrytype = dialog.selectedType();
48  const QgsFields fields = dialog.fields();
49  const QString name = dialog.layerName().isEmpty() ? tr( "New scratch layer" ) : dialog.layerName();
50  QgsVectorLayer *newLayer = QgsMemoryProviderUtils::createMemoryLayer( name, fields, geometrytype, dialog.crs() );
51  return newLayer;
52 }
53 
54 QgsNewMemoryLayerDialog::QgsNewMemoryLayerDialog( QWidget *parent, Qt::WindowFlags fl )
55  : QDialog( parent, fl )
56 {
57  setupUi( this );
59 
60  mNameLineEdit->setText( tr( "New scratch layer" ) );
61 
62  const QgsWkbTypes::Type geomTypes[] =
63  {
75  };
76 
77  for ( const auto type : geomTypes )
78  mGeometryTypeBox->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), type );
79  mGeometryTypeBox->setCurrentIndex( -1 );
80 
81  mGeometryWithZCheckBox->setEnabled( false );
82  mGeometryWithMCheckBox->setEnabled( false );
83  mCrsSelector->setEnabled( false );
84  mCrsSelector->setShowAccuracyWarnings( true );
85 
86  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::String ), QgsVariantUtils::typeToDisplayString( QVariant::String ), "string" );
87  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::Int ), QgsVariantUtils::typeToDisplayString( QVariant::Int ), "integer" );
88  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::Double ), QgsVariantUtils::typeToDisplayString( QVariant::Double ), "double" );
89  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::Bool ), QgsVariantUtils::typeToDisplayString( QVariant::Bool ), "bool" );
90  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::Date ), QgsVariantUtils::typeToDisplayString( QVariant::Date ), "date" );
91  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::Time ), QgsVariantUtils::typeToDisplayString( QVariant::Time ), "time" );
92  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::DateTime ), QgsVariantUtils::typeToDisplayString( QVariant::DateTime ), "datetime" );
93  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::ByteArray ), QgsVariantUtils::typeToDisplayString( QVariant::ByteArray ), "binary" );
94  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::StringList ), QgsVariantUtils::typeToDisplayString( QVariant::StringList ), "stringlist" );
95  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::List, QVariant::Int ), QgsVariantUtils::typeToDisplayString( QVariant::List, QVariant::Int ), "integerlist" );
96  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::List, QVariant::Double ), QgsVariantUtils::typeToDisplayString( QVariant::List, QVariant::Double ), "doublelist" );
97  mTypeBox->addItem( QgsFields::iconForFieldType( QVariant::List, QVariant::LongLong ), QgsVariantUtils::typeToDisplayString( QVariant::List, QVariant::LongLong ), "integer64list" );
98  mTypeBox_currentIndexChanged( 1 );
99 
100  mWidth->setValidator( new QIntValidator( 1, 255, this ) );
101  mPrecision->setValidator( new QIntValidator( 0, 30, this ) );
102 
103  mAddAttributeButton->setEnabled( false );
104  mRemoveAttributeButton->setEnabled( false );
105 
106  mOkButton = mButtonBox->button( QDialogButtonBox::Ok );
107  mOkButton->setEnabled( false );
108 
109  connect( mGeometryTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewMemoryLayerDialog::geometryTypeChanged );
110  connect( mFieldNameEdit, &QLineEdit::textChanged, this, &QgsNewMemoryLayerDialog::fieldNameChanged );
111  connect( mTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewMemoryLayerDialog::mTypeBox_currentIndexChanged );
112  connect( mAttributeView, &QTreeWidget::itemSelectionChanged, this, &QgsNewMemoryLayerDialog::selectionChanged );
113  connect( mAddAttributeButton, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::mAddAttributeButton_clicked );
114  connect( mRemoveAttributeButton, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::mRemoveAttributeButton_clicked );
115  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsNewMemoryLayerDialog::showHelp );
116 }
117 
119 {
121  geomType = static_cast<QgsWkbTypes::Type>
122  ( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
123 
124  if ( geomType != QgsWkbTypes::Unknown && geomType != QgsWkbTypes::NoGeometry )
125  {
126  if ( mGeometryWithZCheckBox->isChecked() )
127  geomType = QgsWkbTypes::addZ( geomType );
128  if ( mGeometryWithMCheckBox->isChecked() )
129  geomType = QgsWkbTypes::addM( geomType );
130  }
131 
132  return geomType;
133 }
134 
135 void QgsNewMemoryLayerDialog::geometryTypeChanged( int )
136 {
137  const QgsWkbTypes::Type geomType = static_cast<QgsWkbTypes::Type>
138  ( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
139 
140  const bool isSpatial = geomType != QgsWkbTypes::NoGeometry;
141  mGeometryWithZCheckBox->setEnabled( isSpatial );
142  mGeometryWithMCheckBox->setEnabled( isSpatial );
143  mCrsSelector->setEnabled( isSpatial );
144 
145  const bool ok = ( !mNameLineEdit->text().isEmpty() && mGeometryTypeBox->currentIndex() != -1 );
146  mOkButton->setEnabled( ok );
147 }
148 
149 void QgsNewMemoryLayerDialog::mTypeBox_currentIndexChanged( int index )
150 {
151  switch ( index )
152  {
153  case 0: // Text data
154  if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 255 )
155  mWidth->setText( QStringLiteral( "255" ) );
156  mPrecision->clear();
157  mPrecision->setEnabled( false );
158  mWidth->setValidator( new QIntValidator( 1, 255, this ) );
159  break;
160  case 1: // Whole number
161  if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 10 )
162  mWidth->setText( QStringLiteral( "10" ) );
163  mPrecision->clear();
164  mPrecision->setEnabled( false );
165  mWidth->setValidator( new QIntValidator( 1, 10, this ) );
166  break;
167  case 2: // Decimal number
168  if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 30 )
169  mWidth->setText( QStringLiteral( "30" ) );
170  if ( mPrecision->text().toInt() < 1 || mPrecision->text().toInt() > 30 )
171  mPrecision->setText( QStringLiteral( "6" ) );
172  mPrecision->setEnabled( true );
173  mWidth->setValidator( new QIntValidator( 1, 20, this ) );
174  break;
175  case 3: // Boolean
176  mWidth->clear();
177  mWidth->setEnabled( false );
178  mPrecision->clear();
179  mPrecision->setEnabled( false );
180  break;
181  case 4: // Date
182  mWidth->clear();
183  mWidth->setEnabled( false );
184  mPrecision->clear();
185  mPrecision->setEnabled( false );
186  break;
187  case 5: // Time
188  mWidth->clear();
189  mWidth->setEnabled( false );
190  mPrecision->clear();
191  mPrecision->setEnabled( false );
192  break;
193  case 6: // Datetime
194  mWidth->clear();
195  mWidth->setEnabled( false );
196  mPrecision->clear();
197  mPrecision->setEnabled( false );
198  break;
199  case 7: // Binary
200  case 8: // Stringlist
201  case 9: // Integerlist
202  case 10: // Doublelist
203  case 11: // Integer64list
204  mWidth->clear();
205  mWidth->setEnabled( false );
206  mPrecision->clear();
207  mPrecision->setEnabled( false );
208  break;
209 
210  default:
211  QgsDebugMsg( QStringLiteral( "unexpected index" ) );
212  break;
213  }
214 }
215 
217 {
218  mCrsSelector->setCrs( crs );
219 }
220 
222 {
223  return mCrsSelector->crs();
224 }
225 
227 {
228  return mNameLineEdit->text();
229 }
230 
231 void QgsNewMemoryLayerDialog::fieldNameChanged( const QString &name )
232 {
233  mAddAttributeButton->setDisabled( name.isEmpty() || ! mAttributeView->findItems( name, Qt::MatchExactly ).isEmpty() );
234 }
235 
236 void QgsNewMemoryLayerDialog::selectionChanged()
237 {
238  mRemoveAttributeButton->setDisabled( mAttributeView->selectedItems().isEmpty() );
239 }
240 
242 {
244 
245  QTreeWidgetItemIterator it( mAttributeView );
246  while ( *it )
247  {
248  const QString name( ( *it )->text( 0 ) );
249  const QString typeName( ( *it )->text( 1 ) );
250  const int width = ( *it )->text( 2 ).toInt();
251  const int precision = ( *it )->text( 3 ).toInt();
252  QVariant::Type fieldType = QVariant::Invalid;
253  QVariant::Type fieldSubType = QVariant::Invalid;
254  if ( typeName == QLatin1String( "string" ) )
255  fieldType = QVariant::String;
256  else if ( typeName == QLatin1String( "integer" ) )
257  fieldType = QVariant::Int;
258  else if ( typeName == QLatin1String( "double" ) )
259  fieldType = QVariant::Double;
260  else if ( typeName == QLatin1String( "bool" ) )
261  fieldType = QVariant::Bool;
262  else if ( typeName == QLatin1String( "date" ) )
263  fieldType = QVariant::Date;
264  else if ( typeName == QLatin1String( "time" ) )
265  fieldType = QVariant::Time;
266  else if ( typeName == QLatin1String( "datetime" ) )
267  fieldType = QVariant::DateTime;
268  else if ( typeName == QLatin1String( "binary" ) )
269  fieldType = QVariant::ByteArray;
270  else if ( typeName == QLatin1String( "stringlist" ) )
271  {
272  fieldType = QVariant::StringList;
273  fieldSubType = QVariant::String;
274  }
275  else if ( typeName == QLatin1String( "integerlist" ) )
276  {
277  fieldType = QVariant::List;
278  fieldSubType = QVariant::Int;
279  }
280  else if ( typeName == QLatin1String( "doublelist" ) )
281  {
282  fieldType = QVariant::List;
283  fieldSubType = QVariant::Double;
284  }
285  else if ( typeName == QLatin1String( "integer64list" ) )
286  {
287  fieldType = QVariant::List;
288  fieldSubType = QVariant::LongLong;
289  }
290 
291  const QgsField field = QgsField( name, fieldType, typeName, width, precision, QString(), fieldSubType );
292  fields.append( field );
293  ++it;
294  }
295 
296  return fields;
297 }
298 
299 void QgsNewMemoryLayerDialog::mAddAttributeButton_clicked()
300 {
301  if ( !mFieldNameEdit->text().isEmpty() )
302  {
303  const QString fieldName = mFieldNameEdit->text();
304  const QString fieldType = mTypeBox->currentData( Qt::UserRole ).toString();
305  const QString width = mWidth->text();
306  const QString precision = mPrecision->text();
307  mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << fieldName << fieldType << width << precision ) );
308 
309  mFieldNameEdit->clear();
310  }
311 }
312 
313 void QgsNewMemoryLayerDialog::mRemoveAttributeButton_clicked()
314 {
315  delete mAttributeView->currentItem();
316 }
317 
318 void QgsNewMemoryLayerDialog::showHelp()
319 {
320  QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-temporary-scratch-layer" ) );
321 }
This class represents a coordinate reference system (CRS).
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
static QIcon iconForFieldType(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid)
Returns an icon corresponding to a field type.
Definition: qgsfields.cpp:294
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:174
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
static QIcon iconForWkbType(QgsWkbTypes::Type type)
Returns the icon for a vector layer whose geometry type is provided.
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, QgsWkbTypes::Type geometryType=QgsWkbTypes::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem()) SIP_FACTORY
Creates a new memory layer using the specified parameters.
QgsWkbTypes::Type selectedType() const
Returns the selected geometry type.
QgsCoordinateReferenceSystem crs() const
Returns the selected CRS for the new layer.
QgsFields fields() const
Returns attributes for the new layer.
QString layerName() const
Returns the layer name.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the crs value for the new layer in the dialog.
static QgsVectorLayer * runAndCreateLayer(QWidget *parent=nullptr, const QgsCoordinateReferenceSystem &defaultCrs=QgsCoordinateReferenceSystem())
Runs the dialog and creates a new memory layer.
QgsNewMemoryLayerDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
New dialog constructor.
static QString typeToDisplayString(QVariant::Type type, QVariant::Type subType=QVariant::Type::Invalid)
Returns a user-friendly translated string representing a QVariant type.
Represents a vector layer which manages a vector based data sets.
static QString translatedDisplayString(Type type) SIP_HOLDGIL
Returns a translated display string type for a WKB type, e.g., the geometry name used in WKT geometry...
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
const QgsField & field
Definition: qgsfield.h:463
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs
const QString & typeName
int precision