File indexing completed on 2024-05-05 03:50:38

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2014 Calin Cruceru <crucerucalincristian@gmail.com>
0004 //
0005 
0006 // Self
0007 #include "EditPolylineDialog.h"
0008 #include "ui_EditPolylineDialog.h"
0009 
0010 // Qt
0011 #include <QColorDialog>
0012 #include <QMessageBox>
0013 
0014 // Marble
0015 #include "GeoDataPlacemark.h"
0016 #include "GeoDataLineString.h"
0017 #include "GeoDataStyle.h"
0018 #include "GeoDataLineStyle.h"
0019 #include "NodeModel.h"
0020 #include "FormattedTextWidget.h"
0021 #include "NodeItemDelegate.h"
0022 #include "StyleBuilder.h"
0023 #include "osm/OsmTagEditorWidget.h"
0024 #include "osm/OsmPlacemarkData.h"
0025 #include "osm/OsmRelationManagerWidget.h"
0026 
0027 
0028 namespace Marble
0029 {
0030 
0031 class Q_DECL_HIDDEN EditPolylineDialog::Private : public Ui::UiEditPolylineDialog
0032 {
0033 public:
0034     Private( GeoDataPlacemark *placemark);
0035     ~Private();
0036 
0037     QColorDialog *m_linesDialog;
0038     OsmTagEditorWidget *m_osmTagEditorWidget;
0039     OsmRelationManagerWidget *m_osmRelationManagerWidget;
0040     GeoDataPlacemark *m_placemark;
0041 
0042     // Used to restore if the Cancel button is pressed.
0043     QString m_initialName;
0044     QString m_initialDescription;
0045     GeoDataLineStyle m_initialLineStyle;
0046     GeoDataLineString m_initialLineString;
0047     OsmPlacemarkData m_initialOsmData;
0048     bool m_hadInitialOsmData;
0049 
0050     NodeItemDelegate *m_delegate;
0051     NodeModel *m_nodeModel;
0052 };
0053 
0054 EditPolylineDialog::Private::Private( GeoDataPlacemark *placemark ) :
0055     Ui::UiEditPolylineDialog(),
0056     m_linesDialog( nullptr ),
0057     m_osmTagEditorWidget( nullptr ),
0058     m_osmRelationManagerWidget( nullptr ),
0059     m_placemark( placemark ),
0060     m_nodeModel( new NodeModel )
0061 {
0062     // nothing to do
0063 }
0064 
0065 EditPolylineDialog::Private::~Private()
0066 {
0067     delete m_linesDialog;
0068     delete m_nodeModel;
0069     delete m_delegate;
0070 }
0071 
0072 EditPolylineDialog::EditPolylineDialog( GeoDataPlacemark *placemark,
0073                                         const QHash<qint64, OsmPlacemarkData> *relations,
0074                                         QWidget *parent ) :
0075     QDialog( parent ) ,
0076     d ( new Private( placemark ) )
0077 {
0078     d->setupUi( this );
0079 
0080     // There's no point showing Relations and Tags tabs if the editor was not
0081     // loaded from the annotate plugin ( loaded from tourWidget.. )
0082     if ( relations ) {
0083         // Adding the osm tag editor widget tab
0084         d->m_osmTagEditorWidget = new OsmTagEditorWidget( placemark, this );
0085         d->tabWidget->addTab( d->m_osmTagEditorWidget, tr( "Tags" ) );
0086         QObject::connect( d->m_osmTagEditorWidget, SIGNAL(placemarkChanged(GeoDataFeature*)),
0087                           this, SLOT(updatePolyline()) );
0088 
0089         // Adding the osm relation editor widget tab
0090         d->m_osmRelationManagerWidget = new OsmRelationManagerWidget( placemark, relations, this );
0091         d->tabWidget->addTab( d->m_osmRelationManagerWidget, tr( "Relations" ) );
0092         QObject::connect( d->m_osmRelationManagerWidget, SIGNAL(relationCreated(OsmPlacemarkData)),
0093                           this, SIGNAL(relationCreated(OsmPlacemarkData)) );
0094 
0095         adjustSize();
0096     }
0097 
0098     d->m_hadInitialOsmData = placemark->hasOsmData();
0099     if ( d->m_hadInitialOsmData ) {
0100         d->m_initialOsmData = placemark->osmData();
0101     }
0102 
0103     // If the polygon has just been drawn, assign it a default name.
0104     if ( d->m_placemark->name().isNull() ) {
0105         d->m_placemark->setName( tr("Untitled Path") );
0106     }
0107 
0108     d->m_initialLineString = *(static_cast<GeoDataLineString*>( placemark->geometry() ) );
0109     d->m_name->setText( placemark->name() );
0110     d->m_initialName = d->m_name->text();
0111     connect( d->m_name, SIGNAL(editingFinished()), this, SLOT(updatePolyline()) );
0112 
0113     d->m_formattedTextWidget->setText( placemark->description() );
0114     d->m_initialDescription = d->m_formattedTextWidget->text();
0115 
0116     d->m_linesWidth->setRange( 0.1, 5.0 );
0117 
0118 
0119     // Get the current style properties.
0120     const GeoDataLineStyle lineStyle = placemark->style()->lineStyle();
0121     d->m_initialLineStyle = lineStyle;
0122 
0123     d->m_linesWidth->setValue( lineStyle.width() );
0124     connect( d->m_linesWidth, SIGNAL(valueChanged(double)), this, SLOT(handleChangingStyle()) );
0125 
0126     // Adjust the color button's icon to the current lines color.
0127     QPixmap linesPixmap( d->m_linesColorButton->iconSize() );
0128     linesPixmap.fill( lineStyle.color() );
0129     d->m_linesColorButton->setIcon( QIcon( linesPixmap ) );
0130 
0131     // Setting the NodeView's delegate: mainly used for the editing the polyline's nodes
0132     d->m_delegate = new NodeItemDelegate( d->m_placemark, d->m_nodeView );
0133 
0134     connect( d->m_delegate, SIGNAL(modelChanged(GeoDataPlacemark*)),
0135              this, SLOT(handleItemMoving(GeoDataPlacemark*)) );
0136     connect( d->m_delegate, SIGNAL(geometryChanged()),
0137              this, SLOT(updatePolyline()) );
0138 
0139     d->m_nodeView->setItemDelegate( d->m_delegate );
0140     d->m_nodeView->setEditTriggers( QAbstractItemView::AllEditTriggers );
0141 
0142     // Setup the color dialogs.
0143     d->m_linesDialog = new QColorDialog( this );
0144     d->m_linesDialog->setOption( QColorDialog::ShowAlphaChannel );
0145     d->m_linesDialog->setCurrentColor( lineStyle.color() );
0146     connect( d->m_linesColorButton, SIGNAL(clicked()), d->m_linesDialog, SLOT(exec()) );
0147     connect( d->m_linesDialog, SIGNAL(colorSelected(QColor)), this, SLOT(updateLinesDialog(QColor)) );
0148     connect( d->m_linesDialog, SIGNAL(colorSelected(QColor)), this, SLOT(handleChangingStyle()) );
0149 
0150     if (const auto lineString = geodata_cast<GeoDataLineString>(placemark->geometry())) {
0151         for( int i = 0; i < lineString->size(); ++i ) {
0152             d->m_nodeModel->addNode( lineString->at( i ) );
0153         }
0154     }
0155     d->m_nodeView->setModel( d->m_nodeModel );
0156 
0157     // Resize column to contents size for better UI.
0158     d->m_nodeView->resizeColumnToContents( 0 );
0159 
0160     // Promote "Ok" button to default button.
0161     d->buttonBox->button( QDialogButtonBox::Ok )->setDefault( true );
0162 
0163     connect( d->buttonBox->button( QDialogButtonBox::Ok ), SIGNAL(pressed()), this, SLOT(checkFields()) );
0164     connect( this, SIGNAL(accepted()), SLOT(updatePolyline()) );
0165     connect( this, SIGNAL(finished(int)), SLOT(restoreInitial(int)) );
0166 
0167     // Ensure that the dialog gets deleted when closing it (either when clicking OK or
0168     // Close).
0169     connect( this, SIGNAL(finished(int)), SLOT(deleteLater()) );
0170 }
0171 
0172 EditPolylineDialog::~EditPolylineDialog()
0173 {
0174     delete d;
0175 }
0176 
0177 void EditPolylineDialog::handleAddingNode( const GeoDataCoordinates &node )
0178 {
0179     d->m_nodeModel->addNode( node );
0180 }
0181 
0182 void EditPolylineDialog::handleItemMoving( GeoDataPlacemark *item )
0183 {
0184     if( item == d->m_placemark ) {
0185         d->m_nodeModel->clear();
0186         if (const auto lineString = geodata_cast<GeoDataLineString>(d->m_placemark->geometry())) {
0187             for( int i = 0; i < lineString->size(); ++i ) {
0188                 d->m_nodeModel->addNode( lineString->at( i ) );
0189             }
0190         }
0191     }
0192 }
0193 
0194 void EditPolylineDialog::handleChangingStyle()
0195 {
0196     // The default style has been changed, thus the old style URL is no longer valid
0197     // The polyline is now considered to have a customStyle
0198     d->m_placemark->setStyleUrl(QString());
0199 
0200     GeoDataStyle::Ptr newStyle(new GeoDataStyle( *d->m_placemark->style() ));
0201     newStyle->lineStyle().setColor( d->m_linesDialog->currentColor() );
0202     newStyle->lineStyle().setWidth( d->m_linesWidth->value() );
0203     newStyle->setId(d->m_placemark->id() + QLatin1String("Style"));
0204     d->m_placemark->setStyle( newStyle );
0205 
0206     updatePolyline();
0207 }
0208 
0209 void EditPolylineDialog::updatePolyline()
0210 {
0211     d->m_placemark->setDescription( d->m_formattedTextWidget->text() );
0212     d->m_placemark->setName( d->m_name->text() );
0213 
0214     // If there is no custom style initialized( default #polyline url is used ) and there is a osmTag-based style
0215     // available, set it
0216     const OsmPlacemarkData osmData = d->m_osmTagEditorWidget->placemarkData();
0217     const GeoDataPlacemark::GeoDataVisualCategory category = StyleBuilder::determineVisualCategory(osmData);
0218     if (d->m_placemark->styleUrl() == QLatin1String("#polyline") && category != GeoDataPlacemark::None) {
0219         d->m_placemark->setStyle( GeoDataStyle::Ptr() ); // first clear style so style gets set by setVisualCategory()
0220         d->m_placemark->setVisualCategory( category );
0221     }
0222 
0223     emit polylineUpdated( d->m_placemark );
0224 }
0225 
0226 
0227 void EditPolylineDialog::updateLinesDialog( const QColor &color )
0228 {
0229     QPixmap linesPixmap( d->m_linesColorButton->iconSize().width(),
0230                          d->m_linesColorButton->iconSize().height() );
0231     linesPixmap.fill( color );
0232     d->m_linesColorButton->setIcon( QIcon( linesPixmap ) );
0233 }
0234 
0235 void EditPolylineDialog::restoreInitial( int result )
0236 {
0237     if ( result ) {
0238         return;
0239     }
0240 
0241     GeoDataLineString* currentLineString = static_cast<GeoDataLineString*>( d->m_placemark->geometry() );
0242 
0243     if( *currentLineString != d->m_initialLineString ) {
0244         d->m_placemark->setGeometry( new GeoDataLineString( d->m_initialLineString ) );
0245     }
0246 
0247     if ( d->m_placemark->name() != d->m_initialName ) {
0248         d->m_placemark->setName( d->m_initialName );
0249     }
0250 
0251     if ( d->m_placemark->description() != d->m_initialDescription ) {
0252         d->m_placemark->setDescription( d->m_initialDescription );
0253     }
0254 
0255     if ( d->m_placemark->style()->lineStyle() != d->m_initialLineStyle ) {
0256         GeoDataStyle::Ptr newStyle(new GeoDataStyle( *d->m_placemark->style() ));
0257         newStyle->setLineStyle( d->m_initialLineStyle );
0258         d->m_placemark->setStyle( newStyle );
0259     }
0260 
0261     if( d->m_hadInitialOsmData ) {
0262         d->m_placemark->setOsmData( d->m_initialOsmData );
0263     }
0264 
0265     emit polylineUpdated( d->m_placemark );
0266 }
0267 
0268 void EditPolylineDialog::checkFields()
0269 {
0270     bool ok = true;
0271     if ( d->m_name->text().isEmpty() ) {
0272         QMessageBox::warning( this,
0273                               tr( "No name specified" ),
0274                               tr( "Please specify a name for this polyline." ) );
0275         ok = false;
0276     } else {
0277         if (const auto lineString = geodata_cast<GeoDataLineString>(d->m_placemark->geometry())) {
0278             if( lineString->size() < 2 ) {
0279                 QMessageBox::warning( this,
0280                                       tr( "Not enough nodes specified." ),
0281                                       tr( "Please specify at least 2 nodes for the path by clicking on the map." ) );
0282                 ok = false;
0283             }
0284         }
0285     }
0286     if( ok ) {
0287         accept();
0288     }
0289 }
0290 
0291 }
0292 
0293 #include "moc_EditPolylineDialog.cpp"