Marble

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

KDE's Doxygen guidelines are available online.