kaddressbook Library API Documentation

geowidget.cpp

00001 /* 00002 This file is part of KAddressBook. 00003 Copyright (c) 2002 Tobias Koenig <tokoe@kde.org> 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 00019 As a special exception, permission is given to link this program 00020 with any edition of Qt, and distribute the resulting executable, 00021 without including the source code for Qt in the source distribution. 00022 */ 00023 00024 #include <kabc/geo.h> 00025 #include <kaccelmanager.h> 00026 #include <kcombobox.h> 00027 #include <kdebug.h> 00028 #include <kiconloader.h> 00029 #include <klocale.h> 00030 #include <knuminput.h> 00031 #include <kstandarddirs.h> 00032 00033 #include <qcheckbox.h> 00034 #include <qfile.h> 00035 #include <qgroupbox.h> 00036 #include <qlabel.h> 00037 #include <qlayout.h> 00038 #include <qlistbox.h> 00039 #include <qpainter.h> 00040 #include <qpixmap.h> 00041 #include <qpushbutton.h> 00042 #include <qregexp.h> 00043 #include <qstring.h> 00044 00045 #include "geowidget.h" 00046 00047 GeoWidget::GeoWidget( QWidget *parent, const char *name ) 00048 : QWidget( parent, name ), mReadOnly( false ) 00049 { 00050 QLabel *label = 0; 00051 00052 QGridLayout *topLayout = new QGridLayout( this, 4, 3 ); 00053 topLayout->setMargin( KDialog::marginHint() ); 00054 topLayout->setSpacing( KDialog::spacingHint() ); 00055 00056 label = new QLabel( this ); 00057 label->setPixmap( KGlobal::iconLoader()->loadIcon( "package_network", 00058 KIcon::Desktop, KIcon::SizeMedium ) ); 00059 label->setAlignment( Qt::AlignTop ); 00060 topLayout->addMultiCellWidget( label, 0, 3, 0, 0 ); 00061 00062 mGeoIsValid = new QCheckBox( i18n( "Use geo data" ), this ); 00063 topLayout->addMultiCellWidget( mGeoIsValid, 0, 0, 1, 2 ); 00064 00065 label = new QLabel( i18n( "Latitude:" ), this ); 00066 topLayout->addWidget( label, 1, 1 ); 00067 00068 mLatitudeBox = new KDoubleSpinBox( -90, 90, 1, 0, 6, this ); 00069 mLatitudeBox->setEnabled( false ); 00070 mLatitudeBox->setSuffix( "°" ); 00071 topLayout->addWidget( mLatitudeBox, 1, 2 ); 00072 label->setBuddy( mLatitudeBox ); 00073 00074 label = new QLabel( i18n( "Longitude:" ), this ); 00075 topLayout->addWidget( label, 2, 1 ); 00076 00077 mLongitudeBox = new KDoubleSpinBox( -180, 180, 1, 0, 6, this ); 00078 mLongitudeBox->setEnabled( false ); 00079 mLongitudeBox->setSuffix( "°" ); 00080 topLayout->addWidget( mLongitudeBox, 2, 2 ); 00081 label->setBuddy( mLongitudeBox ); 00082 00083 mExtendedButton = new QPushButton( i18n( "Edit Geo Data..." ), this ); 00084 mExtendedButton->setEnabled( false ); 00085 topLayout->addMultiCellWidget( mExtendedButton, 3, 3, 1, 2 ); 00086 00087 connect( mLatitudeBox, SIGNAL( valueChanged( double ) ), 00088 SIGNAL( changed() ) ); 00089 connect( mLongitudeBox, SIGNAL( valueChanged( double ) ), 00090 SIGNAL( changed() ) ); 00091 connect( mExtendedButton, SIGNAL( clicked() ), 00092 SLOT( editGeoData() ) ); 00093 00094 connect( mGeoIsValid, SIGNAL( toggled( bool ) ), 00095 mLatitudeBox, SLOT( setEnabled( bool ) ) ); 00096 connect( mGeoIsValid, SIGNAL( toggled( bool ) ), 00097 mLongitudeBox, SLOT( setEnabled( bool ) ) ); 00098 connect( mGeoIsValid, SIGNAL( toggled( bool ) ), 00099 mExtendedButton, SLOT( setEnabled( bool ) ) ); 00100 connect( mGeoIsValid, SIGNAL( toggled( bool ) ), 00101 SIGNAL( changed() ) ); 00102 } 00103 00104 GeoWidget::~GeoWidget() 00105 { 00106 } 00107 00108 void GeoWidget::setReadOnly( bool readOnly ) 00109 { 00110 mReadOnly = readOnly; 00111 00112 mGeoIsValid->setEnabled( !mReadOnly ); 00113 } 00114 00115 void GeoWidget::setGeo( const KABC::Geo &geo ) 00116 { 00117 if ( geo.isValid() ) { 00118 if ( !mReadOnly ) 00119 mGeoIsValid->setChecked( true ); 00120 mLatitudeBox->setValue( geo.latitude() ); 00121 mLongitudeBox->setValue( geo.longitude() ); 00122 } else 00123 mGeoIsValid->setChecked( false ); 00124 } 00125 00126 KABC::Geo GeoWidget::geo() const 00127 { 00128 KABC::Geo geo; 00129 00130 if ( mGeoIsValid->isChecked() ) { 00131 geo.setLatitude( mLatitudeBox->value() ); 00132 geo.setLongitude( mLongitudeBox->value() ); 00133 } else { 00134 geo.setLatitude( 91 ); 00135 geo.setLongitude( 181 ); 00136 } 00137 00138 return geo; 00139 } 00140 00141 void GeoWidget::editGeoData() 00142 { 00143 GeoDialog dlg( this ); 00144 00145 dlg.setLatitude( mLatitudeBox->value() ); 00146 dlg.setLongitude( mLongitudeBox->value() ); 00147 00148 if ( dlg.exec() ) { 00149 mLatitudeBox->setValue( dlg.latitude() ); 00150 mLongitudeBox->setValue( dlg.longitude() ); 00151 00152 emit changed(); 00153 } 00154 } 00155 00156 00157 00158 GeoDialog::GeoDialog( QWidget *parent, const char *name ) 00159 : KDialogBase( Plain, i18n( "Geo Data Input" ), Ok | Cancel, Ok, 00160 parent, name, true, true ), 00161 mUpdateSexagesimalInput( true ) 00162 { 00163 QFrame *page = plainPage(); 00164 00165 QGridLayout *topLayout = new QGridLayout( page, 2, 2, marginHint(), 00166 spacingHint() ); 00167 topLayout->setRowStretch( 1, 1 ); 00168 00169 mMapWidget = new GeoMapWidget( page ); 00170 topLayout->addMultiCellWidget( mMapWidget, 0, 1, 0, 0 ); 00171 00172 mCityCombo = new KComboBox( page ); 00173 topLayout->addWidget( mCityCombo, 0, 1 ); 00174 00175 QGroupBox *sexagesimalGroup = new QGroupBox( 0, Vertical, i18n( "Sexagesimal" ), page ); 00176 QGridLayout *sexagesimalLayout = new QGridLayout( sexagesimalGroup->layout(), 00177 2, 5, spacingHint() ); 00178 00179 QLabel *label = new QLabel( i18n( "Latitude:" ), sexagesimalGroup ); 00180 sexagesimalLayout->addWidget( label, 0, 0 ); 00181 00182 mLatDegrees = new QSpinBox( 0, 90, 1, sexagesimalGroup ); 00183 mLatDegrees->setSuffix( "°" ); 00184 mLatDegrees->setWrapping( false ); 00185 label->setBuddy( mLatDegrees ); 00186 sexagesimalLayout->addWidget( mLatDegrees, 0, 1 ); 00187 00188 mLatMinutes = new QSpinBox( 0, 59, 1, sexagesimalGroup ); 00189 mLatMinutes->setSuffix( "'" ); 00190 sexagesimalLayout->addWidget( mLatMinutes, 0, 2 ); 00191 00192 mLatSeconds = new QSpinBox( 0, 59, 1, sexagesimalGroup ); 00193 mLatSeconds->setSuffix( "\"" ); 00194 sexagesimalLayout->addWidget( mLatSeconds, 0, 3 ); 00195 00196 mLatDirection = new KComboBox( sexagesimalGroup ); 00197 mLatDirection->insertItem( i18n( "North" ) ); 00198 mLatDirection->insertItem( i18n( "South" ) ); 00199 sexagesimalLayout->addWidget( mLatDirection, 0, 4 ); 00200 00201 label = new QLabel( i18n( "Longitude:" ), sexagesimalGroup ); 00202 sexagesimalLayout->addWidget( label, 1, 0 ); 00203 00204 mLongDegrees = new QSpinBox( 0, 180, 1, sexagesimalGroup ); 00205 mLongDegrees->setSuffix( "°" ); 00206 label->setBuddy( mLongDegrees ); 00207 sexagesimalLayout->addWidget( mLongDegrees, 1, 1 ); 00208 00209 mLongMinutes = new QSpinBox( 0, 59, 1, sexagesimalGroup ); 00210 mLongMinutes->setSuffix( "'" ); 00211 sexagesimalLayout->addWidget( mLongMinutes, 1, 2 ); 00212 00213 mLongSeconds = new QSpinBox( 0, 59, 1, sexagesimalGroup ); 00214 mLongSeconds->setSuffix( "\"" ); 00215 sexagesimalLayout->addWidget( mLongSeconds, 1, 3 ); 00216 00217 mLongDirection = new KComboBox( sexagesimalGroup ); 00218 mLongDirection->insertItem( i18n( "East" ) ); 00219 mLongDirection->insertItem( i18n( "West" ) ); 00220 sexagesimalLayout->addWidget( mLongDirection, 1, 4 ); 00221 00222 topLayout->addWidget( sexagesimalGroup, 1, 1 ); 00223 00224 loadCityList(); 00225 00226 connect( mMapWidget, SIGNAL( changed() ), 00227 SLOT( geoMapChanged() ) ); 00228 connect( mCityCombo, SIGNAL( activated( int ) ), 00229 SLOT( cityInputChanged() ) ); 00230 connect( mLatDegrees, SIGNAL( valueChanged( int ) ), 00231 SLOT( sexagesimalInputChanged() ) ); 00232 connect( mLatMinutes, SIGNAL( valueChanged( int ) ), 00233 SLOT( sexagesimalInputChanged() ) ); 00234 connect( mLatSeconds, SIGNAL( valueChanged( int ) ), 00235 SLOT( sexagesimalInputChanged() ) ); 00236 connect( mLatDirection, SIGNAL( activated( int ) ), 00237 SLOT( sexagesimalInputChanged() ) ); 00238 connect( mLongDegrees, SIGNAL( valueChanged( int ) ), 00239 SLOT( sexagesimalInputChanged() ) ); 00240 connect( mLongMinutes, SIGNAL( valueChanged( int ) ), 00241 SLOT( sexagesimalInputChanged() ) ); 00242 connect( mLongSeconds, SIGNAL( valueChanged( int ) ), 00243 SLOT( sexagesimalInputChanged() ) ); 00244 connect( mLongDirection, SIGNAL( activated( int ) ), 00245 SLOT( sexagesimalInputChanged() ) ); 00246 00247 KAcceleratorManager::manage( this ); 00248 } 00249 00250 GeoDialog::~GeoDialog() 00251 { 00252 } 00253 00254 void GeoDialog::setLatitude( double latitude ) 00255 { 00256 mLatitude = latitude; 00257 updateInputs(); 00258 } 00259 00260 double GeoDialog::latitude() const 00261 { 00262 return mLatitude; 00263 } 00264 00265 void GeoDialog::setLongitude( double longitude ) 00266 { 00267 mLongitude = longitude; 00268 updateInputs(); 00269 } 00270 00271 double GeoDialog::longitude() const 00272 { 00273 return mLongitude; 00274 } 00275 00276 void GeoDialog::sexagesimalInputChanged() 00277 { 00278 mLatitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() / 00279 60 + (double)mLatSeconds->value() / 3600 ); 00280 00281 mLatitude *= ( mLatDirection->currentItem() == 1 ? -1 : 1 ); 00282 00283 mLongitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() / 00284 60 + (double)mLongSeconds->value() / 3600 ); 00285 00286 mLongitude *= ( mLongDirection->currentItem() == 1 ? -1 : 1 ); 00287 00288 mUpdateSexagesimalInput = false; 00289 00290 updateInputs(); 00291 } 00292 00293 void GeoDialog::geoMapChanged() 00294 { 00295 mLatitude = mMapWidget->latitude(); 00296 mLongitude = mMapWidget->longitude(); 00297 00298 updateInputs(); 00299 } 00300 00301 void GeoDialog::cityInputChanged() 00302 { 00303 if ( mCityCombo->currentItem() != 0 ) { 00304 GeoData data = mGeoDataMap[ mCityCombo->currentText() ]; 00305 mLatitude = data.latitude; 00306 mLongitude = data.longitude; 00307 } else 00308 mLatitude = mLongitude = 0; 00309 00310 updateInputs(); 00311 } 00312 00313 void GeoDialog::updateInputs() 00314 { 00315 // hmm, doesn't look nice, but there is no better way AFAIK 00316 mCityCombo->blockSignals( true ); 00317 mLatDegrees->blockSignals( true ); 00318 mLatMinutes->blockSignals( true ); 00319 mLatSeconds->blockSignals( true ); 00320 mLatDirection->blockSignals( true ); 00321 mLongDegrees->blockSignals( true ); 00322 mLongMinutes->blockSignals( true ); 00323 mLongSeconds->blockSignals( true ); 00324 mLongDirection->blockSignals( true ); 00325 00326 mMapWidget->setLatitude( mLatitude ); 00327 mMapWidget->setLongitude( mLongitude ); 00328 mMapWidget->update(); 00329 00330 if ( mUpdateSexagesimalInput ) { 00331 int degrees, minutes, seconds; 00332 double latitude = mLatitude; 00333 double longitude = mLongitude; 00334 00335 latitude *= ( mLatitude < 0 ? -1 : 1 ); 00336 longitude *= ( mLongitude < 0 ? -1 : 1 ); 00337 00338 degrees = (int)( latitude * 1 ); 00339 minutes = (int)( ( latitude - degrees ) * 60 ); 00340 seconds = (int)( (double)( (double)latitude - (double)degrees - ( (double)minutes / (double)60 ) ) * (double)3600 ); 00341 00342 mLatDegrees->setValue( degrees ); 00343 mLatMinutes->setValue( minutes ); 00344 mLatSeconds->setValue( seconds ); 00345 00346 mLatDirection->setCurrentItem( mLatitude < 0 ? 1 : 0 ); 00347 00348 degrees = (int)( longitude * 1 ); 00349 minutes = (int)( ( longitude - degrees ) * 60 ); 00350 seconds = (int)( (double)( longitude - (double)degrees - ( (double)minutes / 60 ) ) * 3600 ); 00351 00352 mLongDegrees->setValue( degrees ); 00353 mLongMinutes->setValue( minutes ); 00354 mLongSeconds->setValue( seconds ); 00355 mLongDirection->setCurrentItem( mLongitude < 0 ? 1 : 0 ); 00356 } 00357 mUpdateSexagesimalInput = true; 00358 00359 int pos = nearestCity( mLongitude, mLatitude ); 00360 if ( pos != -1 ) 00361 mCityCombo->setCurrentItem( pos + 1 ); 00362 else 00363 mCityCombo->setCurrentItem( 0 ); 00364 00365 mCityCombo->blockSignals( false ); 00366 mLatDegrees->blockSignals( false ); 00367 mLatMinutes->blockSignals( false ); 00368 mLatSeconds->blockSignals( false ); 00369 mLatDirection->blockSignals( false ); 00370 mLongDegrees->blockSignals( false ); 00371 mLongMinutes->blockSignals( false ); 00372 mLongSeconds->blockSignals( false ); 00373 mLongDirection->blockSignals( false ); 00374 } 00375 00376 void GeoDialog::loadCityList() 00377 { 00378 mCityCombo->clear(); 00379 mGeoDataMap.clear(); 00380 00381 QFile file( locate( "data", "kaddressbook/zone.tab" ) ); 00382 00383 if ( file.open( IO_ReadOnly ) ) { 00384 QTextStream s( &file ); 00385 00386 QString line, country; 00387 QRegExp coord( "[+-]\\d+[+-]\\d+" ); 00388 QRegExp name( "[^\\s]+/[^\\s]+" ); 00389 int pos; 00390 00391 while ( !s.eof() ) { 00392 line = s.readLine().stripWhiteSpace(); 00393 if ( line.isEmpty() || line[ 0 ] == '#' ) 00394 continue; 00395 00396 country = line.left( 2 ); 00397 QString c, n; 00398 pos = coord.search( line, 0 ); 00399 if ( pos >= 0 ) 00400 c = line.mid( pos, coord.matchedLength() ); 00401 00402 pos = name.search(line, pos); 00403 if ( pos > 0 ) { 00404 n = line.mid( pos, name.matchedLength() ).stripWhiteSpace(); 00405 n.replace( '_', " " ); 00406 } 00407 00408 if ( !c.isEmpty() && !n.isEmpty() ) { 00409 pos = c.find( "+", 1 ); 00410 if ( pos < 0 ) 00411 pos = c.find( "-", 1 ); 00412 if ( pos > 0 ) { 00413 GeoData data; 00414 data.latitude = calculateCoordinate( c.left( pos ) ); 00415 data.longitude = calculateCoordinate( c.mid( pos ) ); 00416 data.country = country; 00417 00418 mGeoDataMap.insert( n, data ); 00419 } 00420 } 00421 } 00422 QStringList items( mGeoDataMap.keys() ); 00423 items.prepend( i18n( "Undefined" ) ); 00424 mCityCombo->insertStringList( items ); 00425 00426 file.close(); 00427 } 00428 } 00429 00430 double GeoDialog::calculateCoordinate( const QString &coordinate ) 00431 { 00432 int neg; 00433 int d = 0, m = 0, s = 0; 00434 QString str = coordinate; 00435 00436 neg = str.left( 1 ) == "-"; 00437 str.remove( 0, 1 ); 00438 00439 switch ( str.length() ) { 00440 case 4: 00441 d = str.left( 2 ).toInt(); 00442 m = str.mid( 2 ).toInt(); 00443 break; 00444 case 5: 00445 d = str.left( 3 ).toInt(); 00446 m = str.mid( 3 ).toInt(); 00447 break; 00448 case 6: 00449 d = str.left( 2 ).toInt(); 00450 m = str.mid( 2, 2 ).toInt(); 00451 s = str.right( 2 ).toInt(); 00452 break; 00453 case 7: 00454 d = str.left( 3 ).toInt(); 00455 m = str.mid( 3, 2 ).toInt(); 00456 s = str.right( 2 ).toInt(); 00457 break; 00458 default: 00459 break; 00460 } 00461 00462 if ( neg ) 00463 return - ( d + m / 60.0 + s / 3600.0 ); 00464 else 00465 return d + m / 60.0 + s / 3600.0; 00466 } 00467 00468 int GeoDialog::nearestCity( double x, double y ) 00469 { 00470 QMap<QString, GeoData>::Iterator it; 00471 int pos = 0; 00472 for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, pos++ ) { 00473 double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) + 00474 ( (*it).latitude - y ) * ( (*it).latitude - y ); 00475 if ( dist < 1.5 ) 00476 return pos; 00477 } 00478 00479 return -1; 00480 } 00481 00482 00483 GeoMapWidget::GeoMapWidget( QWidget *parent, const char *name ) 00484 : QWidget( parent, name ), mLatitude( 0 ), mLongitude( 0 ) 00485 { 00486 setBackgroundMode( NoBackground ); 00487 00488 setFixedSize( 400, 200 ); 00489 00490 update(); 00491 } 00492 00493 GeoMapWidget::~GeoMapWidget() 00494 { 00495 } 00496 00497 void GeoMapWidget::setLatitude( double latitude ) 00498 { 00499 mLatitude = latitude; 00500 } 00501 00502 double GeoMapWidget::latitude()const 00503 { 00504 return mLatitude; 00505 } 00506 00507 void GeoMapWidget::setLongitude( double longitude ) 00508 { 00509 mLongitude = longitude; 00510 } 00511 00512 double GeoMapWidget::longitude()const 00513 { 00514 return mLongitude; 00515 } 00516 00517 void GeoMapWidget::mousePressEvent( QMouseEvent *event ) 00518 { 00519 double latMid = height() / 2; 00520 double longMid = width() / 2; 00521 00522 double latOffset = latMid - event->y(); 00523 double longOffset = event->x() - longMid; 00524 00525 mLatitude = ( latOffset * 90 ) / latMid; 00526 mLongitude = ( longOffset * 180 ) / longMid; 00527 00528 emit changed(); 00529 } 00530 00531 void GeoMapWidget::paintEvent( QPaintEvent* ) 00532 { 00533 uint w = width(); 00534 uint h = height(); 00535 00536 QPixmap pm( w, h ); 00537 QPainter p; 00538 p.begin( &pm, this ); 00539 00540 p.setPen( QColor( 255, 0, 0 ) ); 00541 p.setBrush( QColor( 255, 0, 0 ) ); 00542 00543 QPixmap world( locate( "data", "kaddressbook/pics/world.jpg" ) ); 00544 p.drawPixmap( 0, 0, world ); 00545 00546 double latMid = h / 2; 00547 double longMid = w / 2; 00548 00549 double latOffset = ( mLatitude * latMid ) / 90; 00550 double longOffset = ( mLongitude * longMid ) / 180; 00551 00552 int x = (int)(longMid + longOffset); 00553 int y = (int)(latMid - latOffset); 00554 p.drawEllipse( x, y, 4, 4 ); 00555 00556 p.end(); 00557 bitBlt( this, 0, 0, &pm ); 00558 } 00559 00560 #include "geowidget.moc"
KDE Logo
This file is part of the documentation for kaddressbook Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jul 28 23:58:08 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003