22 #include "geoeditwidget.h"
24 #include "autoqpointer_p.h"
26 #include <kabc/addressee.h>
28 #include <kcombobox.h>
30 #include <klocalizedstring.h>
31 #include <kstandarddirs.h>
33 #include <QtCore/QFile>
34 #include <QtCore/QTextStream>
35 #include <QDoubleSpinBox>
36 #include <QGridLayout>
40 #include <QPushButton>
43 class GeoMapWidget :
public QWidget
46 GeoMapWidget( QWidget *parent = 0 )
49 mWorld = QPixmap( KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/pics/world.jpg" ) ) );
51 setAttribute( Qt::WA_NoSystemBackground,
true );
52 setFixedSize( 400, 200 );
57 void setCoordinates(
const KABC::Geo &coordinates )
59 mCoordinates = coordinates;
65 virtual void paintEvent( QPaintEvent* )
69 p.setPen( QColor( 255, 0, 0 ) );
70 p.setBrush( QColor( 255, 0, 0 ) );
72 p.drawPixmap( 0, 0, mWorld );
74 if ( mCoordinates.isValid() ) {
75 const double latMid = height() / 2;
76 const double longMid = width() / 2;
77 const double latOffset = ( mCoordinates.latitude() * latMid ) / 90;
78 const double longOffset = ( mCoordinates.longitude() * longMid ) / 180;
80 const int x = (int)( longMid + longOffset );
81 const int y = (int)( latMid - latOffset );
82 p.drawEllipse( x, y, 4, 4 );
90 KABC::Geo mCoordinates;
93 GeoEditWidget::GeoEditWidget( QWidget *parent )
96 QGridLayout *layout =
new QGridLayout(
this );
97 layout->setMargin( 0 );
99 mMap =
new GeoMapWidget;
100 layout->addWidget( mMap, 0, 0, 1, 4, Qt::AlignCenter|Qt::AlignVCenter );
102 QLabel *label =
new QLabel( i18nc(
"@label",
"Latitude:" ) );
103 label->setAlignment( Qt::AlignRight );
104 layout->addWidget( label, 1, 0 );
106 mLatitudeLabel =
new QLabel;
107 layout->addWidget( mLatitudeLabel, 1, 1 );
109 label =
new QLabel( i18nc(
"@label",
"Longitude:" ) );
110 label->setAlignment( Qt::AlignRight );
111 layout->addWidget( label, 1, 2 );
113 mLongitudeLabel =
new QLabel;
114 layout->addWidget( mLongitudeLabel, 1, 3 );
116 mChangeButton =
new QPushButton( i18nc(
"@label Change the coordinates",
"Change..." ) );
117 layout->addWidget( mChangeButton, 2, 0, 1, 4, Qt::AlignRight );
119 layout->setRowStretch( 3, 1 );
121 connect( mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()) );
126 GeoEditWidget::~GeoEditWidget()
130 void GeoEditWidget::loadContact(
const KABC::Addressee &contact )
132 mCoordinates = contact.geo();
136 void GeoEditWidget::storeContact( KABC::Addressee &contact )
const
138 contact.setGeo( mCoordinates );
141 void GeoEditWidget::setReadOnly(
bool readOnly )
143 mChangeButton->setEnabled( !readOnly );
146 void GeoEditWidget::updateView()
148 if ( !mCoordinates.isValid() ) {
149 mLatitudeLabel->setText( i18nc(
"@label Coordinates are not available",
"n/a" ) );
150 mLongitudeLabel->setText( i18nc(
"@label Coordinates are not available",
"n/a" ) );
152 mLatitudeLabel->setText( i18nc(
"@label The formatted coordinates",
"%1 %2", mCoordinates.latitude(), QChar( 176 ) ) );
153 mLongitudeLabel->setText( i18nc(
"@label The formatted coordinates",
"%1 %2", mCoordinates.longitude(), QChar( 176 ) ) );
155 mMap->setCoordinates( mCoordinates );
158 void GeoEditWidget::changeClicked()
162 mCoordinates = dlg->coordinates();
167 static double calculateCoordinate(
const QString &coordinate )
170 int d = 0, m = 0, s = 0;
171 QString str = coordinate;
173 neg = str.left( 1 ) == QLatin1String(
"-" );
176 switch ( str.length() ) {
178 d = str.left( 2 ).toInt();
179 m = str.mid( 2 ).toInt();
182 d = str.left( 3 ).toInt();
183 m = str.mid( 3 ).toInt();
186 d = str.left( 2 ).toInt();
187 m = str.mid( 2, 2 ).toInt();
188 s = str.right( 2 ).toInt();
191 d = str.left( 3 ).toInt();
192 m = str.mid( 3, 2 ).toInt();
193 s = str.right( 2 ).toInt();
200 return - ( d + m / 60.0 + s / 3600.0 );
202 return d + m / 60.0 + s / 3600.0;
206 GeoDialog::GeoDialog(
const KABC::Geo &coordinates, QWidget *parent )
208 mCoordinates( coordinates )
210 KGlobal::locale()->insertCatalog( QLatin1String(
"timezones4" ) );
211 setCaption( i18nc(
"@title:window",
"Coordinate Selection" ) );
212 setButtons( Ok | Cancel );
213 setDefaultButton( Ok );
214 showButtonSeparator(
true );
217 QFrame *page =
new QFrame(
this );
218 setMainWidget( page );
220 QVBoxLayout *layout =
new QVBoxLayout( page );
222 mCityCombo =
new KComboBox( page );
223 layout->addWidget( mCityCombo );
225 QGroupBox *decimalGroup =
new QGroupBox( i18nc(
"@title:group Decimal representation of coordinates",
"Decimal" ), page );
226 QGridLayout *decimalLayout =
new QGridLayout();
227 decimalGroup->setLayout( decimalLayout );
228 decimalLayout->setSpacing( spacingHint() );
230 QLabel *label =
new QLabel( i18nc(
"@label:spinbox",
"Latitude:" ), decimalGroup );
231 decimalLayout->addWidget( label, 0, 0 );
233 mLatitude =
new QDoubleSpinBox( decimalGroup );
234 mLatitude->setMinimum( -90 );
235 mLatitude->setMaximum( 90 );
236 mLatitude->setSingleStep( 1 );
237 mLatitude->setValue( 0 );
238 mLatitude->setDecimals( 6 );
239 mLatitude->setSuffix( QChar( 176 ) );
240 decimalLayout->addWidget( mLatitude, 0, 1 );
242 label =
new QLabel( i18nc(
"@label:spinbox",
"Longitude:" ), decimalGroup );
243 decimalLayout->addWidget( label, 1, 0 );
245 mLongitude =
new QDoubleSpinBox( decimalGroup );
246 mLongitude->setMinimum( -180 );
247 mLongitude->setMaximum( 180 );
248 mLongitude->setSingleStep( 1 );
249 mLongitude->setValue( 0 );
250 mLongitude->setDecimals( 6 );
251 mLongitude->setSuffix( QChar( 176 ) );
252 decimalLayout->addWidget( mLongitude, 1, 1 );
254 QGroupBox *sexagesimalGroup =
new QGroupBox( i18nc(
"@title:group",
"Sexagesimal" ), page );
255 QGridLayout *sexagesimalLayout =
new QGridLayout();
256 sexagesimalGroup->setLayout( sexagesimalLayout );
257 sexagesimalLayout->setSpacing( spacingHint() );
259 label =
new QLabel( i18nc(
"@label:spinbox",
"Latitude:" ), sexagesimalGroup );
260 sexagesimalLayout->addWidget( label, 0, 0 );
262 mLatDegrees =
new QSpinBox( sexagesimalGroup );
263 mLatDegrees->setMinimum( 0 );
264 mLatDegrees->setMaximum( 90 );
265 mLatDegrees->setValue( 1 );
266 mLatDegrees->setSuffix( QChar( 176 ) );
267 mLatDegrees->setWrapping(
false );
268 label->setBuddy( mLatDegrees );
269 sexagesimalLayout->addWidget( mLatDegrees, 0, 1 );
271 mLatMinutes =
new QSpinBox( sexagesimalGroup );
272 mLatMinutes->setMinimum( 0 );
273 mLatMinutes->setMaximum( 59 );
274 mLatMinutes->setValue( 1 );
276 mLatMinutes->setSuffix( QLatin1String(
"'" ) );
277 sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
279 mLatSeconds =
new QSpinBox( sexagesimalGroup );
280 mLatSeconds->setMinimum( 0 );
281 mLatSeconds->setMaximum( 59 );
282 mLatSeconds->setValue( 1 );
283 mLatSeconds->setSuffix( QLatin1String(
"\"" ) );
284 sexagesimalLayout->addWidget( mLatSeconds, 0, 3 );
286 mLatDirection =
new KComboBox( sexagesimalGroup );
287 mLatDirection->addItem( i18nc(
"@item:inlistbox Latitude direction",
"North" ) );
288 mLatDirection->addItem( i18nc(
"@item:inlistbox Latitude direction",
"South" ) );
289 sexagesimalLayout->addWidget( mLatDirection, 0, 4 );
291 label =
new QLabel( i18nc(
"@label:spinbox",
"Longitude:" ), sexagesimalGroup );
292 sexagesimalLayout->addWidget( label, 1, 0 );
294 mLongDegrees =
new QSpinBox( sexagesimalGroup );
295 mLongDegrees->setMinimum( 0 );
296 mLongDegrees->setMaximum( 180 );
297 mLongDegrees->setValue( 1 );
298 mLongDegrees->setSuffix( QChar( 176 ) );
299 label->setBuddy( mLongDegrees );
300 sexagesimalLayout->addWidget( mLongDegrees, 1, 1 );
302 mLongMinutes =
new QSpinBox( sexagesimalGroup );
303 mLongMinutes->setMinimum( 0 );
304 mLongMinutes->setMaximum( 59 );
305 mLongMinutes->setValue( 1 );
306 mLongMinutes->setSuffix( QLatin1String(
"'" ) );
307 sexagesimalLayout->addWidget( mLongMinutes, 1, 2 );
309 mLongSeconds =
new QSpinBox( sexagesimalGroup );
310 mLongSeconds->setMinimum( 0 );
311 mLongSeconds->setMaximum( 59 );
312 mLongSeconds->setValue( 1 );
313 mLongSeconds->setSuffix( QLatin1String(
"\"" ) );
314 sexagesimalLayout->addWidget( mLongSeconds, 1, 3 );
316 mLongDirection =
new KComboBox( sexagesimalGroup );
317 mLongDirection->addItem( i18nc(
"@item:inlistbox Longtitude direction",
"East" ) );
318 mLongDirection->addItem( i18nc(
"@item:inlistbox Longtitude direction",
"West" ) );
319 sexagesimalLayout->addWidget( mLongDirection, 1, 4 );
321 layout->addWidget( decimalGroup );
322 layout->addWidget( sexagesimalGroup );
326 connect( mCityCombo, SIGNAL(activated(
int)),
327 SLOT(cityInputChanged()) );
328 connect( mLatitude, SIGNAL(valueChanged(
double)),
329 SLOT(decimalInputChanged()) );
330 connect( mLongitude, SIGNAL(valueChanged(
double)),
331 SLOT(decimalInputChanged()) );
332 connect( mLatDegrees, SIGNAL(valueChanged(
int)),
333 SLOT(sexagesimalInputChanged()) );
334 connect( mLatMinutes, SIGNAL(valueChanged(
int)),
335 SLOT(sexagesimalInputChanged()) );
336 connect( mLatSeconds, SIGNAL(valueChanged(
int)),
337 SLOT(sexagesimalInputChanged()) );
338 connect( mLatDirection, SIGNAL(activated(
int)),
339 SLOT(sexagesimalInputChanged()) );
340 connect( mLongDegrees, SIGNAL(valueChanged(
int)),
341 SLOT(sexagesimalInputChanged()) );
342 connect( mLongMinutes, SIGNAL(valueChanged(
int)),
343 SLOT(sexagesimalInputChanged()) );
344 connect( mLongSeconds, SIGNAL(valueChanged(
int)),
345 SLOT(sexagesimalInputChanged()) );
346 connect( mLongDirection, SIGNAL(activated(
int)),
347 SLOT(sexagesimalInputChanged()) );
352 KABC::Geo GeoDialog::coordinates()
const
357 void GeoDialog::cityInputChanged()
359 if ( mCityCombo->currentIndex() != 0 ) {
360 GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
361 mCoordinates.setLatitude( geoData.latitude );
362 mCoordinates.setLongitude( geoData.longitude );
364 mCoordinates.setLatitude( 0 );
365 mCoordinates.setLongitude( 0 );
368 updateInputs( ExceptCity );
371 void GeoDialog::decimalInputChanged()
373 mCoordinates.setLatitude( mLatitude->value() );
374 mCoordinates.setLongitude( mLongitude->value() );
376 updateInputs( ExceptDecimal );
379 void GeoDialog::sexagesimalInputChanged()
381 double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
382 60 + (double)mLatSeconds->value() / 3600 );
383 latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
385 double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
386 60 + (double)mLongSeconds->value() / 3600 );
387 longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
389 mCoordinates.setLatitude( latitude );
390 mCoordinates.setLongitude( longitude );
392 updateInputs( ExceptSexagesimal );
395 void GeoDialog::updateInputs( ExceptType type )
397 mCityCombo->blockSignals(
true );
398 mLatitude->blockSignals(
true );
399 mLongitude->blockSignals(
true );
400 mLatDegrees->blockSignals(
true );
401 mLatMinutes->blockSignals(
true );
402 mLatSeconds->blockSignals(
true );
403 mLatDirection->blockSignals(
true );
404 mLongDegrees->blockSignals(
true );
405 mLongMinutes->blockSignals(
true );
406 mLongSeconds->blockSignals(
true );
407 mLongDirection->blockSignals(
true );
409 if ( !( type & ExceptDecimal ) ) {
410 mLatitude->setValue( mCoordinates.latitude() );
411 mLongitude->setValue( mCoordinates.longitude() );
414 if ( !(type & ExceptSexagesimal) ) {
415 int degrees, minutes, seconds;
416 double latitude = mCoordinates.latitude();
417 double longitude = mCoordinates.longitude();
419 latitude *= ( latitude < 0 ? -1 : 1 );
420 longitude *= ( longitude < 0 ? -1 : 1 );
422 degrees = (int)( latitude * 1 );
423 minutes = (int)( ( latitude - degrees ) * 60 );
424 seconds = (int)( (
double)( (double)latitude - (
double)degrees - ( (double)minutes / (
double)60 ) ) * (double)3600 );
426 mLatDegrees->setValue( degrees );
427 mLatMinutes->setValue( minutes );
428 mLatSeconds->setValue( seconds );
430 mLatDirection->setCurrentIndex( mLatitude->value() < 0 ? 1 : 0 );
432 degrees = (int)( longitude * 1 );
433 minutes = (int)( ( longitude - degrees ) * 60 );
434 seconds = (int)( (
double)( longitude - (double)degrees - ( (
double)minutes / 60 ) ) * 3600 );
436 mLongDegrees->setValue( degrees );
437 mLongMinutes->setValue( minutes );
438 mLongSeconds->setValue( seconds );
439 mLongDirection->setCurrentIndex( mLongitude->value() < 0 ? 1 : 0 );
442 if ( !( type & ExceptCity ) ) {
443 const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
445 mCityCombo->setCurrentIndex( index + 1 );
447 mCityCombo->setCurrentIndex( 0 );
451 mCityCombo->blockSignals(
false );
452 mLatitude->blockSignals(
false );
453 mLongitude->blockSignals(
false );
454 mLatDegrees->blockSignals(
false );
455 mLatMinutes->blockSignals(
false );
456 mLatSeconds->blockSignals(
false );
457 mLatDirection->blockSignals(
false );
458 mLongDegrees->blockSignals(
false );
459 mLongMinutes->blockSignals(
false );
460 mLongSeconds->blockSignals(
false );
461 mLongDirection->blockSignals(
false );
464 void GeoDialog::loadCityList()
469 QFile file( KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/data/zone.tab" ) ) );
471 if ( file.open( QIODevice::ReadOnly ) ) {
472 QTextStream s( &file );
474 QString line, country;
475 QRegExp coord( QLatin1String(
"[+-]\\d+[+-]\\d+" ) );
476 QRegExp name( QLatin1String(
"[^\\s]+/[^\\s]+" ) );
479 while ( !s.atEnd() ) {
480 line = s.readLine().trimmed();
481 if ( line.isEmpty() || line[ 0 ] == QLatin1Char(
'#' ) ) {
485 country = line.left( 2 );
487 pos = coord.indexIn( line, 0 );
489 c = line.mid( pos, coord.matchedLength() );
492 pos = name.indexIn( line, pos );
494 n = line.mid( pos, name.matchedLength() ).trimmed();
497 if ( !c.isEmpty() && !n.isEmpty() ) {
498 pos = c.indexOf( QLatin1Char(
'+' ), 1 );
500 pos = c.indexOf( QLatin1Char(
'-' ), 1 );
504 geoData.latitude = calculateCoordinate( c.left( pos ) );
505 geoData.longitude = calculateCoordinate( c.mid( pos ) );
506 geoData.country = country;
508 mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char(
'_' ), QLatin1Char(
' ' ) ), geoData );
513 QStringList items( mGeoDataMap.keys() );
514 items.prepend( i18nc(
"@item:inlistbox Undefined location",
"Undefined" ) );
515 mCityCombo->addItems( items );
521 int GeoDialog::nearestCity(
double x,
double y )
const
523 QMap<QString, GeoData>::ConstIterator it;
525 for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
526 double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
527 ( (*it).latitude - y ) * ( (*it).latitude - y );
528 if ( dist < 0.0005 ) {
A QPointer which when destructed, deletes the object it points to.