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;
94 GeoEditWidget::GeoEditWidget( QWidget *parent )
97 QGridLayout *layout =
new QGridLayout(
this );
98 layout->setMargin( 0 );
100 mMap =
new GeoMapWidget;
101 layout->addWidget( mMap, 0, 0, 1, 4, Qt::AlignCenter|Qt::AlignVCenter );
103 QLabel *label =
new QLabel( i18nc(
"@label",
"Latitude:" ) );
104 label->setAlignment( Qt::AlignRight );
105 layout->addWidget( label, 1, 0 );
107 mLatitudeLabel =
new QLabel;
108 layout->addWidget( mLatitudeLabel, 1, 1 );
110 label =
new QLabel( i18nc(
"@label",
"Longitude:" ) );
111 label->setAlignment( Qt::AlignRight );
112 layout->addWidget( label, 1, 2 );
114 mLongitudeLabel =
new QLabel;
115 layout->addWidget( mLongitudeLabel, 1, 3 );
117 mChangeButton =
new QPushButton( i18nc(
"@label Change the coordinates",
"Change..." ) );
118 layout->addWidget( mChangeButton, 2, 0, 1, 4, Qt::AlignRight );
120 layout->setRowStretch( 3, 1 );
122 connect( mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()) );
127 GeoEditWidget::~GeoEditWidget()
131 void GeoEditWidget::loadContact(
const KABC::Addressee &contact )
133 mCoordinates = contact.geo();
137 void GeoEditWidget::storeContact( KABC::Addressee &contact )
const
139 contact.setGeo( mCoordinates );
142 void GeoEditWidget::setReadOnly(
bool readOnly )
144 mChangeButton->setEnabled( !readOnly );
147 void GeoEditWidget::updateView()
149 if ( !mCoordinates.isValid() ) {
150 mLatitudeLabel->setText( i18nc(
"@label Coordinates are not available",
"n/a" ) );
151 mLongitudeLabel->setText( i18nc(
"@label Coordinates are not available",
"n/a" ) );
153 mLatitudeLabel->setText( i18nc(
"@label The formatted coordinates",
"%1 %2", mCoordinates.latitude(), QChar( 176 ) ) );
154 mLongitudeLabel->setText( i18nc(
"@label The formatted coordinates",
"%1 %2", mCoordinates.longitude(), QChar( 176 ) ) );
156 mMap->setCoordinates( mCoordinates );
159 void GeoEditWidget::changeClicked()
163 mCoordinates = dlg->coordinates();
168 static double calculateCoordinate(
const QString &coordinate )
171 int d = 0, m = 0, s = 0;
172 QString str = coordinate;
174 neg = str.left( 1 ) == QLatin1String(
"-" );
177 switch ( str.length() ) {
179 d = str.left( 2 ).toInt();
180 m = str.mid( 2 ).toInt();
183 d = str.left( 3 ).toInt();
184 m = str.mid( 3 ).toInt();
187 d = str.left( 2 ).toInt();
188 m = str.mid( 2, 2 ).toInt();
189 s = str.right( 2 ).toInt();
192 d = str.left( 3 ).toInt();
193 m = str.mid( 3, 2 ).toInt();
194 s = str.right( 2 ).toInt();
201 return - ( d + m / 60.0 + s / 3600.0 );
203 return d + m / 60.0 + s / 3600.0;
207 GeoDialog::GeoDialog(
const KABC::Geo &coordinates, QWidget *parent )
209 mCoordinates( coordinates )
211 KGlobal::locale()->insertCatalog( QLatin1String(
"timezones4" ) );
212 setCaption( i18nc(
"@title:window",
"Coordinate Selection" ) );
213 setButtons( Ok | Cancel );
214 setDefaultButton( Ok );
215 showButtonSeparator(
true );
218 QFrame *page =
new QFrame(
this );
219 setMainWidget( page );
221 QVBoxLayout *layout =
new QVBoxLayout( page );
223 mCityCombo =
new KComboBox( page );
224 layout->addWidget( mCityCombo );
226 QGroupBox *decimalGroup =
new QGroupBox( i18nc(
"@title:group Decimal representation of coordinates",
"Decimal" ), page );
227 QGridLayout *decimalLayout =
new QGridLayout();
228 decimalGroup->setLayout( decimalLayout );
229 decimalLayout->setSpacing( spacingHint() );
231 QLabel *label =
new QLabel( i18nc(
"@label:spinbox",
"Latitude:" ), decimalGroup );
232 decimalLayout->addWidget( label, 0, 0 );
234 mLatitude =
new QDoubleSpinBox( decimalGroup );
235 mLatitude->setMinimum( -90 );
236 mLatitude->setMaximum( 90 );
237 mLatitude->setSingleStep( 1 );
238 mLatitude->setValue( 0 );
239 mLatitude->setDecimals( 6 );
240 mLatitude->setSuffix( QChar( 176 ) );
241 decimalLayout->addWidget( mLatitude, 0, 1 );
243 label =
new QLabel( i18nc(
"@label:spinbox",
"Longitude:" ), decimalGroup );
244 decimalLayout->addWidget( label, 1, 0 );
246 mLongitude =
new QDoubleSpinBox( decimalGroup );
247 mLongitude->setMinimum( -180 );
248 mLongitude->setMaximum( 180 );
249 mLongitude->setSingleStep( 1 );
250 mLongitude->setValue( 0 );
251 mLongitude->setDecimals( 6 );
252 mLongitude->setSuffix( QChar( 176 ) );
253 decimalLayout->addWidget( mLongitude, 1, 1 );
255 QGroupBox *sexagesimalGroup =
new QGroupBox( i18nc(
"@title:group",
"Sexagesimal" ), page );
256 QGridLayout *sexagesimalLayout =
new QGridLayout();
257 sexagesimalGroup->setLayout( sexagesimalLayout );
258 sexagesimalLayout->setSpacing( spacingHint() );
260 label =
new QLabel( i18nc(
"@label:spinbox",
"Latitude:" ), sexagesimalGroup );
261 sexagesimalLayout->addWidget( label, 0, 0 );
263 mLatDegrees =
new QSpinBox( sexagesimalGroup );
264 mLatDegrees->setMinimum( 0 );
265 mLatDegrees->setMaximum( 90 );
266 mLatDegrees->setValue( 1 );
267 mLatDegrees->setSuffix( QChar( 176 ) );
268 mLatDegrees->setWrapping(
false );
269 label->setBuddy( mLatDegrees );
270 sexagesimalLayout->addWidget( mLatDegrees, 0, 1 );
272 mLatMinutes =
new QSpinBox( sexagesimalGroup );
273 mLatMinutes->setMinimum( 0 );
274 mLatMinutes->setMaximum( 59 );
275 mLatMinutes->setValue( 1 );
277 mLatMinutes->setSuffix( QLatin1String(
"'" ) );
278 sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
280 mLatSeconds =
new QSpinBox( sexagesimalGroup );
281 mLatSeconds->setMinimum( 0 );
282 mLatSeconds->setMaximum( 59 );
283 mLatSeconds->setValue( 1 );
284 mLatSeconds->setSuffix( QLatin1String(
"\"" ) );
285 sexagesimalLayout->addWidget( mLatSeconds, 0, 3 );
287 mLatDirection =
new KComboBox( sexagesimalGroup );
288 mLatDirection->addItem( i18nc(
"@item:inlistbox Latitude direction",
"North" ) );
289 mLatDirection->addItem( i18nc(
"@item:inlistbox Latitude direction",
"South" ) );
290 sexagesimalLayout->addWidget( mLatDirection, 0, 4 );
292 label =
new QLabel( i18nc(
"@label:spinbox",
"Longitude:" ), sexagesimalGroup );
293 sexagesimalLayout->addWidget( label, 1, 0 );
295 mLongDegrees =
new QSpinBox( sexagesimalGroup );
296 mLongDegrees->setMinimum( 0 );
297 mLongDegrees->setMaximum( 180 );
298 mLongDegrees->setValue( 1 );
299 mLongDegrees->setSuffix( QChar( 176 ) );
300 label->setBuddy( mLongDegrees );
301 sexagesimalLayout->addWidget( mLongDegrees, 1, 1 );
303 mLongMinutes =
new QSpinBox( sexagesimalGroup );
304 mLongMinutes->setMinimum( 0 );
305 mLongMinutes->setMaximum( 59 );
306 mLongMinutes->setValue( 1 );
307 mLongMinutes->setSuffix( QLatin1String(
"'" ) );
308 sexagesimalLayout->addWidget( mLongMinutes, 1, 2 );
310 mLongSeconds =
new QSpinBox( sexagesimalGroup );
311 mLongSeconds->setMinimum( 0 );
312 mLongSeconds->setMaximum( 59 );
313 mLongSeconds->setValue( 1 );
314 mLongSeconds->setSuffix( QLatin1String(
"\"" ) );
315 sexagesimalLayout->addWidget( mLongSeconds, 1, 3 );
317 mLongDirection =
new KComboBox( sexagesimalGroup );
318 mLongDirection->addItem( i18nc(
"@item:inlistbox Longtitude direction",
"East" ) );
319 mLongDirection->addItem( i18nc(
"@item:inlistbox Longtitude direction",
"West" ) );
320 sexagesimalLayout->addWidget( mLongDirection, 1, 4 );
322 layout->addWidget( decimalGroup );
323 layout->addWidget( sexagesimalGroup );
327 connect( mCityCombo, SIGNAL(activated(
int)),
328 SLOT(cityInputChanged()) );
329 connect( mLatitude, SIGNAL(valueChanged(
double)),
330 SLOT(decimalInputChanged()) );
331 connect( mLongitude, SIGNAL(valueChanged(
double)),
332 SLOT(decimalInputChanged()) );
333 connect( mLatDegrees, SIGNAL(valueChanged(
int)),
334 SLOT(sexagesimalInputChanged()) );
335 connect( mLatMinutes, SIGNAL(valueChanged(
int)),
336 SLOT(sexagesimalInputChanged()) );
337 connect( mLatSeconds, SIGNAL(valueChanged(
int)),
338 SLOT(sexagesimalInputChanged()) );
339 connect( mLatDirection, SIGNAL(activated(
int)),
340 SLOT(sexagesimalInputChanged()) );
341 connect( mLongDegrees, SIGNAL(valueChanged(
int)),
342 SLOT(sexagesimalInputChanged()) );
343 connect( mLongMinutes, SIGNAL(valueChanged(
int)),
344 SLOT(sexagesimalInputChanged()) );
345 connect( mLongSeconds, SIGNAL(valueChanged(
int)),
346 SLOT(sexagesimalInputChanged()) );
347 connect( mLongDirection, SIGNAL(activated(
int)),
348 SLOT(sexagesimalInputChanged()) );
353 KABC::Geo GeoDialog::coordinates()
const
358 void GeoDialog::cityInputChanged()
360 if ( mCityCombo->currentIndex() != 0 ) {
361 GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
362 mCoordinates.setLatitude( geoData.latitude );
363 mCoordinates.setLongitude( geoData.longitude );
365 mCoordinates.setLatitude( 0 );
366 mCoordinates.setLongitude( 0 );
369 updateInputs( ExceptCity );
372 void GeoDialog::decimalInputChanged()
374 mCoordinates.setLatitude( mLatitude->value() );
375 mCoordinates.setLongitude( mLongitude->value() );
377 updateInputs( ExceptDecimal );
380 void GeoDialog::sexagesimalInputChanged()
382 double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
383 60 + (double)mLatSeconds->value() / 3600 );
384 latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
386 double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
387 60 + (double)mLongSeconds->value() / 3600 );
388 longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
390 mCoordinates.setLatitude( latitude );
391 mCoordinates.setLongitude( longitude );
393 updateInputs( ExceptSexagesimal );
396 void GeoDialog::updateInputs( ExceptType type )
398 mCityCombo->blockSignals(
true );
399 mLatitude->blockSignals(
true );
400 mLongitude->blockSignals(
true );
401 mLatDegrees->blockSignals(
true );
402 mLatMinutes->blockSignals(
true );
403 mLatSeconds->blockSignals(
true );
404 mLatDirection->blockSignals(
true );
405 mLongDegrees->blockSignals(
true );
406 mLongMinutes->blockSignals(
true );
407 mLongSeconds->blockSignals(
true );
408 mLongDirection->blockSignals(
true );
410 if ( !( type & ExceptDecimal ) ) {
411 mLatitude->setValue( mCoordinates.latitude() );
412 mLongitude->setValue( mCoordinates.longitude() );
416 if ( !(type & ExceptSexagesimal) ) {
417 int degrees, minutes, seconds;
418 double latitude = mCoordinates.latitude();
419 double longitude = mCoordinates.longitude();
421 latitude *= ( latitude < 0 ? -1 : 1 );
422 longitude *= ( longitude < 0 ? -1 : 1 );
424 degrees = (int)( latitude * 1 );
425 minutes = (int)( ( latitude - degrees ) * 60 );
426 seconds = (int)( (
double)( (double)latitude - (
double)degrees - ( (double)minutes / (
double)60 ) ) * (double)3600 );
428 mLatDegrees->setValue( degrees );
429 mLatMinutes->setValue( minutes );
430 mLatSeconds->setValue( seconds );
432 mLatDirection->setCurrentIndex( mLatitude->value() < 0 ? 1 : 0 );
434 degrees = (int)( longitude * 1 );
435 minutes = (int)( ( longitude - degrees ) * 60 );
436 seconds = (int)( (
double)( longitude - (double)degrees - ( (
double)minutes / 60 ) ) * 3600 );
438 mLongDegrees->setValue( degrees );
439 mLongMinutes->setValue( minutes );
440 mLongSeconds->setValue( seconds );
441 mLongDirection->setCurrentIndex( mLongitude->value() < 0 ? 1 : 0 );
444 if ( !( type & ExceptCity ) ) {
445 const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
447 mCityCombo->setCurrentIndex( index + 1 );
449 mCityCombo->setCurrentIndex( 0 );
453 mCityCombo->blockSignals(
false );
454 mLatitude->blockSignals(
false );
455 mLongitude->blockSignals(
false );
456 mLatDegrees->blockSignals(
false );
457 mLatMinutes->blockSignals(
false );
458 mLatSeconds->blockSignals(
false );
459 mLatDirection->blockSignals(
false );
460 mLongDegrees->blockSignals(
false );
461 mLongMinutes->blockSignals(
false );
462 mLongSeconds->blockSignals(
false );
463 mLongDirection->blockSignals(
false );
466 void GeoDialog::loadCityList()
471 QFile file( KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/data/zone.tab" ) ) );
473 if ( file.open( QIODevice::ReadOnly ) ) {
474 QTextStream s( &file );
476 QString line, country;
477 QRegExp coord( QLatin1String(
"[+-]\\d+[+-]\\d+" ) );
478 QRegExp name( QLatin1String(
"[^\\s]+/[^\\s]+" ) );
481 while ( !s.atEnd() ) {
482 line = s.readLine().trimmed();
483 if ( line.isEmpty() || line[ 0 ] == QLatin1Char(
'#' ) ) {
487 country = line.left( 2 );
489 pos = coord.indexIn( line, 0 );
491 c = line.mid( pos, coord.matchedLength() );
494 pos = name.indexIn( line, pos );
496 n = line.mid( pos, name.matchedLength() ).trimmed();
499 if ( !c.isEmpty() && !n.isEmpty() ) {
500 pos = c.indexOf( QLatin1Char(
'+' ), 1 );
502 pos = c.indexOf( QLatin1Char(
'-' ), 1 );
506 geoData.latitude = calculateCoordinate( c.left( pos ) );
507 geoData.longitude = calculateCoordinate( c.mid( pos ) );
508 geoData.country = country;
510 mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char(
'_' ), QLatin1Char(
' ' ) ), geoData );
515 QStringList items( mGeoDataMap.keys() );
516 items.prepend( i18nc(
"@item:inlistbox Undefined location",
"Undefined" ) );
517 mCityCombo->addItems( items );
523 int GeoDialog::nearestCity(
double x,
double y )
const
525 QMap<QString, GeoData>::ConstIterator it;
527 for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
528 double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
529 ( (*it).latitude - y ) * ( (*it).latitude - y );
530 if ( dist < 0.0005 ) {
A QPointer which when destructed, deletes the object it points to.