1 /***************************************************************************
2 qgsnewmeshlayerdialog.cpp - QgsNewMeshLayerDialog
3
4 ---------------------
5 begin : 22.6.2021
6 copyright : (C) 2021 by Vincent Cloarec
7 email : vcloarec at gmail dot com
8 ***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16 #include "qgsnewmeshlayerdialog.h"
17
18 #include <QPushButton>
19 #include <QMessageBox>
20
21 #include "qgsprovidermetadata.h"
22 #include "qgsproviderregistry.h"
23 #include "qgsmeshdataprovider.h"
24 #include "qgsproject.h"
25 #include "qgsmeshlayer.h"
26 #include "qgsapplication.h"
27 #include "qgshelp.h"
28 #include "qgsgui.h"
29
30
QgsNewMeshLayerDialog(QWidget * parent,Qt::WindowFlags fl)31 QgsNewMeshLayerDialog::QgsNewMeshLayerDialog( QWidget *parent, Qt::WindowFlags fl ) : QDialog( parent, fl )
32 {
33 QgsProviderMetadata *meta = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
34
35 if ( !meta )
36 {
37 setLayout( new QVBoxLayout );
38 layout()->addWidget( new QLabel( tr( "MDAL not available, unable to create a new mesh layer" ) ) );
39 return;
40 }
41
42 setupUi( this );
43 QgsGui::enableAutoGeometryRestore( this );
44 const QList<QgsMeshDriverMetadata> driverList = meta->meshDriversMetadata();
45
46 for ( const QgsMeshDriverMetadata &driverMeta : driverList )
47 if ( driverMeta.capabilities() & QgsMeshDriverMetadata::CanWriteMeshData )
48 {
49 const QString description = driverMeta.description();
50 const QString driverName = driverMeta.name();
51 const QString suffix = driverMeta.writeMeshFrameOnFileSuffix();
52 mFormatComboBox->addItem( description, driverName );
53 mDriverSuffixes.insert( driverMeta.name(), suffix );
54 mDriverFileFilters.insert( driverMeta.name(), tr( "%1" ).arg( description ) + QStringLiteral( " (*." ) + suffix + ')' );
55 }
56
57 const QStringList filters = mDriverFileFilters.values();
58 mFormatComboBox->setCurrentIndex( -1 );
59 mFileWidget->setStorageMode( QgsFileWidget::SaveFile );
60 mFileWidget->setFilter( filters.join( QLatin1String( ";;" ) ) );
61 mMeshProjectComboBox->setFilters( QgsMapLayerProxyModel::MeshLayer );
62
63 connect( mFormatComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ),
64 this, &QgsNewMeshLayerDialog::onFormatChanged );
65 connect( mFileWidget, &QgsFileWidget::fileChanged, this, &QgsNewMeshLayerDialog::onFilePathChanged );
66 connect( mInitializeMeshGroupBox, &QGroupBox::toggled, this, &QgsNewMeshLayerDialog::updateDialog );
67 connect( mMeshFileRadioButton, &QRadioButton::toggled, this, &QgsNewMeshLayerDialog::updateDialog );
68 connect( mMeshFromFileWidget, &QgsFileWidget::fileChanged, this, &QgsNewMeshLayerDialog::updateDialog );
69 connect( mMeshProjectComboBox, &QgsMapLayerComboBox::layerChanged, this, &QgsNewMeshLayerDialog::updateDialog );
70
71 connect( buttonBox, &QDialogButtonBox::helpRequested, this, [ = ]
72 {
73 QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-mesh-layer" ) );
74 } );
75
76 updateDialog();
77 }
78
setCrs(const QgsCoordinateReferenceSystem & crs)79 void QgsNewMeshLayerDialog::setCrs( const QgsCoordinateReferenceSystem &crs )
80 {
81 mProjectionSelectionWidget->setCrs( crs );
82 }
83
setSourceMeshLayer(QgsMeshLayer * meshLayer,bool fromExistingAsDefault)84 void QgsNewMeshLayerDialog::setSourceMeshLayer( QgsMeshLayer *meshLayer, bool fromExistingAsDefault )
85 {
86 mMeshProjectComboBox->setLayer( meshLayer );
87 mMeshProjectRadioButton->setChecked( true );
88 mInitializeMeshGroupBox->setChecked( fromExistingAsDefault );
89 }
90
accept()91 void QgsNewMeshLayerDialog::accept()
92 {
93 if ( apply() )
94 QDialog::accept();
95 }
96
updateDialog()97 void QgsNewMeshLayerDialog::updateDialog()
98 {
99 updateSourceMeshframe();
100
101 buttonBox->button( QDialogButtonBox::Ok )->setEnabled(
102 ! mFileWidget->filePath().isEmpty() &&
103 mFormatComboBox->currentIndex() != -1 &&
104 mSourceMeshFrameReady );
105 }
106
updateSourceMeshframe()107 void QgsNewMeshLayerDialog::updateSourceMeshframe()
108 {
109 mMeshProjectComboBox->setEnabled( false );
110 mMeshFromFileWidget->setEnabled( false );
111 if ( !mInitializeMeshGroupBox->isChecked() )
112 {
113 mSourceMeshFromFile.reset();
114 mSourceMeshFrameReady = true;
115 mProjectionSelectionWidget->setEnabled( true );
116 }
117 else if ( mMeshProjectRadioButton->isChecked() )
118 {
119 mMeshProjectComboBox->setEnabled( true );
120 mSourceMeshFromFile.reset();
121 mSourceMeshFrameReady = mMeshProjectComboBox->currentLayer() != nullptr;
122 mProjectionSelectionWidget->setEnabled( false );
123 }
124 else if ( mMeshFileRadioButton->isChecked() )
125 {
126 mMeshFromFileWidget->setEnabled( true );
127 if ( !mSourceMeshFromFile || mSourceMeshFromFile->source() != mMeshFromFileWidget->filePath() )
128 {
129 QgsApplication::setOverrideCursor( Qt::WaitCursor );
130 if ( !mMeshFromFileWidget->filePath().isEmpty() )
131 mSourceMeshFromFile.reset( new QgsMeshLayer( mMeshFromFileWidget->filePath(), QString(), QStringLiteral( "mdal" ) ) );
132
133 if ( mSourceMeshFromFile && !mSourceMeshFromFile->isValid() )
134 mSourceMeshFromFile.reset();
135
136 mProjectionSelectionWidget->setEnabled( false );
137
138 mSourceMeshFrameReady = mSourceMeshFromFile != nullptr;
139
140 QgsApplication::restoreOverrideCursor();
141 }
142 }
143 updateSourceMeshInformation();
144 }
145
onFormatChanged()146 void QgsNewMeshLayerDialog::onFormatChanged()
147 {
148 const QString currentDriverName = mFormatComboBox->currentData().toString();
149 if ( currentDriverName.isEmpty() )
150 return;
151
152 const QString currentFilter = mDriverFileFilters.value( currentDriverName );
153 mFileWidget->setSelectedFilter( currentFilter );
154
155 const QString newSuffix = mDriverSuffixes.value( currentDriverName );
156
157 QString currentFilePath = mFileWidget->filePath();
158 if ( currentFilePath.isEmpty() )
159 return;
160 const QFileInfo fileInfo( currentFilePath );
161 const QString currentSuffix = fileInfo.suffix();
162
163 if ( !currentSuffix.isEmpty() )
164 currentFilePath = currentFilePath.mid( 0, currentFilePath.lastIndexOf( '.' ) );
165
166 if ( currentFilePath.right( 1 ) == QString( '.' ) )
167 currentFilePath.remove( currentFilePath.count() - 1, 1 );
168
169 currentFilePath.append( '.' + newSuffix );
170
171 mFileWidget->setFilePath( currentFilePath );
172
173 updateDialog();
174 }
175
onFilePathChanged()176 void QgsNewMeshLayerDialog::onFilePathChanged()
177 {
178 const QFileInfo fileInfo( mFileWidget->filePath() );
179 const QString ¤tSuffix = fileInfo.suffix();
180
181 const QStringList drivers = mDriverSuffixes.keys();
182 for ( const QString &driverName : drivers )
183 {
184 if ( mDriverSuffixes.value( driverName ) == currentSuffix )
185 {
186 whileBlocking( mFormatComboBox )->setCurrentIndex( mFormatComboBox->findData( driverName ) );
187 }
188 }
189
190 updateDialog();
191 }
192
updateSourceMeshInformation()193 void QgsNewMeshLayerDialog::updateSourceMeshInformation()
194 {
195 QString myStyle = QgsApplication::reportStyleSheet();
196 myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
197
198 mInformationTextBrowser->clear();
199 mInformationTextBrowser->document()->setDefaultStyleSheet( myStyle );
200 if ( mInitializeMeshGroupBox->isChecked() )
201 {
202 if ( mMeshProjectRadioButton->isChecked() )
203 {
204 if ( mMeshProjectComboBox->currentLayer() )
205 mInformationTextBrowser->setHtml( mMeshProjectComboBox->currentLayer()->htmlMetadata() );
206 }
207
208 if ( mMeshFileRadioButton->isChecked() )
209 {
210 if ( mSourceMeshFromFile )
211 mInformationTextBrowser->setHtml( mSourceMeshFromFile->htmlMetadata() );
212 }
213
214 mInformationTextBrowser->setOpenLinks( false );
215 }
216 };
217
apply()218 bool QgsNewMeshLayerDialog::apply()
219 {
220 bool result = false;
221 const QString fileName = mFileWidget->filePath();
222 const QString format = mFormatComboBox->currentData().toString();
223
224 QgsMesh mesh;
225 QgsCoordinateReferenceSystem crs;
226
227 QgsMeshLayer *source = nullptr;
228
229 if ( !mInitializeMeshGroupBox->isChecked() )
230 {
231 crs = mProjectionSelectionWidget->crs();
232 }
233 else if ( mMeshProjectRadioButton->isChecked() )
234 {
235 source = qobject_cast<QgsMeshLayer *>( mMeshProjectComboBox->currentLayer() );
236 }
237 else if ( mMeshFromFileWidget )
238 {
239 source = mSourceMeshFromFile.get();
240 }
241
242 if ( source )
243 {
244 crs = source->crs();
245 source->dataProvider()->populateMesh( &mesh );
246 }
247
248 const QgsProviderMetadata *providerMetadata = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "mdal" ) );
249 if ( providerMetadata )
250 {
251 result = providerMetadata->createMeshData( mesh, fileName, format, crs );
252 if ( result )
253 {
254 QString layerName = mLayerNameLineEdit->text();
255 if ( layerName.isEmpty() )
256 {
257 layerName = fileName;
258 QFileInfo fileInfo( fileName );
259 layerName = fileInfo.baseName();
260 }
261 std::unique_ptr<QgsMeshLayer> newMeshLayer = std::make_unique<QgsMeshLayer>( fileName, layerName, QStringLiteral( "mdal" ) );
262
263 if ( newMeshLayer->crs() != crs )
264 newMeshLayer->setCrs( crs );
265
266 if ( newMeshLayer->isValid() )
267 {
268 mNewLayer = newMeshLayer.get();
269 QgsProject::instance()->addMapLayer( newMeshLayer.release(), true, true );
270 return true;
271 }
272 }
273 }
274
275 QMessageBox::warning( this, windowTitle(), tr( "Unable to create a new mesh layer with format \"%1\"" ).arg( mFormatComboBox->currentText() ) );
276 return false;
277 }
278
newLayer() const279 QgsMeshLayer *QgsNewMeshLayerDialog::newLayer() const
280 {
281 return mNewLayer;
282 }
283
284