QGIS API Documentation  3.25.0-Master (10b47c2603)
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->addItem( QgsFields::iconForFieldType( QVariant::Map ), QgsVariantUtils::typeToDisplayString( QVariant::Map ), "map" );
99  mTypeBox_currentIndexChanged( 1 );
100 
101  mWidth->setValidator( new QIntValidator( 1, 255, this ) );
102  mPrecision->setValidator( new QIntValidator( 0, 30, this ) );
103 
104  mAddAttributeButton->setEnabled( false );
105  mRemoveAttributeButton->setEnabled( false );
106 
107  mOkButton = mButtonBox->button( QDialogButtonBox::Ok );
108  mOkButton->setEnabled( false );
109 
110  connect( mGeometryTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewMemoryLayerDialog::geometryTypeChanged );
111  connect( mFieldNameEdit, &QLineEdit::textChanged, this, &QgsNewMemoryLayerDialog::fieldNameChanged );
112  connect( mTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewMemoryLayerDialog::mTypeBox_currentIndexChanged );
113  connect( mAttributeView, &QTreeWidget::itemSelectionChanged, this, &QgsNewMemoryLayerDialog::selectionChanged );
114  connect( mAddAttributeButton, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::mAddAttributeButton_clicked );
115  connect( mRemoveAttributeButton, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::mRemoveAttributeButton_clicked );
116  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsNewMemoryLayerDialog::showHelp );
117 }
118 
120 {
122  geomType = static_cast<QgsWkbTypes::Type>
123  ( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
124 
125  if ( geomType != QgsWkbTypes::Unknown && geomType != QgsWkbTypes::NoGeometry )
126  {
127  if ( mGeometryWithZCheckBox->isChecked() )
128  geomType = QgsWkbTypes::addZ( geomType );
129  if ( mGeometryWithMCheckBox->isChecked() )
130  geomType = QgsWkbTypes::addM( geomType );
131  }
132 
133  return geomType;
134 }
135 
136 void QgsNewMemoryLayerDialog::geometryTypeChanged( int )
137 {
138  const QgsWkbTypes::Type geomType = static_cast<QgsWkbTypes::Type>
139  ( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
140 
141  const bool isSpatial = geomType != QgsWkbTypes::NoGeometry;
142  mGeometryWithZCheckBox->setEnabled( isSpatial );
143  mGeometryWithMCheckBox->setEnabled( isSpatial );
144  mCrsSelector->setEnabled( isSpatial );
145 
146  const bool ok = ( !mNameLineEdit->text().isEmpty() && mGeometryTypeBox->currentIndex() != -1 );
147  mOkButton->setEnabled( ok );
148 }
149 
150 void QgsNewMemoryLayerDialog::mTypeBox_currentIndexChanged( int index )
151 {
152  switch ( index )
153  {
154  case 0: // Text data
155  if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 255 )
156  mWidth->setText( QStringLiteral( "255" ) );
157  mPrecision->clear();
158  mPrecision->setEnabled( false );
159  mWidth->setValidator( new QIntValidator( 1, 255, this ) );
160  break;
161  case 1: // Whole number
162  if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 10 )
163  mWidth->setText( QStringLiteral( "10" ) );
164  mPrecision->clear();
165  mPrecision->setEnabled( false );
166  mWidth->setValidator( new QIntValidator( 1, 10, this ) );
167  break;
168  case 2: // Decimal number
169  if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 30 )
170  mWidth->setText( QStringLiteral( "30" ) );
171  if ( mPrecision->text().toInt() < 1 || mPrecision->text().toInt() > 30 )
172  mPrecision->setText( QStringLiteral( "6" ) );
173  mPrecision->setEnabled( true );
174  mWidth->setValidator( new QIntValidator( 1, 20, this ) );
175  break;
176  case 3: // Boolean
177  mWidth->clear();
178  mWidth->setEnabled( false );
179  mPrecision->clear();
180  mPrecision->setEnabled( false );
181  break;
182  case 4: // Date
183  mWidth->clear();
184  mWidth->setEnabled( false );
185  mPrecision->clear();
186  mPrecision->setEnabled( false );
187  break;
188  case 5: // Time
189  mWidth->clear();
190  mWidth->setEnabled( false );
191  mPrecision->clear();
192  mPrecision->setEnabled( false );
193  break;
194  case 6: // Datetime
195  mWidth->clear();
196  mWidth->setEnabled( false );
197  mPrecision->clear();
198  mPrecision->setEnabled( false );
199  break;
200  case 7: // Binary
201  case 8: // Stringlist
202  case 9: // Integerlist
203  case 10: // Doublelist
204  case 11: // Integer64list
205  case 12: // Map
206  mWidth->clear();
207  mWidth->setEnabled( false );
208  mPrecision->clear();
209  mPrecision->setEnabled( false );
210  break;
211 
212  default:
213  QgsDebugMsg( QStringLiteral( "unexpected index" ) );
214  break;
215  }
216 }
217 
219 {
220  mCrsSelector->setCrs( crs );
221 }
222 
224 {
225  return mCrsSelector->crs();
226 }
227 
229 {
230  return mNameLineEdit->text();
231 }
232 
233 void QgsNewMemoryLayerDialog::fieldNameChanged( const QString &name )
234 {
235  mAddAttributeButton->setDisabled( name.isEmpty() || ! mAttributeView->findItems( name, Qt::MatchExactly ).isEmpty() );
236 }
237 
238 void QgsNewMemoryLayerDialog::selectionChanged()
239 {
240  mRemoveAttributeButton->setDisabled( mAttributeView->selectedItems().isEmpty() );
241 }
242 
244 {
246 
247  QTreeWidgetItemIterator it( mAttributeView );
248  while ( *it )
249  {
250  const QString name( ( *it )->text( 0 ) );
251  const QString typeName( ( *it )->text( 1 ) );
252  const int width = ( *it )->text( 2 ).toInt();
253  const int precision = ( *it )->text( 3 ).toInt();
254  QVariant::Type fieldType = QVariant::Invalid;
255  QVariant::Type fieldSubType = QVariant::Invalid;
256  if ( typeName == QLatin1String( "string" ) )
257  fieldType = QVariant::String;
258  else if ( typeName == QLatin1String( "integer" ) )
259  fieldType = QVariant::Int;
260  else if ( typeName == QLatin1String( "double" ) )
261  fieldType = QVariant::Double;
262  else if ( typeName == QLatin1String( "bool" ) )
263  fieldType = QVariant::Bool;
264  else if ( typeName == QLatin1String( "date" ) )
265  fieldType = QVariant::Date;
266  else if ( typeName == QLatin1String( "time" ) )
267  fieldType = QVariant::Time;
268  else if ( typeName == QLatin1String( "datetime" ) )
269  fieldType = QVariant::DateTime;
270  else if ( typeName == QLatin1String( "binary" ) )
271  fieldType = QVariant::ByteArray;
272  else if ( typeName == QLatin1String( "stringlist" ) )
273  {
274  fieldType = QVariant::StringList;
275  fieldSubType = QVariant::String;
276  }
277  else if ( typeName == QLatin1String( "integerlist" ) )
278  {
279  fieldType = QVariant::List;
280  fieldSubType = QVariant::Int;
281  }
282  else if ( typeName == QLatin1String( "doublelist" ) )
283  {
284  fieldType = QVariant::List;
285  fieldSubType = QVariant::Double;
286  }
287  else if ( typeName == QLatin1String( "integer64list" ) )
288  {
289  fieldType = QVariant::List;
290  fieldSubType = QVariant::LongLong;
291  }
292  else if ( typeName == QLatin1String( "map" ) )
293  fieldType = QVariant::Map;
294 
295  const QgsField field = QgsField( name, fieldType, typeName, width, precision, QString(), fieldSubType );
296  fields.append( field );
297  ++it;
298  }
299 
300  return fields;
301 }
302 
303 void QgsNewMemoryLayerDialog::mAddAttributeButton_clicked()
304 {
305  if ( !mFieldNameEdit->text().isEmpty() )
306  {
307  const QString fieldName = mFieldNameEdit->text();
308  const QString fieldType = mTypeBox->currentData( Qt::UserRole ).toString();
309  const QString width = mWidth->text();
310  const QString precision = mPrecision->text();
311  mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << fieldName << fieldType << width << precision ) );
312 
313  mFieldNameEdit->clear();
314  }
315 }
316 
317 void QgsNewMemoryLayerDialog::mRemoveAttributeButton_clicked()
318 {
319  delete mAttributeView->currentItem();
320 }
321 
322 void QgsNewMemoryLayerDialog::showHelp()
323 {
324  QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-temporary-scratch-layer" ) );
325 }
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:180
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