• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.11.3 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 <klocalizedstring.h>
31 #include <kstandarddirs.h>
32 
33 #include <QtCore/QFile>
34 #include <QtCore/QTextStream>
35 #include <QDoubleSpinBox>
36 #include <QGridLayout>
37 #include <QGroupBox>
38 #include <QLabel>
39 #include <QPainter>
40 #include <QPushButton>
41 #include <QSpinBox>
42 
43 class GeoMapWidget : public QWidget
44 {
45  public:
46  GeoMapWidget( QWidget *parent = 0 )
47  : QWidget( parent )
48  {
49  mWorld = QPixmap( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/pics/world.jpg" ) ) );
50 
51  setAttribute( Qt::WA_NoSystemBackground, true );
52  setFixedSize( 400, 200 );
53 
54  update();
55  }
56 
57  void setCoordinates( const KABC::Geo &coordinates )
58  {
59  mCoordinates = coordinates;
60 
61  update();
62  }
63 
64  protected:
65  virtual void paintEvent( QPaintEvent* )
66  {
67  QPainter p;
68  p.begin( this );
69  p.setPen( QColor( 255, 0, 0 ) );
70  p.setBrush( QColor( 255, 0, 0 ) );
71 
72  p.drawPixmap( 0, 0, mWorld );
73 
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;
79 
80  const int x = (int)( longMid + longOffset );
81  const int y = (int)( latMid - latOffset );
82  p.drawEllipse( x, y, 4, 4 );
83  }
84 
85  p.end();
86  }
87 
88  private:
89  QPixmap mWorld;
90  KABC::Geo mCoordinates;
91 };
92 
93 
94 GeoEditWidget::GeoEditWidget( QWidget *parent )
95  : QWidget( parent )
96 {
97  QGridLayout *layout = new QGridLayout( this );
98  layout->setMargin( 0 );
99 
100  mMap = new GeoMapWidget;
101  layout->addWidget( mMap, 0, 0, 1, 4, Qt::AlignCenter|Qt::AlignVCenter );
102 
103  QLabel *label = new QLabel( i18nc( "@label", "Latitude:" ) );
104  label->setAlignment( Qt::AlignRight );
105  layout->addWidget( label, 1, 0 );
106 
107  mLatitudeLabel = new QLabel;
108  layout->addWidget( mLatitudeLabel, 1, 1 );
109 
110  label = new QLabel( i18nc( "@label", "Longitude:" ) );
111  label->setAlignment( Qt::AlignRight );
112  layout->addWidget( label, 1, 2 );
113 
114  mLongitudeLabel = new QLabel;
115  layout->addWidget( mLongitudeLabel, 1, 3 );
116 
117  mChangeButton = new QPushButton( i18nc( "@label Change the coordinates", "Change..." ) );
118  layout->addWidget( mChangeButton, 2, 0, 1, 4, Qt::AlignRight );
119 
120  layout->setRowStretch( 3, 1 );
121 
122  connect( mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()) );
123 
124  updateView();
125 }
126 
127 GeoEditWidget::~GeoEditWidget()
128 {
129 }
130 
131 void GeoEditWidget::loadContact( const KABC::Addressee &contact )
132 {
133  mCoordinates = contact.geo();
134  updateView();
135 }
136 
137 void GeoEditWidget::storeContact( KABC::Addressee &contact ) const
138 {
139  contact.setGeo( mCoordinates );
140 }
141 
142 void GeoEditWidget::setReadOnly( bool readOnly )
143 {
144  mChangeButton->setEnabled( !readOnly );
145 }
146 
147 void GeoEditWidget::updateView()
148 {
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" ) );
152  } else {
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 ) ) );
155  }
156  mMap->setCoordinates( mCoordinates );
157 }
158 
159 void GeoEditWidget::changeClicked()
160 {
161  AutoQPointer<GeoDialog> dlg = new GeoDialog( mCoordinates, this );
162  if ( dlg->exec() ) {
163  mCoordinates = dlg->coordinates();
164  updateView();
165  }
166 }
167 
168 static double calculateCoordinate( const QString &coordinate )
169 {
170  int neg;
171  int d = 0, m = 0, s = 0;
172  QString str = coordinate;
173 
174  neg = str.left( 1 ) == QLatin1String( "-" );
175  str.remove( 0, 1 );
176 
177  switch ( str.length() ) {
178  case 4:
179  d = str.left( 2 ).toInt();
180  m = str.mid( 2 ).toInt();
181  break;
182  case 5:
183  d = str.left( 3 ).toInt();
184  m = str.mid( 3 ).toInt();
185  break;
186  case 6:
187  d = str.left( 2 ).toInt();
188  m = str.mid( 2, 2 ).toInt();
189  s = str.right( 2 ).toInt();
190  break;
191  case 7:
192  d = str.left( 3 ).toInt();
193  m = str.mid( 3, 2 ).toInt();
194  s = str.right( 2 ).toInt();
195  break;
196  default:
197  break;
198  }
199 
200  if ( neg ) {
201  return - ( d + m / 60.0 + s / 3600.0 );
202  } else {
203  return d + m / 60.0 + s / 3600.0;
204  }
205 }
206 
207 GeoDialog::GeoDialog( const KABC::Geo &coordinates, QWidget *parent )
208  : KDialog( parent ),
209  mCoordinates( coordinates )
210 {
211  KGlobal::locale()->insertCatalog( QLatin1String( "timezones4" ) );
212  setCaption( i18nc( "@title:window", "Coordinate Selection" ) );
213  setButtons( Ok | Cancel );
214  setDefaultButton( Ok );
215  showButtonSeparator( true );
216  setModal( true );
217 
218  QFrame *page = new QFrame( this );
219  setMainWidget( page );
220 
221  QVBoxLayout *layout = new QVBoxLayout( page );
222 
223  mCityCombo = new KComboBox( page );
224  layout->addWidget( mCityCombo );
225 
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() );
230 
231  QLabel *label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), decimalGroup );
232  decimalLayout->addWidget( label, 0, 0 );
233 
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 );
242 
243  label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), decimalGroup );
244  decimalLayout->addWidget( label, 1, 0 );
245 
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 );
254 
255  QGroupBox *sexagesimalGroup = new QGroupBox( i18nc( "@title:group", "Sexagesimal" ), page );
256  QGridLayout *sexagesimalLayout = new QGridLayout();
257  sexagesimalGroup->setLayout( sexagesimalLayout );
258  sexagesimalLayout->setSpacing( spacingHint() );
259 
260  label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), sexagesimalGroup );
261  sexagesimalLayout->addWidget( label, 0, 0 );
262 
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 );
271 
272  mLatMinutes = new QSpinBox( sexagesimalGroup );
273  mLatMinutes->setMinimum( 0 );
274  mLatMinutes->setMaximum( 59 );
275  mLatMinutes->setValue( 1 );
276 
277  mLatMinutes->setSuffix( QLatin1String( "'" ) );
278  sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
279 
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 );
286 
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 );
291 
292  label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), sexagesimalGroup );
293  sexagesimalLayout->addWidget( label, 1, 0 );
294 
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 );
302 
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 );
309 
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 );
316 
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 );
321 
322  layout->addWidget( decimalGroup );
323  layout->addWidget( sexagesimalGroup );
324 
325  loadCityList();
326 
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()) );
349 
350  updateInputs();
351 }
352 
353 KABC::Geo GeoDialog::coordinates() const
354 {
355  return mCoordinates;
356 }
357 
358 void GeoDialog::cityInputChanged()
359 {
360  if ( mCityCombo->currentIndex() != 0 ) {
361  GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
362  mCoordinates.setLatitude( geoData.latitude );
363  mCoordinates.setLongitude( geoData.longitude );
364  } else {
365  mCoordinates.setLatitude( 0 );
366  mCoordinates.setLongitude( 0 );
367  }
368 
369  updateInputs( ExceptCity );
370 }
371 
372 void GeoDialog::decimalInputChanged()
373 {
374  mCoordinates.setLatitude( mLatitude->value() );
375  mCoordinates.setLongitude( mLongitude->value() );
376 
377  updateInputs( ExceptDecimal );
378 }
379 
380 void GeoDialog::sexagesimalInputChanged()
381 {
382  double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
383  60 + (double)mLatSeconds->value() / 3600 );
384  latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
385 
386  double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
387  60 + (double)mLongSeconds->value() / 3600 );
388  longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
389 
390  mCoordinates.setLatitude( latitude );
391  mCoordinates.setLongitude( longitude );
392 
393  updateInputs( ExceptSexagesimal );
394 }
395 
396 void GeoDialog::updateInputs( ExceptType type )
397 {
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 );
409 
410  if ( !( type & ExceptDecimal ) ) {
411  mLatitude->setValue( mCoordinates.latitude() );
412  mLongitude->setValue( mCoordinates.longitude() );
413  }
414 
415 
416  if ( !(type & ExceptSexagesimal) ) {
417  int degrees, minutes, seconds;
418  double latitude = mCoordinates.latitude();
419  double longitude = mCoordinates.longitude();
420 
421  latitude *= ( latitude < 0 ? -1 : 1 );
422  longitude *= ( longitude < 0 ? -1 : 1 );
423 
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 );
427 
428  mLatDegrees->setValue( degrees );
429  mLatMinutes->setValue( minutes );
430  mLatSeconds->setValue( seconds );
431 
432  mLatDirection->setCurrentIndex( mLatitude->value() < 0 ? 1 : 0 );
433 
434  degrees = (int)( longitude * 1 );
435  minutes = (int)( ( longitude - degrees ) * 60 );
436  seconds = (int)( (double)( longitude - (double)degrees - ( (double)minutes / 60 ) ) * 3600 );
437 
438  mLongDegrees->setValue( degrees );
439  mLongMinutes->setValue( minutes );
440  mLongSeconds->setValue( seconds );
441  mLongDirection->setCurrentIndex( mLongitude->value() < 0 ? 1 : 0 );
442  }
443 
444  if ( !( type & ExceptCity ) ) {
445  const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
446  if ( index != -1 ) {
447  mCityCombo->setCurrentIndex( index + 1 );
448  } else {
449  mCityCombo->setCurrentIndex( 0 );
450  }
451  }
452 
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 );
464 }
465 
466 void GeoDialog::loadCityList()
467 {
468  mCityCombo->clear();
469  mGeoDataMap.clear();
470 
471  QFile file( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/data/zone.tab" ) ) );
472 
473  if ( file.open( QIODevice::ReadOnly ) ) {
474  QTextStream s( &file );
475 
476  QString line, country;
477  QRegExp coord( QLatin1String( "[+-]\\d+[+-]\\d+" ) );
478  QRegExp name( QLatin1String( "[^\\s]+/[^\\s]+" ) );
479  int pos;
480 
481  while ( !s.atEnd() ) {
482  line = s.readLine().trimmed();
483  if ( line.isEmpty() || line[ 0 ] == QLatin1Char( '#' ) ) {
484  continue;
485  }
486 
487  country = line.left( 2 );
488  QString c, n;
489  pos = coord.indexIn( line, 0 );
490  if ( pos >= 0 ) {
491  c = line.mid( pos, coord.matchedLength() );
492  }
493 
494  pos = name.indexIn( line, pos );
495  if ( pos > 0 ) {
496  n = line.mid( pos, name.matchedLength() ).trimmed();
497  }
498 
499  if ( !c.isEmpty() && !n.isEmpty() ) {
500  pos = c.indexOf( QLatin1Char( '+' ), 1 );
501  if ( pos < 0 ) {
502  pos = c.indexOf( QLatin1Char( '-' ), 1 );
503  }
504  if ( pos > 0 ) {
505  GeoData geoData;
506  geoData.latitude = calculateCoordinate( c.left( pos ) );
507  geoData.longitude = calculateCoordinate( c.mid( pos ) );
508  geoData.country = country;
509 
510  mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char( '_' ), QLatin1Char( ' ' ) ), geoData );
511  }
512  }
513  }
514 
515  QStringList items( mGeoDataMap.keys() );
516  items.prepend( i18nc( "@item:inlistbox Undefined location", "Undefined" ) );
517  mCityCombo->addItems( items );
518 
519  file.close();
520  }
521 }
522 
523 int GeoDialog::nearestCity( double x, double y ) const
524 {
525  QMap<QString, GeoData>::ConstIterator it;
526  int pos = 0;
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 ) {
531  return pos;
532  }
533  }
534 
535  return -1;
536 }
537 
AutoQPointer
A QPointer which when destructed, deletes the object it points to.
Definition: autoqpointer_p.h:35
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Nov 26 2013 09:03:17 by doxygen 1.8.5 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.11.3 API Reference

Skip menu "kdepimlibs-4.11.3 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