• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

akonadi

  • akonadi
  • contact
  • editor
geoeditwidget.cpp
1 /*
2  This file is part of Akonadi Contact.
3 
4  Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>
5 
6  This library is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Library General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or (at your
9  option) any later version.
10 
11  This library is distributed in the hope that it will be useful, but WITHOUT
12  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14  License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to the
18  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  02110-1301, USA.
20 */
21 
22 #include "geoeditwidget.h"
23 
24 #include "autoqpointer_p.h"
25 
26 #include <kabc/addressee.h>
27 #include <kabc/geo.h>
28 #include <kcombobox.h>
29 #include <klocale.h>
30 #include <kstandarddirs.h>
31 
32 #include <QtCore/QFile>
33 #include <QtCore/QTextStream>
34 #include <QDoubleSpinBox>
35 #include <QGridLayout>
36 #include <QGroupBox>
37 #include <QLabel>
38 #include <QPainter>
39 #include <QPushButton>
40 #include <QSpinBox>
41 
42 class GeoMapWidget : public QWidget
43 {
44  public:
45  GeoMapWidget( QWidget *parent = 0 )
46  : QWidget( parent )
47  {
48  mWorld = QPixmap( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/pics/world.jpg" ) ) );
49 
50  setAttribute( Qt::WA_NoSystemBackground, true );
51  setFixedSize( 400, 200 );
52 
53  update();
54  }
55 
56  void setCoordinates( const KABC::Geo &coordinates )
57  {
58  mCoordinates = coordinates;
59 
60  update();
61  }
62 
63  protected:
64  virtual void paintEvent( QPaintEvent* )
65  {
66  QPainter p;
67  p.begin( this );
68  p.setPen( QColor( 255, 0, 0 ) );
69  p.setBrush( QColor( 255, 0, 0 ) );
70 
71  p.drawPixmap( 0, 0, mWorld );
72 
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;
78 
79  const int x = (int)( longMid + longOffset );
80  const int y = (int)( latMid - latOffset );
81  p.drawEllipse( x, y, 4, 4 );
82  }
83 
84  p.end();
85  }
86 
87  private:
88  QPixmap mWorld;
89  KABC::Geo mCoordinates;
90 };
91 
92 
93 GeoEditWidget::GeoEditWidget( QWidget *parent )
94  : QWidget( parent )
95 {
96  QGridLayout *layout = new QGridLayout( this );
97  layout->setMargin( 0 );
98 
99  mMap = new GeoMapWidget;
100  layout->addWidget( mMap, 0, 0, 1, 4, Qt::AlignCenter|Qt::AlignVCenter );
101 
102  QLabel *label = new QLabel( i18nc( "@label", "Latitude:" ) );
103  label->setAlignment( Qt::AlignRight );
104  layout->addWidget( label, 1, 0 );
105 
106  mLatitudeLabel = new QLabel;
107  layout->addWidget( mLatitudeLabel, 1, 1 );
108 
109  label = new QLabel( i18nc( "@label", "Longitude:" ) );
110  label->setAlignment( Qt::AlignRight );
111  layout->addWidget( label, 1, 2 );
112 
113  mLongitudeLabel = new QLabel;
114  layout->addWidget( mLongitudeLabel, 1, 3 );
115 
116  mChangeButton = new QPushButton( i18nc( "@label Change the coordinates", "Change..." ) );
117  layout->addWidget( mChangeButton, 2, 0, 1, 4, Qt::AlignRight );
118 
119  layout->setRowStretch( 3, 1 );
120 
121  connect( mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()) );
122 
123  updateView();
124 }
125 
126 GeoEditWidget::~GeoEditWidget()
127 {
128 }
129 
130 void GeoEditWidget::loadContact( const KABC::Addressee &contact )
131 {
132  mCoordinates = contact.geo();
133  updateView();
134 }
135 
136 void GeoEditWidget::storeContact( KABC::Addressee &contact ) const
137 {
138  contact.setGeo( mCoordinates );
139 }
140 
141 void GeoEditWidget::setReadOnly( bool readOnly )
142 {
143  mChangeButton->setEnabled( !readOnly );
144 }
145 
146 void GeoEditWidget::updateView()
147 {
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" ) );
151  } else {
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 ) ) );
154  }
155  mMap->setCoordinates( mCoordinates );
156 }
157 
158 void GeoEditWidget::changeClicked()
159 {
160  AutoQPointer<GeoDialog> dlg = new GeoDialog( mCoordinates, this );
161  if ( dlg->exec() ) {
162  mCoordinates = dlg->coordinates();
163  updateView();
164  }
165 }
166 
167 static double calculateCoordinate( const QString &coordinate )
168 {
169  int neg;
170  int d = 0, m = 0, s = 0;
171  QString str = coordinate;
172 
173  neg = str.left( 1 ) == QLatin1String( "-" );
174  str.remove( 0, 1 );
175 
176  switch ( str.length() ) {
177  case 4:
178  d = str.left( 2 ).toInt();
179  m = str.mid( 2 ).toInt();
180  break;
181  case 5:
182  d = str.left( 3 ).toInt();
183  m = str.mid( 3 ).toInt();
184  break;
185  case 6:
186  d = str.left( 2 ).toInt();
187  m = str.mid( 2, 2 ).toInt();
188  s = str.right( 2 ).toInt();
189  break;
190  case 7:
191  d = str.left( 3 ).toInt();
192  m = str.mid( 3, 2 ).toInt();
193  s = str.right( 2 ).toInt();
194  break;
195  default:
196  break;
197  }
198 
199  if ( neg ) {
200  return - ( d + m / 60.0 + s / 3600.0 );
201  } else {
202  return d + m / 60.0 + s / 3600.0;
203  }
204 }
205 
206 GeoDialog::GeoDialog( const KABC::Geo &coordinates, QWidget *parent )
207  : KDialog( parent ),
208  mCoordinates( coordinates )
209 {
210  KGlobal::locale()->insertCatalog( QLatin1String( "timezones4" ) );
211  setCaption( i18nc( "@title:window", "Coordinate Selection" ) );
212  setButtons( Ok | Cancel );
213  setDefaultButton( Ok );
214  showButtonSeparator( true );
215  setModal( true );
216 
217  QFrame *page = new QFrame( this );
218  setMainWidget( page );
219 
220  QVBoxLayout *layout = new QVBoxLayout( page );
221 
222  mCityCombo = new KComboBox( page );
223  layout->addWidget( mCityCombo );
224 
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() );
229 
230  QLabel *label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), decimalGroup );
231  decimalLayout->addWidget( label, 0, 0 );
232 
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 );
241 
242  label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), decimalGroup );
243  decimalLayout->addWidget( label, 1, 0 );
244 
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 );
253 
254  QGroupBox *sexagesimalGroup = new QGroupBox( i18nc( "@title:group", "Sexagesimal" ), page );
255  QGridLayout *sexagesimalLayout = new QGridLayout();
256  sexagesimalGroup->setLayout( sexagesimalLayout );
257  sexagesimalLayout->setSpacing( spacingHint() );
258 
259  label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), sexagesimalGroup );
260  sexagesimalLayout->addWidget( label, 0, 0 );
261 
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 );
270 
271  mLatMinutes = new QSpinBox( sexagesimalGroup );
272  mLatMinutes->setMinimum( 0 );
273  mLatMinutes->setMaximum( 59 );
274  mLatMinutes->setValue( 1 );
275 
276  mLatMinutes->setSuffix( QLatin1String( "'" ) );
277  sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
278 
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 );
285 
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 );
290 
291  label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), sexagesimalGroup );
292  sexagesimalLayout->addWidget( label, 1, 0 );
293 
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 );
301 
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 );
308 
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 );
315 
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 );
320 
321  layout->addWidget( decimalGroup );
322  layout->addWidget( sexagesimalGroup );
323 
324  loadCityList();
325 
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()) );
348 
349  updateInputs();
350 }
351 
352 KABC::Geo GeoDialog::coordinates() const
353 {
354  return mCoordinates;
355 }
356 
357 void GeoDialog::cityInputChanged()
358 {
359  if ( mCityCombo->currentIndex() != 0 ) {
360  GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
361  mCoordinates.setLatitude( geoData.latitude );
362  mCoordinates.setLongitude( geoData.longitude );
363  } else {
364  mCoordinates.setLatitude( 0 );
365  mCoordinates.setLongitude( 0 );
366  }
367 
368  updateInputs( ExceptCity );
369 }
370 
371 void GeoDialog::decimalInputChanged()
372 {
373  mCoordinates.setLatitude( mLatitude->value() );
374  mCoordinates.setLongitude( mLongitude->value() );
375 
376  updateInputs( ExceptDecimal );
377 }
378 
379 void GeoDialog::sexagesimalInputChanged()
380 {
381  double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
382  60 + (double)mLatSeconds->value() / 3600 );
383  latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
384 
385  double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
386  60 + (double)mLongSeconds->value() / 3600 );
387  longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
388 
389  mCoordinates.setLatitude( latitude );
390  mCoordinates.setLongitude( longitude );
391 
392  updateInputs( ExceptSexagesimal );
393 }
394 
395 void GeoDialog::updateInputs( ExceptType type )
396 {
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 );
408 
409  if ( !( type & ExceptDecimal ) ) {
410  mLatitude->setValue( mCoordinates.latitude() );
411  mLongitude->setValue( mCoordinates.longitude() );
412  }
413 
414 
415  if ( !(type & ExceptSexagesimal) ) {
416  int degrees, minutes, seconds;
417  double latitude = mCoordinates.latitude();
418  double longitude = mCoordinates.longitude();
419 
420  latitude *= ( latitude < 0 ? -1 : 1 );
421  longitude *= ( longitude < 0 ? -1 : 1 );
422 
423  degrees = (int)( latitude * 1 );
424  minutes = (int)( ( latitude - degrees ) * 60 );
425  seconds = (int)( (double)( (double)latitude - (double)degrees - ( (double)minutes / (double)60 ) ) * (double)3600 );
426 
427  mLatDegrees->setValue( degrees );
428  mLatMinutes->setValue( minutes );
429  mLatSeconds->setValue( seconds );
430 
431  mLatDirection->setCurrentIndex( mLatitude->value() < 0 ? 1 : 0 );
432 
433  degrees = (int)( longitude * 1 );
434  minutes = (int)( ( longitude - degrees ) * 60 );
435  seconds = (int)( (double)( longitude - (double)degrees - ( (double)minutes / 60 ) ) * 3600 );
436 
437  mLongDegrees->setValue( degrees );
438  mLongMinutes->setValue( minutes );
439  mLongSeconds->setValue( seconds );
440  mLongDirection->setCurrentIndex( mLongitude->value() < 0 ? 1 : 0 );
441  }
442 
443  if ( !( type & ExceptCity ) ) {
444  const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
445  if ( index != -1 ) {
446  mCityCombo->setCurrentIndex( index + 1 );
447  } else {
448  mCityCombo->setCurrentIndex( 0 );
449  }
450  }
451 
452  mCityCombo->blockSignals( false );
453  mLatitude->blockSignals( false );
454  mLongitude->blockSignals( false );
455  mLatDegrees->blockSignals( false );
456  mLatMinutes->blockSignals( false );
457  mLatSeconds->blockSignals( false );
458  mLatDirection->blockSignals( false );
459  mLongDegrees->blockSignals( false );
460  mLongMinutes->blockSignals( false );
461  mLongSeconds->blockSignals( false );
462  mLongDirection->blockSignals( false );
463 }
464 
465 void GeoDialog::loadCityList()
466 {
467  mCityCombo->clear();
468  mGeoDataMap.clear();
469 
470  QFile file( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/data/zone.tab" ) ) );
471 
472  if ( file.open( QIODevice::ReadOnly ) ) {
473  QTextStream s( &file );
474 
475  QString line, country;
476  QRegExp coord( QLatin1String( "[+-]\\d+[+-]\\d+" ) );
477  QRegExp name( QLatin1String( "[^\\s]+/[^\\s]+" ) );
478  int pos;
479 
480  while ( !s.atEnd() ) {
481  line = s.readLine().trimmed();
482  if ( line.isEmpty() || line[ 0 ] == QLatin1Char( '#' ) ) {
483  continue;
484  }
485 
486  country = line.left( 2 );
487  QString c, n;
488  pos = coord.indexIn( line, 0 );
489  if ( pos >= 0 ) {
490  c = line.mid( pos, coord.matchedLength() );
491  }
492 
493  pos = name.indexIn( line, pos );
494  if ( pos > 0 ) {
495  n = line.mid( pos, name.matchedLength() ).trimmed();
496  }
497 
498  if ( !c.isEmpty() && !n.isEmpty() ) {
499  pos = c.indexOf( QLatin1Char( '+' ), 1 );
500  if ( pos < 0 ) {
501  pos = c.indexOf( QLatin1Char( '-' ), 1 );
502  }
503  if ( pos > 0 ) {
504  GeoData geoData;
505  geoData.latitude = calculateCoordinate( c.left( pos ) );
506  geoData.longitude = calculateCoordinate( c.mid( pos ) );
507  geoData.country = country;
508 
509  mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char( '_' ), QLatin1Char( ' ' ) ), geoData );
510  }
511  }
512  }
513 
514  QStringList items( mGeoDataMap.keys() );
515  items.prepend( i18nc( "@item:inlistbox Undefined location", "Undefined" ) );
516  mCityCombo->addItems( items );
517 
518  file.close();
519  }
520 }
521 
522 int GeoDialog::nearestCity( double x, double y ) const
523 {
524  QMap<QString, GeoData>::ConstIterator it;
525  int pos = 0;
526  for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
527  double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
528  ( (*it).latitude - y ) * ( (*it).latitude - y );
529  if ( dist < 0.0005 ) {
530  return pos;
531  }
532  }
533 
534  return -1;
535 }
536 
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:27:37 by doxygen 1.8.3.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal