22 #include "geoeditwidget.h"
24 #include "autoqpointer_p.h"
26 #include <kabc/addressee.h>
28 #include <kcombobox.h>
30 #include <kstandarddirs.h>
32 #include <QtCore/QFile>
33 #include <QtCore/QTextStream>
34 #include <QtGui/QDoubleSpinBox>
35 #include <QtGui/QGridLayout>
36 #include <QtGui/QGroupBox>
37 #include <QtGui/QLabel>
38 #include <QtGui/QPainter>
39 #include <QtGui/QPushButton>
40 #include <QtGui/QSpinBox>
42 class GeoMapWidget :
public QWidget
45 GeoMapWidget( QWidget *parent = 0 )
48 mWorld = QPixmap( KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/pics/world.jpg" ) ) );
50 setAttribute( Qt::WA_NoSystemBackground,
true );
51 setFixedSize( 400, 200 );
56 void setCoordinates(
const KABC::Geo &coordinates )
58 mCoordinates = coordinates;
64 virtual void paintEvent( QPaintEvent* )
68 p.setPen( QColor( 255, 0, 0 ) );
69 p.setBrush( QColor( 255, 0, 0 ) );
71 p.drawPixmap( 0, 0, mWorld );
73 if ( mCoordinates.isValid() ) {
74 const double latMid = height() / 2;
75 const double longMid = width() / 2;
76 const double latOffset = ( mCoordinates.latitude() * latMid ) / 90;
77 const double longOffset = ( mCoordinates.longitude() * longMid ) / 180;
79 const int x = (int)(longMid + longOffset);
80 const int y = (int)(latMid - latOffset);
81 p.drawEllipse( x, y, 4, 4 );
89 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;
205 GeoDialog::GeoDialog(
const KABC::Geo &coordinates, QWidget *parent )
207 mCoordinates( coordinates )
209 KGlobal::locale()->insertCatalog( QLatin1String(
"timezones4" ) );
210 setCaption( i18nc(
"@title:window",
"Coordinate Selection" ) );
211 setButtons( Ok | Cancel );
212 setDefaultButton( Ok );
213 showButtonSeparator(
true );
216 QFrame *page =
new QFrame(
this);
217 setMainWidget( page );
219 QVBoxLayout *layout =
new QVBoxLayout( page );
221 mCityCombo =
new KComboBox( page );
222 layout->addWidget( mCityCombo );
224 QGroupBox *decimalGroup =
new QGroupBox( i18nc(
"@title:group Decimal representation of coordinates",
"Decimal" ), page );
225 QGridLayout *decimalLayout =
new QGridLayout();
226 decimalGroup->setLayout( decimalLayout );
227 decimalLayout->setSpacing( spacingHint() );
229 QLabel *label =
new QLabel( i18nc(
"@label:spinbox",
"Latitude:" ), decimalGroup );
230 decimalLayout->addWidget( label, 0, 0 );
232 mLatitude =
new QDoubleSpinBox( decimalGroup );
233 mLatitude->setMinimum( -90 );
234 mLatitude->setMaximum( 90 );
235 mLatitude->setSingleStep( 1 );
236 mLatitude->setValue( 0 );
237 mLatitude->setDecimals( 6 );
238 mLatitude->setSuffix( QChar( 176 ) );
239 decimalLayout->addWidget( mLatitude, 0, 1 );
241 label =
new QLabel( i18nc(
"@label:spinbox",
"Longitude:" ), decimalGroup );
242 decimalLayout->addWidget( label, 1, 0 );
244 mLongitude =
new QDoubleSpinBox( decimalGroup );
245 mLongitude->setMinimum( -180 );
246 mLongitude->setMaximum( 180 );
247 mLongitude->setSingleStep( 1 );
248 mLongitude->setValue( 0 );
249 mLongitude->setDecimals( 6 );
250 mLongitude->setSuffix( QChar( 176 ) );
251 decimalLayout->addWidget( mLongitude, 1, 1 );
253 QGroupBox *sexagesimalGroup =
new QGroupBox( i18nc(
"@title:group",
"Sexagesimal" ), page );
254 QGridLayout *sexagesimalLayout =
new QGridLayout();
255 sexagesimalGroup->setLayout( sexagesimalLayout );
256 sexagesimalLayout->setSpacing( spacingHint() );
258 label =
new QLabel( i18nc(
"@label:spinbox",
"Latitude:" ), sexagesimalGroup );
259 sexagesimalLayout->addWidget( label, 0, 0 );
261 mLatDegrees =
new QSpinBox( sexagesimalGroup );
262 mLatDegrees->setMinimum( 0 );
263 mLatDegrees->setMaximum( 90 );
264 mLatDegrees->setValue( 1 );
265 mLatDegrees->setSuffix( QChar( 176 ) );
266 mLatDegrees->setWrapping(
false );
267 label->setBuddy( mLatDegrees );
268 sexagesimalLayout->addWidget( mLatDegrees, 0, 1 );
270 mLatMinutes =
new QSpinBox( sexagesimalGroup );
271 mLatMinutes->setMinimum( 0 );
272 mLatMinutes->setMaximum( 59 );
273 mLatMinutes->setValue( 1 );
275 mLatMinutes->setSuffix( QLatin1String(
"'" ) );
276 sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
278 mLatSeconds =
new QSpinBox( sexagesimalGroup );
279 mLatSeconds->setMinimum( 0 );
280 mLatSeconds->setMaximum( 59 );
281 mLatSeconds->setValue( 1 );
282 mLatSeconds->setSuffix( QLatin1String(
"\"" ) );
283 sexagesimalLayout->addWidget( mLatSeconds, 0, 3 );
285 mLatDirection =
new KComboBox( sexagesimalGroup );
286 mLatDirection->addItem( i18nc(
"@item:inlistbox Latitude direction",
"North" ) );
287 mLatDirection->addItem( i18nc(
"@item:inlistbox Latitude direction",
"South" ) );
288 sexagesimalLayout->addWidget( mLatDirection, 0, 4 );
290 label =
new QLabel( i18nc(
"@label:spinbox",
"Longitude:" ), sexagesimalGroup );
291 sexagesimalLayout->addWidget( label, 1, 0 );
293 mLongDegrees =
new QSpinBox( sexagesimalGroup );
294 mLongDegrees->setMinimum( 0 );
295 mLongDegrees->setMaximum( 180 );
296 mLongDegrees->setValue( 1 );
297 mLongDegrees->setSuffix( QChar( 176 ) );
298 label->setBuddy( mLongDegrees );
299 sexagesimalLayout->addWidget( mLongDegrees, 1, 1 );
301 mLongMinutes =
new QSpinBox( sexagesimalGroup );
302 mLongMinutes->setMinimum( 0 );
303 mLongMinutes->setMaximum( 59 );
304 mLongMinutes->setValue( 1 );
305 mLongMinutes->setSuffix( QLatin1String(
"'" ) );
306 sexagesimalLayout->addWidget( mLongMinutes, 1, 2 );
308 mLongSeconds =
new QSpinBox( sexagesimalGroup );
309 mLongSeconds->setMinimum( 0 );
310 mLongSeconds->setMaximum( 59 );
311 mLongSeconds->setValue( 1 );
312 mLongSeconds->setSuffix( QLatin1String(
"\"" ) );
313 sexagesimalLayout->addWidget( mLongSeconds, 1, 3 );
315 mLongDirection =
new KComboBox( sexagesimalGroup );
316 mLongDirection->addItem( i18nc(
"@item:inlistbox Longtitude direction",
"East" ) );
317 mLongDirection->addItem( i18nc(
"@item:inlistbox Longtitude direction",
"West" ) );
318 sexagesimalLayout->addWidget( mLongDirection, 1, 4 );
320 layout->addWidget( decimalGroup );
321 layout->addWidget( sexagesimalGroup );
325 connect( mCityCombo, SIGNAL(activated(
int)),
326 SLOT(cityInputChanged()) );
327 connect( mLatitude, SIGNAL(valueChanged(
double)),
328 SLOT(decimalInputChanged()) );
329 connect( mLongitude, SIGNAL(valueChanged(
double)),
330 SLOT(decimalInputChanged()) );
331 connect( mLatDegrees, SIGNAL(valueChanged(
int)),
332 SLOT(sexagesimalInputChanged()) );
333 connect( mLatMinutes, SIGNAL(valueChanged(
int)),
334 SLOT(sexagesimalInputChanged()) );
335 connect( mLatSeconds, SIGNAL(valueChanged(
int)),
336 SLOT(sexagesimalInputChanged()) );
337 connect( mLatDirection, SIGNAL(activated(
int)),
338 SLOT(sexagesimalInputChanged()) );
339 connect( mLongDegrees, SIGNAL(valueChanged(
int)),
340 SLOT(sexagesimalInputChanged()) );
341 connect( mLongMinutes, SIGNAL(valueChanged(
int)),
342 SLOT(sexagesimalInputChanged()) );
343 connect( mLongSeconds, SIGNAL(valueChanged(
int)),
344 SLOT(sexagesimalInputChanged()) );
345 connect( mLongDirection, SIGNAL(activated(
int)),
346 SLOT(sexagesimalInputChanged()) );
351 KABC::Geo GeoDialog::coordinates()
const
356 void GeoDialog::cityInputChanged()
358 if ( mCityCombo->currentIndex() != 0 ) {
359 GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
360 mCoordinates.setLatitude( geoData.latitude );
361 mCoordinates.setLongitude( geoData.longitude );
363 mCoordinates.setLatitude( 0 );
364 mCoordinates.setLongitude( 0 );
367 updateInputs( ExceptCity );
370 void GeoDialog::decimalInputChanged()
372 mCoordinates.setLatitude( mLatitude->value() );
373 mCoordinates.setLongitude( mLongitude->value() );
375 updateInputs( ExceptDecimal );
378 void GeoDialog::sexagesimalInputChanged()
380 double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
381 60 + (double)mLatSeconds->value() / 3600 );
382 latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
384 double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
385 60 + (double)mLongSeconds->value() / 3600 );
386 longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
388 mCoordinates.setLatitude( latitude );
389 mCoordinates.setLongitude( longitude );
391 updateInputs( ExceptSexagesimal );
394 void GeoDialog::updateInputs( ExceptType type )
396 mCityCombo->blockSignals(
true );
397 mLatitude->blockSignals(
true );
398 mLongitude->blockSignals(
true );
399 mLatDegrees->blockSignals(
true );
400 mLatMinutes->blockSignals(
true );
401 mLatSeconds->blockSignals(
true );
402 mLatDirection->blockSignals(
true );
403 mLongDegrees->blockSignals(
true );
404 mLongMinutes->blockSignals(
true );
405 mLongSeconds->blockSignals(
true );
406 mLongDirection->blockSignals(
true );
408 if ( !(type & ExceptSexagesimal) ) {
409 int degrees, minutes, seconds;
410 double latitude = mCoordinates.latitude();
411 double longitude = mCoordinates.longitude();
413 latitude *= ( latitude < 0 ? -1 : 1 );
414 longitude *= ( longitude < 0 ? -1 : 1 );
416 degrees = (int)( latitude * 1 );
417 minutes = (int)( ( latitude - degrees ) * 60 );
418 seconds = (int)( (
double)( (double)latitude - (
double)degrees - ( (double)minutes / (
double)60 ) ) * (double)3600 );
420 mLatDegrees->setValue( degrees );
421 mLatMinutes->setValue( minutes );
422 mLatSeconds->setValue( seconds );
424 mLatDirection->setCurrentIndex( mLatitude < 0 ? 1 : 0 );
426 degrees = (int)( longitude * 1 );
427 minutes = (int)( ( longitude - degrees ) * 60 );
428 seconds = (int)( (
double)( longitude - (double)degrees - ( (
double)minutes / 60 ) ) * 3600 );
430 mLongDegrees->setValue( degrees );
431 mLongMinutes->setValue( minutes );
432 mLongSeconds->setValue( seconds );
433 mLongDirection->setCurrentIndex( mLongitude < 0 ? 1 : 0 );
436 if ( !(type & ExceptDecimal) ) {
437 mLatitude->setValue( mCoordinates.latitude() );
438 mLongitude->setValue( mCoordinates.longitude() );
441 if ( !(type & ExceptCity) ) {
442 const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
444 mCityCombo->setCurrentIndex( index + 1 );
446 mCityCombo->setCurrentIndex( 0 );
449 mCityCombo->blockSignals(
false );
450 mLatitude->blockSignals(
false );
451 mLongitude->blockSignals(
false );
452 mLatDegrees->blockSignals(
false );
453 mLatMinutes->blockSignals(
false );
454 mLatSeconds->blockSignals(
false );
455 mLatDirection->blockSignals(
false );
456 mLongDegrees->blockSignals(
false );
457 mLongMinutes->blockSignals(
false );
458 mLongSeconds->blockSignals(
false );
459 mLongDirection->blockSignals(
false );
462 void GeoDialog::loadCityList()
467 QFile file( KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/data/zone.tab" ) ) );
469 if ( file.open( QIODevice::ReadOnly ) ) {
470 QTextStream s( &file );
472 QString line, country;
473 QRegExp coord( QLatin1String(
"[+-]\\d+[+-]\\d+" ) );
474 QRegExp name( QLatin1String(
"[^\\s]+/[^\\s]+" ) );
477 while ( !s.atEnd() ) {
478 line = s.readLine().trimmed();
479 if ( line.isEmpty() || line[ 0 ] == QLatin1Char(
'#' ) )
482 country = line.left( 2 );
484 pos = coord.indexIn( line, 0 );
486 c = line.mid( pos, coord.matchedLength() );
488 pos = name.indexIn(line, pos);
490 n = line.mid( pos, name.matchedLength() ).trimmed();
493 if ( !c.isEmpty() && !n.isEmpty() ) {
494 pos = c.indexOf( QLatin1Char(
'+' ), 1 );
496 pos = c.indexOf( QLatin1Char(
'-' ), 1 );
499 geoData.latitude = calculateCoordinate( c.left( pos ) );
500 geoData.longitude = calculateCoordinate( c.mid( pos ) );
501 geoData.country = country;
503 mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char(
'_' ), QLatin1Char(
' ' ) ), geoData );
508 QStringList items( mGeoDataMap.keys() );
509 items.prepend( i18nc(
"@item:inlistbox Undefined location",
"Undefined" ) );
510 mCityCombo->addItems( items );
516 int GeoDialog::nearestCity(
double x,
double y )
const
518 QMap<QString, GeoData>::ConstIterator it;
520 for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
521 double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
522 ( (*it).latitude - y ) * ( (*it).latitude - y );
530 #include "geoeditwidget.moc"