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