00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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( KABC::AddressBook *ab,
QWidget *parent,
const char *name )
00048 : KAB::ContactEditorWidget( ab, 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 SLOT( setModified() ) );
00089 connect( mLongitudeBox, SIGNAL( valueChanged(
double ) ),
00090 SLOT( setModified() ) );
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 SLOT( setModified() ) );
00102 }
00103
00104 GeoWidget::~GeoWidget()
00105 {
00106 }
00107
00108
void GeoWidget::loadContact( KABC::Addressee *addr )
00109 {
00110 KABC::Geo geo = addr->geo();
00111
00112
if ( geo.isValid() ) {
00113
if ( !mReadOnly )
00114 mGeoIsValid->setChecked(
true );
00115 mLatitudeBox->setValue( geo.latitude() );
00116 mLongitudeBox->setValue( geo.longitude() );
00117 }
else
00118 mGeoIsValid->setChecked(
false );
00119 }
00120
00121
void GeoWidget::storeContact( KABC::Addressee *addr )
00122 {
00123 KABC::Geo geo;
00124
00125
if ( mGeoIsValid->isChecked() ) {
00126 geo.setLatitude( mLatitudeBox->value() );
00127 geo.setLongitude( mLongitudeBox->value() );
00128 }
else {
00129 geo.setLatitude( 91 );
00130 geo.setLongitude( 181 );
00131 }
00132
00133 addr->setGeo( geo );
00134 }
00135
00136
void GeoWidget::setReadOnly(
bool readOnly )
00137 {
00138 mReadOnly = readOnly;
00139
00140 mGeoIsValid->setEnabled( !mReadOnly );
00141 }
00142
00143
void GeoWidget::editGeoData()
00144 {
00145 GeoDialog dlg(
this );
00146
00147 dlg.setLatitude( mLatitudeBox->value() );
00148 dlg.setLongitude( mLongitudeBox->value() );
00149
00150
if ( dlg.exec() ) {
00151 mLatitudeBox->setValue( dlg.latitude() );
00152 mLongitudeBox->setValue( dlg.longitude() );
00153
00154 setModified(
true );
00155 }
00156 }
00157
00158
00159
00160 GeoDialog::GeoDialog(
QWidget *parent,
const char *name )
00161 : KDialogBase( Plain, i18n( "Geo Data Input" ), Ok | Cancel, Ok,
00162 parent, name, true, true ),
00163 mUpdateSexagesimalInput( true )
00164 {
00165
QFrame *page = plainPage();
00166
00167 QGridLayout *topLayout =
new QGridLayout( page, 2, 2, marginHint(),
00168 spacingHint() );
00169 topLayout->setRowStretch( 1, 1 );
00170
00171 mMapWidget =
new GeoMapWidget( page );
00172 topLayout->addMultiCellWidget( mMapWidget, 0, 1, 0, 0 );
00173
00174 mCityCombo =
new KComboBox( page );
00175 topLayout->addWidget( mCityCombo, 0, 1 );
00176
00177
QGroupBox *sexagesimalGroup =
new QGroupBox( 0, Vertical, i18n(
"Sexagesimal" ), page );
00178 QGridLayout *sexagesimalLayout =
new QGridLayout( sexagesimalGroup->layout(),
00179 2, 5, spacingHint() );
00180
00181 QLabel *label =
new QLabel( i18n(
"Latitude:" ), sexagesimalGroup );
00182 sexagesimalLayout->addWidget( label, 0, 0 );
00183
00184 mLatDegrees =
new QSpinBox( 0, 90, 1, sexagesimalGroup );
00185 mLatDegrees->setSuffix(
"°" );
00186 mLatDegrees->setWrapping(
false );
00187 label->setBuddy( mLatDegrees );
00188 sexagesimalLayout->addWidget( mLatDegrees, 0, 1 );
00189
00190 mLatMinutes =
new QSpinBox( 0, 59, 1, sexagesimalGroup );
00191 mLatMinutes->setSuffix(
"'" );
00192 sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
00193
00194 mLatSeconds =
new QSpinBox( 0, 59, 1, sexagesimalGroup );
00195 mLatSeconds->setSuffix(
"\"" );
00196 sexagesimalLayout->addWidget( mLatSeconds, 0, 3 );
00197
00198 mLatDirection =
new KComboBox( sexagesimalGroup );
00199 mLatDirection->insertItem( i18n(
"North" ) );
00200 mLatDirection->insertItem( i18n(
"South" ) );
00201 sexagesimalLayout->addWidget( mLatDirection, 0, 4 );
00202
00203 label =
new QLabel( i18n(
"Longitude:" ), sexagesimalGroup );
00204 sexagesimalLayout->addWidget( label, 1, 0 );
00205
00206 mLongDegrees =
new QSpinBox( 0, 180, 1, sexagesimalGroup );
00207 mLongDegrees->setSuffix(
"°" );
00208 label->setBuddy( mLongDegrees );
00209 sexagesimalLayout->addWidget( mLongDegrees, 1, 1 );
00210
00211 mLongMinutes =
new QSpinBox( 0, 59, 1, sexagesimalGroup );
00212 mLongMinutes->setSuffix(
"'" );
00213 sexagesimalLayout->addWidget( mLongMinutes, 1, 2 );
00214
00215 mLongSeconds =
new QSpinBox( 0, 59, 1, sexagesimalGroup );
00216 mLongSeconds->setSuffix(
"\"" );
00217 sexagesimalLayout->addWidget( mLongSeconds, 1, 3 );
00218
00219 mLongDirection =
new KComboBox( sexagesimalGroup );
00220 mLongDirection->insertItem( i18n(
"East" ) );
00221 mLongDirection->insertItem( i18n(
"West" ) );
00222 sexagesimalLayout->addWidget( mLongDirection, 1, 4 );
00223
00224 topLayout->addWidget( sexagesimalGroup, 1, 1 );
00225
00226 loadCityList();
00227
00228 connect( mMapWidget, SIGNAL( changed() ),
00229 SLOT( geoMapChanged() ) );
00230 connect( mCityCombo, SIGNAL( activated(
int ) ),
00231 SLOT( cityInputChanged() ) );
00232 connect( mLatDegrees, SIGNAL( valueChanged(
int ) ),
00233 SLOT( sexagesimalInputChanged() ) );
00234 connect( mLatMinutes, SIGNAL( valueChanged(
int ) ),
00235 SLOT( sexagesimalInputChanged() ) );
00236 connect( mLatSeconds, SIGNAL( valueChanged(
int ) ),
00237 SLOT( sexagesimalInputChanged() ) );
00238 connect( mLatDirection, SIGNAL( activated(
int ) ),
00239 SLOT( sexagesimalInputChanged() ) );
00240 connect( mLongDegrees, SIGNAL( valueChanged(
int ) ),
00241 SLOT( sexagesimalInputChanged() ) );
00242 connect( mLongMinutes, SIGNAL( valueChanged(
int ) ),
00243 SLOT( sexagesimalInputChanged() ) );
00244 connect( mLongSeconds, SIGNAL( valueChanged(
int ) ),
00245 SLOT( sexagesimalInputChanged() ) );
00246 connect( mLongDirection, SIGNAL( activated(
int ) ),
00247 SLOT( sexagesimalInputChanged() ) );
00248
00249 KAcceleratorManager::manage(
this );
00250 }
00251
00252 GeoDialog::~GeoDialog()
00253 {
00254 }
00255
00256
void GeoDialog::setLatitude(
double latitude )
00257 {
00258 mLatitude = latitude;
00259 updateInputs();
00260 }
00261
00262
double GeoDialog::latitude()
const
00263
{
00264
return mLatitude;
00265 }
00266
00267
void GeoDialog::setLongitude(
double longitude )
00268 {
00269 mLongitude = longitude;
00270 updateInputs();
00271 }
00272
00273
double GeoDialog::longitude()
const
00274
{
00275
return mLongitude;
00276 }
00277
00278
void GeoDialog::sexagesimalInputChanged()
00279 {
00280 mLatitude = (
double)( mLatDegrees->value() + (
double)mLatMinutes->value() /
00281 60 + (
double)mLatSeconds->value() / 3600 );
00282
00283 mLatitude *= ( mLatDirection->currentItem() == 1 ? -1 : 1 );
00284
00285 mLongitude = (
double)( mLongDegrees->value() + (
double)mLongMinutes->value() /
00286 60 + (
double)mLongSeconds->value() / 3600 );
00287
00288 mLongitude *= ( mLongDirection->currentItem() == 1 ? -1 : 1 );
00289
00290 mUpdateSexagesimalInput =
false;
00291
00292 updateInputs();
00293 }
00294
00295
void GeoDialog::geoMapChanged()
00296 {
00297 mLatitude = mMapWidget->latitude();
00298 mLongitude = mMapWidget->longitude();
00299
00300 updateInputs();
00301 }
00302
00303
void GeoDialog::cityInputChanged()
00304 {
00305
if ( mCityCombo->currentItem() != 0 ) {
00306 GeoData data = mGeoDataMap[ mCityCombo->currentText() ];
00307 mLatitude = data.latitude;
00308 mLongitude = data.longitude;
00309 }
else
00310 mLatitude = mLongitude = 0;
00311
00312 updateInputs();
00313 }
00314
00315
void GeoDialog::updateInputs()
00316 {
00317
00318 mCityCombo->blockSignals(
true );
00319 mLatDegrees->blockSignals(
true );
00320 mLatMinutes->blockSignals(
true );
00321 mLatSeconds->blockSignals(
true );
00322 mLatDirection->blockSignals(
true );
00323 mLongDegrees->blockSignals(
true );
00324 mLongMinutes->blockSignals(
true );
00325 mLongSeconds->blockSignals(
true );
00326 mLongDirection->blockSignals(
true );
00327
00328 mMapWidget->setLatitude( mLatitude );
00329 mMapWidget->setLongitude( mLongitude );
00330 mMapWidget->update();
00331
00332
if ( mUpdateSexagesimalInput ) {
00333
int degrees, minutes, seconds;
00334
double latitude = mLatitude;
00335
double longitude = mLongitude;
00336
00337 latitude *= ( mLatitude < 0 ? -1 : 1 );
00338 longitude *= ( mLongitude < 0 ? -1 : 1 );
00339
00340 degrees = (
int)( latitude * 1 );
00341 minutes = (
int)( ( latitude - degrees ) * 60 );
00342 seconds = (
int)( (
double)( (
double)latitude - (
double)degrees - ( (
double)minutes / (
double)60 ) ) * (
double)3600 );
00343
00344 mLatDegrees->setValue( degrees );
00345 mLatMinutes->setValue( minutes );
00346 mLatSeconds->setValue( seconds );
00347
00348 mLatDirection->setCurrentItem( mLatitude < 0 ? 1 : 0 );
00349
00350 degrees = (
int)( longitude * 1 );
00351 minutes = (
int)( ( longitude - degrees ) * 60 );
00352 seconds = (
int)( (
double)( longitude - (
double)degrees - ( (
double)minutes / 60 ) ) * 3600 );
00353
00354 mLongDegrees->setValue( degrees );
00355 mLongMinutes->setValue( minutes );
00356 mLongSeconds->setValue( seconds );
00357 mLongDirection->setCurrentItem( mLongitude < 0 ? 1 : 0 );
00358 }
00359 mUpdateSexagesimalInput =
true;
00360
00361
int pos = nearestCity( mLongitude, mLatitude );
00362
if ( pos != -1 )
00363 mCityCombo->setCurrentItem( pos + 1 );
00364
else
00365 mCityCombo->setCurrentItem( 0 );
00366
00367 mCityCombo->blockSignals(
false );
00368 mLatDegrees->blockSignals(
false );
00369 mLatMinutes->blockSignals(
false );
00370 mLatSeconds->blockSignals(
false );
00371 mLatDirection->blockSignals(
false );
00372 mLongDegrees->blockSignals(
false );
00373 mLongMinutes->blockSignals(
false );
00374 mLongSeconds->blockSignals(
false );
00375 mLongDirection->blockSignals(
false );
00376 }
00377
00378
void GeoDialog::loadCityList()
00379 {
00380 mCityCombo->clear();
00381 mGeoDataMap.clear();
00382
00383
QFile file( locate(
"data",
"kaddressbook/zone.tab" ) );
00384
00385
if ( file.open( IO_ReadOnly ) ) {
00386
QTextStream s( &file );
00387
00388
QString line, country;
00389
QRegExp coord(
"[+-]\\d+[+-]\\d+" );
00390
QRegExp name(
"[^\\s]+/[^\\s]+" );
00391
int pos;
00392
00393
while ( !s.eof() ) {
00394 line = s.readLine().stripWhiteSpace();
00395
if ( line.isEmpty() || line[ 0 ] ==
'#' )
00396
continue;
00397
00398 country = line.left( 2 );
00399
QString c, n;
00400 pos = coord.search( line, 0 );
00401
if ( pos >= 0 )
00402 c = line.mid( pos, coord.matchedLength() );
00403
00404 pos = name.search(line, pos);
00405
if ( pos > 0 ) {
00406 n = line.mid( pos, name.matchedLength() ).stripWhiteSpace();
00407 n.replace(
'_',
" " );
00408 }
00409
00410
if ( !c.isEmpty() && !n.isEmpty() ) {
00411 pos = c.find(
"+", 1 );
00412
if ( pos < 0 )
00413 pos = c.find(
"-", 1 );
00414
if ( pos > 0 ) {
00415 GeoData data;
00416 data.latitude = calculateCoordinate( c.left( pos ) );
00417 data.longitude = calculateCoordinate( c.mid( pos ) );
00418 data.country = country;
00419
00420 mGeoDataMap.insert( n, data );
00421 }
00422 }
00423 }
00424
QStringList items( mGeoDataMap.keys() );
00425 items.prepend( i18n(
"Undefined" ) );
00426 mCityCombo->insertStringList( items );
00427
00428 file.close();
00429 }
00430 }
00431
00432
double GeoDialog::calculateCoordinate(
const QString &coordinate )
00433 {
00434
int neg;
00435
int d = 0, m = 0, s = 0;
00436
QString str = coordinate;
00437
00438 neg = str.left( 1 ) ==
"-";
00439 str.remove( 0, 1 );
00440
00441
switch ( str.length() ) {
00442
case 4:
00443 d = str.left( 2 ).toInt();
00444 m = str.mid( 2 ).toInt();
00445
break;
00446
case 5:
00447 d = str.left( 3 ).toInt();
00448 m = str.mid( 3 ).toInt();
00449
break;
00450
case 6:
00451 d = str.left( 2 ).toInt();
00452 m = str.mid( 2, 2 ).toInt();
00453 s = str.right( 2 ).toInt();
00454
break;
00455
case 7:
00456 d = str.left( 3 ).toInt();
00457 m = str.mid( 3, 2 ).toInt();
00458 s = str.right( 2 ).toInt();
00459
break;
00460
default:
00461
break;
00462 }
00463
00464
if ( neg )
00465
return - ( d + m / 60.0 + s / 3600.0 );
00466
else
00467
return d + m / 60.0 + s / 3600.0;
00468 }
00469
00470
int GeoDialog::nearestCity(
double x,
double y )
00471 {
00472
QMap<QString, GeoData>::Iterator it;
00473
int pos = 0;
00474
for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, pos++ ) {
00475
double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
00476 ( (*it).latitude - y ) * ( (*it).latitude - y );
00477
if ( dist < 1.5 )
00478
return pos;
00479 }
00480
00481
return -1;
00482 }
00483
00484
00485 GeoMapWidget::GeoMapWidget(
QWidget *parent,
const char *name )
00486 :
QWidget( parent, name ), mLatitude( 0 ), mLongitude( 0 )
00487 {
00488 setBackgroundMode( NoBackground );
00489
00490 setFixedSize( 400, 200 );
00491
00492 update();
00493 }
00494
00495 GeoMapWidget::~GeoMapWidget()
00496 {
00497 }
00498
00499
void GeoMapWidget::setLatitude(
double latitude )
00500 {
00501 mLatitude = latitude;
00502 }
00503
00504
double GeoMapWidget::latitude()const
00505 {
00506
return mLatitude;
00507 }
00508
00509
void GeoMapWidget::setLongitude(
double longitude )
00510 {
00511 mLongitude = longitude;
00512 }
00513
00514
double GeoMapWidget::longitude()const
00515 {
00516
return mLongitude;
00517 }
00518
00519
void GeoMapWidget::mousePressEvent(
QMouseEvent *event )
00520 {
00521
double latMid = height() / 2;
00522
double longMid = width() / 2;
00523
00524
double latOffset = latMid - event->y();
00525
double longOffset = event->x() - longMid;
00526
00527 mLatitude = ( latOffset * 90 ) / latMid;
00528 mLongitude = ( longOffset * 180 ) / longMid;
00529
00530 emit changed();
00531 }
00532
00533
void GeoMapWidget::paintEvent(
QPaintEvent* )
00534 {
00535 uint w = width();
00536 uint h = height();
00537
00538
QPixmap pm( w, h );
00539
QPainter p;
00540 p.begin( &pm,
this );
00541
00542 p.setPen(
QColor( 255, 0, 0 ) );
00543 p.setBrush(
QColor( 255, 0, 0 ) );
00544
00545
QPixmap world( locate(
"data",
"kaddressbook/pics/world.jpg" ) );
00546 p.drawPixmap( 0, 0, world );
00547
00548
double latMid = h / 2;
00549
double longMid = w / 2;
00550
00551
double latOffset = ( mLatitude * latMid ) / 90;
00552
double longOffset = ( mLongitude * longMid ) / 180;
00553
00554
int x = (
int)(longMid + longOffset);
00555
int y = (
int)(latMid - latOffset);
00556 p.drawEllipse( x, y, 4, 4 );
00557
00558 p.end();
00559 bitBlt(
this, 0, 0, &pm );
00560 }
00561
00562
#include "geowidget.moc"