diff --git a/src/common/htmlinfobuilder.cpp b/src/common/htmlinfobuilder.cpp
index c110540e5..8f4360d52 100644
--- a/src/common/htmlinfobuilder.cpp
+++ b/src/common/htmlinfobuilder.cpp
@@ -68,6 +68,8 @@ using atools::fs::weather::Metar;
using atools::geo::Pos;
using atools::fs::util::roundComFrequency;
+namespace ahtml = atools::util::html;
+
const float HELIPAD_DISTANCE_KM = 0.200f;
const float STARTPOS_DISTANCE_KM = 0.500f;
@@ -105,15 +107,15 @@ void HtmlInfoBuilder::airportTitle(const MapAirport& airport, HtmlBuilder& html,
}
// Adapt title to airport status
- Flags titleFlags = atools::util::html::BOLD;
+ Flags titleFlags = ahtml::BOLD;
if(airport.closed())
- titleFlags |= atools::util::html::STRIKEOUT;
+ titleFlags |= ahtml::STRIKEOUT;
if(airport.addon())
- titleFlags |= atools::util::html::ITALIC;
+ titleFlags |= ahtml::ITALIC;
if(info)
{
- html.text(tr("%1 (%2)").arg(airport.name).arg(airport.ident), titleFlags | atools::util::html::BIG);
+ html.text(tr("%1 (%2)").arg(airport.name).arg(airport.ident), titleFlags | ahtml::BIG);
html.nbsp().nbsp();
if(rating != -1)
html.text(atools::ratingString(rating, 5)).nbsp().nbsp();
@@ -125,7 +127,7 @@ void HtmlInfoBuilder::airportTitle(const MapAirport& airport, HtmlBuilder& html,
// Add link to map
html.a(tr("Map"),
QString("lnm://show?id=%1&type=%2").arg(airport.id).arg(map::AIRPORT),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
}
else
{
@@ -440,7 +442,7 @@ void HtmlInfoBuilder::airportText(const MapAirport& airport, const map::WeatherC
else
html.row2(QString(), tr("None"));
html.tableEnd();
- }
+ } // if(info)
// Add apt.dat or BGL file links
if(info && !print)
@@ -455,6 +457,140 @@ void HtmlInfoBuilder::airportText(const MapAirport& airport, const map::WeatherC
#endif
}
+void HtmlInfoBuilder::nearestText(const MapAirport& airport, HtmlBuilder& html) const
+{
+ // Do not display as tooltip
+ if(info && infoQuery != nullptr && airport.isValid())
+ {
+ if(!print)
+ airportTitle(airport, html, -1);
+
+ // Get nearest VOR and NDB ====================================
+ MapSearchResultMixed *nearestNavaids = mapQuery->getNearestNavaids(airport.position, 50, map::VOR | map::NDB);
+ nearestMapObjectsText(airport, html, nearestNavaids, tr("Nearest Radio Navaids"), true, false, 15);
+
+ // Get nearest airports that have procedures ====================================
+ MapSearchResultMixed *nearestAirports = airportQueryNav->getNearestAirportsProc(airport.position, 50);
+ nearestMapObjectsText(airport, html, nearestAirports, tr("Nearest Airports with Procedures"), false, true, 15);
+ }
+}
+
+void HtmlInfoBuilder::nearestMapObjectsTextRow(const MapAirport& airport, HtmlBuilder& html,
+ const QString& type, const QString& ident, const QString& name,
+ const QString& freq, const map::MapBase *base, float magVar,
+ bool frequencyCol, bool airportCol) const
+{
+ float distance = airport.position.distanceMeterTo(base->position);
+ float bearing = normalizeCourse(airport.position.angleDegToRhumb(base->position));
+ bearing = normalizeCourse(bearing - magVar);
+
+ QString url;
+ if(base->objType == map::AIRPORT)
+ // Show by id does only work for airport (needed for centering)
+ url = QString("lnm://show?id=%1&type=%2").arg(base->id).arg(base->objType);
+ else
+ // Show all other navaids by coordinate
+ url = QString("lnm://show?lonx=%1&laty=%2").arg(base->position.getLonX()).arg(base->position.getLatY());
+
+ // Create table row ==========================
+ html.tr(QColor());
+
+ if(airportCol)
+ {
+ // Airports have no type and link is on name
+ html.td(ident, ahtml::BOLD);
+ html.tdF(ahtml::ALIGN_RIGHT).a(name, url, ahtml::LINK_NO_UL).tdEnd();
+ }
+ else
+ {
+ // Navaid type
+ html.td(type, ahtml::BOLD);
+ html.td(ident, ahtml::BOLD);
+ html.tdF(ahtml::ALIGN_RIGHT).a(name, url, ahtml::LINK_NO_UL).tdEnd();
+ }
+
+ if(frequencyCol)
+ html.td(freq, ahtml::ALIGN_RIGHT);
+
+ html.td(locale.toString(bearing, 'f', 0), ahtml::ALIGN_RIGHT).
+ td(Unit::distMeter(distance, false), ahtml::ALIGN_RIGHT).
+ trEnd();
+}
+
+void HtmlInfoBuilder::nearestMapObjectsText(const MapAirport& airport, HtmlBuilder& html,
+ const map::MapSearchResultMixed *nearest, const QString& header,
+ bool frequencyCol, bool airportCol, int maxRows) const
+{
+ if(nearest != nullptr && !nearest->getVector().isEmpty())
+ {
+ html.br().br().text(header, ahtml::BOLD | ahtml::BIG);
+ html.table();
+
+ // Create table header ==========================
+ html.tr(QColor());
+
+ if(!airportCol)
+ html.th(tr("Type"));
+
+ html.th(tr("Ident")).
+ th(tr("Name"));
+
+ if(frequencyCol)
+ // Only for navaids
+ html.th(tr("Frequency\nkHz/MHz"));
+
+ html.th(tr("Bearing\n°M")).
+ th(tr("Distance\n%1").arg(Unit::getUnitDistStr())).
+ trEnd();
+
+ // Go through mixed list of map objects ============================================
+ int row = 1;
+ for(const map::MapBase *base : nearest->getVector())
+ {
+ if(row++ > maxRows)
+ // Stop at max
+ break;
+
+ // Airport ======================================
+ const map::MapAirport *ap = base->asType(map::AIRPORT);
+ if(ap != nullptr)
+ {
+ // Convert navdatabase airport to simulator
+ map::MapAirport simAp = mapQuery->getAirportSim(*ap);
+
+ // Omit center airport used as reference
+ if(simAp.isValid() && simAp.id != airport.id)
+ nearestMapObjectsTextRow(airport, html, QString(), simAp.ident, simAp.name,
+ QString(), &simAp, simAp.magvar, frequencyCol, airportCol);
+ }
+
+ const map::MapVor *vor = base->asType(map::VOR);
+ if(vor != nullptr)
+ nearestMapObjectsTextRow(airport, html, map::vorType(*vor), vor->ident, vor->name,
+ locale.toString(vor->frequency / 1000., 'f',
+ 2), vor, vor->magvar, frequencyCol, airportCol);
+
+ const map::MapNdb *ndb = base->asType(map::NDB);
+ if(ndb != nullptr)
+ nearestMapObjectsTextRow(airport, html, tr("NDB"), ndb->ident, ndb->name,
+ locale.toString(ndb->frequency / 100., 'f',
+ 1), ndb, ndb->magvar, frequencyCol, airportCol);
+
+ const map::MapWaypoint *waypoint = base->asType(map::WAYPOINT);
+ if(waypoint != nullptr)
+ nearestMapObjectsTextRow(airport, html, tr("Waypoint"), waypoint->ident, QString(),
+ QString(), waypoint, waypoint->magvar, frequencyCol, airportCol);
+
+ const map::MapIls *ils = base->asType(map::ILS);
+ if(ils != nullptr)
+ nearestMapObjectsTextRow(airport, html, map::ilsType(*ils), ils->ident, ils->name,
+ QString::number(ils->frequency / 1000., 'f',
+ 2), ils, ils->magvar, frequencyCol, airportCol);
+ }
+ html.tableEnd();
+ }
+}
+
void HtmlInfoBuilder::comText(const MapAirport& airport, HtmlBuilder& html) const
{
if(info && infoQuery != nullptr)
@@ -466,9 +602,9 @@ void HtmlInfoBuilder::comText(const MapAirport& airport, HtmlBuilder& html) cons
if(recVector != nullptr)
{
html.table();
- html.tr(QColor()).td(tr("Type"), atools::util::html::BOLD).
- td(tr("Frequency"), atools::util::html::BOLD).
- td(tr("Name"), atools::util::html::BOLD).trEnd();
+ html.tr(QColor()).td(tr("Type"), ahtml::BOLD).
+ td(tr("Frequency"), ahtml::BOLD).
+ td(tr("Name"), ahtml::BOLD).trEnd();
for(const SqlRecord& rec : *recVector)
{
@@ -558,11 +694,11 @@ void HtmlInfoBuilder::bestRunwaysText(const MapAirport& airport, HtmlBuilder& ht
// Table entry ==================
html.tr(QColor()).
- td(end.names.join(tr(", ")), atools::util::html::BOLD).
+ td(end.names.join(tr(", ")), ahtml::BOLD).
td(end.soft ? tr("Soft") : tr("Hard")).
- td(lengthTxt, atools::util::html::ALIGN_RIGHT).
- td(formatter::windInformationHead(end.head), atools::util::html::ALIGN_RIGHT).
- td(Unit::speedKts(end.cross), atools::util::html::ALIGN_RIGHT).
+ td(lengthTxt, ahtml::ALIGN_RIGHT).
+ td(formatter::windInformationHead(end.head), ahtml::ALIGN_RIGHT).
+ td(Unit::speedKts(end.cross), ahtml::ALIGN_RIGHT).
trEnd();
num++;
}
@@ -614,8 +750,8 @@ void HtmlInfoBuilder::runwayText(const MapAirport& airport, HtmlBuilder& html, b
bool closedSec = recSec->valueBool("has_closed_markings");
html.br().text(tr("Runway ") + recPrim->valueStr("name") + ", " + recSec->valueStr("name"),
- (closedPrim & closedSec ? atools::util::html::STRIKEOUT : atools::util::html::NONE)
- | atools::util::html::UNDERLINE | atools::util::html::BIG | atools::util::html::BOLD);
+ (closedPrim & closedSec ? ahtml::STRIKEOUT : ahtml::NONE)
+ | ahtml::UNDERLINE | ahtml::BIG | ahtml::BOLD);
html.table();
html.row2(tr("Size:"), Unit::distShortFeet(rec.valueFloat("length"), false) +
@@ -718,8 +854,8 @@ void HtmlInfoBuilder::runwayText(const MapAirport& airport, HtmlBuilder& html, b
QString num = hasStart ? " " + heliRec.valueStr("runway_name") : tr(" (No Start Position)");
html.h3(tr("Helipad%1").arg(num),
- (closed ? atools::util::html::STRIKEOUT : atools::util::html::NONE)
- | atools::util::html::UNDERLINE);
+ (closed ? ahtml::STRIKEOUT : ahtml::NONE)
+ | ahtml::UNDERLINE);
html.nbsp().nbsp();
Pos pos(heliRec.valueFloat("lonx"), heliRec.valueFloat("laty"));
@@ -727,7 +863,7 @@ void HtmlInfoBuilder::runwayText(const MapAirport& airport, HtmlBuilder& html, b
if(!print)
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2&distance=%3").
arg(pos.getLonX()).arg(pos.getLatY()).arg(HELIPAD_DISTANCE_KM),
- atools::util::html::LINK_NO_UL).br();
+ ahtml::LINK_NO_UL).br();
if(closed)
html.text(tr("Is Closed"));
@@ -778,7 +914,7 @@ void HtmlInfoBuilder::runwayText(const MapAirport& airport, HtmlBuilder& html, b
else
html.a(startText, QString("lnm://show?lonx=%1&laty=%2&distance=%3").
arg(pos.getLonX()).arg(pos.getLatY()).arg(STARTPOS_DISTANCE_KM),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
i++;
}
}
@@ -793,8 +929,8 @@ void HtmlInfoBuilder::runwayEndText(HtmlBuilder& html, const MapAirport& airport
{
bool closed = rec->valueBool("has_closed_markings");
- html.br().br().text(rec->valueStr("name"), (closed ? (atools::util::html::STRIKEOUT) : atools::util::html::NONE) |
- atools::util::html::BOLD | atools::util::html::BIG);
+ html.br().br().text(rec->valueStr("name"), (closed ? (ahtml::STRIKEOUT) : ahtml::NONE) |
+ ahtml::BOLD | ahtml::BIG);
html.table();
if(closed)
html.row2(tr("Closed"), QString());
@@ -901,7 +1037,7 @@ void HtmlInfoBuilder::ilsText(const atools::sql::SqlRecord *ilsRec, HtmlBuilder&
// Add map link if not tooltip
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2").
- arg(ilsRec->valueFloat("lonx")).arg(ilsRec->valueFloat("laty")), atools::util::html::LINK_NO_UL);
+ arg(ilsRec->valueFloat("lonx")).arg(ilsRec->valueFloat("laty")), ahtml::LINK_NO_UL);
}
html.table();
}
@@ -911,7 +1047,7 @@ void HtmlInfoBuilder::ilsText(const atools::sql::SqlRecord *ilsRec, HtmlBuilder&
html.row2(prefix + tr(":"), name);
else
{
- html.br().br().text(text, atools::util::html::BOLD | atools::util::html::BIG);
+ html.br().br().text(text, ahtml::BOLD | ahtml::BIG);
html.table();
}
}
@@ -922,8 +1058,8 @@ void HtmlInfoBuilder::ilsText(const atools::sql::SqlRecord *ilsRec, HtmlBuilder&
bearingText(atools::geo::Pos(ilsRec->valueFloat("lonx"), ilsRec->valueFloat("laty")),
ilsRec->valueFloat("mag_var"), html);
- html.row2If(tr("Airport:"), ilsRec->valueStr("loc_airport_ident"), atools::util::html::BOLD);
- html.row2If(tr("Runway:"), ilsRec->valueStr("loc_runway_name"), atools::util::html::BOLD);
+ html.row2If(tr("Airport:"), ilsRec->valueStr("loc_airport_ident"), ahtml::BOLD);
+ html.row2If(tr("Runway:"), ilsRec->valueStr("loc_runway_name"), ahtml::BOLD);
if(info)
{
@@ -975,7 +1111,7 @@ void HtmlInfoBuilder::helipadText(const MapHelipad& helipad, HtmlBuilder& html)
html.brText(tr("Is Closed"));
}
-void HtmlInfoBuilder::windText(const atools::grib::WindPosVector& windStack, atools::util::HtmlBuilder& html,
+void HtmlInfoBuilder::windText(const atools::grib::WindPosVector& windStack, HtmlBuilder& html,
float currentAltitude) const
{
if(!windStack.isEmpty())
@@ -988,7 +1124,7 @@ void HtmlInfoBuilder::windText(const atools::grib::WindPosVector& windStack, ato
// Display currently selected altitude bold
float alt = wind.pos.getAltitude();
Flags flags =
- atools::almostEqual(alt, currentAltitude, 10.f) ? atools::util::html::BOLD : atools::util::html::NONE;
+ atools::almostEqual(alt, currentAltitude, 10.f) ? ahtml::BOLD : ahtml::NONE;
// One table row with three data fields
html.tr().
@@ -1048,7 +1184,7 @@ void HtmlInfoBuilder::procedureText(const MapAirport& airport, HtmlBuilder& html
header = tr("Approach %1 %2 %3 %4").arg(proc::procedureType(procType)).
arg(recApp.valueStr("suffix")).arg(fix).arg(runwayTxt);
- html.h3(header, atools::util::html::UNDERLINE);
+ html.h3(header, ahtml::UNDERLINE);
// Fill table ==========================================================
html.table();
@@ -1176,7 +1312,7 @@ void HtmlInfoBuilder::procedureText(const MapAirport& airport, HtmlBuilder& html
html.row2(tr("DME Channel:"), vorReg.valueStr("channel"));
html.row2(tr("DME Range:"), Unit::distNm(vorReg.valueInt("range")));
html.row2(tr("DME Morse:"), morse->getCode(vorReg.valueStr("ident")),
- atools::util::html::BOLD | atools::util::html::NO_ENTITIES);
+ ahtml::BOLD | ahtml::NO_ENTITIES);
}
else
html.row2(tr("DME data not found for %1/%2.").
@@ -1197,7 +1333,7 @@ void HtmlInfoBuilder::procedureText(const MapAirport& airport, HtmlBuilder& html
}
}
-void HtmlInfoBuilder::addRadionavFixType(atools::util::HtmlBuilder& html, const SqlRecord& recApp) const
+void HtmlInfoBuilder::addRadionavFixType(HtmlBuilder& html, const SqlRecord& recApp) const
{
QString fixType = recApp.valueStr("fix_type");
@@ -1233,7 +1369,7 @@ void HtmlInfoBuilder::addRadionavFixType(atools::util::HtmlBuilder& html, const
if(vor.range > 0)
html.row2(tr("VORTAC Range:"), Unit::distNm(vor.range));
html.row2(tr("VORTAC Morse:"), morse->getCode(
- vor.ident), atools::util::html::BOLD | atools::util::html::NO_ENTITIES);
+ vor.ident), ahtml::BOLD | ahtml::NO_ENTITIES);
}
else
{
@@ -1242,7 +1378,7 @@ void HtmlInfoBuilder::addRadionavFixType(atools::util::HtmlBuilder& html, const
if(vor.range > 0)
html.row2(tr("VOR Range:"), Unit::distNm(vor.range));
html.row2(tr("VOR Morse:"), morse->getCode(
- vor.ident), atools::util::html::BOLD | atools::util::html::NO_ENTITIES);
+ vor.ident), ahtml::BOLD | ahtml::NO_ENTITIES);
}
}
#ifdef DEBUG_INFORMATION
@@ -1267,13 +1403,13 @@ void HtmlInfoBuilder::addRadionavFixType(atools::util::HtmlBuilder& html, const
if(!ndb.type.isEmpty())
html.row2(tr("NDB Type:"), map::navTypeNameNdb(ndb.type));
- html.row2(tr("NDB Frequency:"), locale.toString(ndb.frequency / 100., 'f', 2) + tr(" MHz"));
+ html.row2(tr("NDB Frequency:"), locale.toString(ndb.frequency / 100., 'f', 2) + tr(" kHz"));
if(ndb.range > 0)
html.row2(tr("NDB Range:"), Unit::distNm(ndb.range));
html.row2(tr("NDB Morse:"), morse->getCode(ndb.ident),
- atools::util::html::BOLD | atools::util::html::NO_ENTITIES);
+ ahtml::BOLD | ahtml::NO_ENTITIES);
}
#ifdef DEBUG_INFORMATION
else
@@ -1282,10 +1418,10 @@ void HtmlInfoBuilder::addRadionavFixType(atools::util::HtmlBuilder& html, const
}
}
-static const Flags WEATHER_TITLE_FLAGS = atools::util::html::BOLD | atools::util::html::BIG;
+static const Flags WEATHER_TITLE_FLAGS = ahtml::BOLD | ahtml::BIG;
void HtmlInfoBuilder::weatherText(const map::WeatherContext& context, const MapAirport& airport,
- atools::util::HtmlBuilder& html) const
+ HtmlBuilder& html) const
{
if(info)
{
@@ -1329,7 +1465,7 @@ void HtmlInfoBuilder::weatherText(const map::WeatherContext& context, const MapA
// Add link to airport
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?id=%1&type=%2").arg(reportAirport.id).arg(map::AIRPORT),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
}
decodedMetar(html, airport, reportAirport, met, false /* interpolated */, fsxP3d,
@@ -1344,7 +1480,7 @@ void HtmlInfoBuilder::weatherText(const map::WeatherContext& context, const MapA
}
}
else if(!print && OptionData::instance().getFlags() & opts::WEATHER_INFO_FS)
- html.p(tr("Not connected to simulator."), atools::util::html::BOLD);
+ html.p(tr("Not connected to simulator."), ahtml::BOLD);
// Active Sky metar ===========================
if(!context.asMetar.isEmpty())
@@ -1406,7 +1542,7 @@ void HtmlInfoBuilder::decodedMetars(HtmlBuilder& html, const atools::fs::weather
html.nbsp().nbsp();
html.a(tr("Map"),
QString("lnm://show?id=%1&type=%2").arg(reportAirport.id).arg(map::AIRPORT),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
}
decodedMetar(html, airport, reportAirport, met, false, false, mapDisplay);
@@ -1446,11 +1582,11 @@ void HtmlInfoBuilder::decodedMetar(HtmlBuilder& html, const map::MapAirport& air
time.setTime(QTime(parsed.getHour(), parsed.getMinute()));
QDateTime oldUtc = QDateTime::currentDateTimeUtc().addSecs(-3600 * WEATHER_MAX_AGE_HOURS);
- atools::util::html::Flags flags = atools::util::html::NONE;
+ ahtml::Flags flags = ahtml::NONE;
QColor color;
if(time < oldUtc)
{
- flags |= atools::util::html::BOLD;
+ flags |= ahtml::BOLD;
color = Qt::red;
}
html.row2(tr("Time: "), locale.toString(time, QLocale::ShortFormat) + " " + time.timeZoneAbbreviation(),
@@ -1567,7 +1703,7 @@ void HtmlInfoBuilder::decodedMetar(HtmlBuilder& html, const map::MapAirport& air
html.tableEnd();
if(hasClouds)
- html.p(tr("Clouds"), atools::util::html::BOLD);
+ html.p(tr("Clouds"), ahtml::BOLD);
html.table();
if(hasClouds)
@@ -1586,24 +1722,24 @@ void HtmlInfoBuilder::decodedMetar(HtmlBuilder& html, const map::MapAirport& air
html.tableEnd();
if(parsed.getCavok())
- html.p().text(tr("CAVOK:"), atools::util::html::BOLD).br().
+ html.p().text(tr("CAVOK:"), ahtml::BOLD).br().
text(tr("No cloud below 5,000 ft (1,500 m), visibility of 10 km (6 nm) or more")).pEnd();
if(!metar.getParsedMetar().getRemark().isEmpty())
- html.p().text(tr("Remarks:"), atools::util::html::BOLD).br().
+ html.p().text(tr("Remarks:"), ahtml::BOLD).br().
text(metar.getParsedMetar().getRemark()).pEnd();
if(!parsed.isValid())
{
// Print error report if invalid
- html.p(tr("Report is not valid. Raw and clean METAR were:"), atools::util::html::BOLD, Qt::red);
+ html.p(tr("Report is not valid. Raw and clean METAR were:"), ahtml::BOLD, Qt::red);
html.pre(metar.getMetar());
if(metar.getMetar() != metar.getCleanMetar())
html.pre(metar.getCleanMetar());
}
if(!parsed.getUnusedData().isEmpty())
- html.p().text(tr("Additional information:"), atools::util::html::BOLD).br().text(parsed.getUnusedData()).pEnd();
+ html.p().text(tr("Additional information:"), ahtml::BOLD).br().text(parsed.getUnusedData()).pEnd();
bestRunwaysText(airport, html, windSpeedKts, parsed.getWindDir(), 8 /* max entries */, true /* details */);
@@ -1630,7 +1766,7 @@ void HtmlInfoBuilder::vorText(const MapVor& vor, HtmlBuilder& html) const
// Add map link if not tooltip
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2").
- arg(vor.position.getLonX()).arg(vor.position.getLatY()), atools::util::html::LINK_NO_UL);
+ arg(vor.position.getLonX()).arg(vor.position.getLatY()), ahtml::LINK_NO_UL);
}
html.table();
@@ -1670,7 +1806,7 @@ void HtmlInfoBuilder::vorText(const MapVor& vor, HtmlBuilder& html) const
html.row2(tr("Elevation:"), Unit::altFeet(vor.getPosition().getAltitude()));
html.row2(tr("Range:"), Unit::distNm(vor.range));
html.row2(tr("Morse:"), morse->getCode(vor.ident),
- atools::util::html::BOLD | atools::util::html::NO_ENTITIES);
+ ahtml::BOLD | ahtml::NO_ENTITIES);
addCoordinates(rec, html);
html.tableEnd();
@@ -1699,7 +1835,7 @@ void HtmlInfoBuilder::ndbText(const MapNdb& ndb, HtmlBuilder& html) const
// Add map link if not tooltip
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2").
- arg(ndb.position.getLonX()).arg(ndb.position.getLatY()), atools::util::html::LINK_NO_UL);
+ arg(ndb.position.getLonX()).arg(ndb.position.getLatY()), ahtml::LINK_NO_UL);
}
html.table();
@@ -1722,7 +1858,7 @@ void HtmlInfoBuilder::ndbText(const MapNdb& ndb, HtmlBuilder& html) const
html.row2(tr("Elevation:"), Unit::altFeet(ndb.getPosition().getAltitude()));
if(ndb.range > 0)
html.row2(tr("Range:"), Unit::distNm(ndb.range));
- html.row2(tr("Morse:"), morse->getCode(ndb.ident), atools::util::html::BOLD | atools::util::html::NO_ENTITIES);
+ html.row2(tr("Morse:"), morse->getCode(ndb.ident), ahtml::BOLD | ahtml::NO_ENTITIES);
addCoordinates(rec, html);
html.tableEnd();
@@ -1755,7 +1891,7 @@ void HtmlInfoBuilder::userpointText(MapUserpoint userpoint, HtmlBuilder& html) c
// Add map link if not tooltip
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2").
- arg(userpoint.position.getLonX()).arg(userpoint.position.getLatY()), atools::util::html::LINK_NO_UL);
+ arg(userpoint.position.getLonX()).arg(userpoint.position.getLatY()), ahtml::LINK_NO_UL);
}
html.table();
@@ -1763,15 +1899,15 @@ void HtmlInfoBuilder::userpointText(MapUserpoint userpoint, HtmlBuilder& html) c
bearingText(userpoint.position, NavApp::getMagVar(userpoint.position), html);
// Be cautious with user defined data and adapt it for HTML display
- html.row2If(tr("Type:"), userpoint.type, atools::util::html::REPLACE_CRLF);
- html.row2If(tr("Ident:"), userpoint.ident, atools::util::html::REPLACE_CRLF);
- html.row2If(tr("Region:"), userpoint.region, atools::util::html::REPLACE_CRLF);
- html.row2If(tr("Name:"), userpoint.name, atools::util::html::REPLACE_CRLF);
+ html.row2If(tr("Type:"), userpoint.type, ahtml::REPLACE_CRLF);
+ html.row2If(tr("Ident:"), userpoint.ident, ahtml::REPLACE_CRLF);
+ html.row2If(tr("Region:"), userpoint.region, ahtml::REPLACE_CRLF);
+ html.row2If(tr("Name:"), userpoint.name, ahtml::REPLACE_CRLF);
QString description = atools::elideTextLinesShort(userpoint.description, info ? 40 : 4);
- html.row2If(tr("Description:"), description, (info ? atools::util::html::AUTOLINK : atools::util::html::NONE));
+ html.row2If(tr("Description:"), description, (info ? ahtml::AUTOLINK : ahtml::NONE));
- html.row2If(tr("Tags:"), userpoint.tags, atools::util::html::REPLACE_CRLF);
+ html.row2If(tr("Tags:"), userpoint.tags, ahtml::REPLACE_CRLF);
if(!rec.isNull("altitude"))
html.row2If(tr("Elevation:"), Unit::altFeet(rec.valueFloat("altitude")));
@@ -1795,7 +1931,7 @@ void HtmlInfoBuilder::userpointText(MapUserpoint userpoint, HtmlBuilder& html) c
head(html, tr("File"));
html.table();
html.row2(tr("Imported from:"), filepathTextShow(rec.valueStr("import_file_path")),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
html.tableEnd();
}
@@ -1807,7 +1943,7 @@ void HtmlInfoBuilder::userpointText(MapUserpoint userpoint, HtmlBuilder& html) c
qWarning() << Q_FUNC_INFO << "Empty record";
}
-void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlBuilder& html) const
+void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, HtmlBuilder& html) const
{
atools::sql::SqlRecord rec = NavApp::getLogdataController()->getLogEntryRecordById(logEntry.id);
@@ -1827,7 +1963,7 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
// atools::geo::Rect rect = logEntry.bounding();
// html.a(tr("Map"), QString("lnm://show?west=%1&north=%2&east=%3&south=%4").
// arg(rect.getWest()).arg(rect.getNorth()).arg(rect.getEast()).arg(rect.getSouth()),
- // atools::util::html::LINK_NO_UL);
+ // ahtml::LINK_NO_UL);
// }
// else
// html.text(tr("Map"));
@@ -1838,12 +1974,12 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
airportLink(html, logEntry.departureIdent, logEntry.departureName) +
(logEntry.departureIdent.isEmpty() ? QString() :
tr(", %1").arg(Unit::altFeet(rec.valueFloat("departure_alt")))),
- atools::util::html::NO_ENTITIES | atools::util::html::BOLD);
+ ahtml::NO_ENTITIES | ahtml::BOLD);
html.row2(tr("To:"),
airportLink(html, logEntry.destinationIdent, logEntry.destinationName) +
(logEntry.destinationIdent.isEmpty() ? QString() :
tr(", %1").arg(Unit::altFeet(rec.valueFloat("destination_alt")))),
- atools::util::html::NO_ENTITIES | atools::util::html::BOLD);
+ ahtml::NO_ENTITIES | ahtml::BOLD);
if(info)
{
@@ -1869,7 +2005,7 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
html.tableEnd();
// Flight =======================================================
- html.p(tr("Flight"), atools::util::html::BOLD);
+ html.p(tr("Flight"), ahtml::BOLD);
html.table();
}
@@ -1910,7 +2046,7 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
html.tableEnd();
// Departure =======================================================
- html.p(tr("Departure"), atools::util::html::BOLD);
+ html.p(tr("Departure"), ahtml::BOLD);
html.table();
QDateTime departTime = rec.valueDateTime("departure_time");
@@ -1939,7 +2075,7 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
html.tableEnd();
// Destination =======================================================
- html.p(tr("Destination"), atools::util::html::BOLD);
+ html.p(tr("Destination"), ahtml::BOLD);
html.table();
html.row2If(tr("Runway:"), rec.valueStr("destination_runway"));
@@ -1968,10 +2104,10 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
// Fuel =======================================================
if(rec.valueFloat("trip_fuel") > 0.f || rec.valueFloat("block_fuel") > 0.f || rec.valueFloat("block_fuel") > 0.f)
{
- html.p(tr("Fuel"), atools::util::html::BOLD);
+ html.p(tr("Fuel"), ahtml::BOLD);
html.table();
bool jetfuel = rec.valueBool("is_jetfuel");
- atools::util::html::Flags flags = atools::util::html::ALIGN_RIGHT;
+ ahtml::Flags flags = ahtml::ALIGN_RIGHT;
html.row2(tr("Type:"), jetfuel ? tr("Jetfuel") : tr("Avgas"));
html.row2(tr("Trip:"), Unit::fuelLbsAndGal(rec.valueFloat("trip_fuel"),
fromLbsToGal(jetfuel, rec.valueFloat("trip_fuel"))), flags);
@@ -1985,12 +2121,12 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
// Files =======================================================
if(!rec.valueStr("flightplan_file").isEmpty() || !rec.valueStr("performance_file").isEmpty())
{
- html.p(tr("Files"), atools::util::html::BOLD);
+ html.p(tr("Files"), ahtml::BOLD);
html.table();
html.row2(tr("Flight plan:"), filepathTextShow(rec.valueStr("flightplan_file")),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
html.row2(tr("Aircraft performance:"), filepathTextShow(rec.valueStr("performance_file")),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
html.tableEnd();
}
@@ -2001,7 +2137,7 @@ void HtmlInfoBuilder::logEntryText(MapLogbookEntry logEntry, atools::util::HtmlB
html.p().b(tr("Description")).pEnd();
html.table();
html.row2(QString(), atools::elideTextLinesShort(description, info ? 200 : 4),
- (info ? atools::util::html::AUTOLINK : atools::util::html::NONE));
+ (info ? ahtml::AUTOLINK : ahtml::NONE));
}
} // if(info)
html.tableEnd();
@@ -2020,8 +2156,8 @@ void HtmlInfoBuilder::airportRow(const map::MapAirport& ap, HtmlBuilder& html) c
if(apSim.isValid())
{
HtmlBuilder apHtml = html.cleared();
- apHtml.a(apSim.ident, QString("lnm://show?airport=%1").arg(apSim.ident), atools::util::html::LINK_NO_UL);
- html.row2(tr("Airport:"), apHtml.getHtml(), atools::util::html::NO_ENTITIES);
+ apHtml.a(apSim.ident, QString("lnm://show?airport=%1").arg(apSim.ident), ahtml::LINK_NO_UL);
+ html.row2(tr("Airport:"), apHtml.getHtml(), ahtml::NO_ENTITIES);
}
}
}
@@ -2044,7 +2180,7 @@ void HtmlInfoBuilder::waypointText(const MapWaypoint& waypoint, HtmlBuilder& htm
// Add map link if not tooltip
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2").
- arg(waypoint.position.getLonX()).arg(waypoint.position.getLatY()), atools::util::html::LINK_NO_UL);
+ arg(waypoint.position.getLonX()).arg(waypoint.position.getLatY()), ahtml::LINK_NO_UL);
}
html.table();
@@ -2176,7 +2312,7 @@ void HtmlInfoBuilder::airspaceText(const MapAirspace& airspace, const atools::sq
arg(airspace.id).
arg(map::AIRSPACE).
arg(airspace.src),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
}
QStringList header;
@@ -2333,18 +2469,18 @@ void HtmlInfoBuilder::airwayText(const MapAirway& airway, HtmlBuilder& html) con
if(info)
{
tempHtml.a(tr("%1/%2").arg(from.ident).arg(from.region), QString("lnm://show?lonx=%1&laty=%2").
- arg(from.position.getLonX()).arg(from.position.getLatY()), atools::util::html::LINK_NO_UL);
+ arg(from.position.getLonX()).arg(from.position.getLatY()), ahtml::LINK_NO_UL);
tempHtml.text(connector);
tempHtml.a(tr("%1/%2").arg(to.ident).arg(to.region), QString("lnm://show?lonx=%1&laty=%2").
- arg(to.position.getLonX()).arg(to.position.getLatY()), atools::util::html::LINK_NO_UL);
+ arg(to.position.getLonX()).arg(to.position.getLatY()), ahtml::LINK_NO_UL);
}
else
tempHtml.text(tr("%1/%2%3%4/%5").arg(from.ident).arg(from.region).arg(connector).arg(to.ident).arg(to.region));
if(airway.direction != map::DIR_BOTH)
- html.row2(tr("Segment One-way:"), tempHtml.getHtml(), atools::util::html::NO_ENTITIES);
+ html.row2(tr("Segment One-way:"), tempHtml.getHtml(), ahtml::NO_ENTITIES);
else
- html.row2(tr("Segment:"), tempHtml.getHtml(), atools::util::html::NO_ENTITIES);
+ html.row2(tr("Segment:"), tempHtml.getHtml(), ahtml::NO_ENTITIES);
QString altTxt = map::airwayAltText(airway);
@@ -2370,7 +2506,7 @@ void HtmlInfoBuilder::airwayText(const MapAirway& airway, HtmlBuilder& html) con
arg(wprec.valueStr("from_region")),
QString("lnm://show?lonx=%1&laty=%2").
arg(wprec.valueFloat("from_lonx")).
- arg(wprec.valueFloat("from_laty")), atools::util::html::LINK_NO_UL);
+ arg(wprec.valueFloat("from_laty")), ahtml::LINK_NO_UL);
}
tempLinkHtml.text(", ");
tempLinkHtml.a(tr("%1/%2").
@@ -2378,9 +2514,9 @@ void HtmlInfoBuilder::airwayText(const MapAirway& airway, HtmlBuilder& html) con
arg(waypoints.last().valueStr("to_region")),
QString("lnm://show?lonx=%1&laty=%2").
arg(waypoints.last().valueFloat("to_lonx")).
- arg(waypoints.last().valueFloat("to_laty")), atools::util::html::LINK_NO_UL);
+ arg(waypoints.last().valueFloat("to_laty")), ahtml::LINK_NO_UL);
- html.row2(tr("Waypoints Ident/Region:"), tempLinkHtml.getHtml(), atools::util::html::NO_ENTITIES);
+ html.row2(tr("Waypoints Ident/Region:"), tempLinkHtml.getHtml(), ahtml::NO_ENTITIES);
}
}
html.tableEnd();
@@ -2424,7 +2560,7 @@ void HtmlInfoBuilder::parkingText(const MapParking& parking, HtmlBuilder& html)
QString txt = atools::elideTextLinesShort(atools::blockText(parking.airlineCodes.split(","), 10, ",", "\n"), 8);
// Do not allow tooltip to break line
- html.br().text(tr("Airline Codes: ") + txt, atools::util::html::NOBR | atools::util::html::REPLACE_CRLF);
+ html.br().text(tr("Airline Codes: ") + txt, ahtml::NOBR | ahtml::REPLACE_CRLF);
}
}
@@ -2513,7 +2649,7 @@ void HtmlInfoBuilder::aircraftText(const atools::fs::sc::SimConnectAircraft& air
{
aircraftText = tr("User Aircraft");
if(info && !(NavApp::getShownMapFeatures() & map::AIRCRAFT))
- html.p(tr("User aircraft is not shown on map."), atools::util::html::BOLD);
+ html.p(tr("User aircraft is not shown on map."), ahtml::BOLD);
}
else
{
@@ -2551,7 +2687,7 @@ void HtmlInfoBuilder::aircraftText(const atools::fs::sc::SimConnectAircraft& air
aircraftText = tr("%1%2").arg(typeText).arg(type);
if(info && num == 1 && !(NavApp::getShownMapFeatures() & map::AIRCRAFT_AI))
- html.p(tr("No %2 shown on map.").arg(typeText), atools::util::html::BOLD);
+ html.p(tr("No %2 shown on map.").arg(typeText), ahtml::BOLD);
}
head(html, aircraftText);
@@ -2779,7 +2915,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
{
aircraftTitle(aircraft, html, moreLessSwitch, less);
if(!(NavApp::getShownMapFeatures() & map::AIRCRAFT))
- html.p(tr("User aircraft is not shown on map."), atools::util::html::BOLD);
+ html.p(tr("User aircraft is not shown on map."), ahtml::BOLD);
}
float distFromStartNm = 0.f, distToDestNm = 0.f, nearestLegDistance = 0.f, crossTrackDistance = 0.f;
@@ -3052,7 +3188,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
html.row2(tr("Cross Track Distance:"),
Unit::distNm(std::abs(
- crossTrackDistance)) + " " + crossDirection, atools::util::html::NO_ENTITIES);
+ crossTrackDistance)) + " " + crossDirection, ahtml::NO_ENTITIES);
}
else
html.row2(tr("Cross Track Distance:"), tr("Not along Track"));
@@ -3087,8 +3223,8 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
head(html, tr("Flight Plan"));
html.table();
- html.row2(tr("Departure:"), airportLink(html, aircraft.getFromIdent()), atools::util::html::NO_ENTITIES);
- html.row2(tr("Destination:"), airportLink(html, aircraft.getToIdent()), atools::util::html::NO_ENTITIES);
+ html.row2(tr("Departure:"), airportLink(html, aircraft.getFromIdent()), ahtml::NO_ENTITIES);
+ html.row2(tr("Destination:"), airportLink(html, aircraft.getToIdent()), ahtml::NO_ENTITIES);
html.tableEnd();
html.br();
}
@@ -3108,7 +3244,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
hdg.append(locale.toString(heading, 'f', 0) + tr("°M"));
if(!hdg.isEmpty())
- html.row2(tr("Heading:"), hdg.join(", "), atools::util::html::BOLD);
+ html.row2(tr("Heading:"), hdg.join(", "), ahtml::BOLD);
if(userAircaft != nullptr && info)
{
@@ -3158,7 +3294,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
if(aircraft.getCategory() != atools::fs::sc::BOAT)
{
if(longDisplay && aircraft.getIndicatedAltitudeFt() < atools::fs::sc::SC_INVALID_FLOAT)
- html.row2(tr("Indicated:"), Unit::altFeet(aircraft.getIndicatedAltitudeFt()), atools::util::html::BOLD);
+ html.row2(tr("Indicated:"), Unit::altFeet(aircraft.getIndicatedAltitudeFt()), ahtml::BOLD);
}
html.row2(longDisplay ? tr("Actual:") : tr("Altitude:"), Unit::altFeet(aircraft.getPosition().getAltitude()));
@@ -3184,7 +3320,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
else if(diff <= -100)
upDown = tr(", below ▲");
- html.row2(tr("Vertical Path Dev.:"), Unit::altFeet(diff) + upDown, atools::util::html::NO_ENTITIES);
+ html.row2(tr("Vertical Path Dev.:"), Unit::altFeet(diff) + upDown, ahtml::NO_ENTITIES);
}
}
html.tableEnd();
@@ -3200,7 +3336,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
html.table();
if(longDisplay && aircraft.getCategory() != atools::fs::sc::BOAT &&
aircraft.getIndicatedSpeedKts() < atools::fs::sc::SC_INVALID_FLOAT)
- html.row2(tr("Indicated:"), Unit::speedKts(aircraft.getIndicatedSpeedKts()), atools::util::html::BOLD);
+ html.row2(tr("Indicated:"), Unit::speedKts(aircraft.getIndicatedSpeedKts()), ahtml::BOLD);
if(aircraft.getGroundSpeedKts() < atools::fs::sc::SC_INVALID_FLOAT)
html.row2(longDisplay ? tr("Ground:") : tr("Groundspeed:"), Unit::speedKts(aircraft.getGroundSpeedKts()));
@@ -3233,7 +3369,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
vspeed = 0.f;
html.row2(longDisplay ? tr("Vertical:") : tr("Vertical Speed:"), Unit::speedVertFpm(vspeed) + upDown,
- atools::util::html::NO_ENTITIES);
+ ahtml::NO_ENTITIES);
}
}
html.tableEnd();
@@ -3261,7 +3397,7 @@ void HtmlInfoBuilder::aircraftProgressText(const atools::fs::sc::SimConnectAircr
// if(!value.isEmpty())
// Keep an empty line to avoid flickering
- html.row2(QString(), windPtr, atools::util::html::NO_ENTITIES);
+ html.row2(QString(), windPtr, ahtml::NO_ENTITIES);
}
// Total air temperature (TAT) is also called: indicated air temperature (IAT) or ram air temperature (RAT)
@@ -3334,12 +3470,12 @@ QString HtmlInfoBuilder::airportLink(const HtmlBuilder& html, const QString& ide
{
if(name.isEmpty())
// Ident only
- builder.a(ident, QString("lnm://show?airport=%1").arg(ident), atools::util::html::LINK_NO_UL);
+ builder.a(ident, QString("lnm://show?airport=%1").arg(ident), ahtml::LINK_NO_UL);
else
{
// Name and ident
builder.text(tr("%1 (").arg(name));
- builder.a(ident, QString("lnm://show?airport=%1").arg(ident), atools::util::html::LINK_NO_UL);
+ builder.a(ident, QString("lnm://show?airport=%1").arg(ident), ahtml::LINK_NO_UL);
builder.text(tr(")"));
}
}
@@ -3388,14 +3524,14 @@ void HtmlInfoBuilder::aircraftTitle(const atools::fs::sc::SimConnectAircraft& ai
#endif
- html.text(title, atools::util::html::BOLD | atools::util::html::BIG);
+ html.text(title, ahtml::BOLD | ahtml::BIG);
if(info && !print)
{
html.nbsp().nbsp();
html.a(tr("Map"), QString("lnm://show?lonx=%1&laty=%2").
arg(aircraft.getPosition().getLonX()).arg(aircraft.getPosition().getLatY()),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
if(moreLessSwitch)
{
// Show more/less links =============================================
@@ -3405,12 +3541,12 @@ void HtmlInfoBuilder::aircraftTitle(const atools::fs::sc::SimConnectAircraft& ai
{"align", "right"}, {"valign", "top"}
});
- atools::util::HtmlBuilder linkHtml(html.cleared());
+ HtmlBuilder linkHtml(html.cleared());
linkHtml.a(less ? tr("More") : tr("Less"), QString("lnm://do?lessprogress"),
- atools::util::html::LINK_NO_UL);
+ ahtml::LINK_NO_UL);
- atools::util::HtmlBuilder disabledLinkHtml(html.cleared());
- disabledLinkHtml.text(less ? tr("Less") : tr("More"), atools::util::html::BOLD);
+ HtmlBuilder disabledLinkHtml(html.cleared());
+ disabledLinkHtml.text(less ? tr("Less") : tr("More"), ahtml::BOLD);
if(less)
html.textHtml(linkHtml).nbsp().nbsp().textHtml(disabledLinkHtml);
@@ -3438,7 +3574,7 @@ void HtmlInfoBuilder::addScenery(const atools::sql::SqlRecord *rec, HtmlBuilder&
head(html, tr("Scenery"));
html.table();
html.row2(rec->valueStr("title"), filepathTextShow(rec->valueStr("filepath")),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
html.tableEnd();
}
@@ -3452,12 +3588,12 @@ void HtmlInfoBuilder::addAirportFolder(const MapAirport& airport, HtmlBuilder& h
html.table();
html.row2(tr("Path:"), filepathTextOpen(AirportFiles::getAirportFilesBase(airport.ident), true),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
int i = 0;
for(const QFileInfo& file : airportFiles)
html.row2(i++ > 0 ? QString() : tr("Files:"), filepathTextOpen(file, false),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
html.tableEnd();
}
}
@@ -3479,11 +3615,11 @@ void HtmlInfoBuilder::addAirportScenery(const MapAirport& airport, HtmlBuilder&
title = i == 0 ? tr("X-Plane") : QString();
html.row2(title, filepathTextShow(rec.valueStr("filepath")),
- atools::util::html::NO_ENTITIES | atools::util::html::SMALL);
+ ahtml::NO_ENTITIES | ahtml::SMALL);
i++;
}
- atools::util::html::Flags linkFlags = atools::util::html::SMALL | atools::util::html::LINK_NO_UL;
+ ahtml::Flags linkFlags = ahtml::SMALL | ahtml::LINK_NO_UL;
QStringList links;
if(NavApp::getCurrentSimulatorDb() == atools::fs::FsPaths::XPLANE11)
@@ -3496,7 +3632,7 @@ void HtmlInfoBuilder::addAirportScenery(const MapAirport& airport, HtmlBuilder&
arg(airport.ident), linkFlags).getHtml());
if(!links.isEmpty())
- html.row2(QString(), links.join(tr(", ")), atools::util::html::NO_ENTITIES);
+ html.row2(QString(), links.join(tr(", ")), ahtml::NO_ENTITIES);
}
html.tableEnd();
@@ -3507,7 +3643,7 @@ QString HtmlInfoBuilder::filepathTextShow(const QString& filepath) const
HtmlBuilder link(true);
if(QFileInfo::exists(filepath))
- link.a(filepath, QString("lnm://show?filepath=%1").arg(filepath), atools::util::html::LINK_NO_UL);
+ link.a(filepath, QString("lnm://show?filepath=%1").arg(filepath), ahtml::LINK_NO_UL);
else
link.text(filepath);
return link.getHtml();
@@ -3519,7 +3655,7 @@ QString HtmlInfoBuilder::filepathTextOpen(const QFileInfo& filepath, bool showPa
if(filepath.exists())
link.a(showPath ? filepath.filePath() : filepath.fileName(),
- QUrl::fromLocalFile(filepath.filePath()).toString(QUrl::EncodeSpaces), atools::util::html::LINK_NO_UL);
+ QUrl::fromLocalFile(filepath.filePath()).toString(QUrl::EncodeSpaces), ahtml::LINK_NO_UL);
return link.getHtml();
}
@@ -3549,7 +3685,7 @@ void HtmlInfoBuilder::head(HtmlBuilder& html, const QString& text) const
void HtmlInfoBuilder::navaidTitle(HtmlBuilder& html, const QString& text) const
{
if(info)
- html.text(text, atools::util::html::BOLD | atools::util::html::BIG);
+ html.text(text, ahtml::BOLD | ahtml::BIG);
else
html.b(text);
}
diff --git a/src/common/htmlinfobuilder.h b/src/common/htmlinfobuilder.h
index 8344cbde9..f0a1e96ee 100644
--- a/src/common/htmlinfobuilder.h
+++ b/src/common/htmlinfobuilder.h
@@ -52,6 +52,8 @@ struct MapProcedurePoint;
struct MapProcedureRef;
struct MapUserpoint;
struct MapLogbookEntry;
+struct MapBase;
+struct MapSearchResultMixed;
}
namespace atools {
@@ -148,6 +150,10 @@ class HtmlInfoBuilder
*/
void procedureText(const map::MapAirport& airport, atools::util::HtmlBuilder& html) const;
+ /* Get information for navaids and airports near the currently displayed airport */
+ void nearestText(const map::MapAirport& airport, atools::util::HtmlBuilder& html) const;
+
+ /* Create HTML for decoded weather report for current airport */
void weatherText(const map::WeatherContext& context, const map::MapAirport& airport,
atools::util::HtmlBuilder& html) const;
@@ -175,6 +181,9 @@ class HtmlInfoBuilder
*/
void waypointText(const map::MapWaypoint& waypoint, atools::util::HtmlBuilder& html) const;
+ /* Get information for one ILS */
+ void ilsText(const map::MapIls& ils, atools::util::HtmlBuilder& html) const;
+
/* Description for user defined points */
void userpointText(map::MapUserpoint userpoint, atools::util::HtmlBuilder& html) const;
@@ -275,11 +284,18 @@ class HtmlInfoBuilder
symbolSizeTitle = value;
}
- void ilsText(const map::MapIls& ils, atools::util::HtmlBuilder& html) const;
-
private:
void head(atools::util::HtmlBuilder& html, const QString& text) const;
+ void nearestMapObjectsText(const map::MapAirport& airport, atools::util::HtmlBuilder& html,
+ const map::MapSearchResultMixed *nearest, const QString& header, bool frequencyCol,
+ bool airportCol,
+ int maxRows) const;
+ void nearestMapObjectsTextRow(const map::MapAirport& airport, atools::util::HtmlBuilder& html, const QString& type,
+ const QString& ident, const QString& name, const QString& freq,
+ const map::MapBase *base,
+ float magVar, bool frequencyCol, bool airportCol) const;
+
/* Add scenery entries and links into table */
void addScenery(const atools::sql::SqlRecord *rec, atools::util::HtmlBuilder& html) const;
void addAirportScenery(const map::MapAirport& airport, atools::util::HtmlBuilder& html) const;
@@ -370,6 +386,7 @@ class HtmlInfoBuilder
atools::fs::util::MorseCode *morse;
bool info, print;
QLocale locale;
+
};
#endif // MAPHTMLINFOBUILDER
diff --git a/src/common/maptypes.cpp b/src/common/maptypes.cpp
index 1fa2e3ac9..acf38e5d3 100644
--- a/src/common/maptypes.cpp
+++ b/src/common/maptypes.cpp
@@ -1147,11 +1147,21 @@ QString vorText(const MapVor& vor)
return QObject::tr("%1 %2 (%3)").arg(vorType(vor)).arg(atools::capString(vor.name)).arg(vor.ident);
}
+QString vorTextShort(const MapVor& vor)
+{
+ return QObject::tr("%1 (%2)").arg(atools::capString(vor.name)).arg(vor.ident);
+}
+
QString ndbText(const MapNdb& ndb)
{
return QObject::tr("NDB %1 (%2)").arg(atools::capString(ndb.name)).arg(ndb.ident);
}
+QString ndbTextShort(const MapNdb& ndb)
+{
+ return QObject::tr("%1 (%2)").arg(atools::capString(ndb.name)).arg(ndb.ident);
+}
+
QString waypointText(const MapWaypoint& waypoint)
{
return QObject::tr("Waypoint %1").arg(waypoint.ident);
@@ -2023,7 +2033,7 @@ QString ilsText(const MapIls& ils)
QString::number(ils.frequency / 1000., 'f', 2) + " / " +
QString::number(atools::geo::normalizeCourse(ils.heading - ils.magvar), 'f', 0) + QObject::tr("°M");
- if(ils.slope > 0)
+ if(ils.slope > 0.1f)
text += QObject::tr(" / GS ") + QString::number(ils.slope, 'f', 1) + QObject::tr("°");
if(ils.hasDme)
text += QObject::tr(" / DME");
@@ -2031,11 +2041,16 @@ QString ilsText(const MapIls& ils)
return text;
}
-QString ilsTextShort(map::MapIls& ils)
+QString ilsTextShort(const map::MapIls& ils)
{
return ilsTextShort(ils.ident, ils.name, ils.slope > 0.f, ils.hasDme);
}
+QString ilsType(const map::MapIls& ils)
+{
+ return ils.slope > 0.f ? QObject::tr("ILS") : QObject::tr("LOC");
+}
+
QString ilsTextShort(QString ident, QString name, bool gs, bool dme)
{
QString text;
@@ -2113,7 +2128,7 @@ void MapSearchResultMixed::addFromResult(const MapSearchResult& result, const Ma
addCopyAll(result.logbookEntries);
}
-void MapSearchResultMixed::sortByDistance(const atools::geo::Pos& pos, bool reverse)
+void MapSearchResultMixed::sortByDistance(const atools::geo::Pos& pos, bool sortNearToFar)
{
if(vector.isEmpty() || !pos.isValid())
return;
@@ -2122,7 +2137,7 @@ void MapSearchResultMixed::sortByDistance(const atools::geo::Pos& pos, bool reve
[ = ](const MapBase *obj1, const MapBase *obj2) -> bool
{
bool result = obj1->getPosition().distanceMeterTo(pos) < obj2->getPosition().distanceMeterTo(pos);
- return reverse ? result : !result;
+ return sortNearToFar ? result : !result;
});
}
diff --git a/src/common/maptypes.h b/src/common/maptypes.h
index 6cfd3286d..ea9c75ea8 100644
--- a/src/common/maptypes.h
+++ b/src/common/maptypes.h
@@ -104,12 +104,21 @@ bool isSoftSurface(const QString& surface);
// =====================================================================
/* Base struct for all map objects covering id and position
- * Position is used to check for validity, i.e. not initialized objects */
+ * Position is used to check for validity, i.e. not initialized objects
+ * Object type can be NONE if no polymorphism is needed */
struct MapBase
{
+ MapBase(map::MapObjectType type)
+ : objType(type)
+ {
+ }
+
int id;
atools::geo::Pos position;
+ /* Use simple type information to avoid vtable and RTTI overhead. Avoid QFlags here. */
+ map::MapObjectType objType;
+
bool isValid() const
{
return position.isValid();
@@ -125,6 +134,15 @@ struct MapBase
return id;
}
+ template
+ const TYPE *asType(map::MapObjectTypes type) const
+ {
+ if(objType == type)
+ return static_cast(this);
+ else
+ return nullptr;
+ }
+
};
// =====================================================================
@@ -133,6 +151,10 @@ struct MapBase
struct MapAirport
: public MapBase
{
+ MapAirport() : MapBase(map::AIRPORT)
+ {
+ }
+
QString ident, /* ICAO ident*/ name, region;
int longestRunwayLength = 0, longestRunwayHeading = 0, transitionAltitude = 0;
int rating = -1;
@@ -192,6 +214,10 @@ struct MapAirport
struct MapRunway
: public MapBase
{
+ MapRunway() : MapBase(map::NONE)
+ {
+ }
+
QString surface, shoulder, primaryName, secondaryName, edgeLight;
int length /* ft */, primaryEndId, secondaryEndId;
float heading, patternAlt;
@@ -243,6 +269,10 @@ struct MapRunway
struct MapRunwayEnd
: public MapBase
{
+ MapRunwayEnd() : MapBase(map::RUNWAYEND)
+ {
+ }
+
QString name, leftVasiType, rightVasiType, pattern;
float heading, leftVasiPitch = 0.f, rightVasiPitch = 0.f;
bool secondary;
@@ -254,6 +284,10 @@ struct MapRunwayEnd
struct MapApron
: public MapBase
{
+ MapApron() : MapBase(map::NONE)
+ {
+ }
+
/* FSX/P3D simple geometry */
atools::geo::LineString vertices;
@@ -291,6 +325,10 @@ struct MapTaxiPath
struct MapParking
: public MapBase
{
+ MapParking() : MapBase(map::PARKING)
+ {
+ }
+
QString type, name, airlineCodes /* Comma separated list of airline codes */;
int airportId /* database id airport.airport_id */;
int number, /* -1 for X-Plane style free names. Otherwise FSX/P3D number */
@@ -304,6 +342,10 @@ struct MapParking
struct MapStart
: public MapBase
{
+ MapStart() : MapBase(map::NONE)
+ {
+ }
+
QString type /* RUNWAY, HELIPAD or WATER */, runwayName /* not empty if this is a runway start */;
int airportId /* database id airport.airport_id */;
int heading, helipadNumber /* -1 if not a helipad otherwise sequence number as it appeared in the BGL */;
@@ -314,6 +356,10 @@ struct MapStart
struct MapHelipad
: public MapBase
{
+ MapHelipad() : MapBase(map::HELIPAD)
+ {
+ }
+
QString surface, type, runwayName;
int startId, airportId, length, width, heading, start;
bool closed, transparent;
@@ -325,6 +371,10 @@ struct MapHelipad
struct MapVor
: public MapBase
{
+ MapVor() : MapBase(map::VOR)
+ {
+ }
+
QString ident, region, type /* HIGH, LOW, TERMINAL */, name /*, airportIdent*/;
float magvar;
int frequency /* MHz * 1000 */, range /* nm */;
@@ -348,6 +398,10 @@ struct MapVor
struct MapNdb
: public MapBase
{
+ MapNdb() : MapBase(map::NDB)
+ {
+ }
+
QString ident, region, type /* HH, H, COMPASS_POINT, etc. */, name /*, airportIdent*/;
float magvar;
int frequency /* kHz * 100 */, range /* nm */;
@@ -359,6 +413,10 @@ struct MapNdb
struct MapWaypoint
: public MapBase
{
+ MapWaypoint() : MapBase(map::WAYPOINT)
+ {
+ }
+
float magvar;
QString ident, region, type /* NAMED, UNAMED, etc. *//*, airportIdent*/;
int routeIndex = -1; /* Filled by the get nearest methods for building the context menu */
@@ -379,6 +437,10 @@ struct MapAirwayWaypoint
struct MapUserpointRoute
: public MapBase
{
+ MapUserpointRoute() : MapBase(map::USERPOINTROUTE)
+ {
+ }
+
QString name;
float magvar;
int routeIndex = -1; /* Filled by the get nearest methods for building the context menu */
@@ -389,6 +451,10 @@ struct MapUserpointRoute
struct MapUserpoint
: public MapBase
{
+ MapUserpoint() : MapBase(map::USERPOINT)
+ {
+ }
+
QString name, ident, region, type, description, tags;
bool temp = false;
};
@@ -398,6 +464,10 @@ struct MapUserpoint
struct MapLogbookEntry
: public MapBase
{
+ MapLogbookEntry() : MapBase(map::LOGBOOK)
+ {
+ }
+
QString departureName, departureIdent, departureRunway,
destinationName, destinationIdent, destinationRunway,
description, simulator, aircraftType,
@@ -443,6 +513,10 @@ enum MapAirwayDirection
struct MapAirway
: public MapBase
{
+ MapAirway() : MapBase(map::AIRWAY)
+ {
+ }
+
QString name;
map::MapAirwayType type;
int fromWaypointId, toWaypointId /* all database ids */;
@@ -461,6 +535,10 @@ struct MapAirway
struct MapMarker
: public MapBase
{
+ MapMarker() : MapBase(map::MARKER)
+ {
+ }
+
QString type, ident;
int heading;
};
@@ -471,6 +549,10 @@ struct MapMarker
struct MapIls
: public MapBase
{
+ MapIls() : MapBase(map::ILS)
+ {
+ }
+
QString ident, name, region;
float magvar, slope, heading, width;
int frequency /* MHz * 1000 */, range /* nm */;
@@ -487,6 +569,10 @@ struct MapIls
struct MapAirspace
: public MapBase
{
+ MapAirspace() : MapBase(map::AIRSPACE)
+ {
+ }
+
int minAltitude, maxAltitude;
QString name, /* Airspace name or callsign for online ATC */
comName, comType, minAltitudeType, maxAltitudeType,
@@ -679,7 +765,7 @@ struct MapSearchResultMixed
void addFromResult(const map::MapSearchResult& result, const MapObjectTypes& types = map::ALL);
/* Sort objects by distance to given position from closest to farthest */
- void sortByDistance(const atools::geo::Pos& pos, bool reverse);
+ void sortByDistance(const atools::geo::Pos& pos, bool sortNearToFar);
/* Remove all objects which are more far away from pos than max distance */
void filterByDistance(const atools::geo::Pos& pos, float maxDistanceNm);
@@ -854,7 +940,8 @@ const QString& navTypeNameNdb(const QString& type);
const QString& navTypeNameWaypoint(const QString& type);
QString ilsText(const map::MapIls& ils);
-QString ilsTextShort(map::MapIls& ils);
+QString ilsType(const MapIls& ils);
+QString ilsTextShort(const MapIls& ils);
QString ilsTextShort(QString ident, QString name, bool gs, bool dme);
QString edgeLights(const QString& type);
@@ -913,9 +1000,11 @@ QString airportText(const map::MapAirport& airport, int elideName = 1000);
QString airportTextShort(const map::MapAirport& airport);
QString vorFullShortText(const map::MapVor& vor);
QString vorText(const map::MapVor& vor);
+QString vorTextShort(const MapVor& vor);
QString vorType(const map::MapVor& vor);
QString ndbFullShortText(const map::MapNdb& ndb);
QString ndbText(const map::MapNdb& ndb);
+QString ndbTextShort(const MapNdb& ndb);
QString waypointText(const map::MapWaypoint& waypoint);
QString userpointRouteText(const map::MapUserpointRoute& userpoint);
QString userpointText(const MapUserpoint& userpoint);
diff --git a/src/common/tabindexes.h b/src/common/tabindexes.h
index ca29c25cb..37300b904 100644
--- a/src/common/tabindexes.h
+++ b/src/common/tabindexes.h
@@ -38,12 +38,13 @@ enum TabIndex
INFO_RUNWAYS = 1,
INFO_COM = 2,
INFO_APPROACHES = 3,
- INFO_WEATHER = 4,
- INFO_NAVAID = 5,
- INFO_AIRSPACE = 6,
- INFO_LOGBOOK = 7,
- INFO_ONLINE_CLIENT = 8,
- INFO_ONLINE_CENTER = 9
+ INFO_NEAREST = 4,
+ INFO_WEATHER = 5,
+ INFO_NAVAID = 6,
+ INFO_AIRSPACE = 7,
+ INFO_LOGBOOK = 8,
+ INFO_ONLINE_CLIENT = 9,
+ INFO_ONLINE_CENTER = 10
};
/* Info controller aircraft progress tabs */
diff --git a/src/gui/mainwindow.ui b/src/gui/mainwindow.ui
index f1aad391a..1ea5f2a78 100644
--- a/src/gui/mainwindow.ui
+++ b/src/gui/mainwindow.ui
@@ -4906,6 +4906,41 @@ Wind speed will be interpolated for climb and descent phases.
+
+
+ Nearest
+
+
+ Nearest navaids and airports in relation to airport
+
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+ -
+
+
+ No airport selected.
+
+
+ false
+
+
+
+
+
Weather
diff --git a/src/info/infocontroller.cpp b/src/info/infocontroller.cpp
index 4e95cd65d..9aa2c8718 100644
--- a/src/info/infocontroller.cpp
+++ b/src/info/infocontroller.cpp
@@ -70,6 +70,7 @@ InfoController::InfoController(MainWindow *parent)
ui->textBrowserRunwayInfo->setSearchPaths(paths);
ui->textBrowserComInfo->setSearchPaths(paths);
ui->textBrowserApproachInfo->setSearchPaths(paths);
+ ui->textBrowserNearest->setSearchPaths(paths);
ui->textBrowserWeatherInfo->setSearchPaths(paths);
ui->textBrowserNavaidInfo->setSearchPaths(paths);
ui->textBrowserAirspaceInfo->setSearchPaths(paths);
@@ -86,6 +87,7 @@ InfoController::InfoController(MainWindow *parent)
connect(ui->textBrowserRunwayInfo, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
connect(ui->textBrowserComInfo, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
connect(ui->textBrowserApproachInfo, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
+ connect(ui->textBrowserNearest, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
connect(ui->textBrowserWeatherInfo, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
connect(ui->textBrowserNavaidInfo, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
connect(ui->textBrowserAirspaceInfo, &QTextBrowser::anchorClicked, this, &InfoController::anchorClicked);
@@ -154,6 +156,7 @@ void InfoController::currentInfoTabChanged(int index)
case ic::INFO_RUNWAYS:
case ic::INFO_COM:
case ic::INFO_APPROACHES:
+ case ic::INFO_NEAREST:
case ic::INFO_WEATHER:
case ic::INFO_AIRSPACE:
case ic::INFO_LOGBOOK:
@@ -444,6 +447,7 @@ void InfoController::clearInfoTextBrowsers()
ui->textBrowserRunwayInfo->clear();
ui->textBrowserComInfo->clear();
ui->textBrowserApproachInfo->clear();
+ ui->textBrowserNearest->clear();
ui->textBrowserWeatherInfo->clear();
ui->textBrowserNavaidInfo->clear();
ui->textBrowserLogbookInfo->clear();
@@ -588,6 +592,11 @@ void InfoController::showInformationInternal(map::MapSearchResult result, map::M
atools::gui::util::updateTextEdit(ui->textBrowserApproachInfo, html.getHtml(),
scrollToTop, !scrollToTop /* keep selection */);
+ html.clear();
+ infoBuilder->nearestText(airport, html);
+ atools::gui::util::updateTextEdit(ui->textBrowserNearest, html.getHtml(),
+ scrollToTop, !scrollToTop /* keep selection */);
+
foundAirport = true;
}
@@ -726,7 +735,7 @@ void InfoController::showInformationInternal(map::MapSearchResult result, map::M
ic::TabIndex idx = static_cast(ui->tabWidgetInformation->currentIndex());
// Is any airport related tab active?
bool airportActive = idx == ic::INFO_AIRPORT || idx == ic::INFO_RUNWAYS || idx == ic::INFO_COM ||
- idx == ic::INFO_APPROACHES || idx == ic::INFO_WEATHER;
+ idx == ic::INFO_APPROACHES || idx == ic::INFO_NEAREST || idx == ic::INFO_WEATHER;
ic::TabIndex newIdx = idx;
@@ -784,6 +793,7 @@ void InfoController::showInformationInternal(map::MapSearchResult result, map::M
case ic::INFO_RUNWAYS:
case ic::INFO_COM:
case ic::INFO_APPROACHES:
+ case ic::INFO_NEAREST:
case ic::INFO_WEATHER:
mainWindow->setStatusMessage(tr("Showing information for airport."));
break;
@@ -1143,6 +1153,7 @@ void InfoController::updateTextEditFontSizes()
setTextEditFontSize(ui->textBrowserRunwayInfo, infoFontPtSize, sizePercent);
setTextEditFontSize(ui->textBrowserComInfo, infoFontPtSize, sizePercent);
setTextEditFontSize(ui->textBrowserApproachInfo, infoFontPtSize, sizePercent);
+ setTextEditFontSize(ui->textBrowserNearest, infoFontPtSize, sizePercent);
setTextEditFontSize(ui->textBrowserWeatherInfo, infoFontPtSize, sizePercent);
setTextEditFontSize(ui->textBrowserNavaidInfo, infoFontPtSize, sizePercent);
setTextEditFontSize(ui->textBrowserAirspaceInfo, infoFontPtSize, sizePercent);
diff --git a/src/mapgui/mapscreenindex.cpp b/src/mapgui/mapscreenindex.cpp
index 36cd19461..ad8018c19 100644
--- a/src/mapgui/mapscreenindex.cpp
+++ b/src/mapgui/mapscreenindex.cpp
@@ -497,7 +497,7 @@ void MapScreenIndex::getAllNearest(int xs, int ys, int maxDistance, map::MapSear
getNearestHighlights(xs, ys, maxDistance, result);
// Get objects from cache - already present objects will be skipped
- mapQuery->getNearestObjects(conv, mapLayer, mapLayerEffective->isAirportDiagram(),
+ mapQuery->getNearestScreenObjects(conv, mapLayer, mapLayerEffective->isAirportDiagram(),
shown &
(map::AIRPORT_ALL | map::VOR | map::NDB | map::WAYPOINT |
map::MARKER | map::AIRWAYJ | map::AIRWAYV | map::USERPOINT | map::LOGBOOK),
diff --git a/src/mappainter/mappainterils.cpp b/src/mappainter/mappainterils.cpp
index 88e361bff..e1ee8d247 100644
--- a/src/mappainter/mappainterils.cpp
+++ b/src/mappainter/mappainterils.cpp
@@ -96,7 +96,7 @@ void MapPainterIls::drawIlsSymbol(const PaintContext *context, const map::MapIls
QPoint p1 = wToS(ils.pos1, size, &visible);
QPoint p2 = wToS(ils.pos2, size, &visible);
- if(ils.slope > 0.f)
+ if(ils.slope > 0.1f)
{
context->painter->drawPolygon(QPolygonF({origin, p1, p2, origin}));
context->painter->drawPolyline(QPolygonF({p1, pmid, p2}));
diff --git a/src/online/onlinedatacontroller.cpp b/src/online/onlinedatacontroller.cpp
index 220b4de8a..2fcdaa2d6 100644
--- a/src/online/onlinedatacontroller.cpp
+++ b/src/online/onlinedatacontroller.cpp
@@ -505,7 +505,7 @@ const QList *OnlinedataController::getAircra
for(const Marble::GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, aircraftByRectQuery);
+ query::bindRect(r, aircraftByRectQuery);
aircraftByRectQuery->exec();
while(aircraftByRectQuery->next())
{
diff --git a/src/query/airportquery.cpp b/src/query/airportquery.cpp
index 9491596f8..a0cc97dae 100644
--- a/src/query/airportquery.cpp
+++ b/src/query/airportquery.cpp
@@ -20,6 +20,7 @@
#include "common/constants.h"
#include "common/maptypesfactory.h"
#include "common/maptools.h"
+#include "query/querytypes.h"
#include "fs/common/binarygeometry.h"
#include "sql/sqlquery.h"
#include "sql/sqlrecord.h"
@@ -39,6 +40,11 @@ using map::MapAirport;
using map::MapParking;
using map::MapHelipad;
+inline uint qHash(const AirportQuery::NearestCacheKeyAirport& key)
+{
+ return qHash(key.pos) ^ qHash(key.distanceNm) ^ key.sortNearToFar;
+}
+
/* maximum difference in angle for aircraft to recognize the right runway */
const static float MAX_HEADING_RUNWAY_DEVIATION = 20.f;
const static float MAX_RUNWAY_DISTANCE_FT = 5000.f;
@@ -501,6 +507,38 @@ const QList *AirportQuery::getHelipads(int airportId)
}
}
+map::MapSearchResultMixed *AirportQuery::getNearestAirportsProc(const Pos& pos, float distanceNm,
+ bool sortNearToFar)
+{
+ NearestCacheKeyAirport key = {pos, distanceNm, sortNearToFar};
+
+ map::MapSearchResultMixed *result = nearestAirportCache.object(key);
+
+ if(result == nullptr)
+ {
+ result = new map::MapSearchResultMixed;
+
+ // Create a rectangle that roughly covers the requested region
+ atools::geo::Rect rect(pos, atools::geo::nmToMeter(distanceNm));
+
+ bool xplane = NavApp::getCurrentSimulatorDb() == atools::fs::FsPaths::XPLANE11;
+ query::fetchObjectsForRect(rect, airportByRectAndProcQuery, [ = ](atools::sql::SqlQuery *query) -> void {
+ map::MapAirport obj;
+ mapTypesFactory->fillAirport(query->record(), obj, true, navdata, xplane);
+ result->addCopy(obj);
+ });
+
+ // Remove all that are too far away
+ result->filterByDistance(pos, distanceNm);
+
+ // Sort the rest by distance
+ result->sortByDistance(pos, sortNearToFar);
+
+ nearestAirportCache.insert(key, result);
+ }
+ return result;
+}
+
void AirportQuery::getBestRunwayEndAndAirport(map::MapRunwayEnd& runwayEnd, map::MapAirport& airport,
const QVector& runways, const atools::geo::Pos& pos,
float heading)
@@ -801,6 +839,10 @@ void AirportQuery::initQueries()
airportCoordsByIdentQuery = new SqlQuery(db);
airportCoordsByIdentQuery->prepare("select lonx, laty from airport where ident = :ident ");
+ airportByRectAndProcQuery = new SqlQuery(db);
+ airportByRectAndProcQuery->prepare("select " + airportQueryBase.join(", ") + " from airport where " + whereRect +
+ " and num_approach > 0 " + whereLimit);
+
runwayEndByIdQuery = new SqlQuery(db);
runwayEndByIdQuery->prepare("select runway_end_id, end_type, name, heading, left_vasi_pitch, right_vasi_pitch, is_pattern, "
"left_vasi_type, right_vasi_type, "
@@ -942,6 +984,9 @@ void AirportQuery::deInitQueries()
delete airportCoordsByIdentQuery;
airportCoordsByIdentQuery = nullptr;
+ delete airportByRectAndProcQuery;
+ airportByRectAndProcQuery = nullptr;
+
delete runwayEndByIdQuery;
runwayEndByIdQuery = nullptr;
diff --git a/src/query/airportquery.h b/src/query/airportquery.h
index 4df619632..1d54d786c 100644
--- a/src/query/airportquery.h
+++ b/src/query/airportquery.h
@@ -126,6 +126,10 @@ class AirportQuery
const QList *getHelipads(int airportId);
+ /* Get nearest airports that have a procedure sorted by distance to pos with a maximum distance distanceNm */
+ map::MapSearchResultMixed *getNearestAirportsProc(const atools::geo::Pos& pos, float distanceNm,
+ bool sortNearToFar = true);
+
/* Get a list of runways of all airports inside rectangle sorted by distance to pos */
void getRunways(QVector& runways, const atools::geo::Rect& rect, const atools::geo::Pos& pos);
@@ -150,6 +154,28 @@ class AirportQuery
static QStringList airportOverviewColumns(const atools::sql::SqlDatabase *db);
private:
+ /* Key for nearestCache combining all query parameters */
+ struct NearestCacheKeyAirport
+ {
+ atools::geo::Pos pos;
+ float distanceNm;
+ bool sortNearToFar;
+
+ bool operator==(const NearestCacheKeyAirport& other) const
+ {
+ return pos == other.pos && std::abs(distanceNm - other.distanceNm) < 0.01 &&
+ sortNearToFar == other.sortNearToFar;
+ }
+
+ bool operator!=(const NearestCacheKeyAirport& other) const
+ {
+ return !operator==(other);
+ }
+
+ };
+
+ friend inline uint qHash(const AirportQuery::NearestCacheKeyAirport& key);
+
const QList *fetchAirports(const Marble::GeoDataLatLonBox& rect,
atools::sql::SqlQuery *query, bool reverse,
bool lazy, bool overview);
@@ -175,6 +201,7 @@ class AirportQuery
QCache airportIdentCache;
QCache airportIdCache;
+ QCache nearestAirportCache;
/* Database queries */
atools::sql::SqlQuery *runwayOverviewQuery = nullptr, *apronQuery = nullptr,
@@ -184,10 +211,10 @@ class AirportQuery
*parkingTypeAndNumberQuery = nullptr,
*parkingNameQuery = nullptr;
- atools::sql::SqlQuery *airportByIdentQuery = nullptr, *airportCoordsByIdentQuery = nullptr;
- atools::sql::SqlQuery *runwayEndByIdQuery = nullptr, *runwayEndByNameQuery = nullptr;
- atools::sql::SqlQuery *airportByIdQuery = nullptr, *airportAdminByIdQuery = nullptr,
- *airportProcByIdentQuery = nullptr,
+ atools::sql::SqlQuery *airportByIdentQuery = nullptr, *airportCoordsByIdentQuery = nullptr,
+ *airportByRectAndProcQuery = nullptr,
+ *runwayEndByIdQuery = nullptr, *runwayEndByNameQuery = nullptr, *airportByIdQuery = nullptr,
+ *airportAdminByIdQuery = nullptr, *airportProcByIdentQuery = nullptr,
*procArrivalByAirportIdentQuery = nullptr, *procDepartureByAirportIdentQuery = nullptr;
};
diff --git a/src/query/airspacequery.cpp b/src/query/airspacequery.cpp
index 72f46da78..19a3b28bf 100644
--- a/src/query/airspacequery.cpp
+++ b/src/query/airspacequery.cpp
@@ -196,7 +196,7 @@ const QList *AirspaceQuery::getAirspaces(const GeoDataLatLonBo
for(const QString& typeStr : typeStrings)
{
- query::bindCoordinatePointInRect(r, query);
+ query::bindRect(r, query);
query->bindValue(":type", typeStr);
if(alt > 0)
diff --git a/src/query/mapquery.cpp b/src/query/mapquery.cpp
index 8e9bf0d50..40258eca9 100644
--- a/src/query/mapquery.cpp
+++ b/src/query/mapquery.cpp
@@ -49,6 +49,11 @@ using map::MapParking;
using map::MapHelipad;
using map::MapUserpoint;
+inline uint qHash(const MapQuery::NearestCacheKeyNavaid& key)
+{
+ return qHash(key.pos) ^ qHash(key.type) ^ qHash(key.distanceNm) ^ key.sortNearToFar;
+}
+
static double queryRectInflationFactor = 0.2;
static double queryRectInflationIncrement = 0.1;
int MapQuery::queryMaxRows = 5000;
@@ -147,6 +152,66 @@ void MapQuery::getNdbNearest(map::MapNdb& ndb, const atools::geo::Pos& pos)
ndbNearestQuery->finish();
}
+map::MapSearchResultMixed *MapQuery::getNearestNavaids(const Pos& pos, float distanceNm, map::MapObjectTypes type,
+ bool sortNearToFar)
+{
+ NearestCacheKeyNavaid key = {pos, distanceNm, type, sortNearToFar};
+
+ map::MapSearchResultMixed *result = nearestNavaidCache.object(key);
+
+ if(result == nullptr)
+ {
+ result = new map::MapSearchResultMixed;
+
+ // Create a rectangle that roughly covers the requested region
+ atools::geo::Rect rect(pos, atools::geo::nmToMeter(distanceNm));
+
+ if(type & map::VOR)
+ {
+ query::fetchObjectsForRect(rect, vorsByRectQuery, [ = ](atools::sql::SqlQuery *query) -> void {
+ map::MapVor obj;
+ mapTypesFactory->fillVor(query->record(), obj);
+ result->addCopy(obj);
+ });
+ }
+
+ if(type & map::NDB)
+ {
+ query::fetchObjectsForRect(rect, ndbsByRectQuery, [ = ](atools::sql::SqlQuery *query) -> void {
+ map::MapNdb obj;
+ mapTypesFactory->fillNdb(query->record(), obj);
+ result->addCopy(obj);
+ });
+ }
+
+ if(type & map::WAYPOINT)
+ {
+ query::fetchObjectsForRect(rect, waypointsByRectQuery, [ = ](atools::sql::SqlQuery *query) -> void {
+ map::MapWaypoint obj;
+ mapTypesFactory->fillWaypoint(query->record(), obj);
+ result->addCopy(obj);
+ });
+ }
+
+ if(type & map::ILS)
+ {
+ query::fetchObjectsForRect(rect, ilsByRectQuery, [ = ](atools::sql::SqlQuery *query) -> void {
+ map::MapIls obj;
+ mapTypesFactory->fillIls(query->record(), obj);
+ result->addCopy(obj);
+ });
+ }
+ // Remove all that are too far away
+ result->filterByDistance(pos, distanceNm);
+
+ // Sort the rest by distance
+ result->sortByDistance(pos, sortNearToFar);
+
+ nearestNavaidCache.insert(key, result);
+ }
+ return result;
+}
+
void MapQuery::getAirwaysForWaypoint(QList& airways, int waypointId)
{
airwayByWaypointIdQuery->bindValue(":id", waypointId);
@@ -523,10 +588,10 @@ map::MapUserpoint MapQuery::getUserdataPointById(int id)
return up;
}
-void MapQuery::getNearestObjects(const CoordinateConverter& conv, const MapLayer *mapLayer,
- bool airportDiagram, map::MapObjectTypes types,
- int xs, int ys, int screenDistance,
- map::MapSearchResult& result)
+void MapQuery::getNearestScreenObjects(const CoordinateConverter& conv, const MapLayer *mapLayer,
+ bool airportDiagram, map::MapObjectTypes types,
+ int xs, int ys, int screenDistance,
+ map::MapSearchResult& result)
{
using maptools::insertSortedByDistance;
using maptools::insertSortedByTowerDistance;
@@ -710,7 +775,7 @@ const QList *MapQuery::getWaypoints(const GeoDataLatLonBox& re
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, waypointsByRectQuery);
+ query::bindRect(r, waypointsByRectQuery);
waypointsByRectQuery->exec();
while(waypointsByRectQuery->next())
{
@@ -738,7 +803,7 @@ const QList *MapQuery::getVors(const GeoDataLatLonBox& rect, const
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, vorsByRectQuery);
+ query::bindRect(r, vorsByRectQuery);
vorsByRectQuery->exec();
while(vorsByRectQuery->next())
{
@@ -766,7 +831,7 @@ const QList *MapQuery::getNdbs(const GeoDataLatLonBox& rect, const
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, ndbsByRectQuery);
+ query::bindRect(r, ndbsByRectQuery);
ndbsByRectQuery->exec();
while(ndbsByRectQuery->next())
{
@@ -796,7 +861,7 @@ const QList MapQuery::getUserdataPoints(const GeoDataLatLonBo
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, userdataPointByRectQuery);
+ query::bindRect(r, userdataPointByRectQuery);
userdataPointByRectQuery->bindValue(":dist", distance);
QStringList queryTypes;
@@ -849,7 +914,7 @@ const QList *MapQuery::getMarkers(const GeoDataLatLonBox& rect,
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, markersByRectQuery);
+ query::bindRect(r, markersByRectQuery);
markersByRectQuery->exec();
while(markersByRectQuery->next())
{
@@ -883,7 +948,7 @@ const QList *MapQuery::getIls(GeoDataLatLonBox rect, const MapLayer
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, ilsByRectQuery);
+ query::bindRect(r, ilsByRectQuery);
ilsByRectQuery->exec();
while(ilsByRectQuery->next())
@@ -912,7 +977,7 @@ const QList *MapQuery::getAirways(const GeoDataLatLonBox& rect,
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, airwayByRectQuery);
+ query::bindRect(r, airwayByRectQuery);
airwayByRectQuery->exec();
while(airwayByRectQuery->next())
{
@@ -955,7 +1020,7 @@ const QList *MapQuery::fetchAirports(const Marble::GeoDataLatLo
for(const GeoDataLatLonBox& r :
query::splitAtAntiMeridian(rect, queryRectInflationFactor, queryRectInflationIncrement))
{
- query::bindCoordinatePointInRect(r, query);
+ query::bindRect(r, query);
query->exec();
while(query->next())
{
diff --git a/src/query/mapquery.h b/src/query/mapquery.h
index edcf276d3..6e1500c0f 100644
--- a/src/query/mapquery.h
+++ b/src/query/mapquery.h
@@ -139,9 +139,14 @@ class MapQuery
* @param screenDistance maximum distance to coordinates
* @param result will receive objects based on type
*/
- void getNearestObjects(const CoordinateConverter& conv, const MapLayer *mapLayer, bool airportDiagram,
- map::MapObjectTypes types, int xs, int ys, int screenDistance,
- map::MapSearchResult& result);
+ void getNearestScreenObjects(const CoordinateConverter& conv, const MapLayer *mapLayer, bool airportDiagram,
+ map::MapObjectTypes types, int xs, int ys, int screenDistance,
+ map::MapSearchResult& result);
+
+ /* Only VOR, NDB, ILS and waypoints */
+ /* All sorted by distance to pos with a maximum distance distanceNm */
+ map::MapSearchResultMixed *getNearestNavaids(const atools::geo::Pos& pos, float distanceNm,
+ map::MapObjectTypes type, bool sortNearToFar = true);
/*
* Fetch airports for a map coordinate rectangle
@@ -187,6 +192,29 @@ class MapQuery
void deInitQueries();
private:
+ /* Key for nearestCache combining all query parameters */
+ struct NearestCacheKeyNavaid
+ {
+ atools::geo::Pos pos;
+ float distanceNm;
+ map::MapObjectTypes type;
+ bool sortNearToFar;
+
+ bool operator==(const NearestCacheKeyNavaid& other) const
+ {
+ return pos == other.pos && std::abs(distanceNm - other.distanceNm) < 0.01 && type == other.type &&
+ sortNearToFar == other.sortNearToFar;
+ }
+
+ bool operator!=(const NearestCacheKeyNavaid& other) const
+ {
+ return !operator==(other);
+ }
+
+ };
+
+ friend inline uint qHash(const MapQuery::NearestCacheKeyNavaid& key);
+
void mapObjectByIdentInternal(map::MapSearchResult& result, map::MapObjectTypes type,
const QString& ident, const QString& region, const QString& airport,
const atools::geo::Pos& sortByDistancePos,
@@ -213,6 +241,7 @@ class MapQuery
/* ID/object caches */
QCache > runwayOverwiewCache;
+ QCache nearestNavaidCache;
static int queryMaxRows;
diff --git a/src/query/querytypes.cpp b/src/query/querytypes.cpp
index f59db4ed7..358c7f270 100644
--- a/src/query/querytypes.cpp
+++ b/src/query/querytypes.cpp
@@ -18,6 +18,7 @@
#include "query/querytypes.h"
#include "sql/sqlquery.h"
+#include "geo/rect.h"
using namespace Marble;
@@ -47,8 +48,8 @@ void inflateQueryRect(Marble::GeoDataLatLonBox& rect, double factor, double incr
* @param query
* @param prefix used to prefix each bind variable
*/
-void bindCoordinatePointInRect(const Marble::GeoDataLatLonBox& rect, atools::sql::SqlQuery *query,
- const QString& prefix)
+void bindRect(const Marble::GeoDataLatLonBox& rect, atools::sql::SqlQuery *query,
+ const QString& prefix)
{
query->bindValue(":" + prefix + "leftx", rect.west(GeoDataCoordinates::Degree));
query->bindValue(":" + prefix + "rightx", rect.east(GeoDataCoordinates::Degree));
@@ -56,6 +57,15 @@ void bindCoordinatePointInRect(const Marble::GeoDataLatLonBox& rect, atools::sql
query->bindValue(":" + prefix + "topy", rect.north(GeoDataCoordinates::Degree));
}
+void bindRect(const atools::geo::Rect& rect, atools::sql::SqlQuery *query,
+ const QString& prefix)
+{
+ query->bindValue(":" + prefix + "leftx", rect.getWest());
+ query->bindValue(":" + prefix + "rightx", rect.getEast());
+ query->bindValue(":" + prefix + "bottomy", rect.getSouth());
+ query->bindValue(":" + prefix + "topy", rect.getNorth());
+}
+
/* Inflates the rectangle and splits it at the antimeridian (date line) if it overlaps */
QList splitAtAntiMeridian(const Marble::GeoDataLatLonBox& rect, double factor,
double increment)
@@ -84,4 +94,16 @@ QList splitAtAntiMeridian(const Marble::GeoDataLatLonB
return QList({newRect});
}
+void fetchObjectsForRect(const atools::geo::Rect& rect, atools::sql::SqlQuery *query,
+ std::function callback)
+{
+ for(const atools::geo::Rect& r : rect.splitAtAntiMeridian())
+ {
+ query::bindRect(r, query);
+ query->exec();
+ while(query->next())
+ callback(query);
+ }
+}
+
}
diff --git a/src/query/querytypes.h b/src/query/querytypes.h
index cc3ba28c4..98ec6520f 100644
--- a/src/query/querytypes.h
+++ b/src/query/querytypes.h
@@ -26,6 +26,9 @@
#include
namespace atools {
+namespace geo {
+class Rect;
+}
namespace sql {
class SqlQuery;
}
@@ -34,8 +37,12 @@ class SqlQuery;
class MapLayer;
namespace query {
-void bindCoordinatePointInRect(const Marble::GeoDataLatLonBox& rect, atools::sql::SqlQuery *query,
- const QString& prefix = QString());
+void bindRect(const Marble::GeoDataLatLonBox& rect, atools::sql::SqlQuery *query, const QString& prefix = QString());
+void bindRect(const atools::geo::Rect& rect, atools::sql::SqlQuery *query, const QString& prefix = QString());
+
+/* Run query for rect potentially splitting at anti-meridian and call callback */
+void fetchObjectsForRect(const atools::geo::Rect& rect, atools::sql::SqlQuery *query,
+ std::function callback);
QList splitAtAntiMeridian(const Marble::GeoDataLatLonBox& rect, double factor,
double increment);
@@ -49,7 +56,7 @@ void inflateQueryRect(Marble::GeoDataLatLonBox& rect, double factor, double incr
template
struct SimpleRectCache
{
- typedef std::function LayerCompareFunc;
+ typedef std::function LayerCompareFunc;
/*
* @param rect bounding rectangle - all objects inside this rectangle are returned