File indexing completed on 2024-04-14 03:48:11

0001 // SPDX-FileCopyrightText: 2011 Friedrich W. H. Kossebau <kossebau@kde.org>
0002 // SPDX-License-Identifier: LGPL-2.1-or-later
0003 
0004 #include "plasmarunner.h"
0005 
0006 // Marble
0007 #include <GeoDataCoordinates.h>
0008 #include <GeoDataFolder.h>
0009 #include <GeoDataLookAt.h>
0010 #include <GeoDataPlacemark.h>
0011 #include <BookmarkManager.h>
0012 #include <GeoDataTreeModel.h>
0013 
0014 // KF
0015 #include <KLocalizedString>
0016 
0017 // Qt
0018 #include <QProcess>
0019 
0020 
0021 #define TRANSLATION_DOMAIN "plasma_runner_marble"
0022 
0023 namespace Marble
0024 {
0025 
0026 static const int minContainsMatchLength = 3;
0027 
0028 #if KRUNNER_VERSION >= QT_VERSION_CHECK(5, 77, 0)
0029     PlasmaRunner::PlasmaRunner(QObject *parent, const KPluginMetaData &pluginMetaData, const QVariantList &args)
0030   : AbstractRunner(parent, pluginMetaData, args)
0031 #else
0032     PlasmaRunner::PlasmaRunner(QObject *parent, const QVariantList &args)
0033   : AbstractRunner(parent, args)
0034 #endif
0035 {
0036     addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Shows the coordinates :q: in OpenStreetMap with Marble.")));
0037     addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Shows the geo bookmark containing :q: in OpenStreetMap with Marble.")));
0038 }
0039 
0040 void PlasmaRunner::match(Plasma::RunnerContext &context)
0041 {
0042     QList<Plasma::QueryMatch> matches;
0043 
0044     const QString query = context.query();
0045 
0046     bool success = false;
0047     // TODO: how to estimate that input is in Degree, not Radian?
0048     GeoDataCoordinates coordinates = GeoDataCoordinates::fromString(query, success);
0049 
0050     if (success) {
0051         const QVariant coordinatesData = QVariantList()
0052             << QVariant(coordinates.longitude(GeoDataCoordinates::Degree))
0053             << QVariant(coordinates.latitude(GeoDataCoordinates::Degree))
0054             << QVariant(0.1); // TODO: make this distance value configurable
0055 
0056         Plasma::QueryMatch match(this);
0057         match.setIcon(QIcon::fromTheme(QStringLiteral("marble")));
0058         match.setText(i18n("Show the coordinates %1 in OpenStreetMap with Marble", query));
0059         match.setData(coordinatesData);
0060         match.setId(query);
0061         match.setRelevance(1.0);
0062         match.setType(Plasma::QueryMatch::ExactMatch);
0063 
0064         matches << match;
0065     }
0066 
0067     // TODO: BookmarkManager does not yet listen to updates, also does not sync between processes :(
0068     // So for now always load on demand, even if expensive possibly
0069     BookmarkManager bookmarkManager(new GeoDataTreeModel);
0070     bookmarkManager.loadFile( QStringLiteral("bookmarks/bookmarks.kml") );
0071 
0072     for (GeoDataFolder* folder: bookmarkManager.folders()) {
0073         collectMatches(matches, query, folder);
0074     }
0075 
0076     if ( ! matches.isEmpty() ) {
0077         context.addMatches(matches);
0078     }
0079 }
0080 
0081 void PlasmaRunner::collectMatches(QList<Plasma::QueryMatch> &matches,
0082                                   const QString &query, const GeoDataFolder *folder)
0083 {
0084     const QString queryLower = query.toLower();
0085 
0086     QVector<GeoDataFeature*>::const_iterator it = folder->constBegin();
0087     QVector<GeoDataFeature*>::const_iterator end = folder->constEnd();
0088 
0089     for (; it != end; ++it) {
0090         GeoDataFolder *folder = dynamic_cast<GeoDataFolder*>(*it);
0091         if ( folder ) {
0092             collectMatches(matches, query, folder);
0093             continue;
0094         }
0095 
0096         GeoDataPlacemark *placemark = dynamic_cast<GeoDataPlacemark*>( *it );
0097         if ( placemark ) {
0098             // For short query strings only match exactly, to get a sane number of matches
0099             if (query.length() < minContainsMatchLength) {
0100                 if ( placemark->name().toLower() != queryLower &&
0101                      ( placemark->descriptionIsCDATA() || // TODO: support also with CDATA
0102                        placemark->description().toLower() != queryLower ) ) {
0103                     continue;
0104                 }
0105             } else {
0106                 if ( ! placemark->name().toLower().contains(queryLower) &&
0107                      ( placemark->descriptionIsCDATA() || // TODO: support also with CDATA
0108                        ! placemark->description().toLower().contains(queryLower) ) ) {
0109                     continue;
0110                 }
0111             }
0112 
0113             const GeoDataCoordinates coordinates = placemark->coordinate();
0114             const qreal lon = coordinates.longitude(GeoDataCoordinates::Degree);
0115             const qreal lat = coordinates.latitude(GeoDataCoordinates::Degree);
0116             const QVariant coordinatesData = QVariantList()
0117                 << QVariant(lon)
0118                 << QVariant(lat)
0119                 << QVariant(placemark->lookAt()->range()*METER2KM);
0120 
0121             Plasma::QueryMatch match(this);
0122             match.setIcon(QIcon::fromTheme(QStringLiteral("marble")));
0123             match.setText(placemark->name());
0124             match.setSubtext(i18n("Show in OpenStreetMap with Marble"));
0125             match.setData(coordinatesData);
0126             match.setId(placemark->name()+QString::number(lat)+QString::number(lon));
0127             match.setRelevance(1.0);
0128             match.setType(Plasma::QueryMatch::ExactMatch);
0129 
0130             matches << match;
0131         }
0132     }
0133 }
0134 
0135 void PlasmaRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match)
0136 {
0137     Q_UNUSED(context)
0138 
0139     const QVariantList data = match.data().toList();
0140 
0141     // pass in C locale, should be always understood
0142     const QString latLon =
0143         QString::number(data.at(1).toReal()) + QLatin1Char(' ') + QString::number(data.at(0).toReal());
0144 
0145     const QString distance = data.at(2).toString();
0146 
0147     const QStringList parameters = QStringList()
0148         << QStringLiteral( "--latlon" )
0149         << latLon
0150         << QStringLiteral( "--distance" )
0151         << distance
0152         << QStringLiteral( "--map" )
0153         << QStringLiteral( "earth/openstreetmap/openstreetmap.dgml" );
0154     QProcess::startDetached( QStringLiteral("marble"), parameters );
0155 }
0156 
0157 }
0158 
0159 #include "moc_plasmarunner.cpp"