summaryrefslogtreecommitdiffabout
path: root/kaddressbook/geowidget.cpp
Unidiff
Diffstat (limited to 'kaddressbook/geowidget.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--kaddressbook/geowidget.cpp629
1 files changed, 629 insertions, 0 deletions
diff --git a/kaddressbook/geowidget.cpp b/kaddressbook/geowidget.cpp
new file mode 100644
index 0000000..13cd084
--- a/dev/null
+++ b/kaddressbook/geowidget.cpp
@@ -0,0 +1,629 @@
1/*
2 This file is part of KAddressBook.
3 Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 As a special exception, permission is given to link this program
20 with any edition of Qt, and distribute the resulting executable,
21 without including the source code for Qt in the source distribution.
22*/
23
24#include <kabc/geo.h>
25
26#ifndef KAB_EMBEDDED
27#include <kaccelmanager.h>
28#else //KAB_EMBEDDED
29
30#include <qtextstream.h>
31#include <kglobal.h>
32#endif //KAB_EMBEDDED
33
34#include <knuminput.h>
35#include <kcombobox.h>
36#include <kdebug.h>
37#include <kiconloader.h>
38#include <klocale.h>
39#include <kstandarddirs.h>
40
41#include <qcheckbox.h>
42#include <qfile.h>
43#include <qapplication.h>
44#include <qgroupbox.h>
45#include <qlabel.h>
46#include <qlayout.h>
47#include <qlistbox.h>
48#include <qpainter.h>
49#include <qpixmap.h>
50#include <qpushbutton.h>
51#include <qregexp.h>
52#include <qstring.h>
53#include <stdlib.h>
54
55#include "geowidget.h"
56
57GeoWidget::GeoWidget( QWidget *parent, const char *name )
58 : QWidget( parent, name )
59{
60 QLabel *label = 0;
61
62 QGridLayout *topLayout = new QGridLayout( this, 4, 3 );
63 topLayout->setMargin( KDialog::marginHint() );
64 topLayout->setSpacing( KDialog::spacingHint() );
65
66 label = new QLabel( this );
67//US ambiguous call to loadIcon. Add an additional parameter
68//US label->setPixmap( KGlobal::iconLoader()->loadIcon( "package_network", KIcon::Desktop ) );
69 label->setPixmap( KGlobal::iconLoader()->loadIcon( "package_network", KIcon::Desktop, 0 ) );
70 label->setAlignment( Qt::AlignTop );
71 topLayout->addMultiCellWidget( label, 0, 3, 0, 0 );
72 label->setAlignment( AlignCenter );
73 mGeoIsValid = new QCheckBox( i18n( "Use geo data" ), this );
74 topLayout->addMultiCellWidget( mGeoIsValid, 0, 0, 1, 2 );
75
76 label = new QLabel( i18n( "Latitude:" ), this );
77 topLayout->addWidget( label, 1, 1 );
78
79 mLatitudeBox = new KDoubleSpinBox( -90, 90, 1, 0, 6, this );
80 mLatitudeBox->setEnabled( false );
81 mLatitudeBox->setSuffix( "" );
82 topLayout->addWidget( mLatitudeBox, 1, 2 );
83 label->setBuddy( mLatitudeBox );
84
85 label = new QLabel( i18n( "Longitude:" ), this );
86 topLayout->addWidget( label, 2, 1 );
87
88 mLongitudeBox = new KDoubleSpinBox( -180, 180, 1, 0, 6, this );
89 mLongitudeBox->setEnabled( false );
90 mLongitudeBox->setSuffix( "" );
91 topLayout->addWidget( mLongitudeBox, 2, 2 );
92 label->setBuddy( mLongitudeBox );
93
94 mExtendedButton = new QPushButton( i18n( "Edit Geo Data..." ), this );
95 mExtendedButton->setEnabled( false );
96 topLayout->addMultiCellWidget( mExtendedButton, 3, 3, 1, 2 );
97
98 connect( mLatitudeBox, SIGNAL( valueChanged( double ) ),
99 SIGNAL( changed() ) );
100 connect( mLongitudeBox, SIGNAL( valueChanged( double ) ),
101 SIGNAL( changed() ) );
102 connect( mExtendedButton, SIGNAL( clicked() ),
103 SLOT( editGeoData() ) );
104
105 connect( mGeoIsValid, SIGNAL( toggled( bool ) ),
106 mLatitudeBox, SLOT( setEnabled( bool ) ) );
107 connect( mGeoIsValid, SIGNAL( toggled( bool ) ),
108 mLongitudeBox, SLOT( setEnabled( bool ) ) );
109 connect( mGeoIsValid, SIGNAL( toggled( bool ) ),
110 mExtendedButton, SLOT( setEnabled( bool ) ) );
111 connect( mGeoIsValid, SIGNAL( toggled( bool ) ),
112 SIGNAL( changed() ) );
113
114#ifndef KAB_EMBEDDED
115 KAcceleratorManager::manage( this );
116#endif //KAB_EMBEDDED
117}
118
119GeoWidget::~GeoWidget()
120{
121}
122
123void GeoWidget::setGeo( const KABC::Geo &geo )
124{
125 if ( geo.isValid() ) {
126 mGeoIsValid->setChecked( true );
127 mLatitudeBox->setValue( geo.latitude() );
128 mLongitudeBox->setValue( geo.longitude() );
129 } else
130 mGeoIsValid->setChecked( false );
131}
132
133KABC::Geo GeoWidget::geo() const
134{
135 KABC::Geo geo;
136
137 if ( mGeoIsValid->isChecked() ) {
138 geo.setLatitude( mLatitudeBox->value() );
139 geo.setLongitude( mLongitudeBox->value() );
140 } else {
141 geo.setLatitude( 91 );
142 geo.setLongitude( 181 );
143 }
144
145 return geo;
146}
147
148void GeoWidget::editGeoData()
149{
150 GeoDialog dlg( this );
151
152 dlg.setLatitude( mLatitudeBox->value() );
153 dlg.setLongitude( mLongitudeBox->value() );
154
155 if ( dlg.exec() ) {
156 mLatitudeBox->setValue( dlg.latitude() );
157 mLongitudeBox->setValue( dlg.longitude() );
158
159 emit changed();
160 }
161}
162
163
164
165GeoDialog::GeoDialog( QWidget *parent, const char *name )
166 : KDialogBase( Plain, i18n( "Geo Data Input" ), Ok | Cancel, Ok,
167 parent, name, true, true ),
168 mUpdateSexagesimalInput( true )
169{
170 QFrame *page = plainPage();
171
172 QGridLayout *topLayout = new QGridLayout( page, 1, 1, marginHintSmall(),
173 spacingHint() );
174 //topLayout->setRowStretch( 1, 1 );
175
176 mMapWidget = new GeoMapWidget( page );
177 mCityCombo = new KComboBox( page );
178 QGroupBox *sexagesimalGroup = new QGroupBox( 0, Vertical, i18n( "Sexagesimal" ), page );
179 QGridLayout *sexagesimalLayout = new QGridLayout( sexagesimalGroup->layout(),
180 2, 5, spacingHint() );
181 QLabel *label;
182 if ( QApplication::desktop()->width() < 320 ) {
183 label = new QLabel( i18n( "La." ), sexagesimalGroup );
184 sexagesimalLayout->setSpacing ( spacingHintSmall() );
185 sexagesimalLayout->setMargin ( marginHintSmall() );
186 topLayout->setMargin ( 0 );
187 mCityCombo->setMaximumWidth( 220 );
188 sexagesimalGroup->setMaximumWidth( 220 );
189 }
190 else
191 label = new QLabel( i18n( "Latitude:" ), sexagesimalGroup );
192 sexagesimalLayout->addWidget( label, 0, 0 );
193
194 int maxWid = 60;
195 if ( QApplication::desktop()->width() < 320 )
196 maxWid = 40;
197 mLatDegrees = new QSpinBox( 0, 90, 1, sexagesimalGroup );
198 mLatDegrees->setSuffix( "" );
199 mLatDegrees->setWrapping( false );
200 sexagesimalLayout->addWidget( mLatDegrees, 0, 1 );
201 mLatDegrees->setMaximumWidth( maxWid );
202
203 mLatMinutes = new QSpinBox( 0, 59, 1, sexagesimalGroup );
204 mLatMinutes->setSuffix( "'" );
205 sexagesimalLayout->addWidget( mLatMinutes, 0, 2 );
206 mLatMinutes->setMaximumWidth( maxWid );
207
208 mLatSeconds = new QSpinBox( 0, 59, 1, sexagesimalGroup );
209 mLatSeconds->setSuffix( "\"" );
210 sexagesimalLayout->addWidget( mLatSeconds, 0, 3 );
211 mLatSeconds->setMaximumWidth( maxWid );
212
213 mLatDirection = new KComboBox( sexagesimalGroup );
214 mLatDirection->insertItem( i18n( "North" ) );
215 mLatDirection->insertItem( i18n( "South" ) );
216 sexagesimalLayout->addWidget( mLatDirection, 0, 4 );
217
218
219 if ( QApplication::desktop()->width() < 320 )
220 label = new QLabel( i18n( "Lo." ), sexagesimalGroup );
221 else
222 label = new QLabel( i18n( "Longitude:" ), sexagesimalGroup );
223
224
225 sexagesimalLayout->addWidget( label, 1, 0 );
226
227 mLongDegrees = new QSpinBox( 0, 180, 1, sexagesimalGroup );
228 mLongDegrees->setSuffix( "" );
229 sexagesimalLayout->addWidget( mLongDegrees, 1, 1 );
230 mLongDegrees->setMaximumWidth( maxWid );
231
232 mLongMinutes = new QSpinBox( 0, 59, 1, sexagesimalGroup );
233 mLongMinutes->setSuffix( "'" );
234 sexagesimalLayout->addWidget( mLongMinutes, 1, 2 );
235 mLongMinutes->setMaximumWidth( maxWid );
236
237 mLongSeconds = new QSpinBox( 0, 59, 1, sexagesimalGroup );
238 mLongSeconds->setSuffix( "\"" );
239 sexagesimalLayout->addWidget( mLongSeconds, 1, 3 );
240 mLongSeconds->setMaximumWidth( maxWid );
241
242 mLongDirection = new KComboBox( sexagesimalGroup );
243 mLongDirection->insertItem( i18n( "East" ) );
244 mLongDirection->insertItem( i18n( "West" ) );
245 sexagesimalLayout->addWidget( mLongDirection, 1, 4 );
246 if ( true /*QApplication::desktop()->width() < 640*/ ) {
247
248 topLayout->addWidget( mMapWidget, 0, 0 );
249 topLayout->addWidget( mCityCombo, 1, 0 );
250 topLayout->addWidget( sexagesimalGroup, 2, 0 );
251
252 } else {
253 topLayout->addMultiCellWidget( mMapWidget, 0, 1, 0, 0 );
254 topLayout->addWidget( mCityCombo, 0, 1 );
255 topLayout->addWidget( sexagesimalGroup, 1, 1 );
256 }
257
258 loadCityList();
259
260 connect( mMapWidget, SIGNAL( changed() ),
261 SLOT( geoMapChanged() ) );
262 connect( mCityCombo, SIGNAL( activated( int ) ),
263 SLOT( cityInputChanged() ) );
264 connect( mLatDegrees, SIGNAL( valueChanged( int ) ),
265 SLOT( sexagesimalInputChanged() ) );
266 connect( mLatMinutes, SIGNAL( valueChanged( int ) ),
267 SLOT( sexagesimalInputChanged() ) );
268 connect( mLatSeconds, SIGNAL( valueChanged( int ) ),
269 SLOT( sexagesimalInputChanged() ) );
270 connect( mLatDirection, SIGNAL( activated( int ) ),
271 SLOT( sexagesimalInputChanged() ) );
272 connect( mLongDegrees, SIGNAL( valueChanged( int ) ),
273 SLOT( sexagesimalInputChanged() ) );
274 connect( mLongMinutes, SIGNAL( valueChanged( int ) ),
275 SLOT( sexagesimalInputChanged() ) );
276 connect( mLongSeconds, SIGNAL( valueChanged( int ) ),
277 SLOT( sexagesimalInputChanged() ) );
278 connect( mLongDirection, SIGNAL( activated( int ) ),
279 SLOT( sexagesimalInputChanged() ) );
280 mLongitude = 0.0;
281 mLatitude = 0.0;
282#ifndef DESKTOP_VERSION
283 showMaximized();
284#endif
285}
286
287GeoDialog::~GeoDialog()
288{
289}
290
291void GeoDialog::setLatitude( double latitude )
292{
293 mLatitude = latitude;
294 updateInputs();
295}
296
297double GeoDialog::latitude() const
298{
299 return mLatitude;
300}
301
302void GeoDialog::setLongitude( double longitude )
303{
304 mLongitude = longitude;
305 updateInputs();
306}
307
308double GeoDialog::longitude() const
309{
310 return mLongitude;
311}
312
313void GeoDialog::sexagesimalInputChanged()
314{
315 mLatitude = (double)( mLatDegrees->value() + (double)mLatMinutes->value() /
316 60 + (double)mLatSeconds->value() / 3600 );
317
318 mLatitude *= ( mLatDirection->currentItem() == 1 ? -1 : 1 );
319
320 mLongitude = (double)( mLongDegrees->value() + (double)mLongMinutes->value() /
321 60 + (double)mLongSeconds->value() / 3600 );
322
323 mLongitude *= ( mLongDirection->currentItem() == 1 ? -1 : 1 );
324
325 mUpdateSexagesimalInput = false;
326
327 updateInputs();
328}
329
330void GeoDialog::geoMapChanged()
331{
332 mLatitude = mMapWidget->latitude();
333 mLongitude = mMapWidget->longitude();
334
335 updateInputs();
336}
337
338void GeoDialog::cityInputChanged()
339{
340 if ( mCityCombo->currentItem() != 0 ) {
341 GeoData data = mGeoDataMap[ mCityCombo->currentText() ];
342 mLatitude = data.latitude;
343 mLongitude = data.longitude;
344 } else
345 mLatitude = mLongitude = 0;
346
347 updateInputs();
348}
349
350void GeoDialog::updateInputs()
351{
352 // hmm, doesn't look nice, but there is no better way AFAIK
353 mCityCombo->blockSignals( true );
354 mLatDegrees->blockSignals( true );
355 mLatMinutes->blockSignals( true );
356 mLatSeconds->blockSignals( true );
357 mLatDirection->blockSignals( true );
358 mLongDegrees->blockSignals( true );
359 mLongMinutes->blockSignals( true );
360 mLongSeconds->blockSignals( true );
361 mLongDirection->blockSignals( true );
362
363 mMapWidget->setLatitude( mLatitude );
364 mMapWidget->setLongitude( mLongitude );
365 mMapWidget->update();
366
367 if ( mUpdateSexagesimalInput ) {
368 int degrees, minutes, seconds;
369 double latitude = mLatitude;
370 double longitude = mLongitude;
371
372 latitude *= ( mLatitude < 0 ? -1 : 1 );
373 longitude *= ( mLongitude < 0 ? -1 : 1 );
374
375 degrees = (int)( latitude * 1 );
376 minutes = (int)( ( latitude - degrees ) * 60 );
377 seconds = (int)( (double)( (double)latitude - (double)degrees - ( (double)minutes / (double)60 ) ) * (double)3600 );
378
379 mLatDegrees->setValue( degrees );
380 mLatMinutes->setValue( minutes );
381 mLatSeconds->setValue( seconds );
382
383 mLatDirection->setCurrentItem( mLatitude < 0 ? 1 : 0 );
384
385 degrees = (int)( longitude * 1 );
386 minutes = (int)( ( longitude - degrees ) * 60 );
387 seconds = (int)( (double)( longitude - (double)degrees - ( (double)minutes / 60 ) ) * 3600 );
388
389 mLongDegrees->setValue( degrees );
390 mLongMinutes->setValue( minutes );
391 mLongSeconds->setValue( seconds );
392 mLongDirection->setCurrentItem( mLongitude < 0 ? 1 : 0 );
393 }
394 mUpdateSexagesimalInput = true;
395
396 int pos = nearestCity( mLongitude, mLatitude );
397 if ( pos != -1 )
398 mCityCombo->setCurrentItem( pos + 1 );
399 else
400 mCityCombo->setCurrentItem( 0 );
401
402 mCityCombo->blockSignals( false );
403 mLatDegrees->blockSignals( false );
404 mLatMinutes->blockSignals( false );
405 mLatSeconds->blockSignals( false );
406 mLatDirection->blockSignals( false );
407 mLongDegrees->blockSignals( false );
408 mLongMinutes->blockSignals( false );
409 mLongSeconds->blockSignals( false );
410 mLongDirection->blockSignals( false );
411}
412
413void GeoDialog::loadCityList()
414{
415 mCityCombo->clear();
416 mGeoDataMap.clear();
417
418 QString fileName ;
419#ifdef DESKTOP_VERSION
420#ifndef _WIN32_
421 fileName = qApp->applicationDirPath () + "/kdepim/kaddressbook/zone.tab";
422#else
423 fileName = qApp->applicationDirPath () + "\\kdepim\\kaddressbook\\zone.tab";
424#endif
425#else
426 fileName = getenv("QPEDIR");
427 fileName += "/pics/kdepim/kaddressbook/zone.tab";
428#endif
429
430 QFile file( fileName);
431
432 if ( file.open( IO_ReadOnly ) ) {
433 QTextStream s( &file );
434
435 QString line, country;
436 QRegExp coord( "[+-]\\d+[+-]\\d+" );
437 QRegExp name( "[^\\s]+/[^\\s]+" );
438 int posc, posn, pos;
439
440 while ( !s.eof() ) {
441 line = s.readLine().stripWhiteSpace();
442 if ( line.isEmpty() || line[ 0 ] == '#' )
443 continue;
444
445 country = line.left( 2 );
446 QString c, n;
447#ifdef DESKTOP_VERSION
448 posc = coord.search( line, 0 );
449#else
450 posc = coord.find( line, 0 );
451#endif
452 // if ( pos >= 0 )
453 //c = line.mid( pos, coord.matchedLength() );
454
455#ifdef DESKTOP_VERSION
456 posn = name.search(line, posc);
457#else
458 posn = name.find(line, posc);
459#endif
460 if ( posn > 0 ) {
461 c = line.mid( posc, posn-posc ).stripWhiteSpace();
462 //qDebug("*%s* ", c.latin1());
463 int nend = line.find(" ", posn );
464 if ( nend < 0 )
465 nend = line.length();
466 n = line.mid( posn, nend-posn).stripWhiteSpace();
467 //n.replace( '_', " " );
468 }
469
470 if ( !c.isEmpty() && !n.isEmpty() ) {
471 pos = c.find( "+", 1 );
472 if ( pos < 0 )
473 pos = c.find( "-", 1 );
474 if ( pos > 0 ) {
475 GeoData data;
476 data.latitude = calculateCoordinate( c.left( pos ) );
477 data.longitude = calculateCoordinate( c.mid( pos ) );
478 data.country = country;
479
480 mGeoDataMap.insert( n, data );
481 }
482 }
483 }
484//US I have no mGeoDataMap.keys().
485//US QStringList items( mGeoDataMap.keys() );
486 QStringList items;
487
488 QMap<QString, GeoData>::ConstIterator it;
489 for( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it )
490 items << it.key().latin1();
491
492 items.prepend( i18n( "Undefined" ) );
493 mCityCombo->insertStringList( items );
494
495 file.close();
496 }
497}
498
499double GeoDialog::calculateCoordinate( const QString &coordinate )
500{
501 int neg;
502 int d = 0, m = 0, s = 0;
503 QString str = coordinate;
504
505 neg = str.left( 1 ) == "-";
506 str.remove( 0, 1 );
507
508 switch ( str.length() ) {
509 case 4:
510 d = str.left( 2 ).toInt();
511 m = str.mid( 2 ).toInt();
512 break;
513 case 5:
514 d = str.left( 3 ).toInt();
515 m = str.mid( 3 ).toInt();
516 break;
517 case 6:
518 d = str.left( 2 ).toInt();
519 m = str.mid( 2, 2 ).toInt();
520 s = str.right( 2 ).toInt();
521 break;
522 case 7:
523 d = str.left( 3 ).toInt();
524 m = str.mid( 3, 2 ).toInt();
525 s = str.right( 2 ).toInt();
526 break;
527 default:
528 break;
529 }
530
531 if ( neg )
532 return - ( d + m / 60.0 + s / 3600.0 );
533 else
534 return d + m / 60.0 + s / 3600.0;
535}
536
537int GeoDialog::nearestCity( double x, double y )
538{
539 QMap<QString, GeoData>::Iterator it;
540 int pos = 0;
541 for ( it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, pos++ ) {
542 double dist = ( (*it).longitude - x ) * ( (*it).longitude - x ) +
543 ( (*it).latitude - y ) * ( (*it).latitude - y );
544 if ( dist < 1.5 )
545 return pos;
546 }
547
548 return -1;
549}
550
551
552GeoMapWidget::GeoMapWidget( QWidget *parent, const char *name )
553 : QWidget( parent, name ), mLatitude( 0 ), mLongitude( 0 )
554{
555 setBackgroundMode( NoBackground );
556
557 setFixedSize( 240, 120 );
558
559 update();
560}
561
562GeoMapWidget::~GeoMapWidget()
563{
564}
565
566void GeoMapWidget::setLatitude( double latitude )
567{
568 mLatitude = latitude;
569}
570
571double GeoMapWidget::latitude()const
572{
573 return mLatitude;
574}
575
576void GeoMapWidget::setLongitude( double longitude )
577{
578 mLongitude = longitude;
579}
580
581double GeoMapWidget::longitude()const
582{
583 return mLongitude;
584}
585
586void GeoMapWidget::mousePressEvent( QMouseEvent *event )
587{
588 double latMid = height() / 2;
589 double longMid = width() / 2;
590
591 double latOffset = latMid - event->y();
592 double longOffset = event->x() - longMid;
593
594 mLatitude = ( latOffset * 90 ) / latMid;
595 mLongitude = ( longOffset * 180 ) / longMid;
596
597 emit changed();
598}
599
600void GeoMapWidget::paintEvent( QPaintEvent* )
601{
602 uint w = width();
603 uint h = height();
604
605 QPixmap world = KGlobal::iconLoader()->loadIcon( "world", KIcon::Desktop, 0 );
606
607 QPainter p;
608 p.begin( &world, this );
609
610 p.setPen( QColor( 255, 0, 0 ) );
611 p.setBrush( QColor( 255, 0, 0 ) );
612
613 double latMid = h / 2;
614 double longMid = w / 2;
615
616 double latOffset = ( mLatitude * latMid ) / 90;
617 double longOffset = ( mLongitude * longMid ) / 180;
618
619 int x = (int)(longMid + longOffset);
620 int y = (int)(latMid - latOffset);
621 p.drawEllipse( x, y, 4, 4 );
622
623 p.end();
624 bitBlt( this, 0, 0, &world );
625}
626
627#ifndef KAB_EMBEDDED
628#include "geowidget.moc"
629#endif //KAB_EMBEDDED