void LocationFilterDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &origIdx) const { QFont fontBigger = qApp->font(); QFont fontSmaller = qApp->font(); QFontMetrics fmBigger(fontBigger); QStyleOptionViewItemV4 opt = option; const QAbstractProxyModel *proxyModel = dynamic_cast<const QAbstractProxyModel*>(origIdx.model()); QModelIndex index = proxyModel->mapToSource(origIdx); QStyledItemDelegate::initStyleOption(&opt, index); QString diveSiteName = index.data().toString(); QString bottomText; QIcon icon = index.data(Qt::DecorationRole).value<QIcon>(); struct dive_site *ds = get_dive_site_by_uuid( index.model()->data(index.model()->index(index.row(),0)).toInt() ); //Special case: do not show name, but instead, show if (index.row() < 2) { diveSiteName = index.data().toString(); bottomText = index.data(Qt::ToolTipRole).toString(); goto print_part; } if (!ds) return; for (int i = 0; i < 3; i++) { if (prefs.geocoding.category[i] == TC_NONE) continue; int idx = taxonomy_index_for_category(&ds->taxonomy, prefs.geocoding.category[i]); if (idx == -1) continue; if(!bottomText.isEmpty()) bottomText += " / "; bottomText += QString(ds->taxonomy.category[idx].value); } if (bottomText.isEmpty()) { const char *gpsCoords = printGPSCoords(ds->latitude.udeg, ds->longitude.udeg); bottomText = QString(gpsCoords); free( (void*) gpsCoords); } if (dive_site_has_gps_location(ds) && dive_site_has_gps_location(&displayed_dive_site)) { // so we are showing a completion and both the current dive site and the completion // have a GPS fix... so let's show the distance if (ds->latitude.udeg == displayed_dive_site.latitude.udeg && ds->longitude.udeg == displayed_dive_site.longitude.udeg) { bottomText += tr(" (same GPS fix)"); } else { int distanceMeters = get_distance(ds->latitude, ds->longitude, displayed_dive_site.latitude, displayed_dive_site.longitude); QString distance = distance_string(distanceMeters); int nr = nr_of_dives_at_dive_site(ds->uuid, false); bottomText += tr(" (~%1 away").arg(distance); bottomText += tr(", %1 dive(s) here)").arg(nr); } } if (bottomText.isEmpty()) { if (dive_site_has_gps_location(&displayed_dive_site)) bottomText = tr("(no existing GPS data, add GPS fix from this dive)"); else bottomText = tr("(no GPS data)"); } bottomText = tr("Pick site: ") + bottomText; print_part: fontBigger.setPointSize(fontBigger.pointSize() + 1); fontBigger.setBold(true); QPen textPen = QPen(option.state & QStyle::State_Selected ? option.palette.highlightedText().color() : option.palette.text().color(), 1); initStyleOption(&opt, index); opt.text = QString(); opt.icon = QIcon(); painter->setClipRect(option.rect); painter->save(); if (option.state & QStyle::State_Selected) { painter->setPen(QPen(opt.palette.highlight().color().darker())); painter->setBrush(opt.palette.highlight()); const qreal pad = 1.0; const qreal pad2 = pad * 2.0; const qreal rounding = 5.0; painter->drawRoundedRect(option.rect.x() + pad, option.rect.y() + pad, option.rect.width() - pad2, option.rect.height() - pad2, rounding, rounding); } painter->setPen(textPen); painter->setFont(fontBigger); const qreal textPad = 5.0; painter->drawText(option.rect.x() + textPad, option.rect.y() + fmBigger.boundingRect("YH").height(), diveSiteName); double pointSize = fontSmaller.pointSizeF(); fontSmaller.setPointSizeF(0.9 * pointSize); painter->setFont(fontSmaller); painter->drawText(option.rect.x() + textPad, option.rect.y() + fmBigger.boundingRect("YH").height() * 2, bottomText); painter->restore(); if (!icon.isNull()) { painter->save(); painter->drawPixmap( option.rect.x() + option.rect.width() - 24, option.rect.y() + option.rect.height() - 24, icon.pixmap(20,20)); painter->restore(); } }
void ReverseGeoLookupThread::run() { if (geo_lookup_data.isEmpty()) return; QNetworkRequest request; QNetworkAccessManager *rgl = new QNetworkAccessManager(); QEventLoop loop; QString mapquestURL("http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&accept-language=%1&lat=%2&lon=%3"); QString geonamesURL("http://api.geonames.org/findNearbyPlaceNameJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh"); QString geonamesOceanURL("http://api.geonames.org/oceanJSON?language=%1&lat=%2&lng=%3&radius=50&username=dirkhh"); QString divelogsURL("https://www.divelogs.de/mapsearch_divespotnames.php?lat=%1&lng=%2&radius=50"); QTimer timer; request.setRawHeader("Accept", "text/json"); request.setRawHeader("User-Agent", getUserAgent().toUtf8()); connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); Q_FOREACH (const GeoLookupInfo& info, geo_lookup_data ) { struct dive_site *ds = info.uuid ? get_dive_site_by_uuid(info.uuid) : &displayed_dive_site; // first check the findNearbyPlaces API from geonames - that should give us country, state, city request.setUrl(geonamesURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0)); QNetworkReply *reply = rgl->get(request); timer.setSingleShot(true); connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); timer.start(5000); // 5 secs. timeout loop.exec(); if(timer.isActive()) { timer.stop(); if(reply->error() > 0) { report_error("got error accessing geonames.org: %s", qPrintable(reply->errorString())); goto clear_reply; } int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (v < 200 || v >= 300) goto clear_reply; QByteArray fullReply = reply->readAll(); QJsonParseError errorObject; QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject); if (errorObject.error != QJsonParseError::NoError) { report_error("error parsing geonames.org response: %s", qPrintable(errorObject.errorString())); goto clear_reply; } QJsonObject obj = jsonDoc.object(); QVariant geoNamesObject = obj.value("geonames").toVariant(); QVariantList geoNames = geoNamesObject.toList(); if (geoNames.count() > 0) { QVariantMap firstData = geoNames.at(0).toMap(); int ri = 0, l3 = -1, lt = -1; if (ds->taxonomy.category == NULL) { ds->taxonomy.category = alloc_taxonomy(); } else { // clear out the data (except for the ocean data) int ocean; if ((ocean = taxonomy_index_for_category(&ds->taxonomy, TC_OCEAN)) > 0) { ds->taxonomy.category[0] = ds->taxonomy.category[ocean]; ds->taxonomy.nr = 1; } else { // ocean is -1 if there is no such entry, and we didn't copy above // if ocean is 0, so the following gets us the correct count ds->taxonomy.nr = ocean + 1; } } // get all the data - OCEAN is special, so start at COUNTRY for (int j = TC_COUNTRY; j < TC_NR_CATEGORIES; j++) { if (firstData[taxonomy_api_names[j]].isValid()) { ds->taxonomy.category[ri].category = j; ds->taxonomy.category[ri].origin = taxonomy::GEOCODED; free((void*)ds->taxonomy.category[ri].value); ds->taxonomy.category[ri].value = copy_string(qPrintable(firstData[taxonomy_api_names[j]].toString())); ri++; } } ds->taxonomy.nr = ri; l3 = taxonomy_index_for_category(&ds->taxonomy, TC_ADMIN_L3); lt = taxonomy_index_for_category(&ds->taxonomy, TC_LOCALNAME); if (l3 == -1 && lt != -1) { // basically this means we did get a local name (what we call town), but just like most places // we didn't get an adminName_3 - which in some regions is the actual city that town belongs to, // then we copy the town into the city ds->taxonomy.category[ri].value = copy_string(ds->taxonomy.category[lt].value); ds->taxonomy.category[ri].origin = taxonomy::COPIED; ds->taxonomy.category[ri].category = TC_ADMIN_L3; ds->taxonomy.nr++; } mark_divelist_changed(true); } else { report_error("geonames.org did not provide reverse lookup information"); qDebug() << "no reverse geo lookup; geonames returned\n" << fullReply; } } else { report_error("timeout accessing geonames.org"); disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit())); reply->abort(); } // next check the oceans API to figure out the body of water request.setUrl(geonamesOceanURL.arg(uiLanguage(NULL)).arg(info.lat.udeg / 1000000.0).arg(info.lon.udeg / 1000000.0)); reply = rgl->get(request); connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); timer.start(5000); // 5 secs. timeout loop.exec(); if(timer.isActive()) { timer.stop(); if(reply->error() > 0) { report_error("got error accessing oceans API of geonames.org: %s", qPrintable(reply->errorString())); goto clear_reply; } int v = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (v < 200 || v >= 300) goto clear_reply; QByteArray fullReply = reply->readAll(); QJsonParseError errorObject; QJsonDocument jsonDoc = QJsonDocument::fromJson(fullReply, &errorObject); if (errorObject.error != QJsonParseError::NoError) { report_error("error parsing geonames.org response: %s", qPrintable(errorObject.errorString())); goto clear_reply; } QJsonObject obj = jsonDoc.object(); QVariant oceanObject = obj.value("ocean").toVariant(); QVariantMap oceanName = oceanObject.toMap(); if (oceanName["name"].isValid()) { int idx; if (ds->taxonomy.category == NULL) ds->taxonomy.category = alloc_taxonomy(); idx = taxonomy_index_for_category(&ds->taxonomy, TC_OCEAN); if (idx == -1) idx = ds->taxonomy.nr; if (idx < TC_NR_CATEGORIES) { ds->taxonomy.category[idx].category = TC_OCEAN; ds->taxonomy.category[idx].origin = taxonomy::GEOCODED; ds->taxonomy.category[idx].value = copy_string(qPrintable(oceanName["name"].toString())); if (idx == ds->taxonomy.nr) ds->taxonomy.nr++; } mark_divelist_changed(true); } } else { report_error("timeout accessing geonames.org"); disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit())); reply->abort(); } clear_reply: reply->deleteLater(); } rgl->deleteLater(); }