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

akonadi/contact

geoeditwidget.cpp
00001 /*
00002     This file is part of Akonadi Contact.
00003 
00004     Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or modify it
00007     under the terms of the GNU Library General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or (at your
00009     option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful, but WITHOUT
00012     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00014     License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to the
00018     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00019     02110-1301, USA.
00020 */
00021 
00022 #include "geoeditwidget.h"
00023 
00024 #include "autoqpointer_p.h"
00025 
00026 #include <kabc/addressee.h>
00027 #include <kabc/geo.h>
00028 #include <kcombobox.h>
00029 #include <klocale.h>
00030 #include <kstandarddirs.h>
00031 
00032 #include <QtCore/QFile>
00033 #include <QtCore/QTextStream>
00034 #include <QtGui/QDoubleSpinBox>
00035 #include <QtGui/QGridLayout>
00036 #include <QtGui/QGroupBox>
00037 #include <QtGui/QLabel>
00038 #include <QtGui/QPainter>
00039 #include <QtGui/QPushButton>
00040 #include <QtGui/QSpinBox>
00041 
00042 class GeoMapWidget : public QWidget
00043 {
00044   public:
00045     GeoMapWidget( QWidget *parent = 0 )
00046       : QWidget( parent )
00047     {
00048       mWorld = QPixmap( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/pics/world.jpg" ) ) );
00049 
00050       setAttribute( Qt::WA_NoSystemBackground, true );
00051       setFixedSize( 400, 200 );
00052 
00053       update();
00054     }
00055 
00056     void setCoordinates( const KABC::Geo &coordinates )
00057     {
00058       mCoordinates = coordinates;
00059 
00060       update();
00061     }
00062 
00063   protected:
00064     virtual void paintEvent( QPaintEvent* )
00065     {
00066       QPainter p;
00067       p.begin( this );
00068       p.setPen( QColor( 255, 0, 0 ) );
00069       p.setBrush( QColor( 255, 0, 0 ) );
00070 
00071       p.drawPixmap( 0, 0, mWorld );
00072 
00073       if ( mCoordinates.isValid() ) {
00074         const double latMid = height() / 2;
00075         const double longMid = width() / 2;
00076         const double latOffset = ( mCoordinates.latitude() * latMid ) / 90;
00077         const double longOffset = ( mCoordinates.longitude() * longMid ) / 180;
00078 
00079         const int x = (int)(longMid + longOffset);
00080         const int y = (int)(latMid - latOffset);
00081         p.drawEllipse( x, y, 4, 4 );
00082       }
00083 
00084       p.end();
00085     }
00086 
00087   private:
00088     QPixmap mWorld;
00089     KABC::Geo mCoordinates;
00090 };
00091 
00092 
00093 GeoEditWidget::GeoEditWidget( QWidget *parent )
00094   : QWidget( parent )
00095 {
00096   QGridLayout *layout = new QGridLayout( this );
00097   layout->setMargin( 0 );
00098 
00099   mMap = new GeoMapWidget;
00100   layout->addWidget( mMap, 0, 0, 1, 4, Qt::AlignCenter|Qt::AlignVCenter );
00101 
00102   QLabel *label = new QLabel( i18nc( "@label", "Latitude:" ) );
00103   label->setAlignment( Qt::AlignRight );
00104   layout->addWidget( label, 1, 0 );
00105 
00106   mLatitudeLabel = new QLabel;
00107   layout->addWidget( mLatitudeLabel, 1, 1 );
00108 
00109   label = new QLabel( i18nc( "@label", "Longitude:" ) );
00110   label->setAlignment( Qt::AlignRight );
00111   layout->addWidget( label, 1, 2 );
00112 
00113   mLongitudeLabel = new QLabel;
00114   layout->addWidget( mLongitudeLabel, 1, 3 );
00115 
00116   mChangeButton = new QPushButton( i18nc( "@label Change the coordinates", "Change..." ) );
00117   layout->addWidget( mChangeButton, 2, 0, 1, 4, Qt::AlignRight );
00118 
00119   layout->setRowStretch( 3, 1 );
00120 
00121   connect( mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()) );
00122 
00123   updateView();
00124 }
00125 
00126 GeoEditWidget::~GeoEditWidget()
00127 {
00128 }
00129 
00130 void GeoEditWidget::loadContact( const KABC::Addressee &contact )
00131 {
00132   mCoordinates = contact.geo();
00133   updateView();
00134 }
00135 
00136 void GeoEditWidget::storeContact( KABC::Addressee &contact ) const
00137 {
00138   contact.setGeo( mCoordinates );
00139 }
00140 
00141 void GeoEditWidget::setReadOnly( bool readOnly )
00142 {
00143   mChangeButton->setEnabled( !readOnly );
00144 }
00145 
00146 void GeoEditWidget::updateView()
00147 {
00148   if ( !mCoordinates.isValid() ) {
00149     mLatitudeLabel->setText( i18nc( "@label Coordinates are not available", "n/a" ) );
00150     mLongitudeLabel->setText( i18nc( "@label Coordinates are not available", "n/a" ) );
00151   } else {
00152     mLatitudeLabel->setText( i18nc( "@label The formatted coordinates", "%1 %2", mCoordinates.latitude(), QChar( 176 ) ) );
00153     mLongitudeLabel->setText( i18nc( "@label The formatted coordinates", "%1 %2", mCoordinates.longitude(), QChar( 176 ) ) );
00154   }
00155   mMap->setCoordinates( mCoordinates );
00156 }
00157 
00158 void GeoEditWidget::changeClicked()
00159 {
00160   AutoQPointer<GeoDialog> dlg = new GeoDialog( mCoordinates, this );
00161   if ( dlg->exec() ) {
00162     mCoordinates = dlg->coordinates();
00163     updateView();
00164   }
00165 }
00166 
00167 static double calculateCoordinate( const QString &coordinate )
00168 {
00169   int neg;
00170   int d = 0, m = 0, s = 0;
00171   QString str = coordinate;
00172 
00173   neg = str.left( 1 ) == QLatin1String( "-" );
00174   str.remove( 0, 1 );
00175 
00176   switch ( str.length() ) {
00177     case 4:
00178       d = str.left( 2 ).toInt();
00179       m = str.mid( 2 ).toInt();
00180       break;
00181     case 5:
00182       d = str.left( 3 ).toInt();
00183       m = str.mid( 3 ).toInt();
00184       break;
00185     case 6:
00186       d = str.left( 2 ).toInt();
00187       m = str.mid( 2, 2 ).toInt();
00188       s = str.right( 2 ).toInt();
00189       break;
00190     case 7:
00191       d = str.left( 3 ).toInt();
00192       m = str.mid( 3, 2 ).toInt();
00193       s = str.right( 2 ).toInt();
00194       break;
00195     default:
00196       break;
00197   }
00198 
00199   if ( neg )
00200     return - ( d + m / 60.0 + s / 3600.0 );
00201   else
00202     return d + m / 60.0 + s / 3600.0;
00203 }
00204 
00205 GeoDialog::GeoDialog( const KABC::Geo &coordinates, QWidget *parent )
00206   : KDialog( parent ),
00207     mCoordinates( coordinates )
00208 {
00209   KGlobal::locale()->insertCatalog( QLatin1String( "timezones4" ) );
00210   setCaption( i18nc( "@title:window", "Coordinate Selection" ) );
00211   setButtons( Ok | Cancel );
00212   setDefaultButton( Ok );
00213   showButtonSeparator( true );
00214   setModal( true );
00215 
00216   QFrame *page = new QFrame(this);
00217   setMainWidget( page );
00218 
00219   QVBoxLayout *layout = new QVBoxLayout( page );
00220 
00221   mCityCombo = new KComboBox( page );
00222   layout->addWidget( mCityCombo );
00223 
00224   QGroupBox *decimalGroup = new QGroupBox( i18nc( "@title:group Decimal representation of coordinates", "Decimal" ), page );
00225   QGridLayout *decimalLayout = new QGridLayout();
00226   decimalGroup->setLayout( decimalLayout );
00227   decimalLayout->setSpacing( spacingHint() );
00228 
00229   QLabel *label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), decimalGroup );
00230   decimalLayout->addWidget( label, 0, 0 );
00231 
00232   mLatitude = new QDoubleSpinBox( decimalGroup );
00233   mLatitude->setMinimum( -90 );
00234   mLatitude->setMaximum( 90 );
00235   mLatitude->setSingleStep( 1 );
00236   mLatitude->setValue( 0 );
00237   mLatitude->setDecimals( 6 );
00238   mLatitude->setSuffix( QChar( 176 ) );
00239   decimalLayout->addWidget( mLatitude, 0, 1 );
00240 
00241   label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), decimalGroup );
00242   decimalLayout->addWidget( label, 1, 0 );
00243 
00244   mLongitude = new QDoubleSpinBox( decimalGroup );
00245   mLongitude->setMinimum( -180 );
00246   mLongitude->setMaximum( 180 );
00247   mLongitude->setSingleStep( 1 );
00248   mLongitude->setValue( 0 );
00249   mLongitude->setDecimals( 6 );
00250   mLongitude->setSuffix( QChar( 176 ) );
00251   decimalLayout->addWidget( mLongitude, 1, 1 );
00252 
00253   QGroupBox *sexagesimalGroup = new QGroupBox( i18nc( "@title:group", "Sexagesimal" ), page );
00254   QGridLayout *sexagesimalLayout = new QGridLayout();
00255   sexagesimalGroup->setLayout( sexagesimalLayout );
00256   sexagesimalLayout->setSpacing( spacingHint() );
00257 
00258   label = new QLabel( i18nc( "@label:spinbox", "Latitude:" ), sexagesimalGroup );
00259   sexagesimalLayout->addWidget( label, 0, 0 );
00260 
00261   mLatDegrees = new QSpinBox( sexagesimalGroup );
00262   mLatDegrees->setMinimum( 0 );
00263   mLatDegrees->setMaximum( 90 );
00264   mLatDegrees->setValue( 1 );
00265   mLatDegrees->setSuffix( QChar( 176 ) );
00266   mLatDegrees->setWrapping( false );
00267   label->setBuddy( mLatDegrees );
00268   sexagesimalLayout->addWidget( mLatDegrees, 0, 1 );
00269 
00270   mLatMinutes = new QSpinBox( sexagesimalGroup );
00271   mLatMinutes->setMinimum( 0 );
00272   mLatMinutes->setMaximum( 59 );
00273   mLatMinutes->setValue( 1 );
00274 
00275   mLatMinutes->setSuffix( QLatin1String( "'" ) );
00276   sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
00277 
00278   mLatSeconds = new QSpinBox( sexagesimalGroup );
00279   mLatSeconds->setMinimum( 0 );
00280   mLatSeconds->setMaximum( 59 );
00281   mLatSeconds->setValue( 1 );
00282   mLatSeconds->setSuffix( QLatin1String( "\"" ) );
00283   sexagesimalLayout->addWidget( mLatSeconds, 0, 3 );
00284 
00285   mLatDirection = new KComboBox( sexagesimalGroup );
00286   mLatDirection->addItem( i18nc( "@item:inlistbox Latitude direction", "North" ) );
00287   mLatDirection->addItem( i18nc( "@item:inlistbox Latitude direction", "South" ) );
00288   sexagesimalLayout->addWidget( mLatDirection, 0, 4 );
00289 
00290   label = new QLabel( i18nc( "@label:spinbox", "Longitude:" ), sexagesimalGroup );
00291   sexagesimalLayout->addWidget( label, 1, 0 );
00292 
00293   mLongDegrees = new QSpinBox( sexagesimalGroup );
00294   mLongDegrees->setMinimum( 0 );
00295   mLongDegrees->setMaximum( 180 );
00296   mLongDegrees->setValue( 1 );
00297   mLongDegrees->setSuffix( QChar( 176 ) );
00298   label->setBuddy( mLongDegrees );
00299   sexagesimalLayout->addWidget( mLongDegrees, 1, 1 );
00300 
00301   mLongMinutes = new QSpinBox( sexagesimalGroup );
00302   mLongMinutes->setMinimum( 0 );
00303   mLongMinutes->setMaximum( 59 );
00304   mLongMinutes->setValue( 1 );
00305   mLongMinutes->setSuffix( QLatin1String( "'" ) );
00306   sexagesimalLayout->addWidget( mLongMinutes, 1, 2 );
00307 
00308   mLongSeconds = new QSpinBox( sexagesimalGroup );
00309   mLongSeconds->setMinimum( 0 );
00310   mLongSeconds->setMaximum( 59 );
00311   mLongSeconds->setValue( 1 );
00312   mLongSeconds->setSuffix( QLatin1String( "\"" ) );
00313   sexagesimalLayout->addWidget( mLongSeconds, 1, 3 );
00314 
00315   mLongDirection = new KComboBox( sexagesimalGroup );
00316   mLongDirection->addItem( i18nc( "@item:inlistbox Longtitude direction", "East" ) );
00317   mLongDirection->addItem( i18nc( "@item:inlistbox Longtitude direction", "West" ) );
00318   sexagesimalLayout->addWidget( mLongDirection, 1, 4 );
00319 
00320   layout->addWidget( decimalGroup );
00321   layout->addWidget( sexagesimalGroup );
00322 
00323   loadCityList();
00324 
00325   connect( mCityCombo, SIGNAL(activated(int)),
00326            SLOT(cityInputChanged()) );
00327   connect( mLatitude, SIGNAL(valueChanged(double)),
00328            SLOT(decimalInputChanged()) );
00329   connect( mLongitude, SIGNAL(valueChanged(double)),
00330            SLOT(decimalInputChanged()) );
00331   connect( mLatDegrees, SIGNAL(valueChanged(int)),
00332            SLOT(sexagesimalInputChanged()) );
00333   connect( mLatMinutes, SIGNAL(valueChanged(int)),
00334            SLOT(sexagesimalInputChanged()) );
00335   connect( mLatSeconds, SIGNAL(valueChanged(int)),
00336            SLOT(sexagesimalInputChanged()) );
00337   connect( mLatDirection, SIGNAL(activated(int)),
00338            SLOT(sexagesimalInputChanged()) );
00339   connect( mLongDegrees, SIGNAL(valueChanged(int)),
00340            SLOT(sexagesimalInputChanged()) );
00341   connect( mLongMinutes, SIGNAL(valueChanged(int)),
00342            SLOT(sexagesimalInputChanged()) );
00343   connect( mLongSeconds, SIGNAL(valueChanged(int)),
00344            SLOT(sexagesimalInputChanged()) );
00345   connect( mLongDirection, SIGNAL(activated(int)),
00346            SLOT(sexagesimalInputChanged()) );
00347 
00348   updateInputs();
00349 }
00350 
00351 KABC::Geo GeoDialog::coordinates() const
00352 {
00353   return mCoordinates;
00354 }
00355 
00356 void GeoDialog::cityInputChanged()
00357 {
00358   if ( mCityCombo->currentIndex() != 0 ) {
00359     GeoData geoData = mGeoDataMap[ mCityCombo->currentText() ];
00360     mCoordinates.setLatitude( geoData.latitude );
00361     mCoordinates.setLongitude( geoData.longitude );
00362   } else {
00363     mCoordinates.setLatitude( 0 );
00364     mCoordinates.setLongitude( 0 );
00365   }
00366 
00367   updateInputs( ExceptCity );
00368 }
00369 
00370 void GeoDialog::decimalInputChanged()
00371 {
00372   mCoordinates.setLatitude( mLatitude->value() );
00373   mCoordinates.setLongitude( mLongitude->value() );
00374 
00375   updateInputs( ExceptDecimal );
00376 }
00377 
00378 void GeoDialog::sexagesimalInputChanged()
00379 {
00380   double latitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
00381                     60 + (double)mLatSeconds->value() / 3600 );
00382   latitude *= ( mLatDirection->currentIndex() == 1 ? -1 : 1 );
00383 
00384   double longitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
00385                      60 + (double)mLongSeconds->value() / 3600 );
00386   longitude *= ( mLongDirection->currentIndex() == 1 ? -1 : 1 );
00387 
00388   mCoordinates.setLatitude( latitude );
00389   mCoordinates.setLongitude( longitude );
00390 
00391   updateInputs( ExceptSexagesimal );
00392 }
00393 
00394 void GeoDialog::updateInputs( ExceptType type )
00395 {
00396   mCityCombo->blockSignals( true );
00397   mLatitude->blockSignals( true );
00398   mLongitude->blockSignals( true );
00399   mLatDegrees->blockSignals( true );
00400   mLatMinutes->blockSignals( true );
00401   mLatSeconds->blockSignals( true );
00402   mLatDirection->blockSignals( true );
00403   mLongDegrees->blockSignals( true );
00404   mLongMinutes->blockSignals( true );
00405   mLongSeconds->blockSignals( true );
00406   mLongDirection->blockSignals( true );
00407 
00408   if ( !(type & ExceptSexagesimal) ) {
00409     int degrees, minutes, seconds;
00410     double latitude = mCoordinates.latitude();
00411     double longitude = mCoordinates.longitude();
00412 
00413     latitude *= ( latitude < 0 ? -1 : 1 );
00414     longitude *= ( longitude < 0 ? -1 : 1 );
00415 
00416     degrees = (int)( latitude * 1 );
00417     minutes = (int)( ( latitude - degrees ) * 60 );
00418     seconds = (int)( (double)( (double)latitude - (double)degrees - ( (double)minutes / (double)60 ) ) * (double)3600 );
00419 
00420     mLatDegrees->setValue( degrees );
00421     mLatMinutes->setValue( minutes );
00422     mLatSeconds->setValue( seconds );
00423 
00424     mLatDirection->setCurrentIndex( mLatitude < 0 ? 1 : 0 );
00425 
00426     degrees = (int)( longitude * 1 );
00427     minutes = (int)( ( longitude - degrees ) * 60 );
00428     seconds = (int)( (double)( longitude - (double)degrees - ( (double)minutes / 60 ) ) * 3600 );
00429 
00430     mLongDegrees->setValue( degrees );
00431     mLongMinutes->setValue( minutes );
00432     mLongSeconds->setValue( seconds );
00433     mLongDirection->setCurrentIndex( mLongitude < 0 ? 1 : 0 );
00434   }
00435 
00436   if ( !(type & ExceptDecimal) ) {
00437     mLatitude->setValue( mCoordinates.latitude() );
00438     mLongitude->setValue( mCoordinates.longitude() );
00439   }
00440 
00441   if ( !(type & ExceptCity) ) {
00442     const int index = nearestCity( mCoordinates.longitude(), mCoordinates.latitude() );
00443     if ( index != -1 )
00444       mCityCombo->setCurrentIndex( index + 1 );
00445     else
00446       mCityCombo->setCurrentIndex( 0 );
00447   }
00448 
00449   mCityCombo->blockSignals( false );
00450   mLatitude->blockSignals( false );
00451   mLongitude->blockSignals( false );
00452   mLatDegrees->blockSignals( false );
00453   mLatMinutes->blockSignals( false );
00454   mLatSeconds->blockSignals( false );
00455   mLatDirection->blockSignals( false );
00456   mLongDegrees->blockSignals( false );
00457   mLongMinutes->blockSignals( false );
00458   mLongSeconds->blockSignals( false );
00459   mLongDirection->blockSignals( false );
00460 }
00461 
00462 void GeoDialog::loadCityList()
00463 {
00464   mCityCombo->clear();
00465   mGeoDataMap.clear();
00466 
00467   QFile file( KStandardDirs::locate( "data", QLatin1String( "akonadi/contact/data/zone.tab" ) ) );
00468 
00469   if ( file.open( QIODevice::ReadOnly ) ) {
00470     QTextStream s( &file );
00471 
00472     QString line, country;
00473     QRegExp coord( QLatin1String( "[+-]\\d+[+-]\\d+" ) );
00474     QRegExp name( QLatin1String( "[^\\s]+/[^\\s]+" ) );
00475     int pos;
00476 
00477     while ( !s.atEnd() ) {
00478       line = s.readLine().trimmed();
00479       if ( line.isEmpty() || line[ 0 ] == QLatin1Char( '#' ) )
00480         continue;
00481 
00482       country = line.left( 2 );
00483       QString c, n;
00484       pos = coord.indexIn( line, 0 );
00485       if ( pos >= 0 )
00486         c = line.mid( pos, coord.matchedLength() );
00487 
00488       pos = name.indexIn(line, pos);
00489       if ( pos > 0 ) {
00490         n = line.mid( pos, name.matchedLength() ).trimmed();
00491       }
00492 
00493       if ( !c.isEmpty() && !n.isEmpty() ) {
00494         pos = c.indexOf( QLatin1Char( '+' ), 1 );
00495         if ( pos < 0 )
00496           pos = c.indexOf( QLatin1Char( '-' ), 1 );
00497         if ( pos > 0 ) {
00498           GeoData geoData;
00499           geoData.latitude = calculateCoordinate( c.left( pos ) );
00500           geoData.longitude = calculateCoordinate( c.mid( pos ) );
00501           geoData.country = country;
00502 
00503           mGeoDataMap.insert( i18n( qPrintable ( n ) ).replace( QLatin1Char( '_' ),  QLatin1Char( ' ' ) ), geoData );
00504         }
00505       }
00506     }
00507 
00508     QStringList items( mGeoDataMap.keys() );
00509     items.prepend( i18nc( "@item:inlistbox Undefined location", "Undefined" ) );
00510     mCityCombo->addItems( items );
00511 
00512     file.close();
00513   }
00514 }
00515 
00516 int GeoDialog::nearestCity( double x, double y ) const
00517 {
00518   QMap<QString, GeoData>::ConstIterator it;
00519   int pos = 0;
00520   for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos ) {
00521     double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
00522                   ( (*it).latitude - y ) * ( (*it).latitude - y );
00523     if ( dist < 0.0005 )
00524       return pos;
00525   }
00526 
00527   return -1;
00528 }
00529 
00530 #include "geoeditwidget.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Thu Aug 2 2012 15:25:43 by doxygen 1.7.5 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.8.5 API Reference

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