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

akonadi/contact

  • 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 <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>
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 GeoDialog::GeoDialog( const KABC::Geo &coordinates, QWidget *parent )
206  : KDialog( parent ),
207  mCoordinates( coordinates )
208 {
209  KGlobal::locale()->insertCatalog( QLatin1String( "timezones4" ) );
210  setCaption( i18nc( "@title:window", "Coordinate Selection" ) );
211  setButtons( Ok | Cancel );
212  setDefaultButton( Ok );
213  showButtonSeparator( true );
214  setModal( true );
215 
216  QFrame *page = new QFrame(this);
217  setMainWidget( page );
218 
219  QVBoxLayout *layout = new QVBoxLayout( page );
220 
221  mCityCombo = new KComboBox( page );
222  layout->addWidget( mCityCombo );
223 
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() );
228 
229  QLabel *label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), decimalGroup );
230  decimalLayout->addWidget( label, 0, 0 );
231 
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 );
240 
241  label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), decimalGroup );
242  decimalLayout->addWidget( label, 1, 0 );
243 
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 );
252 
253  QGroupBox *sexagesimalGroup = new QGroupBox( i18nc( "@title:group", "Sexagesimal" ), page );
254  QGridLayout *sexagesimalLayout = new QGridLayout();
255  sexagesimalGroup->setLayout( sexagesimalLayout );
256  sexagesimalLayout->setSpacing( spacingHint() );
257 
258  label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), sexagesimalGroup );
259  sexagesimalLayout->addWidget( label, 0, 0 );
260 
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 );
269 
270  mLatMinutes = new QSpinBox( sexagesimalGroup );
271  mLatMinutes->setMinimum( 0 );
272  mLatMinutes->setMaximum( 59 );
273  mLatMinutes->setValue( 1 );
274 
275  mLatMinutes->setSuffix( QLatin1String( "'" ) );
276  sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
277 
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 );
284 
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 );
289 
290  label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), sexagesimalGroup );
291  sexagesimalLayout->addWidget( label, 1, 0 );
292 
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 );
300 
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 );
307 
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 );
314 
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 );
319 
320  layout->addWidget( decimalGroup );
321  layout->addWidget( sexagesimalGroup );
322 
323  loadCityList();
324 
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()) );
347 
348  updateInputs();
349 }
350 
351 KABC::Geo GeoDialog::coordinates() const
352 {
353  return mCoordinates;
354 }
355 
356 void GeoDialog::cityInputChanged()
357 {
358  if ( mCityCombo->currentIndex() != 0 ) {
359  GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
360  mCoordinates.setLatitude( geoData.latitude );
361  mCoordinates.setLongitude( geoData.longitude );
362  } else {
363  mCoordinates.setLatitude( 0 );
364  mCoordinates.setLongitude( 0 );
365  }
366 
367  updateInputs( ExceptCity );
368 }
369 
370 void GeoDialog::decimalInputChanged()
371 {
372  mCoordinates.setLatitude( mLatitude->value() );
373  mCoordinates.setLongitude( mLongitude->value() );
374 
375  updateInputs( ExceptDecimal );
376 }
377 
378 void GeoDialog::sexagesimalInputChanged()
379 {
380  double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
381  60 + (double)mLatSeconds->value() / 3600 );
382  latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
383 
384  double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
385  60 + (double)mLongSeconds->value() / 3600 );
386  longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
387 
388  mCoordinates.setLatitude( latitude );
389  mCoordinates.setLongitude( longitude );
390 
391  updateInputs( ExceptSexagesimal );
392 }
393 
394 void GeoDialog::updateInputs( ExceptType type )
395 {
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 );
407 
408  if ( !( type & ExceptDecimal ) ) {
409  mLatitude->setValue( mCoordinates.latitude() );
410  mLongitude->setValue( mCoordinates.longitude() );
411  }
412 
413 
414  if ( !(type & ExceptSexagesimal) ) {
415  int degrees, minutes, seconds;
416  double latitude = mCoordinates.latitude();
417  double longitude = mCoordinates.longitude();
418 
419  latitude *= ( latitude < 0 ? -1 : 1 );
420  longitude *= ( longitude < 0 ? -1 : 1 );
421 
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 );
425 
426  mLatDegrees->setValue( degrees );
427  mLatMinutes->setValue( minutes );
428  mLatSeconds->setValue( seconds );
429 
430  mLatDirection->setCurrentIndex( mLatitude->value() < 0 ? 1 : 0 );
431 
432  degrees = (int)( longitude * 1 );
433  minutes = (int)( ( longitude - degrees ) * 60 );
434  seconds = (int)( (double)( longitude - (double)degrees - ( (double)minutes / 60 ) ) * 3600 );
435 
436  mLongDegrees->setValue( degrees );
437  mLongMinutes->setValue( minutes );
438  mLongSeconds->setValue( seconds );
439  mLongDirection->setCurrentIndex( mLongitude->value() < 0 ? 1 : 0 );
440  }
441 
442  if ( !(type & ExceptCity) ) {
443  const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
444  if ( index != -1 )
445  mCityCombo->setCurrentIndex( index + 1 );
446  else
447  mCityCombo->setCurrentIndex( 0 );
448  }
449 
450  mCityCombo->blockSignals( false );
451  mLatitude->blockSignals( false );
452  mLongitude->blockSignals( false );
453  mLatDegrees->blockSignals( false );
454  mLatMinutes->blockSignals( false );
455  mLatSeconds->blockSignals( false );
456  mLatDirection->blockSignals( false );
457  mLongDegrees->blockSignals( false );
458  mLongMinutes->blockSignals( false );
459  mLongSeconds->blockSignals( false );
460  mLongDirection->blockSignals( false );
461 }
462 
463 void GeoDialog::loadCityList()
464 {
465  mCityCombo->clear();
466  mGeoDataMap.clear();
467 
468  QFile file( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/data/zone.tab" ) ) );
469 
470  if ( file.open( QIODevice::ReadOnly ) ) {
471  QTextStream s( &file );
472 
473  QString line, country;
474  QRegExp coord( QLatin1String( "[+-]\\d+[+-]\\d+" ) );
475  QRegExp name( QLatin1String( "[^\\s]+/[^\\s]+" ) );
476  int pos;
477 
478  while ( !s.atEnd() ) {
479  line = s.readLine().trimmed();
480  if ( line.isEmpty() || line[ 0 ] == QLatin1Char( '#' ) )
481  continue;
482 
483  country = line.left( 2 );
484  QString c, n;
485  pos = coord.indexIn( line, 0 );
486  if ( pos >= 0 )
487  c = line.mid( pos, coord.matchedLength() );
488 
489  pos = name.indexIn(line, pos);
490  if ( pos > 0 ) {
491  n = line.mid( pos, name.matchedLength() ).trimmed();
492  }
493 
494  if ( !c.isEmpty() && !n.isEmpty() ) {
495  pos = c.indexOf( QLatin1Char( '+' ), 1 );
496  if ( pos < 0 )
497  pos = c.indexOf( QLatin1Char( '-' ), 1 );
498  if ( pos > 0 ) {
499  GeoData geoData;
500  geoData.latitude = calculateCoordinate( c.left( pos ) );
501  geoData.longitude = calculateCoordinate( c.mid( pos ) );
502  geoData.country = country;
503 
504  mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char( '_' ), QLatin1Char( ' ' ) ), geoData );
505  }
506  }
507  }
508 
509  QStringList items( mGeoDataMap.keys() );
510  items.prepend( i18nc( "@item:inlistbox Undefined location", "Undefined" ) );
511  mCityCombo->addItems( items );
512 
513  file.close();
514  }
515 }
516 
517 int GeoDialog::nearestCity( double x, double y ) const
518 {
519  QMap<QString, GeoData>::ConstIterator it;
520  int pos = 0;
521  for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
522  double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
523  ( (*it).latitude - y ) * ( (*it).latitude - y );
524  if ( dist < 0.0005 )
525  return pos;
526  }
527 
528  return -1;
529 }
530 
531 #include "geoeditwidget.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Wed Nov 28 2012 21:55:23 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi/contact

Skip menu "akonadi/contact"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.9.3 API Reference

Skip menu "kdepimlibs-4.9.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • 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