22#include "geoeditwidget.h"
24#include "autoqpointer_p.h"
26#include <kabc/addressee.h>
30#include <klocalizedstring.h>
31#include <kstandarddirs.h>
33#include <QtCore/QFile>
34#include <QtCore/QTextStream>
35#include <QDoubleSpinBox>
43class GeoMapWidget :
public QWidget
46 GeoMapWidget(QWidget *parent = 0)
49 mWorld = QPixmap(KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/pics/world.jpg")));
51 setAttribute(Qt::WA_NoSystemBackground,
true);
52 setFixedSize(400, 200);
57 void setCoordinates(
const KABC::Geo &coordinates)
59 mCoordinates = coordinates;
65 virtual void paintEvent(QPaintEvent *)
69 p.setPen(QColor(255, 0, 0));
70 p.setBrush(QColor(255, 0, 0));
72 p.drawPixmap(0, 0, mWorld);
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;
80 const int x = (int)(longMid + longOffset);
81 const int y = (int)(latMid - latOffset);
82 p.drawEllipse(x, y, 4, 4);
90 KABC::Geo mCoordinates;
93GeoEditWidget::GeoEditWidget(QWidget *parent)
96 QGridLayout *layout =
new QGridLayout(
this);
99 mMap =
new GeoMapWidget;
100 layout->addWidget(mMap, 0, 0, 1, 4, Qt::AlignCenter | Qt::AlignVCenter);
102 QLabel *label =
new QLabel(i18nc(
"@label",
"Latitude:"));
103 label->setAlignment(Qt::AlignRight);
104 layout->addWidget(label, 1, 0);
106 mLatitudeLabel =
new QLabel;
107 layout->addWidget(mLatitudeLabel, 1, 1);
109 label =
new QLabel(i18nc(
"@label",
"Longitude:"));
110 label->setAlignment(Qt::AlignRight);
111 layout->addWidget(label, 1, 2);
113 mLongitudeLabel =
new QLabel;
114 layout->addWidget(mLongitudeLabel, 1, 3);
116 mChangeButton =
new QPushButton(i18nc(
"@label Change the coordinates",
"Change..."));
117 layout->addWidget(mChangeButton, 2, 0, 1, 4, Qt::AlignRight);
119 layout->setRowStretch(3, 1);
121 connect(mChangeButton, SIGNAL(clicked()), SLOT(changeClicked()));
126GeoEditWidget::~GeoEditWidget()
130void GeoEditWidget::loadContact(
const KABC::Addressee &contact)
132 mCoordinates = contact.geo();
136void GeoEditWidget::storeContact(KABC::Addressee &contact)
const
138 contact.setGeo(mCoordinates);
141void GeoEditWidget::setReadOnly(
bool readOnly)
143 mChangeButton->setEnabled(!readOnly);
146void GeoEditWidget::updateView()
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"));
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)));
155 mMap->setCoordinates(mCoordinates);
158void GeoEditWidget::changeClicked()
162 mCoordinates = dlg->coordinates();
167static double calculateCoordinate(
const QString &coordinate)
170 int d = 0, m = 0, s = 0;
171 QString str = coordinate;
173 neg = str.left(1) == QLatin1String(
"-");
176 switch (str.length()) {
178 d = str.left(2).toInt();
179 m = str.mid(2).toInt();
182 d = str.left(3).toInt();
183 m = str.mid(3).toInt();
186 d = str.left(2).toInt();
187 m = str.mid(2, 2).toInt();
188 s = str.right(2).toInt();
191 d = str.left(3).toInt();
192 m = str.mid(3, 2).toInt();
193 s = str.right(2).toInt();
200 return - (d + m / 60.0 + s / 3600.0);
202 return d + m / 60.0 + s / 3600.0;
206GeoDialog::GeoDialog(
const KABC::Geo &coordinates, QWidget *parent)
208 , mCoordinates(coordinates)
210 KGlobal::locale()->insertCatalog(QLatin1String(
"timezones4"));
211 setCaption(i18nc(
"@title:window",
"Coordinate Selection"));
212 setButtons(Ok | Cancel);
213 setDefaultButton(Ok);
214 showButtonSeparator(
true);
217 QFrame *page =
new QFrame(
this);
220 QVBoxLayout *layout =
new QVBoxLayout(page);
222 mCityCombo =
new KComboBox(page);
223 layout->addWidget(mCityCombo);
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());
230 QLabel *label =
new QLabel(i18nc(
"@label:spinbox",
"Latitude:"), decimalGroup);
231 decimalLayout->addWidget(label, 0, 0);
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);
242 label =
new QLabel(i18nc(
"@label:spinbox",
"Longitude:"), decimalGroup);
243 decimalLayout->addWidget(label, 1, 0);
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);
254 QGroupBox *sexagesimalGroup =
new QGroupBox(i18nc(
"@title:group",
"Sexagesimal"), page);
255 QGridLayout *sexagesimalLayout =
new QGridLayout();
256 sexagesimalGroup->setLayout(sexagesimalLayout);
257 sexagesimalLayout->setSpacing(spacingHint());
259 label =
new QLabel(i18nc(
"@label:spinbox",
"Latitude:"), sexagesimalGroup);
260 sexagesimalLayout->addWidget(label, 0, 0);
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);
271 mLatMinutes =
new QSpinBox(sexagesimalGroup);
272 mLatMinutes->setMinimum(0);
273 mLatMinutes->setMaximum(59);
274 mLatMinutes->setValue(1);
276 mLatMinutes->setSuffix(QLatin1String(
"'"));
277 sexagesimalLayout->addWidget(mLatMinutes, 0, 2);
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);
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);
291 label =
new QLabel(i18nc(
"@label:spinbox",
"Longitude:"), sexagesimalGroup);
292 sexagesimalLayout->addWidget(label, 1, 0);
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);
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);
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);
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);
321 layout->addWidget(decimalGroup);
322 layout->addWidget(sexagesimalGroup);
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()));
352KABC::Geo GeoDialog::coordinates()
const
357void GeoDialog::cityInputChanged()
359 if (mCityCombo->currentIndex() != 0) {
360 GeoData geoData = mGeoDataMap[mCityCombo->currentText()];
361 mCoordinates.setLatitude(geoData.latitude);
362 mCoordinates.setLongitude(geoData.longitude);
364 mCoordinates.setLatitude(0);
365 mCoordinates.setLongitude(0);
368 updateInputs(ExceptCity);
371void GeoDialog::decimalInputChanged()
373 mCoordinates.setLatitude(mLatitude->value());
374 mCoordinates.setLongitude(mLongitude->value());
376 updateInputs(ExceptDecimal);
379void GeoDialog::sexagesimalInputChanged()
381 double latitude = (double)(mLatDegrees->value() + (double)mLatMinutes->value() /
382 60 + (double)mLatSeconds->value() / 3600);
383 latitude *= (mLatDirection->currentIndex() == 1 ? -1 : 1);
385 double longitude = (double)(mLongDegrees->value() + (double)mLongMinutes->value() /
386 60 + (double)mLongSeconds->value() / 3600);
387 longitude *= (mLongDirection->currentIndex() == 1 ? -1 : 1);
389 mCoordinates.setLatitude(latitude);
390 mCoordinates.setLongitude(longitude);
392 updateInputs(ExceptSexagesimal);
395void GeoDialog::updateInputs(ExceptType type)
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);
409 if (!(type &ExceptDecimal)) {
410 mLatitude->setValue(mCoordinates.latitude());
411 mLongitude->setValue(mCoordinates.longitude());
414 if (!(type &ExceptSexagesimal)) {
415 int degrees, minutes, seconds;
416 double latitude = mCoordinates.latitude();
417 double longitude = mCoordinates.longitude();
419 latitude *= (latitude < 0 ? -1 : 1);
420 longitude *= (longitude < 0 ? -1 : 1);
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);
426 mLatDegrees->setValue(degrees);
427 mLatMinutes->setValue(minutes);
428 mLatSeconds->setValue(seconds);
430 mLatDirection->setCurrentIndex(mLatitude->value() < 0 ? 1 : 0);
432 degrees = (int)(longitude * 1);
433 minutes = (int)((longitude - degrees) * 60);
434 seconds = (int)((
double)(longitude - (double)degrees - ((
double)minutes / 60)) * 3600);
436 mLongDegrees->setValue(degrees);
437 mLongMinutes->setValue(minutes);
438 mLongSeconds->setValue(seconds);
439 mLongDirection->setCurrentIndex(mLongitude->value() < 0 ? 1 : 0);
442 if (!(type &ExceptCity)) {
443 const int index = nearestCity(mCoordinates.longitude(), mCoordinates.latitude());
445 mCityCombo->setCurrentIndex(index + 1);
447 mCityCombo->setCurrentIndex(0);
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);
464void GeoDialog::loadCityList()
469 QFile file(KStandardDirs::locate(
"data", QLatin1String(
"akonadi/contact/data/zone.tab")));
471 if (file.open(QIODevice::ReadOnly)) {
472 QTextStream s(&file);
474 QString line, country;
475 QRegExp coord(QLatin1String(
"[+-]\\d+[+-]\\d+"));
476 QRegExp name(QLatin1String(
"[^\\s]+/[^\\s]+"));
480 line = s.readLine().trimmed();
481 if (line.isEmpty() || line[0] == QLatin1Char(
'#')) {
485 country = line.left(2);
487 pos = coord.indexIn(line, 0);
489 c = line.mid(pos, coord.matchedLength());
492 pos = name.indexIn(line, pos);
494 n = line.mid(pos, name.matchedLength()).trimmed();
497 if (!c.isEmpty() && !n.isEmpty()) {
498 pos = c.indexOf(QLatin1Char(
'+'), 1);
500 pos = c.indexOf(QLatin1Char(
'-'), 1);
504 geoData.latitude = calculateCoordinate(c.left(pos));
505 geoData.longitude = calculateCoordinate(c.mid(pos));
506 geoData.country = country;
508 mGeoDataMap.insert(i18n(qPrintable(n)).replace(QLatin1Char(
'_'), QLatin1Char(
' ')), geoData);
513 QStringList items(mGeoDataMap.keys());
514 items.prepend(i18nc(
"@item:inlistbox Undefined location",
"Undefined"));
515 mCityCombo->addItems(items);
521int GeoDialog::nearestCity(
double x,
double y)
const
523 QMap<QString, GeoData>::ConstIterator it;
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);
A QPointer which when destructed, deletes the object it points to.