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

akonadi

  • sources
  • kde-4.12
  • kdepimlibs
  • 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 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  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 
451  mCityCombo->blockSignals( false );
452  mLatitude->blockSignals( false );
453  mLongitude->blockSignals( false );
454  mLatDegrees->blockSignals( false );
455  mLatMinutes->blockSignals( false );
456  mLatSeconds->blockSignals( false );
457  mLatDirection->blockSignals( false );
458  mLongDegrees->blockSignals( false );
459  mLongMinutes->blockSignals( false );
460  mLongSeconds->blockSignals( false );
461  mLongDirection->blockSignals( false );
462 }
463 
464 void GeoDialog::loadCityList()
465 {
466  mCityCombo->clear();
467  mGeoDataMap.clear();
468 
469  QFile file( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/data/zone.tab" ) ) );
470 
471  if ( file.open( QIODevice::ReadOnly ) ) {
472  QTextStream s( &file );
473 
474  QString line, country;
475  QRegExp coord( QLatin1String( "[+-]\\d+[+-]\\d+" ) );
476  QRegExp name( QLatin1String( "[^\\s]+/[^\\s]+" ) );
477  int pos;
478 
479  while ( !s.atEnd() ) {
480  line = s.readLine().trimmed();
481  if ( line.isEmpty() || line[ 0 ] == QLatin1Char( '#' ) ) {
482  continue;
483  }
484 
485  country = line.left( 2 );
486  QString c, n;
487  pos = coord.indexIn( line, 0 );
488  if ( pos >= 0 ) {
489  c = line.mid( pos, coord.matchedLength() );
490  }
491 
492  pos = name.indexIn( line, pos );
493  if ( pos > 0 ) {
494  n = line.mid( pos, name.matchedLength() ).trimmed();
495  }
496 
497  if ( !c.isEmpty() && !n.isEmpty() ) {
498  pos = c.indexOf( QLatin1Char( '+' ), 1 );
499  if ( pos < 0 ) {
500  pos = c.indexOf( QLatin1Char( '-' ), 1 );
501  }
502  if ( pos > 0 ) {
503  GeoData geoData;
504  geoData.latitude = calculateCoordinate( c.left( pos ) );
505  geoData.longitude = calculateCoordinate( c.mid( pos ) );
506  geoData.country = country;
507 
508  mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char( '_' ), QLatin1Char( ' ' ) ), geoData );
509  }
510  }
511  }
512 
513  QStringList items( mGeoDataMap.keys() );
514  items.prepend( i18nc( "@item:inlistbox Undefined location", "Undefined" ) );
515  mCityCombo->addItems( items );
516 
517  file.close();
518  }
519 }
520 
521 int GeoDialog::nearestCity( double x, double y ) const
522 {
523  QMap<QString, GeoData>::ConstIterator it;
524  int pos = 0;
525  for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
526  double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
527  ( (*it).latitude - y ) * ( (*it).latitude - y );
528  if ( dist < 0.0005 ) {
529  return pos;
530  }
531  }
532 
533  return -1;
534 }
535 
AutoQPointer
A QPointer which when destructed, deletes the object it points to.
Definition: autoqpointer_p.h:34
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:00:27 by doxygen 1.8.7 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 API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



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