File indexing completed on 2025-01-05 04:00:14

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2023-12-24
0007  * Description : geo-location setup page.
0008  *
0009  * SPDX-FileCopyrightText: 2022-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "setupgeolocation.h"
0016 
0017 // Qt includes
0018 
0019 #include <QApplication>
0020 #include <QStyle>
0021 #include <QVBoxLayout>
0022 #include <QLabel>
0023 #include <QFileInfo>
0024 #include <QFile>
0025 #include <QDir>
0026 #include <QUrl>
0027 #include <QStandardPaths>
0028 #include <QLineEdit>
0029 #include <QPushButton>
0030 #include <QTabWidget>
0031 #include <QList>
0032 
0033 // KDE includes
0034 
0035 #include <klocalizedstring.h>
0036 
0037 // Local includes
0038 
0039 #include "MarbleConfigView.h"
0040 #include "geolocationsettings.h"
0041 #include "digikam_debug.h"
0042 
0043 using namespace Marble;
0044 
0045 namespace Digikam
0046 {
0047 
0048 class Q_DECL_HIDDEN SetupGeolocation::Private
0049 {
0050 public:
0051 
0052     Private() = default;
0053 
0054     MarbleConfigView* tab      = nullptr;
0055     QWidget* gMapView          = nullptr;
0056     QLineEdit* gMapApi         = nullptr;
0057 
0058     QString oldKey;
0059 
0060 public:
0061 
0062     QString htmlFilePath(QString& htmlPath) const
0063     {
0064         htmlPath  = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
0065         htmlPath += QLatin1String("/digikam/geoiface/");
0066 
0067         return (htmlPath + QLatin1String("backend-googlemaps.html"));
0068     }
0069 
0070     QString htmlTemplate() const
0071     {
0072         return QLatin1String("<html>\n<head>\n"
0073                              "<base href=\"%1\"/>\n"
0074                              "<script type=\"text/javascript\" src=\"https://maps.google.com/maps/"
0075                              "api/js?key=%2\"></script>\n"
0076                              "<script type=\"text/javascript\" src=\"backend-googlemaps-js.js\"></script>\n"
0077                              "</head>\n"
0078                              "<body onload=\"kgeomapInitialize()\" style=\"padding: 0px; margin: 0px;\">\n"
0079                              "    <div id=\"map_canvas\" style=\"width:100%; height:400px;\"></div>\n"
0080                              "</body>\n</html>\n");
0081     }
0082 };
0083 
0084 SetupGeolocation::SetupGeolocation(QWidget* const parent)
0085     : QScrollArea(parent),
0086       d          (new Private)
0087 {
0088     QWidget* const panel     = new QWidget(viewport());
0089     setWidget(panel);
0090     setWidgetResizable(true);
0091 
0092     const int spacing       = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0093                                    QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0094 
0095     QVBoxLayout* const vbl  = new QVBoxLayout();
0096     panel->setLayout(vbl);
0097 
0098     d->tab                  = new MarbleConfigView(GeolocationSettings::instance()->mainMarbleWidget(), this);
0099 
0100     // ---
0101 
0102     d->gMapView             = new QWidget(this);
0103     QLabel* const title     = new QLabel(i18n("API Key:"), d->gMapView);
0104     d->gMapApi              = new QLineEdit(d->gMapView);
0105     d->gMapApi->setEchoMode(QLineEdit::Normal);
0106 
0107     QFrame* const infoBox       = new QFrame;
0108     QVBoxLayout* const infoVlay = new QVBoxLayout;
0109     infoBox->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
0110 
0111     QLabel* const explanation   = new QLabel(infoBox);
0112     explanation->setOpenExternalLinks(true);
0113     explanation->setWordWrap(true);
0114     QString txt = i18nc("@info", "To work friendly, Google Maps requires an API key that end users must buy online "
0115                                  "to gain credentials. Without this key, Google Maps is still usable but with an "
0116                                  "overlay frame annotated \"For Development Only\". For more information, see this "
0117                                  "<a href='https://mapsplatform.google.com/pricing/'>Google page</a> about "
0118                                  "usages, practices, and prices.");
0119 
0120     explanation->setText(txt);
0121     infoVlay->addWidget(explanation);
0122     infoVlay->setContentsMargins(spacing, spacing, spacing, spacing);
0123     infoVlay->setSpacing(0);
0124     infoBox->setLayout(infoVlay);
0125 
0126     QVBoxLayout* const vlay = new QVBoxLayout(d->gMapView);
0127     vlay->addWidget(title);
0128     vlay->addWidget(d->gMapApi);
0129     vlay->addWidget(infoBox);
0130     vlay->addStretch();
0131     d->tab->insertTab(GoogleMaps, d->gMapView, i18n("Google Maps"));
0132 
0133     // ---
0134 
0135     vbl->addWidget(d->tab);
0136 
0137     readSettings();
0138 }
0139 
0140 SetupGeolocation::~SetupGeolocation()
0141 {
0142     delete d;
0143 }
0144 
0145 void SetupGeolocation::cancel()
0146 {
0147     d->tab->cancel();
0148 }
0149 
0150 void SetupGeolocation::setActiveTab(GeolocationTab tab)
0151 {
0152     d->tab->setCurrentIndex(tab);
0153 }
0154 
0155 SetupGeolocation::GeolocationTab SetupGeolocation::activeTab() const
0156 {
0157     return (GeolocationTab)d->tab->currentIndex();
0158 }
0159 
0160 void SetupGeolocation::applySettings()
0161 {
0162     d->tab->applySettings();
0163 
0164     if (d->gMapApi->text() == d->oldKey)
0165     {
0166         return;
0167     }
0168 
0169     QString htmlPath;
0170     QString key      = d->gMapApi->text().trimmed();
0171     QString htmlFile = d->htmlFilePath(htmlPath);
0172 
0173     if (key.isEmpty())
0174     {
0175         if (QFileInfo::exists(htmlFile))
0176         {
0177             QFile::remove(htmlFile);
0178         }
0179 
0180         GeolocationSettings::instance()->reloadGoogleMaps();
0181         return;
0182     }
0183 
0184     QString jsFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0185                                             QLatin1String("digikam/geoiface/backend-googlemaps-js.js"));
0186 
0187     if (!QFileInfo::exists(jsFile))
0188     {
0189         return;
0190     }
0191 
0192     QUrl baseUrl     = QUrl::fromLocalFile(jsFile).adjusted(QUrl::RemoveFilename);
0193     QString htmlText = d->htmlTemplate().arg(baseUrl.toString()).arg(key);
0194 
0195     if (!QFileInfo::exists(htmlPath))
0196     {
0197         QDir().mkpath(htmlPath);
0198     }
0199 
0200     QFile writeFile(htmlFile);
0201 
0202     if (writeFile.open(QIODevice::WriteOnly))
0203     {
0204         writeFile.write(htmlText.toUtf8());
0205         writeFile.close();
0206 
0207         GeolocationSettings::instance()->reloadGoogleMaps();
0208     }
0209 }
0210 
0211 void SetupGeolocation::readSettings()
0212 {
0213     d->tab->readSettings();
0214 
0215     // Read Google API key
0216 
0217     QString htmlPath;
0218     QString htmlFile = d->htmlFilePath(htmlPath);
0219 
0220     if (QFileInfo::exists(htmlFile))
0221     {
0222         QFile readFile(htmlFile);
0223 
0224         if (readFile.open(QIODevice::ReadOnly))
0225         {
0226             QString oldHtml = QString::fromUtf8(readFile.readAll());
0227             readFile.close();
0228 
0229             if (!oldHtml.isEmpty())
0230             {
0231                 int firstIdx = oldHtml.indexOf(QLatin1String("key="));
0232 
0233                 if (firstIdx != -1)
0234                 {
0235                     int lastIdx = oldHtml.indexOf(QLatin1String("\"></script>"), firstIdx);
0236 
0237                     if (lastIdx > (firstIdx + 4))
0238                     {
0239                         d->oldKey = oldHtml.mid(firstIdx + 4, lastIdx - firstIdx - 4);
0240                     }
0241                 }
0242             }
0243         }
0244     }
0245 
0246     d->gMapApi->setText(d->oldKey);
0247 }
0248 
0249 } // namespace Digikam
0250 
0251 #include "moc_setupgeolocation.cpp"