QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
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
20#include "qgis.h"
22#include "qgsfield.h"
23#include "qgsfields.h"
24#include "qgsgui.h"
25#include "qgsiconutils.h"
27#include "qgsvariantutils.h"
28#include "qgsvectorlayer.h"
29
30#include <QComboBox>
31#include <QFileDialog>
32#include <QMessageBox>
33#include <QPushButton>
34#include <QString>
35#include <QUuid>
36
37#include "moc_qgsnewmemorylayerdialog.cpp"
38
39using namespace Qt::StringLiterals;
40
42{
43 QgsNewMemoryLayerDialog dialog( parent );
44 dialog.setCrs( defaultCrs );
45 if ( dialog.exec() == QDialog::Rejected )
46 {
47 return nullptr;
48 }
49
50 const Qgis::WkbType geometrytype = dialog.selectedType();
51 const QgsFields fields = dialog.fields();
52 const QString name = dialog.layerName().isEmpty() ? tr( "New scratch layer" ) : dialog.layerName();
53 QgsVectorLayer *newLayer = QgsMemoryProviderUtils::createMemoryLayer( name, fields, geometrytype, dialog.crs() );
54 return newLayer;
55}
56
57QgsNewMemoryLayerDialog::QgsNewMemoryLayerDialog( QWidget *parent, Qt::WindowFlags fl )
58 : QDialog( parent, fl )
59{
60 setupUi( this );
62
63 mNameLineEdit->setText( tr( "New scratch layer" ) );
64
65 const Qgis::WkbType geomTypes[] = {
80 };
81
82 for ( const auto type : geomTypes )
83 mGeometryTypeBox->addItem( QgsIconUtils::iconForWkbType( type ), QgsWkbTypes::translatedDisplayString( type ), static_cast<quint32>( type ) );
84 mGeometryTypeBox->setCurrentIndex( -1 );
85
86 mGeometryWithZCheckBox->setEnabled( false );
87 mGeometryWithMCheckBox->setEnabled( false );
88 mCrsSelector->setEnabled( false );
89 mCrsSelector->setShowAccuracyWarnings( true );
90
91 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QString ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QString ), "string" );
92 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::Int ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::Int ), "integer" );
93 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::Double ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::Double ), "double" );
94 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::Bool ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::Bool ), "bool" );
95 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QDate ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QDate ), "date" );
96 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QTime ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QTime ), "time" );
97 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QDateTime ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QDateTime ), "datetime" );
98 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QByteArray ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QByteArray ), "binary" );
99 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QStringList ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QStringList ), "stringlist" );
100 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QVariantList, QMetaType::Type::Int ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantList, QMetaType::Type::Int ), "integerlist" );
101 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QVariantList, QMetaType::Type::Double ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantList, QMetaType::Type::Double ), "doublelist" );
102 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QVariantList, QMetaType::Type::LongLong ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantList, QMetaType::Type::LongLong ), "integer64list" );
103 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::QVariantMap ), QgsVariantUtils::typeToDisplayString( QMetaType::Type::QVariantMap ), "map" );
104 mTypeBox->addItem( QgsFields::iconForFieldType( QMetaType::Type::User, QMetaType::Type::UnknownType, u"geometry"_s ), tr( "Geometry" ), "geometry" );
105 mTypeBox_currentIndexChanged( 0 );
106
107 mWidth->setValidator( new QIntValidator( 1, 255, this ) );
108 mPrecision->setValidator( new QIntValidator( 0, 30, this ) );
109
110 mAddAttributeButton->setEnabled( false );
111 mRemoveAttributeButton->setEnabled( false );
112 mButtonUp->setEnabled( false );
113 mButtonDown->setEnabled( false );
114
115 mOkButton = mButtonBox->button( QDialogButtonBox::Ok );
116 mOkButton->setEnabled( false );
117
118 connect( mGeometryTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewMemoryLayerDialog::geometryTypeChanged );
119 connect( mFieldNameEdit, &QLineEdit::textChanged, this, &QgsNewMemoryLayerDialog::fieldNameChanged );
120 connect( mTypeBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsNewMemoryLayerDialog::mTypeBox_currentIndexChanged );
121 connect( mAttributeView, &QTreeWidget::itemSelectionChanged, this, &QgsNewMemoryLayerDialog::selectionChanged );
122 connect( mAddAttributeButton, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::mAddAttributeButton_clicked );
123 connect( mRemoveAttributeButton, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::mRemoveAttributeButton_clicked );
124 connect( mButtonUp, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::moveFieldsUp );
125 connect( mButtonDown, &QToolButton::clicked, this, &QgsNewMemoryLayerDialog::moveFieldsDown );
126
127 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsNewMemoryLayerDialog::showHelp );
128 connect( mButtonBox, &QDialogButtonBox::accepted, this, &QgsNewMemoryLayerDialog::accept );
129 connect( mButtonBox, &QDialogButtonBox::rejected, this, &QgsNewMemoryLayerDialog::reject );
130
131 mNameLineEdit->selectAll();
132 mNameLineEdit->setFocus();
133}
134
136{
138 geomType = static_cast<Qgis::WkbType>( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
139
140 if ( geomType != Qgis::WkbType::Unknown && geomType != Qgis::WkbType::NoGeometry )
141 {
142 if ( mGeometryWithZCheckBox->isChecked() )
143 geomType = QgsWkbTypes::addZ( geomType );
144 if ( mGeometryWithMCheckBox->isChecked() )
145 geomType = QgsWkbTypes::addM( geomType );
146 }
147
148 return geomType;
149}
150
151void QgsNewMemoryLayerDialog::geometryTypeChanged( int )
152{
153 const Qgis::WkbType geomType = static_cast<Qgis::WkbType>( mGeometryTypeBox->currentData( Qt::UserRole ).toInt() );
154
155 const bool isSpatial = geomType != Qgis::WkbType::NoGeometry;
156 mGeometryWithZCheckBox->setEnabled( isSpatial );
157 mGeometryWithMCheckBox->setEnabled( isSpatial );
158 mCrsSelector->setEnabled( isSpatial );
159
160 const bool ok = ( !mNameLineEdit->text().isEmpty() && mGeometryTypeBox->currentIndex() != -1 );
161 mOkButton->setEnabled( ok );
162}
163
164void QgsNewMemoryLayerDialog::mTypeBox_currentIndexChanged( int )
165{
166 const QString fieldType = mTypeBox->currentData().toString();
167 if ( fieldType == "string"_L1 )
168 {
169 if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 255 )
170 mWidth->setText( u"255"_s );
171 mPrecision->clear();
172 mPrecision->setEnabled( false );
173 mWidth->setValidator( new QIntValidator( 1, 255, this ) );
174 mWidth->setEnabled( true );
175 }
176 else if ( fieldType == "integer"_L1 )
177 {
178 if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 10 )
179 mWidth->setText( u"10"_s );
180 mPrecision->clear();
181 mPrecision->setEnabled( false );
182 mWidth->setValidator( new QIntValidator( 1, 10, this ) );
183 mWidth->setEnabled( true );
184 }
185 else if ( fieldType == "double"_L1 )
186 {
187 if ( mWidth->text().toInt() < 1 || mWidth->text().toInt() > 30 )
188 mWidth->setText( u"30"_s );
189 if ( mPrecision->text().toInt() < 1 || mPrecision->text().toInt() > 30 )
190 mPrecision->setText( u"6"_s );
191 mPrecision->setEnabled( true );
192 mWidth->setValidator( new QIntValidator( 1, 20, this ) );
193 mWidth->setEnabled( true );
194 }
195 else if ( fieldType == "bool"_L1 )
196 {
197 mWidth->clear();
198 mWidth->setEnabled( false );
199 mPrecision->clear();
200 mPrecision->setEnabled( false );
201 }
202 else if ( fieldType == "date"_L1 )
203 {
204 mWidth->clear();
205 mWidth->setEnabled( false );
206 mPrecision->clear();
207 mPrecision->setEnabled( false );
208 }
209 else if ( fieldType == "time"_L1 )
210 {
211 mWidth->clear();
212 mWidth->setEnabled( false );
213 mPrecision->clear();
214 mPrecision->setEnabled( false );
215 }
216 else if ( fieldType == "datetime"_L1 )
217 {
218 mWidth->clear();
219 mWidth->setEnabled( false );
220 mPrecision->clear();
221 mPrecision->setEnabled( false );
222 }
223 else if ( fieldType == u"binary"_s
224 || fieldType == u"stringlist"_s
225 || fieldType == u"integerlist"_s
226 || fieldType == u"doublelist"_s
227 || fieldType == u"integer64list"_s
228 || fieldType == u"map"_s
229 || fieldType == "geometry"_L1 )
230 {
231 mWidth->clear();
232 mWidth->setEnabled( false );
233 mPrecision->clear();
234 mPrecision->setEnabled( false );
235 }
236 else
237 {
238 QgsDebugError( u"unexpected index"_s );
239 }
240}
241
243{
244 mCrsSelector->setCrs( crs );
245}
246
248{
249 return mCrsSelector->crs();
250}
251
253{
254 return mNameLineEdit->text();
255}
256
257void QgsNewMemoryLayerDialog::fieldNameChanged( const QString &name )
258{
259 mAddAttributeButton->setDisabled( name.isEmpty() || !mAttributeView->findItems( name, Qt::MatchExactly ).isEmpty() );
260}
261
262void QgsNewMemoryLayerDialog::selectionChanged()
263{
264 mRemoveAttributeButton->setDisabled( mAttributeView->selectedItems().isEmpty() );
265 mButtonUp->setDisabled( mAttributeView->selectedItems().isEmpty() );
266 mButtonDown->setDisabled( mAttributeView->selectedItems().isEmpty() );
267}
268
270{
272
273 QTreeWidgetItemIterator it( mAttributeView );
274 while ( *it )
275 {
276 const QString name( ( *it )->text( 0 ) );
277 const QString typeName( ( *it )->text( 1 ) );
278 const int width = ( *it )->text( 2 ).toInt();
279 const int precision = ( *it )->text( 3 ).toInt();
280 QMetaType::Type fieldType = QMetaType::Type::UnknownType;
281 QMetaType::Type fieldSubType = QMetaType::Type::UnknownType;
282 if ( typeName == "string"_L1 )
283 fieldType = QMetaType::Type::QString;
284 else if ( typeName == "integer"_L1 )
285 fieldType = QMetaType::Type::Int;
286 else if ( typeName == "double"_L1 )
287 fieldType = QMetaType::Type::Double;
288 else if ( typeName == "bool"_L1 )
289 fieldType = QMetaType::Type::Bool;
290 else if ( typeName == "date"_L1 )
291 fieldType = QMetaType::Type::QDate;
292 else if ( typeName == "time"_L1 )
293 fieldType = QMetaType::Type::QTime;
294 else if ( typeName == "datetime"_L1 )
295 fieldType = QMetaType::Type::QDateTime;
296 else if ( typeName == "binary"_L1 )
297 fieldType = QMetaType::Type::QByteArray;
298 else if ( typeName == "stringlist"_L1 )
299 {
300 fieldType = QMetaType::Type::QStringList;
301 fieldSubType = QMetaType::Type::QString;
302 }
303 else if ( typeName == "integerlist"_L1 )
304 {
305 fieldType = QMetaType::Type::QVariantList;
306 fieldSubType = QMetaType::Type::Int;
307 }
308 else if ( typeName == "doublelist"_L1 )
309 {
310 fieldType = QMetaType::Type::QVariantList;
311 fieldSubType = QMetaType::Type::Double;
312 }
313 else if ( typeName == "integer64list"_L1 )
314 {
315 fieldType = QMetaType::Type::QVariantList;
316 fieldSubType = QMetaType::Type::LongLong;
317 }
318 else if ( typeName == "map"_L1 )
319 fieldType = QMetaType::Type::QVariantMap;
320 else if ( typeName == "geometry"_L1 )
321 fieldType = QMetaType::Type::User;
322
323 const QgsField field = QgsField( name, fieldType, typeName, width, precision, QString(), fieldSubType );
324 fields.append( field );
325 ++it;
326 }
327
328 return fields;
329}
330
332{
333 if ( !mFieldNameEdit->text().trimmed().isEmpty() )
334 {
335 const QString currentFieldName = mFieldNameEdit->text();
336 if ( fields().lookupField( currentFieldName ) == -1 )
337 {
338 if ( QMessageBox::question( this, tr( "New Temporary Scratch Layer" ), tr( "The field “%1” has not been added to the fields list. Are you sure you want to proceed and discard this field?" ).arg( currentFieldName ), QMessageBox::Ok | QMessageBox::Cancel ) != QMessageBox::Ok )
339 {
340 return;
341 }
342 }
343 }
344
345 QDialog::accept();
346}
347
348void QgsNewMemoryLayerDialog::mAddAttributeButton_clicked()
349{
350 if ( !mFieldNameEdit->text().isEmpty() )
351 {
352 const QString fieldName = mFieldNameEdit->text();
353 const QString fieldType = mTypeBox->currentData( Qt::UserRole ).toString();
354 const QString width = mWidth->text();
355 const QString precision = mPrecision->text();
356 mAttributeView->addTopLevelItem( new QTreeWidgetItem( QStringList() << fieldName << fieldType << width << precision ) );
357
358 mFieldNameEdit->clear();
359
360 if ( !mFieldNameEdit->hasFocus() )
361 {
362 mFieldNameEdit->setFocus();
363 }
364 }
365}
366
367void QgsNewMemoryLayerDialog::mRemoveAttributeButton_clicked()
368{
369 delete mAttributeView->currentItem();
370}
371
372void QgsNewMemoryLayerDialog::showHelp()
373{
374 QgsHelp::openHelp( u"managing_data_source/create_layers.html#creating-a-new-temporary-scratch-layer"_s );
375}
376
377void QgsNewMemoryLayerDialog::moveFieldsUp()
378{
379 int currentRow = mAttributeView->currentIndex().row();
380 if ( currentRow == 0 )
381 return;
382
383 mAttributeView->insertTopLevelItem( currentRow - 1, mAttributeView->takeTopLevelItem( currentRow ) );
384 mAttributeView->setCurrentIndex( mAttributeView->model()->index( currentRow - 1, 0 ) );
385}
386
387void QgsNewMemoryLayerDialog::moveFieldsDown()
388{
389 int currentRow = mAttributeView->currentIndex().row();
390 if ( currentRow == mAttributeView->topLevelItemCount() - 1 )
391 return;
392
393 mAttributeView->insertTopLevelItem( currentRow + 1, mAttributeView->takeTopLevelItem( currentRow ) );
394 mAttributeView->setCurrentIndex( mAttributeView->model()->index( currentRow + 1, 0 ) );
395}
WkbType
The WKB type describes the number of dimensions a geometry has.
Definition qgis.h:280
@ CompoundCurve
CompoundCurve.
Definition qgis.h:291
@ Point
Point.
Definition qgis.h:282
@ LineString
LineString.
Definition qgis.h:283
@ TIN
TIN.
Definition qgis.h:296
@ MultiPoint
MultiPoint.
Definition qgis.h:286
@ Polygon
Polygon.
Definition qgis.h:284
@ MultiPolygon
MultiPolygon.
Definition qgis.h:288
@ Triangle
Triangle.
Definition qgis.h:285
@ NoGeometry
No geometry.
Definition qgis.h:298
@ MultiLineString
MultiLineString.
Definition qgis.h:287
@ Unknown
Unknown.
Definition qgis.h:281
@ MultiCurve
MultiCurve.
Definition qgis.h:293
@ CurvePolygon
CurvePolygon.
Definition qgis.h:292
@ PolyhedralSurface
PolyhedralSurface.
Definition qgis.h:295
@ MultiSurface
MultiSurface.
Definition qgis.h:294
Represents a coordinate reference system (CRS).
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
Container of fields for a vector layer.
Definition qgsfields.h:46
static QIcon iconForFieldType(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType, const QString &typeString=QString())
Returns an icon corresponding to a field type.
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:224
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
static QIcon iconForWkbType(Qgis::WkbType type)
Returns the icon for a vector layer whose geometry type is provided.
static QgsVectorLayer * createMemoryLayer(const QString &name, const QgsFields &fields, Qgis::WkbType geometryType=Qgis::WkbType::NoGeometry, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), bool loadDefaultStyle=true) SIP_FACTORY
Creates a new memory layer using the specified parameters.
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.
Qgis::WkbType selectedType() const
Returns the selected geometry type.
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(QMetaType::Type type, QMetaType::Type subType=QMetaType::Type::UnknownType)
Returns a user-friendly translated string representing a QVariant type.
Represents a vector layer which manages a vector based dataset.
static Q_INVOKABLE QString translatedDisplayString(Qgis::WkbType type)
Returns a translated display string type for a WKB type, e.g., the geometry name used in WKT geometry...
static Qgis::WkbType addM(Qgis::WkbType type)
Adds the m dimension to a WKB type and returns the new type.
static Qgis::WkbType addZ(Qgis::WkbType type)
Adds the z dimension to a WKB type and returns the new type.
#define QgsDebugError(str)
Definition qgslogger.h:59