Marble

EditPlacemarkDialog.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2014 Calin Cruceru <crucerucalincristian@gmail.com>
4// SPDX-FileCopyrightText: 2015 Ilya Kowalewski <illya.kovalevskyy@gmail.com>
5//
6
7// self
8#include "EditPlacemarkDialog.h"
9#include "ui_EditPlacemarkDialog.h"
10#include "ui_ElevationWidget.h"
11
12// Qt
13#include <QMessageBox>
14#include <QFileInfo>
15#include <QColorDialog>
16#include <QCheckBox>
17
18// Marble
19#include "GeoDataStyle.h"
20#include "GeoDataIconStyle.h"
21#include "GeoDataLabelStyle.h"
22#include "GeoDataPlacemark.h"
23#include "MarbleWidget.h"
24#include "MarbleLocale.h"
25#include "FormattedTextWidget.h"
26#include "StyleBuilder.h"
27#include "osm/OsmTagEditorWidget.h"
28#include "osm/OsmPlacemarkData.h"
29#include "osm/OsmRelationManagerWidget.h"
30
31namespace Marble {
32
33class Q_DECL_HIDDEN EditPlacemarkDialog::Private : public Ui::UiEditPlacemarkDialog
34{
35public:
36 Private( GeoDataPlacemark *placemark );
37 ~Private();
38
39 GeoDataPlacemark *m_placemark;
40
41 // Attached to label/icon/text color selectors.
42 QColorDialog *m_iconColorDialog;
43 QColorDialog *m_labelColorDialog;
44
45 // Used to restore if the Cancel button is pressed.
46 QString m_initialDescription;
47 QString m_initialName;
48 GeoDataCoordinates m_initialCoords;
49 GeoDataStyle m_initialStyle;
50 GeoDataPlacemark::GeoDataVisualCategory m_initialVisualCategory;
51 OsmPlacemarkData m_initialOsmData;
52 QString m_styleColorTabName;
53 bool m_initialIsPlacemarkVisible;
54 bool m_initialIsBaloonVisible;
55 bool m_initialDescriptionIsCDATA;
56 bool m_hadInitialOsmData;
57 QString m_initialId;
58 Ui::ElevationWidget *m_elevationWidget;
59 OsmTagEditorWidget *m_osmTagEditorWidget;
60 OsmRelationManagerWidget *m_osmRelationManagerWidget;
61 MarbleLocale::MeasureUnit m_elevationUnit;
62 QString m_initialTargetId;
63 bool m_isReadOnly;
64};
65
66EditPlacemarkDialog::Private::Private( GeoDataPlacemark *placemark ) :
67 Ui::UiEditPlacemarkDialog(),
68 m_placemark( placemark ),
69 m_iconColorDialog( nullptr ),
70 m_labelColorDialog( nullptr ),
71 m_osmTagEditorWidget( nullptr ),
72 m_osmRelationManagerWidget( nullptr ),
73 m_isReadOnly(false)
74{
75 // nothing to do
76}
77
78EditPlacemarkDialog::Private::~Private()
79{
80 delete m_elevationWidget;
81 delete m_osmTagEditorWidget;
82 delete m_osmRelationManagerWidget;
83 delete m_iconColorDialog;
84 delete m_labelColorDialog;
85}
86
87EditPlacemarkDialog::EditPlacemarkDialog( GeoDataPlacemark *placemark,
88 const QHash<qint64, OsmPlacemarkData> *relations,
89 QWidget *parent ) :
90 QDialog( parent ),
91 d( new Private( placemark ) )
92{
93 d->setupUi( this );
94
95 // Store initial style so that it can be restored if the 'Cancel' button is pressed.
96 d->m_initialStyle = *placemark->style();
97
98 d->m_initialVisualCategory = placemark->visualCategory();
99
100
101 d->m_hadInitialOsmData = placemark->hasOsmData();
102 if ( d->m_hadInitialOsmData ) {
103 d->m_initialOsmData = placemark->osmData();
104 }
105
106
107 // If the placemark has just been created, assign it a default name.
108 if ( placemark->name().isNull() ) {
109 placemark->setName( tr("Untitled Placemark") );
110 }
111 // Setup id, name, icon link and latitude/longitude values.
112 d->m_header->setId( placemark->id() );
113 d->m_initialId = placemark->id();
114 d->m_header->setName( placemark->name() );
115 d->m_initialName = placemark->name();
116 d->m_isPlacemarkVisible->setChecked( placemark->isVisible() );
117 d->m_initialIsPlacemarkVisible = placemark->isVisible();
118 d->m_header->setIconLink( placemark->style()->iconStyle().iconPath() );
119 d->m_header->setTargetId( placemark->targetId() );
120 d->m_initialTargetId = placemark->targetId();
121 MarbleWidget* marbleWidget = dynamic_cast<MarbleWidget*>( parent );
122 if( marbleWidget != nullptr ) {
123 const AngleUnit defaultAngleUnit = marbleWidget->defaultAngleUnit();
124 const GeoDataCoordinates::Notation notation =
125 (defaultAngleUnit == DecimalDegree) ? GeoDataCoordinates::Decimal :
126 (defaultAngleUnit == DMSDegree) ? GeoDataCoordinates::DMS :
127 /* else, UTM */ GeoDataCoordinates::UTM;
128 d->m_header->setNotation( notation );
129 }
130 connect( d->m_header, SIGNAL(valueChanged()), this, SLOT(
131 updateTextAnnotation()) );
132
133 d->m_formattedTextWidget->setText( placemark->description() );
134 d->m_initialDescription = placemark->description();
135 d->m_initialDescriptionIsCDATA = placemark->descriptionIsCDATA();
136 d->m_isBalloonVisible->setChecked( placemark->isBalloonVisible() );
137 d->m_initialIsBaloonVisible = placemark->isBalloonVisible();
138
139 d->m_header->setLatitude( placemark->coordinate().latitude( GeoDataCoordinates::Degree ) );
140 d->m_header->setLongitude( placemark->coordinate().longitude( GeoDataCoordinates::Degree ) );
141 d->m_initialCoords = GeoDataCoordinates( d->m_header->longitude(),
142 d->m_header->latitude(),
143 0,
144 GeoDataCoordinates::Degree );
145
146 // There's no point showing Relations and Tags tabs if the editor was not
147 // loaded from the annotate plugin ( loaded from tourWidget.. )
148 if ( relations ) {
149 // Adding the osm tag editor widget tab
150 d->m_osmTagEditorWidget = new OsmTagEditorWidget( placemark, this );
151 d->tabWidget->addTab( d->m_osmTagEditorWidget, tr( "Tags" ) );
152 QObject::connect( d->m_osmTagEditorWidget, SIGNAL(placemarkChanged(GeoDataFeature*)),
153 this, SLOT(updateTextAnnotation()) );
154
155 // Adding the osm relation editor widget tab
156 d->m_osmRelationManagerWidget = new OsmRelationManagerWidget( placemark, relations, this );
157 d->tabWidget->addTab( d->m_osmRelationManagerWidget, tr( "Relations" ) );
158 QObject::connect( d->m_osmRelationManagerWidget, SIGNAL(relationCreated(OsmPlacemarkData)),
159 this, SIGNAL(relationCreated(OsmPlacemarkData)) );
160 }
161
162 // Adding the elevation widget tab
163 d->m_elevationWidget = new Ui::ElevationWidget;
164 QWidget *elevationTab = new QWidget;
165 d->m_elevationWidget->setupUi( elevationTab );
166 d->tabWidget->addTab( elevationTab, tr("Elevation") );
167 qreal altitude = d->m_placemark->coordinate().altitude();
168 MarbleLocale *locale = MarbleGlobal::getInstance()->locale();
169 if ( altitude == 0.0 ) {
170 switch ( locale->measurementSystem() ) {
171 case MarbleLocale::MetricSystem:
172 d->m_elevationUnit = MarbleLocale::Meter;
173 break;
174 case MarbleLocale::ImperialSystem:
175 d->m_elevationUnit = MarbleLocale::Foot;
176 break;
177 case MarbleLocale::NauticalSystem:
178 d->m_elevationUnit = MarbleLocale::NauticalMile;
179 break;
180 }
181
182 d->m_elevationWidget->elevationSpinBox->setSuffix( locale->unitAbbreviation((d->m_elevationUnit)) );
183 } else {
184 qreal convertedAltitude;
185 const MarbleLocale::MeasurementSystem currentSystem = locale->measurementSystem();
186 locale->meterToTargetUnit( altitude, currentSystem, convertedAltitude, d->m_elevationUnit );
187 d->m_elevationWidget->elevationSpinBox->setValue( convertedAltitude );
188 d->m_elevationWidget->elevationSpinBox->setSuffix( locale->unitAbbreviation(d->m_elevationUnit) );
189 }
190
191 // Adjust icon and label scales.
192 d->m_iconScale->setValue( placemark->style()->iconStyle().scale() );
193 connect( d->m_iconScale, SIGNAL(valueChanged(double)), this, SLOT(updateTextAnnotation()) );
194
195 d->m_labelScale->setValue( placemark->style()->labelStyle().scale() );
196 connect( d->m_labelScale, SIGNAL(valueChanged(double)), this, SLOT(updateTextAnnotation()) );
197
198
199 // Adjust the current color of the two push buttons' pixmap to resemble the label and icon colors.
200 const GeoDataLabelStyle labelStyle = placemark->style()->labelStyle();
201 const GeoDataIconStyle iconStyle = placemark->style()->iconStyle();
202
203 QPixmap labelPixmap( d->m_labelButton->iconSize().width(),
204 d->m_labelButton->iconSize().height() );
205 labelPixmap.fill( labelStyle.color() );
206 d->m_labelButton->setIcon( QIcon( labelPixmap ) );
207
208 QPixmap iconPixmap( d->m_iconButton->iconSize().width(),
209 d->m_iconButton->iconSize().height() );
210 iconPixmap.fill( iconStyle.color() );
211 d->m_iconButton->setIcon( QIcon( iconPixmap ) );
212
213 // Setup the color dialogs.
214 d->m_labelColorDialog = new QColorDialog( this );
215 d->m_labelColorDialog->setOption( QColorDialog::ShowAlphaChannel );
216 d->m_labelColorDialog->setCurrentColor( labelStyle.color() );
217 connect( d->m_labelButton, SIGNAL(clicked()), d->m_labelColorDialog, SLOT(exec()) );
218 connect( d->m_labelColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateLabelDialog(QColor)) );
219 connect( d->m_labelColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateTextAnnotation()) );
220
221 d->m_iconColorDialog = new QColorDialog( this );
222 d->m_iconColorDialog->setOption( QColorDialog::ShowAlphaChannel );
223 d->m_iconColorDialog->setCurrentColor( iconStyle.color() );
224 connect( d->m_iconButton, SIGNAL(clicked()), d->m_iconColorDialog, SLOT(exec()) );
225 connect( d->m_iconColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateIconDialog(QColor)) );
226 connect( d->m_iconColorDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateTextAnnotation()) );
227
228 connect( d->m_isBalloonVisible, SIGNAL(toggled(bool)), this, SLOT(updateTextAnnotation()) );
229
230 // Promote "Ok" button to default button.
231 d->buttonBox->button( QDialogButtonBox::Ok )->setDefault( true );
232
233 connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) );
234 connect( this, SIGNAL(accepted()), SLOT(updateTextAnnotation()) );
235 connect( this, SIGNAL(accepted()), SLOT(updatePlacemarkAltitude()) );
236 connect( this, SIGNAL(finished(int)), SLOT(restoreInitial(int)) );
237
238 // Ensure that the dialog gets deleted when closing it (either when clicking OK or
239 // Close).
240 connect( this, SIGNAL(finished(int)), SLOT(deleteLater()) );
241}
242
243EditPlacemarkDialog::~EditPlacemarkDialog()
244{
245 delete d;
246}
247
248void EditPlacemarkDialog::setLabelColor( const QColor &color )
249{
250 d->m_labelColorDialog->setCurrentColor(color);
251 updateLabelDialog(color);
252}
253
254QStringList EditPlacemarkDialog::idFilter() const
255{
256 return d->m_header->idFilter();
257}
258
259QStringList EditPlacemarkDialog::targetIds() const
260{
261 return d->m_header->targetIdList();
262}
263
264bool EditPlacemarkDialog::isTargetIdFieldVisible() const
265{
266 return d->m_header->isTargetIdVisible();
267}
268
269bool EditPlacemarkDialog::isIdFieldVisible() const
270{
271 return d->m_header->isIdVisible();
272}
273
274void EditPlacemarkDialog::updateDialogFields()
275{
276 d->m_header->setLatitude( d->m_placemark->coordinate().latitude( GeoDataCoordinates::Degree ) );
277 d->m_header->setLongitude( d->m_placemark->coordinate().longitude( GeoDataCoordinates::Degree ) );
278}
279
280void EditPlacemarkDialog::setIdFilter(const QStringList &filter)
281{
282 d->m_header->setIdFilter( filter );
283}
284
285void EditPlacemarkDialog::setTargetIds(const QStringList &targetIds)
286{
287 d->m_header->setTargetIdList( targetIds );
288}
289
290void EditPlacemarkDialog::setTargetIdFieldVisible(bool visible)
291{
292 d->m_header->setTargetIdVisible( visible );
293}
294
295void EditPlacemarkDialog::setIdFieldVisible(bool visible)
296{
297 d->m_header->setIdVisible( visible );
298}
299
300bool EditPlacemarkDialog::isReadOnly() const
301{
302 return d->m_isReadOnly;
303}
304
305void EditPlacemarkDialog::setReadOnly(bool state)
306{
307 d->m_isReadOnly = state;
308 d->m_header->setReadOnly(state);
309 d->m_formattedTextWidget->setReadOnly(state);
310 d->m_isBalloonVisible->setDisabled(state);
311 d->m_isPlacemarkVisible->setDisabled(state);
312 d->style_color_tab->setDisabled(state);
313}
314
315void EditPlacemarkDialog::updateTextAnnotation()
316{
317 if (isReadOnly()) return;
318
319 d->m_placemark->setDescription( d->m_formattedTextWidget->text() );
320 //allow for HTML in the description
321 d->m_placemark->setDescriptionCDATA( true );
322 d->m_placemark->setName( d->m_header->name() );
323 d->m_placemark->setCoordinate( GeoDataCoordinates( d->m_header->longitude(),
324 d->m_header->latitude(),
325 0,
326 GeoDataCoordinates::Degree ) );
327
328 d->m_placemark->setVisible( d->m_isPlacemarkVisible->isChecked() );
329 d->m_placemark->setBalloonVisible( d->m_isBalloonVisible->isChecked() );
330 d->m_placemark->setId( d->m_header->id() );
331 d->m_placemark->setTargetId( d->m_header->targetId() );
332
333
334 if ( !d->m_header->iconLink().isEmpty() ) {
335 QFileInfo fileInfo( d->m_header->iconLink() );
336
337 GeoDataStyle::Ptr newStyle(new GeoDataStyle( *d->m_placemark->style() ));
338 if ( fileInfo.exists() ) {
339 newStyle->iconStyle().setIconPath( d->m_header->iconLink() );
340 }
341
342 newStyle->iconStyle().setScale( d->m_iconScale->value() );
343 newStyle->labelStyle().setScale( d->m_labelScale->value() );
344 newStyle->iconStyle().setColor( d->m_iconColorDialog->currentColor() );
345 newStyle->labelStyle().setColor( d->m_labelColorDialog->currentColor() );
346 d->m_placemark->setStyle( newStyle );
347 }
348 else {
349 const OsmPlacemarkData osmData = d->m_osmTagEditorWidget->placemarkData();
350 const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData);
351 if (category != GeoDataPlacemark::None) {
352 d->m_placemark->setStyle(GeoDataStyle::Ptr());
353 d->m_placemark->setVisualCategory( category );
354 }
355 }
356
357 emit textAnnotationUpdated( d->m_placemark );
358}
359
360void EditPlacemarkDialog::checkFields()
361{
362 if (isReadOnly()) {
363 accept();
364 return;
365 }
366
367 if ( d->m_header->name().isEmpty() ) {
369 tr( "No name specified" ),
370 tr( "Please specify a name for this placemark." ) );
371 } else if ( isIdFieldVisible() && d->m_header->id().isEmpty() ) {
373 tr( "No ID specified" ),
374 tr( "Please specify a ID for this placemark." ) );
375 } else if ( isIdFieldVisible() && !d->m_header->isIdValid() ) {
377 tr( "ID is invalid" ),
378 tr( "Please specify a valid ID for this placemark." ) );
379 } else if (d->m_header->iconLink().isEmpty() && d->m_placemark->visualCategory() == GeoDataPlacemark::None) {
381 tr( "No image specified" ),
382 tr( "Please specify an icon for this placemark or add a valid tag." ) );
383 } else if( !d->m_header->iconLink().isEmpty() && !QFileInfo( d->m_header->iconLink() ).exists() ) {
385 tr( "Invalid icon path" ),
386 tr( "Please specify a valid path for the icon file." ) );
387 } else {
388 accept();
389 }
390}
391
392void EditPlacemarkDialog::updateLabelDialog( const QColor &color )
393{
394 if (isReadOnly()) return;
395
396 QPixmap labelPixmap( d->m_labelButton->iconSize().width(),
397 d->m_labelButton->iconSize().height() );
398 labelPixmap.fill( color );
399 d->m_labelButton->setIcon( QIcon( labelPixmap ) );
400}
401
402void EditPlacemarkDialog::updateIconDialog( const QColor &color )
403{
404 if (isReadOnly()) return;
405
406 QPixmap iconPixmap( d->m_iconButton->iconSize().width(),
407 d->m_iconButton->iconSize().height() );
408 iconPixmap.fill( color );
409 d->m_iconButton->setIcon( QIcon( iconPixmap ) );
410}
411
412void EditPlacemarkDialog::updatePlacemarkAltitude()
413{
414 if (isReadOnly()) return;
415
416 GeoDataCoordinates coord = d->m_placemark->coordinate();
417 qreal altitude = d->m_elevationWidget->elevationSpinBox->value();
418
419 switch (d->m_elevationUnit) {
420 case MarbleLocale::Meter:
421 break;
422 case MarbleLocale::Milimeter:
423 altitude *= MM2M;
424 break;
425 case MarbleLocale::Kilometer:
426 altitude *= KM2METER;
427 break;
428 case MarbleLocale::Centimeter:
429 altitude *= CM2M;
430 break;
431 case MarbleLocale::Foot:
432 altitude *= FT2M;
433 break;
434 case MarbleLocale::Inch:
435 altitude *= IN2M;
436 break;
437 case MarbleLocale::Yard:
438 altitude *= YD2M;
439 break;
440 case MarbleLocale::Mile:
441 altitude *= MI2KM * KM2METER;
442 break;
443 case MarbleLocale::NauticalMile:
444 altitude *= NM2KM * KM2METER;
445 break;
446 default:
447 break;
448 }
449
450 coord.setAltitude(altitude);
451 d->m_placemark->setCoordinate(coord);
452}
453
454void EditPlacemarkDialog::restoreInitial( int result )
455{
456 if ( isReadOnly() || result ) {
457 return;
458 }
459
460 if ( d->m_placemark->name() != d->m_initialName ) {
461 d->m_placemark->setName( d->m_initialName );
462 }
463
464 if ( isIdFieldVisible() && d->m_placemark->id() != d->m_initialId ) {
465 d->m_placemark->setId( d->m_initialId );
466 }
467
468 if ( isTargetIdFieldVisible() && d->m_placemark->targetId() != d->m_initialTargetId ) {
469 d->m_placemark->setTargetId( d->m_initialTargetId );
470 }
471
472 if ( d->m_placemark->description() != d->m_initialDescription ) {
473 d->m_placemark->setDescription( d->m_initialDescription );
474 }
475
476 if ( d->m_placemark->descriptionIsCDATA() != d->m_initialDescriptionIsCDATA ) {
477 d->m_placemark->setDescriptionCDATA( d->m_initialDescriptionIsCDATA );
478 }
479
480 if ( d->m_placemark->coordinate().latitude( GeoDataCoordinates::Degree ) !=
481 d->m_initialCoords.latitude( GeoDataCoordinates::Degree ) ||
482 d->m_placemark->coordinate().longitude( GeoDataCoordinates::Degree ) !=
483 d->m_initialCoords.longitude( GeoDataCoordinates::Degree ) ) {
484 d->m_placemark->setCoordinate( d->m_initialCoords );
485 }
486
487 if ( d->m_placemark->visualCategory() != d->m_initialVisualCategory ) {
488 d->m_placemark->setVisualCategory( d->m_initialVisualCategory );
489 }
490
491 if ( *d->m_placemark->style() != d->m_initialStyle ) {
492 d->m_placemark->setStyle( GeoDataStyle::Ptr(new GeoDataStyle( d->m_initialStyle )) );
493 }
494
495 if( d->m_placemark->isVisible() != d->m_initialIsPlacemarkVisible ) {
496 d->m_placemark->setVisible( d->m_initialIsPlacemarkVisible );
497 }
498
499 if( d->m_hadInitialOsmData ) {
500 d->m_placemark->setOsmData( d->m_initialOsmData );
501 }
502
503 if( d->m_placemark->isBalloonVisible() != d->m_initialIsBaloonVisible ) {
504 d->m_placemark->setVisible( d->m_initialIsBaloonVisible );
505 }
506
507 emit textAnnotationUpdated( d->m_placemark );
508}
509
510}
511
512#include "moc_EditPlacemarkDialog.cpp"
This file contains the headers for MarbleWidget.
A 3d point representation.
an addressable style group
Category category(StandardShortcut id)
Binds a QML item to a specific geodetic location in screen coordinates.
AngleUnit
This enum is used to choose the unit chosen to measure angles.
@ UTM
UTM.
@ DMSDegree
Degrees in DMS notation.
@ DecimalDegree
Degrees in decimal notation.
bool exists(const QString &path)
StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setupUi(QWidget *widget)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:18:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.