File indexing completed on 2024-05-05 07:49:27
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2014 Calin Cruceru <crucerucalincristian@gmail.com> 0004 // SPDX-FileCopyrightText: 2015 Ilya Kowalewski <illya.kovalevskyy@gmail.com> 0005 // 0006 0007 // self 0008 #include "EditPlacemarkDialog.h" 0009 #include "ui_EditPlacemarkDialog.h" 0010 #include "ui_ElevationWidget.h" 0011 0012 // Qt 0013 #include <QMessageBox> 0014 #include <QFileInfo> 0015 #include <QColorDialog> 0016 #include <QCheckBox> 0017 0018 // Marble 0019 #include "GeoDataStyle.h" 0020 #include "GeoDataIconStyle.h" 0021 #include "GeoDataLabelStyle.h" 0022 #include "GeoDataPlacemark.h" 0023 #include "MarbleWidget.h" 0024 #include "MarbleLocale.h" 0025 #include "FormattedTextWidget.h" 0026 #include "StyleBuilder.h" 0027 #include "osm/OsmTagEditorWidget.h" 0028 #include "osm/OsmPlacemarkData.h" 0029 #include "osm/OsmRelationManagerWidget.h" 0030 0031 namespace Marble { 0032 0033 class Q_DECL_HIDDEN EditPlacemarkDialog::Private : public Ui::UiEditPlacemarkDialog 0034 { 0035 public: 0036 Private( GeoDataPlacemark *placemark ); 0037 ~Private(); 0038 0039 GeoDataPlacemark *m_placemark; 0040 0041 // Attached to label/icon/text color selectors. 0042 QColorDialog *m_iconColorDialog; 0043 QColorDialog *m_labelColorDialog; 0044 0045 // Used to restore if the Cancel button is pressed. 0046 QString m_initialDescription; 0047 QString m_initialName; 0048 GeoDataCoordinates m_initialCoords; 0049 GeoDataStyle m_initialStyle; 0050 GeoDataPlacemark::GeoDataVisualCategory m_initialVisualCategory; 0051 OsmPlacemarkData m_initialOsmData; 0052 QString m_styleColorTabName; 0053 bool m_initialIsPlacemarkVisible; 0054 bool m_initialIsBaloonVisible; 0055 bool m_initialDescriptionIsCDATA; 0056 bool m_hadInitialOsmData; 0057 QString m_initialId; 0058 Ui::ElevationWidget *m_elevationWidget; 0059 OsmTagEditorWidget *m_osmTagEditorWidget; 0060 OsmRelationManagerWidget *m_osmRelationManagerWidget; 0061 MarbleLocale::MeasureUnit m_elevationUnit; 0062 QString m_initialTargetId; 0063 bool m_isReadOnly; 0064 }; 0065 0066 EditPlacemarkDialog::Private::Private( GeoDataPlacemark *placemark ) : 0067 Ui::UiEditPlacemarkDialog(), 0068 m_placemark( placemark ), 0069 m_iconColorDialog( nullptr ), 0070 m_labelColorDialog( nullptr ), 0071 m_osmTagEditorWidget( nullptr ), 0072 m_osmRelationManagerWidget( nullptr ), 0073 m_isReadOnly(false) 0074 { 0075 // nothing to do 0076 } 0077 0078 EditPlacemarkDialog::Private::~Private() 0079 { 0080 delete m_elevationWidget; 0081 delete m_osmTagEditorWidget; 0082 delete m_osmRelationManagerWidget; 0083 delete m_iconColorDialog; 0084 delete m_labelColorDialog; 0085 } 0086 0087 EditPlacemarkDialog::EditPlacemarkDialog( GeoDataPlacemark *placemark, 0088 const QHash<qint64, OsmPlacemarkData> *relations, 0089 QWidget *parent ) : 0090 QDialog( parent ), 0091 d( new Private( placemark ) ) 0092 { 0093 d->setupUi( this ); 0094 0095 // Store initial style so that it can be restored if the 'Cancel' button is pressed. 0096 d->m_initialStyle = *placemark->style(); 0097 0098 d->m_initialVisualCategory = placemark->visualCategory(); 0099 0100 0101 d->m_hadInitialOsmData = placemark->hasOsmData(); 0102 if ( d->m_hadInitialOsmData ) { 0103 d->m_initialOsmData = placemark->osmData(); 0104 } 0105 0106 0107 // If the placemark has just been created, assign it a default name. 0108 if ( placemark->name().isNull() ) { 0109 placemark->setName( tr("Untitled Placemark") ); 0110 } 0111 // Setup id, name, icon link and latitude/longitude values. 0112 d->m_header->setId( placemark->id() ); 0113 d->m_initialId = placemark->id(); 0114 d->m_header->setName( placemark->name() ); 0115 d->m_initialName = placemark->name(); 0116 d->m_isPlacemarkVisible->setChecked( placemark->isVisible() ); 0117 d->m_initialIsPlacemarkVisible = placemark->isVisible(); 0118 d->m_header->setIconLink( placemark->style()->iconStyle().iconPath() ); 0119 d->m_header->setTargetId( placemark->targetId() ); 0120 d->m_initialTargetId = placemark->targetId(); 0121 MarbleWidget* marbleWidget = dynamic_cast<MarbleWidget*>( parent ); 0122 if( marbleWidget != nullptr ) { 0123 const AngleUnit defaultAngleUnit = marbleWidget->defaultAngleUnit(); 0124 const GeoDataCoordinates::Notation notation = 0125 (defaultAngleUnit == DecimalDegree) ? GeoDataCoordinates::Decimal : 0126 (defaultAngleUnit == DMSDegree) ? GeoDataCoordinates::DMS : 0127 /* else, UTM */ GeoDataCoordinates::UTM; 0128 d->m_header->setNotation( notation ); 0129 } 0130 connect( d->m_header, SIGNAL(valueChanged()), this, SLOT( 0131 updateTextAnnotation()) ); 0132 0133 d->m_formattedTextWidget->setText( placemark->description() ); 0134 d->m_initialDescription = placemark->description(); 0135 d->m_initialDescriptionIsCDATA = placemark->descriptionIsCDATA(); 0136 d->m_isBalloonVisible->setChecked( placemark->isBalloonVisible() ); 0137 d->m_initialIsBaloonVisible = placemark->isBalloonVisible(); 0138 0139 d->m_header->setLatitude( placemark->coordinate().latitude( GeoDataCoordinates::Degree ) ); 0140 d->m_header->setLongitude( placemark->coordinate().longitude( GeoDataCoordinates::Degree ) ); 0141 d->m_initialCoords = GeoDataCoordinates( d->m_header->longitude(), 0142 d->m_header->latitude(), 0143 0, 0144 GeoDataCoordinates::Degree ); 0145 0146 // There's no point showing Relations and Tags tabs if the editor was not 0147 // loaded from the annotate plugin ( loaded from tourWidget.. ) 0148 if ( relations ) { 0149 // Adding the osm tag editor widget tab 0150 d->m_osmTagEditorWidget = new OsmTagEditorWidget( placemark, this ); 0151 d->tabWidget->addTab( d->m_osmTagEditorWidget, tr( "Tags" ) ); 0152 QObject::connect( d->m_osmTagEditorWidget, SIGNAL(placemarkChanged(GeoDataFeature*)), 0153 this, SLOT(updateTextAnnotation()) ); 0154 0155 // Adding the osm relation editor widget tab 0156 d->m_osmRelationManagerWidget = new OsmRelationManagerWidget( placemark, relations, this ); 0157 d->tabWidget->addTab( d->m_osmRelationManagerWidget, tr( "Relations" ) ); 0158 QObject::connect( d->m_osmRelationManagerWidget, SIGNAL(relationCreated(OsmPlacemarkData)), 0159 this, SIGNAL(relationCreated(OsmPlacemarkData)) ); 0160 } 0161 0162 // Adding the elevation widget tab 0163 d->m_elevationWidget = new Ui::ElevationWidget; 0164 QWidget *elevationTab = new QWidget; 0165 d->m_elevationWidget->setupUi( elevationTab ); 0166 d->tabWidget->addTab( elevationTab, tr("Elevation") ); 0167 qreal altitude = d->m_placemark->coordinate().altitude(); 0168 MarbleLocale *locale = MarbleGlobal::getInstance()->locale(); 0169 if ( altitude == 0.0 ) { 0170 switch ( locale->measurementSystem() ) { 0171 case MarbleLocale::MetricSystem: 0172 d->m_elevationUnit = MarbleLocale::Meter; 0173 break; 0174 case MarbleLocale::ImperialSystem: 0175 d->m_elevationUnit = MarbleLocale::Foot; 0176 break; 0177 case MarbleLocale::NauticalSystem: 0178 d->m_elevationUnit = MarbleLocale::NauticalMile; 0179 break; 0180 } 0181 0182 d->m_elevationWidget->elevationSpinBox->setSuffix( locale->unitAbbreviation((d->m_elevationUnit)) ); 0183 } else { 0184 qreal convertedAltitude; 0185 const MarbleLocale::MeasurementSystem currentSystem = locale->measurementSystem(); 0186 locale->meterToTargetUnit( altitude, currentSystem, convertedAltitude, d->m_elevationUnit ); 0187 d->m_elevationWidget->elevationSpinBox->setValue( convertedAltitude ); 0188 d->m_elevationWidget->elevationSpinBox->setSuffix( locale->unitAbbreviation(d->m_elevationUnit) ); 0189 } 0190 0191 // Adjust icon and label scales. 0192 d->m_iconScale->setValue( placemark->style()->iconStyle().scale() ); 0193 connect( d->m_iconScale, SIGNAL(valueChanged(double)), this, SLOT(updateTextAnnotation()) ); 0194 0195 d->m_labelScale->setValue( placemark->style()->labelStyle().scale() ); 0196 connect( d->m_labelScale, SIGNAL(valueChanged(double)), this, SLOT(updateTextAnnotation()) ); 0197 0198 0199 // Adjust the current color of the two push buttons' pixmap to resemble the label and icon colors. 0200 const GeoDataLabelStyle labelStyle = placemark->style()->labelStyle(); 0201 const GeoDataIconStyle iconStyle = placemark->style()->iconStyle(); 0202 0203 QPixmap labelPixmap( d->m_labelButton->iconSize().width(), 0204 d->m_labelButton->iconSize().height() ); 0205 labelPixmap.fill( labelStyle.color() ); 0206 d->m_labelButton->setIcon( QIcon( labelPixmap ) ); 0207 0208 QPixmap iconPixmap( d->m_iconButton->iconSize().width(), 0209 d->m_iconButton->iconSize().height() ); 0210 iconPixmap.fill( iconStyle.color() ); 0211 d->m_iconButton->setIcon( QIcon( iconPixmap ) ); 0212 0213 // Setup the color dialogs. 0214 d->m_labelColorDialog = new QColorDialog( this ); 0215 d->m_labelColorDialog->setOption( QColorDialog::ShowAlphaChannel ); 0216 d->m_labelColorDialog->setCurrentColor( labelStyle.color() ); 0217 connect( d->m_labelButton, SIGNAL(clicked()), d->m_labelColorDialog, SLOT(exec()) ); 0218 connect( d->m_labelColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateLabelDialog(QColor)) ); 0219 connect( d->m_labelColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateTextAnnotation()) ); 0220 0221 d->m_iconColorDialog = new QColorDialog( this ); 0222 d->m_iconColorDialog->setOption( QColorDialog::ShowAlphaChannel ); 0223 d->m_iconColorDialog->setCurrentColor( iconStyle.color() ); 0224 connect( d->m_iconButton, SIGNAL(clicked()), d->m_iconColorDialog, SLOT(exec()) ); 0225 connect( d->m_iconColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateIconDialog(QColor)) ); 0226 connect( d->m_iconColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateTextAnnotation()) ); 0227 0228 connect( d->m_isBalloonVisible, SIGNAL(toggled(bool)), this, SLOT(updateTextAnnotation()) ); 0229 0230 // Promote "Ok" button to default button. 0231 d->buttonBox->button( QDialogButtonBox::Ok )->setDefault( true ); 0232 0233 connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) ); 0234 connect( this, SIGNAL(accepted()), SLOT(updateTextAnnotation()) ); 0235 connect( this, SIGNAL(accepted()), SLOT(updatePlacemarkAltitude()) ); 0236 connect( this, SIGNAL(finished(int)), SLOT(restoreInitial(int)) ); 0237 0238 // Ensure that the dialog gets deleted when closing it (either when clicking OK or 0239 // Close). 0240 connect( this, SIGNAL(finished(int)), SLOT(deleteLater()) ); 0241 } 0242 0243 EditPlacemarkDialog::~EditPlacemarkDialog() 0244 { 0245 delete d; 0246 } 0247 0248 void EditPlacemarkDialog::setLabelColor( const QColor &color ) 0249 { 0250 d->m_labelColorDialog->setCurrentColor(color); 0251 updateLabelDialog(color); 0252 } 0253 0254 QStringList EditPlacemarkDialog::idFilter() const 0255 { 0256 return d->m_header->idFilter(); 0257 } 0258 0259 QStringList EditPlacemarkDialog::targetIds() const 0260 { 0261 return d->m_header->targetIdList(); 0262 } 0263 0264 bool EditPlacemarkDialog::isTargetIdFieldVisible() const 0265 { 0266 return d->m_header->isTargetIdVisible(); 0267 } 0268 0269 bool EditPlacemarkDialog::isIdFieldVisible() const 0270 { 0271 return d->m_header->isIdVisible(); 0272 } 0273 0274 void EditPlacemarkDialog::updateDialogFields() 0275 { 0276 d->m_header->setLatitude( d->m_placemark->coordinate().latitude( GeoDataCoordinates::Degree ) ); 0277 d->m_header->setLongitude( d->m_placemark->coordinate().longitude( GeoDataCoordinates::Degree ) ); 0278 } 0279 0280 void EditPlacemarkDialog::setIdFilter(const QStringList &filter) 0281 { 0282 d->m_header->setIdFilter( filter ); 0283 } 0284 0285 void EditPlacemarkDialog::setTargetIds(const QStringList &targetIds) 0286 { 0287 d->m_header->setTargetIdList( targetIds ); 0288 } 0289 0290 void EditPlacemarkDialog::setTargetIdFieldVisible(bool visible) 0291 { 0292 d->m_header->setTargetIdVisible( visible ); 0293 } 0294 0295 void EditPlacemarkDialog::setIdFieldVisible(bool visible) 0296 { 0297 d->m_header->setIdVisible( visible ); 0298 } 0299 0300 bool EditPlacemarkDialog::isReadOnly() const 0301 { 0302 return d->m_isReadOnly; 0303 } 0304 0305 void EditPlacemarkDialog::setReadOnly(bool state) 0306 { 0307 d->m_isReadOnly = state; 0308 d->m_header->setReadOnly(state); 0309 d->m_formattedTextWidget->setReadOnly(state); 0310 d->m_isBalloonVisible->setDisabled(state); 0311 d->m_isPlacemarkVisible->setDisabled(state); 0312 d->style_color_tab->setDisabled(state); 0313 } 0314 0315 void EditPlacemarkDialog::updateTextAnnotation() 0316 { 0317 if (isReadOnly()) return; 0318 0319 d->m_placemark->setDescription( d->m_formattedTextWidget->text() ); 0320 //allow for HTML in the description 0321 d->m_placemark->setDescriptionCDATA( true ); 0322 d->m_placemark->setName( d->m_header->name() ); 0323 d->m_placemark->setCoordinate( GeoDataCoordinates( d->m_header->longitude(), 0324 d->m_header->latitude(), 0325 0, 0326 GeoDataCoordinates::Degree ) ); 0327 0328 d->m_placemark->setVisible( d->m_isPlacemarkVisible->isChecked() ); 0329 d->m_placemark->setBalloonVisible( d->m_isBalloonVisible->isChecked() ); 0330 d->m_placemark->setId( d->m_header->id() ); 0331 d->m_placemark->setTargetId( d->m_header->targetId() ); 0332 0333 0334 if ( !d->m_header->iconLink().isEmpty() ) { 0335 QFileInfo fileInfo( d->m_header->iconLink() ); 0336 0337 GeoDataStyle::Ptr newStyle(new GeoDataStyle( *d->m_placemark->style() )); 0338 if ( fileInfo.exists() ) { 0339 newStyle->iconStyle().setIconPath( d->m_header->iconLink() ); 0340 } 0341 0342 newStyle->iconStyle().setScale( d->m_iconScale->value() ); 0343 newStyle->labelStyle().setScale( d->m_labelScale->value() ); 0344 newStyle->iconStyle().setColor( d->m_iconColorDialog->currentColor() ); 0345 newStyle->labelStyle().setColor( d->m_labelColorDialog->currentColor() ); 0346 d->m_placemark->setStyle( newStyle ); 0347 } 0348 else { 0349 const OsmPlacemarkData osmData = d->m_osmTagEditorWidget->placemarkData(); 0350 const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData); 0351 if (category != GeoDataPlacemark::None) { 0352 d->m_placemark->setStyle(GeoDataStyle::Ptr()); 0353 d->m_placemark->setVisualCategory( category ); 0354 } 0355 } 0356 0357 emit textAnnotationUpdated( d->m_placemark ); 0358 } 0359 0360 void EditPlacemarkDialog::checkFields() 0361 { 0362 if (isReadOnly()) { 0363 accept(); 0364 return; 0365 } 0366 0367 if ( d->m_header->name().isEmpty() ) { 0368 QMessageBox::warning( this, 0369 tr( "No name specified" ), 0370 tr( "Please specify a name for this placemark." ) ); 0371 } else if ( isIdFieldVisible() && d->m_header->id().isEmpty() ) { 0372 QMessageBox::warning( this, 0373 tr( "No ID specified" ), 0374 tr( "Please specify a ID for this placemark." ) ); 0375 } else if ( isIdFieldVisible() && !d->m_header->isIdValid() ) { 0376 QMessageBox::warning( this, 0377 tr( "ID is invalid" ), 0378 tr( "Please specify a valid ID for this placemark." ) ); 0379 } else if (d->m_header->iconLink().isEmpty() && d->m_placemark->visualCategory() == GeoDataPlacemark::None) { 0380 QMessageBox::warning( this, 0381 tr( "No image specified" ), 0382 tr( "Please specify an icon for this placemark or add a valid tag." ) ); 0383 } else if( !d->m_header->iconLink().isEmpty() && !QFileInfo( d->m_header->iconLink() ).exists() ) { 0384 QMessageBox::warning( this, 0385 tr( "Invalid icon path" ), 0386 tr( "Please specify a valid path for the icon file." ) ); 0387 } else { 0388 accept(); 0389 } 0390 } 0391 0392 void EditPlacemarkDialog::updateLabelDialog( const QColor &color ) 0393 { 0394 if (isReadOnly()) return; 0395 0396 QPixmap labelPixmap( d->m_labelButton->iconSize().width(), 0397 d->m_labelButton->iconSize().height() ); 0398 labelPixmap.fill( color ); 0399 d->m_labelButton->setIcon( QIcon( labelPixmap ) ); 0400 } 0401 0402 void EditPlacemarkDialog::updateIconDialog( const QColor &color ) 0403 { 0404 if (isReadOnly()) return; 0405 0406 QPixmap iconPixmap( d->m_iconButton->iconSize().width(), 0407 d->m_iconButton->iconSize().height() ); 0408 iconPixmap.fill( color ); 0409 d->m_iconButton->setIcon( QIcon( iconPixmap ) ); 0410 } 0411 0412 void EditPlacemarkDialog::updatePlacemarkAltitude() 0413 { 0414 if (isReadOnly()) return; 0415 0416 GeoDataCoordinates coord = d->m_placemark->coordinate(); 0417 qreal altitude = d->m_elevationWidget->elevationSpinBox->value(); 0418 0419 switch (d->m_elevationUnit) { 0420 case MarbleLocale::Meter: 0421 break; 0422 case MarbleLocale::Milimeter: 0423 altitude *= MM2M; 0424 break; 0425 case MarbleLocale::Kilometer: 0426 altitude *= KM2METER; 0427 break; 0428 case MarbleLocale::Centimeter: 0429 altitude *= CM2M; 0430 break; 0431 case MarbleLocale::Foot: 0432 altitude *= FT2M; 0433 break; 0434 case MarbleLocale::Inch: 0435 altitude *= IN2M; 0436 break; 0437 case MarbleLocale::Yard: 0438 altitude *= YD2M; 0439 break; 0440 case MarbleLocale::Mile: 0441 altitude *= MI2KM * KM2METER; 0442 break; 0443 case MarbleLocale::NauticalMile: 0444 altitude *= NM2KM * KM2METER; 0445 break; 0446 default: 0447 break; 0448 } 0449 0450 coord.setAltitude(altitude); 0451 d->m_placemark->setCoordinate(coord); 0452 } 0453 0454 void EditPlacemarkDialog::restoreInitial( int result ) 0455 { 0456 if ( isReadOnly() || result ) { 0457 return; 0458 } 0459 0460 if ( d->m_placemark->name() != d->m_initialName ) { 0461 d->m_placemark->setName( d->m_initialName ); 0462 } 0463 0464 if ( isIdFieldVisible() && d->m_placemark->id() != d->m_initialId ) { 0465 d->m_placemark->setId( d->m_initialId ); 0466 } 0467 0468 if ( isTargetIdFieldVisible() && d->m_placemark->targetId() != d->m_initialTargetId ) { 0469 d->m_placemark->setTargetId( d->m_initialTargetId ); 0470 } 0471 0472 if ( d->m_placemark->description() != d->m_initialDescription ) { 0473 d->m_placemark->setDescription( d->m_initialDescription ); 0474 } 0475 0476 if ( d->m_placemark->descriptionIsCDATA() != d->m_initialDescriptionIsCDATA ) { 0477 d->m_placemark->setDescriptionCDATA( d->m_initialDescriptionIsCDATA ); 0478 } 0479 0480 if ( d->m_placemark->coordinate().latitude( GeoDataCoordinates::Degree ) != 0481 d->m_initialCoords.latitude( GeoDataCoordinates::Degree ) || 0482 d->m_placemark->coordinate().longitude( GeoDataCoordinates::Degree ) != 0483 d->m_initialCoords.longitude( GeoDataCoordinates::Degree ) ) { 0484 d->m_placemark->setCoordinate( d->m_initialCoords ); 0485 } 0486 0487 if ( d->m_placemark->visualCategory() != d->m_initialVisualCategory ) { 0488 d->m_placemark->setVisualCategory( d->m_initialVisualCategory ); 0489 } 0490 0491 if ( *d->m_placemark->style() != d->m_initialStyle ) { 0492 d->m_placemark->setStyle( GeoDataStyle::Ptr(new GeoDataStyle( d->m_initialStyle )) ); 0493 } 0494 0495 if( d->m_placemark->isVisible() != d->m_initialIsPlacemarkVisible ) { 0496 d->m_placemark->setVisible( d->m_initialIsPlacemarkVisible ); 0497 } 0498 0499 if( d->m_hadInitialOsmData ) { 0500 d->m_placemark->setOsmData( d->m_initialOsmData ); 0501 } 0502 0503 if( d->m_placemark->isBalloonVisible() != d->m_initialIsBaloonVisible ) { 0504 d->m_placemark->setVisible( d->m_initialIsBaloonVisible ); 0505 } 0506 0507 emit textAnnotationUpdated( d->m_placemark ); 0508 } 0509 0510 } 0511 0512 #include "moc_EditPlacemarkDialog.cpp"