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

akonadi/contact

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

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.2-20100208
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal