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

akonadi

  • akonadi
  • contact
  • editor
geoeditwidget.cpp
1/*
2 This file is part of Akonadi Contact.
3
4 Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Library General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at your
9 option) any later version.
10
11 This library is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
14 License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA.
20*/
21
22#include "geoeditwidget.h"
23
24#include "autoqpointer_p.h"
25
26#include <kabc/addressee.h>
27#include <kabc/geo.h>
28#include <kcombobox.h>
29#include <klocale.h>
30#include <klocalizedstring.h>
31#include <kstandarddirs.h>
32
33#include <QtCore/QFile>
34#include <QtCore/QTextStream>
35#include <QDoubleSpinBox>
36#include <QGridLayout>
37#include <QGroupBox>
38#include <QLabel>
39#include <QPainter>
40#include <QPushButton>
41#include <QSpinBox>
42
43class GeoMapWidget : public QWidget
44{
45public:
46 GeoMapWidget(QWidget *parent = 0)
47 : QWidget(parent)
48 {
49 mWorld = QPixmap(KStandardDirs::locate("data", QLatin1String("akonadi/contact/pics/world.jpg")));
50
51 setAttribute(Qt::WA_NoSystemBackground, true);
52 setFixedSize(400, 200);
53
54 update();
55 }
56
57 void setCoordinates(const KABC::Geo &coordinates)
58 {
59 mCoordinates = coordinates;
60
61 update();
62 }
63
64protected:
65 virtual void paintEvent(QPaintEvent *)
66 {
67 QPainter p;
68 p.begin(this);
69 p.setPen(QColor(255, 0, 0));
70 p.setBrush(QColor(255, 0, 0));
71
72 p.drawPixmap(0, 0, mWorld);
73
74 if (mCoordinates.isValid()) {
75 const double latMid = height() / 2;
76 const double longMid = width() / 2;
77 const double latOffset = (mCoordinates.latitude() * latMid) / 90;
78 const double longOffset = (mCoordinates.longitude() * longMid) / 180;
79
80 const int x = (int)(longMid + longOffset);
81 const int y = (int)(latMid - latOffset);
82 p.drawEllipse(x, y, 4, 4);
83 }
84
85 p.end();
86 }
87
88private:
89 QPixmap mWorld;
90 KABC::Geo mCoordinates;
91};
92
93GeoEditWidget::GeoEditWidget(QWidget *parent)
94 : QWidget(parent)
95{
96 QGridLayout *layout = new QGridLayout(this);
97 layout->setMargin(0);
98
99 mMap = new GeoMapWidget;
100 layout->addWidget(mMap, 0, 0, 1, 4, Qt::AlignCenter | Qt::AlignVCenter);
101
102 QLabel *label = new QLabel(i18nc("@label", "Latitude:"));
103 label->setAlignment(Qt::AlignRight);
104 layout->addWidget(label, 1, 0);
105
106 mLatitudeLabel = new QLabel;
107 layout->addWidget(mLatitudeLabel, 1, 1);
108
109 label = new QLabel(i18nc("@label", "Longitude:"));
110 label->setAlignment(Qt::AlignRight);
111 layout->addWidget(label, 1, 2);
112
113 mLongitudeLabel = new QLabel;
114 layout->addWidget(mLongitudeLabel, 1, 3);
115
116 mChangeButton = new QPushButton(i18nc("@label Change the coordinates", "Change..."));
117 layout->addWidget(mChangeButton, 2, 0, 1, 4, Qt::AlignRight);
118
119 layout->setRowStretch(3, 1);
120
121 connect(mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()));
122
123 updateView();
124}
125
126GeoEditWidget::~GeoEditWidget()
127{
128}
129
130void GeoEditWidget::loadContact(const KABC::Addressee &contact)
131{
132 mCoordinates = contact.geo();
133 updateView();
134}
135
136void GeoEditWidget::storeContact(KABC::Addressee &contact) const
137{
138 contact.setGeo(mCoordinates);
139}
140
141void GeoEditWidget::setReadOnly(bool readOnly)
142{
143 mChangeButton->setEnabled(!readOnly);
144}
145
146void GeoEditWidget::updateView()
147{
148 if (!mCoordinates.isValid()) {
149 mLatitudeLabel->setText(i18nc("@label Coordinates are not available", "n/a"));
150 mLongitudeLabel->setText(i18nc("@label Coordinates are not available", "n/a"));
151 } else {
152 mLatitudeLabel->setText(i18nc("@label The formatted coordinates", "%1 %2", mCoordinates.latitude(), QChar(176)));
153 mLongitudeLabel->setText(i18nc("@label The formatted coordinates", "%1 %2", mCoordinates.longitude(), QChar(176)));
154 }
155 mMap->setCoordinates(mCoordinates);
156}
157
158void GeoEditWidget::changeClicked()
159{
160 AutoQPointer<GeoDialog> dlg = new GeoDialog(mCoordinates, this);
161 if (dlg->exec()) {
162 mCoordinates = dlg->coordinates();
163 updateView();
164 }
165}
166
167static double calculateCoordinate(const QString &coordinate)
168{
169 int neg;
170 int d = 0, m = 0, s = 0;
171 QString str = coordinate;
172
173 neg = str.left(1) == QLatin1String("-");
174 str.remove(0, 1);
175
176 switch (str.length()) {
177 case 4:
178 d = str.left(2).toInt();
179 m = str.mid(2).toInt();
180 break;
181 case 5:
182 d = str.left(3).toInt();
183 m = str.mid(3).toInt();
184 break;
185 case 6:
186 d = str.left(2).toInt();
187 m = str.mid(2, 2).toInt();
188 s = str.right(2).toInt();
189 break;
190 case 7:
191 d = str.left(3).toInt();
192 m = str.mid(3, 2).toInt();
193 s = str.right(2).toInt();
194 break;
195 default:
196 break;
197 }
198
199 if (neg) {
200 return - (d + m / 60.0 + s / 3600.0);
201 } else {
202 return d + m / 60.0 + s / 3600.0;
203 }
204}
205
206GeoDialog::GeoDialog(const KABC::Geo &coordinates, QWidget *parent)
207 : KDialog(parent)
208 , mCoordinates(coordinates)
209{
210 KGlobal::locale()->insertCatalog(QLatin1String("timezones4"));
211 setCaption(i18nc("@title:window", "Coordinate Selection"));
212 setButtons(Ok | Cancel);
213 setDefaultButton(Ok);
214 showButtonSeparator(true);
215 setModal(true);
216
217 QFrame *page = new QFrame(this);
218 setMainWidget(page);
219
220 QVBoxLayout *layout = new QVBoxLayout(page);
221
222 mCityCombo = new KComboBox(page);
223 layout->addWidget(mCityCombo);
224
225 QGroupBox *decimalGroup = new QGroupBox(i18nc("@title:group Decimal representation of coordinates", "Decimal"), page);
226 QGridLayout *decimalLayout = new QGridLayout();
227 decimalGroup->setLayout(decimalLayout);
228 decimalLayout->setSpacing(spacingHint());
229
230 QLabel *label = new QLabel(i18nc("@label:spinbox", "Latitude:"), decimalGroup);
231 decimalLayout->addWidget(label, 0, 0);
232
233 mLatitude = new QDoubleSpinBox(decimalGroup);
234 mLatitude->setMinimum(-90);
235 mLatitude->setMaximum(90);
236 mLatitude->setSingleStep(1);
237 mLatitude->setValue(0);
238 mLatitude->setDecimals(6);
239 mLatitude->setSuffix(QChar(176));
240 decimalLayout->addWidget(mLatitude, 0, 1);
241
242 label = new QLabel(i18nc("@label:spinbox", "Longitude:"), decimalGroup);
243 decimalLayout->addWidget(label, 1, 0);
244
245 mLongitude = new QDoubleSpinBox(decimalGroup);
246 mLongitude->setMinimum(-180);
247 mLongitude->setMaximum(180);
248 mLongitude->setSingleStep(1);
249 mLongitude->setValue(0);
250 mLongitude->setDecimals(6);
251 mLongitude->setSuffix(QChar(176));
252 decimalLayout->addWidget(mLongitude, 1, 1);
253
254 QGroupBox *sexagesimalGroup = new QGroupBox(i18nc("@title:group", "Sexagesimal"), page);
255 QGridLayout *sexagesimalLayout = new QGridLayout();
256 sexagesimalGroup->setLayout(sexagesimalLayout);
257 sexagesimalLayout->setSpacing(spacingHint());
258
259 label = new QLabel(i18nc("@label:spinbox", "Latitude:"), sexagesimalGroup);
260 sexagesimalLayout->addWidget(label, 0, 0);
261
262 mLatDegrees = new QSpinBox(sexagesimalGroup);
263 mLatDegrees->setMinimum(0);
264 mLatDegrees->setMaximum(90);
265 mLatDegrees->setValue(1);
266 mLatDegrees->setSuffix(QChar(176));
267 mLatDegrees->setWrapping(false);
268 label->setBuddy(mLatDegrees);
269 sexagesimalLayout->addWidget(mLatDegrees, 0, 1);
270
271 mLatMinutes = new QSpinBox(sexagesimalGroup);
272 mLatMinutes->setMinimum(0);
273 mLatMinutes->setMaximum(59);
274 mLatMinutes->setValue(1);
275
276 mLatMinutes->setSuffix(QLatin1String("'"));
277 sexagesimalLayout->addWidget(mLatMinutes, 0, 2);
278
279 mLatSeconds = new QSpinBox(sexagesimalGroup);
280 mLatSeconds->setMinimum(0);
281 mLatSeconds->setMaximum(59);
282 mLatSeconds->setValue(1);
283 mLatSeconds->setSuffix(QLatin1String("\""));
284 sexagesimalLayout->addWidget(mLatSeconds, 0, 3);
285
286 mLatDirection = new KComboBox(sexagesimalGroup);
287 mLatDirection->addItem(i18nc("@item:inlistbox Latitude direction", "North"));
288 mLatDirection->addItem(i18nc("@item:inlistbox Latitude direction", "South"));
289 sexagesimalLayout->addWidget(mLatDirection, 0, 4);
290
291 label = new QLabel(i18nc("@label:spinbox", "Longitude:"), sexagesimalGroup);
292 sexagesimalLayout->addWidget(label, 1, 0);
293
294 mLongDegrees = new QSpinBox(sexagesimalGroup);
295 mLongDegrees->setMinimum(0);
296 mLongDegrees->setMaximum(180);
297 mLongDegrees->setValue(1);
298 mLongDegrees->setSuffix(QChar(176));
299 label->setBuddy(mLongDegrees);
300 sexagesimalLayout->addWidget(mLongDegrees, 1, 1);
301
302 mLongMinutes = new QSpinBox(sexagesimalGroup);
303 mLongMinutes->setMinimum(0);
304 mLongMinutes->setMaximum(59);
305 mLongMinutes->setValue(1);
306 mLongMinutes->setSuffix(QLatin1String("'"));
307 sexagesimalLayout->addWidget(mLongMinutes, 1, 2);
308
309 mLongSeconds = new QSpinBox(sexagesimalGroup);
310 mLongSeconds->setMinimum(0);
311 mLongSeconds->setMaximum(59);
312 mLongSeconds->setValue(1);
313 mLongSeconds->setSuffix(QLatin1String("\""));
314 sexagesimalLayout->addWidget(mLongSeconds, 1, 3);
315
316 mLongDirection = new KComboBox(sexagesimalGroup);
317 mLongDirection->addItem(i18nc("@item:inlistbox Longtitude direction", "East"));
318 mLongDirection->addItem(i18nc("@item:inlistbox Longtitude direction", "West"));
319 sexagesimalLayout->addWidget(mLongDirection, 1, 4);
320
321 layout->addWidget(decimalGroup);
322 layout->addWidget(sexagesimalGroup);
323
324 loadCityList();
325
326 connect(mCityCombo, SIGNAL(activated(int)),
327 SLOT(cityInputChanged()));
328 connect(mLatitude, SIGNAL(valueChanged(double)),
329 SLOT(decimalInputChanged()));
330 connect(mLongitude, SIGNAL(valueChanged(double)),
331 SLOT(decimalInputChanged()));
332 connect(mLatDegrees, SIGNAL(valueChanged(int)),
333 SLOT(sexagesimalInputChanged()));
334 connect(mLatMinutes, SIGNAL(valueChanged(int)),
335 SLOT(sexagesimalInputChanged()));
336 connect(mLatSeconds, SIGNAL(valueChanged(int)),
337 SLOT(sexagesimalInputChanged()));
338 connect(mLatDirection, SIGNAL(activated(int)),
339 SLOT(sexagesimalInputChanged()));
340 connect(mLongDegrees, SIGNAL(valueChanged(int)),
341 SLOT(sexagesimalInputChanged()));
342 connect(mLongMinutes, SIGNAL(valueChanged(int)),
343 SLOT(sexagesimalInputChanged()));
344 connect(mLongSeconds, SIGNAL(valueChanged(int)),
345 SLOT(sexagesimalInputChanged()));
346 connect(mLongDirection, SIGNAL(activated(int)),
347 SLOT(sexagesimalInputChanged()));
348
349 updateInputs();
350}
351
352KABC::Geo GeoDialog::coordinates() const
353{
354 return mCoordinates;
355}
356
357void GeoDialog::cityInputChanged()
358{
359 if (mCityCombo->currentIndex() != 0) {
360 GeoData geoData = mGeoDataMap[mCityCombo->currentText()];
361 mCoordinates.setLatitude(geoData.latitude);
362 mCoordinates.setLongitude(geoData.longitude);
363 } else {
364 mCoordinates.setLatitude(0);
365 mCoordinates.setLongitude(0);
366 }
367
368 updateInputs(ExceptCity);
369}
370
371void GeoDialog::decimalInputChanged()
372{
373 mCoordinates.setLatitude(mLatitude->value());
374 mCoordinates.setLongitude(mLongitude->value());
375
376 updateInputs(ExceptDecimal);
377}
378
379void GeoDialog::sexagesimalInputChanged()
380{
381 double latitude = (double)(mLatDegrees->value() + (double)mLatMinutes->value() /
382 60 + (double)mLatSeconds->value() / 3600);
383 latitude *= (mLatDirection->currentIndex() == 1 ? -1 : 1);
384
385 double longitude = (double)(mLongDegrees->value() + (double)mLongMinutes->value() /
386 60 + (double)mLongSeconds->value() / 3600);
387 longitude *= (mLongDirection->currentIndex() == 1 ? -1 : 1);
388
389 mCoordinates.setLatitude(latitude);
390 mCoordinates.setLongitude(longitude);
391
392 updateInputs(ExceptSexagesimal);
393}
394
395void GeoDialog::updateInputs(ExceptType type)
396{
397 mCityCombo->blockSignals(true);
398 mLatitude->blockSignals(true);
399 mLongitude->blockSignals(true);
400 mLatDegrees->blockSignals(true);
401 mLatMinutes->blockSignals(true);
402 mLatSeconds->blockSignals(true);
403 mLatDirection->blockSignals(true);
404 mLongDegrees->blockSignals(true);
405 mLongMinutes->blockSignals(true);
406 mLongSeconds->blockSignals(true);
407 mLongDirection->blockSignals(true);
408
409 if (!(type &ExceptDecimal)) {
410 mLatitude->setValue(mCoordinates.latitude());
411 mLongitude->setValue(mCoordinates.longitude());
412 }
413
414 if (!(type &ExceptSexagesimal)) {
415 int degrees, minutes, seconds;
416 double latitude = mCoordinates.latitude();
417 double longitude = mCoordinates.longitude();
418
419 latitude *= (latitude < 0 ? -1 : 1);
420 longitude *= (longitude < 0 ? -1 : 1);
421
422 degrees = (int)(latitude * 1);
423 minutes = (int)((latitude - degrees) * 60);
424 seconds = (int)((double)((double)latitude - (double)degrees - ((double)minutes / (double)60)) * (double)3600);
425
426 mLatDegrees->setValue(degrees);
427 mLatMinutes->setValue(minutes);
428 mLatSeconds->setValue(seconds);
429
430 mLatDirection->setCurrentIndex(mLatitude->value() < 0 ? 1 : 0);
431
432 degrees = (int)(longitude * 1);
433 minutes = (int)((longitude - degrees) * 60);
434 seconds = (int)((double)(longitude - (double)degrees - ((double)minutes / 60)) * 3600);
435
436 mLongDegrees->setValue(degrees);
437 mLongMinutes->setValue(minutes);
438 mLongSeconds->setValue(seconds);
439 mLongDirection->setCurrentIndex(mLongitude->value() < 0 ? 1 : 0);
440 }
441
442 if (!(type &ExceptCity)) {
443 const int index = nearestCity(mCoordinates.longitude(), mCoordinates.latitude());
444 if (index != -1) {
445 mCityCombo->setCurrentIndex(index + 1);
446 } else {
447 mCityCombo->setCurrentIndex(0);
448 }
449 }
450
451 mCityCombo->blockSignals(false);
452 mLatitude->blockSignals(false);
453 mLongitude->blockSignals(false);
454 mLatDegrees->blockSignals(false);
455 mLatMinutes->blockSignals(false);
456 mLatSeconds->blockSignals(false);
457 mLatDirection->blockSignals(false);
458 mLongDegrees->blockSignals(false);
459 mLongMinutes->blockSignals(false);
460 mLongSeconds->blockSignals(false);
461 mLongDirection->blockSignals(false);
462}
463
464void GeoDialog::loadCityList()
465{
466 mCityCombo->clear();
467 mGeoDataMap.clear();
468
469 QFile file(KStandardDirs::locate("data", QLatin1String("akonadi/contact/data/zone.tab")));
470
471 if (file.open(QIODevice::ReadOnly)) {
472 QTextStream s(&file);
473
474 QString line, country;
475 QRegExp coord(QLatin1String("[+-]\\d+[+-]\\d+"));
476 QRegExp name(QLatin1String("[^\\s]+/[^\\s]+"));
477 int pos;
478
479 while (!s.atEnd()) {
480 line = s.readLine().trimmed();
481 if (line.isEmpty() || line[0] == QLatin1Char('#')) {
482 continue;
483 }
484
485 country = line.left(2);
486 QString c, n;
487 pos = coord.indexIn(line, 0);
488 if (pos >= 0) {
489 c = line.mid(pos, coord.matchedLength());
490 }
491
492 pos = name.indexIn(line, pos);
493 if (pos > 0) {
494 n = line.mid(pos, name.matchedLength()).trimmed();
495 }
496
497 if (!c.isEmpty() && !n.isEmpty()) {
498 pos = c.indexOf(QLatin1Char('+'), 1);
499 if (pos < 0) {
500 pos = c.indexOf(QLatin1Char('-'), 1);
501 }
502 if (pos > 0) {
503 GeoData geoData;
504 geoData.latitude = calculateCoordinate(c.left(pos));
505 geoData.longitude = calculateCoordinate(c.mid(pos));
506 geoData.country = country;
507
508 mGeoDataMap.insert(i18n(qPrintable(n)).replace(QLatin1Char('_'), QLatin1Char(' ')), geoData);
509 }
510 }
511 }
512
513 QStringList items(mGeoDataMap.keys());
514 items.prepend(i18nc("@item:inlistbox Undefined location", "Undefined"));
515 mCityCombo->addItems(items);
516
517 file.close();
518 }
519}
520
521int GeoDialog::nearestCity(double x, double y) const
522{
523 QMap<QString, GeoData>::ConstIterator it;
524 int pos = 0;
525 for (it = mGeoDataMap.begin(); it != mGeoDataMap.end(); ++it, ++pos) {
526 double dist = ((*it).longitude - x) * ((*it).longitude - x) +
527 ((*it).latitude - y) * ((*it).latitude - y);
528 if (dist < 0.0005) {
529 return pos;
530 }
531 }
532
533 return -1;
534}
AutoQPointer
A QPointer which when destructed, deletes the object it points to.
Definition: autoqpointer_p.h:35
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Jul 21 2022 00:00:00 by doxygen 1.9.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs-4.14.10 API Reference

Skip menu "kdepimlibs-4.14.10 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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