File indexing completed on 2025-01-05 03:58:35

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-12-01
0007  * Description : Widget for displaying HTML in the backends - QtWebKit version
0008  *
0009  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2009-2011 by Michael G. Hansen <mike at mghansen dot de>
0011  * SPDX-FileCopyrightText: 2015      by Mohamed_Anwer <m_dot_anwer at gmx dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "htmlwidget_qwebkit.h"
0018 
0019 // Qt includes
0020 
0021 #include <QTimer>
0022 #include <QResizeEvent>
0023 #include <QWebSettings>
0024 #include <qwebframe.h>
0025 
0026 // Local includes
0027 
0028 #include "digikam_debug.h"
0029 
0030 namespace Digikam
0031 {
0032 
0033 class Q_DECL_HIDDEN HTMLWidget::Private
0034 {
0035 public:
0036 
0037     explicit Private()
0038       : parent                          (nullptr),
0039         isReady                         (false),
0040         selectionStatus                 (false),
0041         firstSelectionPoint             (),
0042         intermediateSelectionPoint      (),
0043         firstSelectionScreenPoint       (),
0044         intermediateSelectionScreenPoint()
0045     {
0046     }
0047 
0048     QWidget*       parent;
0049     bool           isReady;
0050 
0051     bool           selectionStatus;
0052     GeoCoordinates firstSelectionPoint;
0053     GeoCoordinates intermediateSelectionPoint;
0054     QPoint         firstSelectionScreenPoint;
0055     QPoint         intermediateSelectionScreenPoint;
0056 };
0057 
0058 HTMLWidget::HTMLWidget(QWidget* const parent)
0059     : QWebView(parent),
0060       d       (new Private()),
0061       s       (nullptr)
0062 {
0063     d->parent = parent;
0064     setAcceptDrops(false);
0065     setFocusPolicy(Qt::WheelFocus);
0066     setRenderHint(QPainter::TextAntialiasing);
0067     page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
0068 
0069     settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true);
0070     settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, true);
0071     settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
0072     settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
0073 
0074     d->parent->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0075 
0076     connect(this, SIGNAL(loadProgress(int)),
0077             this, SLOT(progress(int)));
0078 
0079     connect(this, SIGNAL(loadFinished(bool)),
0080             this, SLOT(slotHTMLCompleted(bool)));
0081 
0082     connect(this, SIGNAL(statusBarMessage(QString)),
0083             this, SLOT(slotScanForJSMessages(QString)));
0084 
0085     if (d->parent)
0086     {
0087         d->parent->installEventFilter(this);
0088     }
0089 }
0090 
0091 HTMLWidget::~HTMLWidget()
0092 {
0093     delete d;
0094 }
0095 
0096 void HTMLWidget::progress(int progress)
0097 {
0098     qCDebug(DIGIKAM_GEOIFACE_LOG) << "Maps Loading Progress: " << progress << "%";
0099 }
0100 
0101 void HTMLWidget::slotHTMLCompleted(bool ok)
0102 {
0103     qCDebug(DIGIKAM_GEOIFACE_LOG) << "Map Loading Completed: " << ok;
0104     d->isReady = ok;
0105 
0106     Q_EMIT signalJavaScriptReady();
0107 }
0108 
0109 void HTMLWidget::mousePressEvent(QMouseEvent* e)
0110 {
0111     slotScanForJSMessages(QLatin1String("(event)"));
0112     QWebView::mousePressEvent(e);
0113 }
0114 
0115 void HTMLWidget::mouseReleaseEvent(QMouseEvent* e)
0116 {
0117     if (s->currentMouseMode == MouseModeRegionSelection)
0118     {
0119         if (!d->firstSelectionPoint.hasCoordinates())
0120         {
0121             runScript2Coordinates(QString::fromLatin1("kgeomapPixelToLatLng(%1, %2);")
0122                                   .arg(e->x())
0123                                   .arg(e->y()),
0124                                   &d->firstSelectionPoint);
0125 
0126             d->firstSelectionScreenPoint = QPoint(e->x(), e->y());
0127         }
0128         else
0129         {
0130             runScript2Coordinates(QString::fromLatin1("kgeomapPixelToLatLng(%1, %2);")
0131                                   .arg(e->x())
0132                                   .arg(e->y()),
0133                                   &d->intermediateSelectionPoint);
0134 
0135             d->intermediateSelectionScreenPoint = QPoint(e->x(), e->y());
0136 
0137             qreal lonWest, latNorth, lonEast, latSouth;
0138 
0139             if (d->firstSelectionScreenPoint.x() < d->intermediateSelectionScreenPoint.x())
0140             {
0141                 lonWest  = d->firstSelectionPoint.lon();
0142                 lonEast  = d->intermediateSelectionPoint.lon();
0143             }
0144             else
0145             {
0146                 lonEast  = d->firstSelectionPoint.lon();
0147                 lonWest  = d->intermediateSelectionPoint.lon();
0148             }
0149 
0150             if (d->firstSelectionScreenPoint.y() < d->intermediateSelectionScreenPoint.y())
0151             {
0152                 latNorth = d->firstSelectionPoint.lat();
0153                 latSouth = d->intermediateSelectionPoint.lat();
0154             }
0155             else
0156             {
0157                 latNorth = d->intermediateSelectionPoint.lat();
0158                 latSouth = d->firstSelectionPoint.lat();
0159             }
0160 
0161             runScript(QLatin1String("kgeomapRemoveTemporarySelectionRectangle();"));
0162             runScript(QString::fromLatin1("kgeomapSetSelectionRectangle(%1, %2, %3, %4);")
0163                      .arg(lonWest)
0164                      .arg(latNorth)
0165                      .arg(lonEast)
0166                      .arg(latSouth));
0167 
0168             const GeoCoordinates::Pair selectionCoordinates(
0169                     GeoCoordinates(latNorth, lonWest),
0170                     GeoCoordinates(latSouth, lonEast));
0171 
0172             d->firstSelectionPoint.clear();
0173             d->intermediateSelectionPoint.clear();
0174 
0175             Q_EMIT selectionHasBeenMade(selectionCoordinates);
0176         }
0177     }
0178 
0179     slotScanForJSMessages(QLatin1String("(event)"));
0180     QWebView::mouseReleaseEvent(e);
0181 }
0182 
0183 void HTMLWidget::mouseMoveEvent(QMouseEvent *e)
0184 {
0185     if ((s->currentMouseMode == MouseModeRegionSelection) &&
0186         d->firstSelectionPoint.hasCoordinates())
0187     {
0188         runScript2Coordinates(QString::fromLatin1("kgeomapPixelToLatLng(%1, %2);")
0189                               .arg(e->x())
0190                               .arg(e->y()),
0191                               &d->intermediateSelectionPoint);
0192 
0193         d->intermediateSelectionScreenPoint = QPoint(e->x(), e->y());
0194 
0195         qCDebug(DIGIKAM_GEOIFACE_LOG) << d->firstSelectionScreenPoint << QLatin1Char(' ')
0196                                       << d->intermediateSelectionScreenPoint;
0197 
0198         qreal lonWest, latNorth, lonEast, latSouth;
0199 
0200         if (d->firstSelectionScreenPoint.x() < d->intermediateSelectionScreenPoint.x())
0201         {
0202             lonWest  = d->firstSelectionPoint.lon();
0203             lonEast  = d->intermediateSelectionPoint.lon();
0204         }
0205         else
0206         {
0207             lonEast  = d->firstSelectionPoint.lon();
0208             lonWest  = d->intermediateSelectionPoint.lon();
0209         }
0210 
0211         if (d->firstSelectionScreenPoint.y() < d->intermediateSelectionScreenPoint.y())
0212         {
0213             latNorth = d->firstSelectionPoint.lat();
0214             latSouth = d->intermediateSelectionPoint.lat();
0215         }
0216         else
0217         {
0218             latNorth = d->intermediateSelectionPoint.lat();
0219             latSouth = d->firstSelectionPoint.lat();
0220         }
0221 
0222         runScript(QString::fromLatin1("kgeomapSetTemporarySelectionRectangle(%1, %2, %3, %4);")
0223                   .arg(lonWest)
0224                   .arg(latNorth)
0225                   .arg(lonEast)
0226                   .arg(latSouth));
0227     }
0228 
0229     QWebView::mouseMoveEvent(e);
0230 }
0231 
0232 void HTMLWidget::slotScanForJSMessages(const QString& message)
0233 {
0234     if (message != QLatin1String("(event)"))
0235     {
0236         return;
0237     }
0238 
0239     //qCDebug(DIGIKAM_GEOIFACE_LOG) << message;
0240 
0241     const QString eventBufferString = runScript(QLatin1String("kgeomapReadEventStrings();")).toString();
0242 
0243     if (eventBufferString.isEmpty())
0244     {
0245         return;
0246     }
0247 
0248     const QStringList events = eventBufferString.split(QLatin1Char('|'));
0249 
0250     Q_EMIT signalHTMLEvents(events);
0251 }
0252 
0253 /**
0254  * @brief Wrapper around executeScript to catch more errors
0255  */
0256 QVariant HTMLWidget::runScript(const QString& scriptCode, bool /*async*/)
0257 {
0258     GEOIFACE_ASSERT(d->isReady);
0259 
0260     if (!d->isReady)
0261     {
0262         return QVariant();
0263     }
0264 
0265     //qCDebug(DIGIKAM_GEOIFACE_LOG) << scriptCode;
0266 
0267     return page()->mainFrame()->evaluateJavaScript(scriptCode);
0268 }
0269 
0270 /**
0271  * @brief Execute a script which returns coordinates and parse these
0272  */
0273 bool HTMLWidget::runScript2Coordinates(const QString& scriptCode, GeoCoordinates* const coordinates)
0274 {
0275     const QVariant scriptResult = runScript(scriptCode);
0276 
0277     return GeoIfaceHelperParseLatLonString(scriptResult.toString(), coordinates);
0278 }
0279 
0280 bool HTMLWidget::eventFilter(QObject* object, QEvent* event)
0281 {
0282     if (d->parent && (object == d->parent))
0283     {
0284         if (event->type() == QEvent::Resize)
0285         {
0286             QResizeEvent* const resizeEvent = dynamic_cast<QResizeEvent*>(event);
0287 
0288             if (resizeEvent)
0289             {
0290                 resize(resizeEvent->size());
0291             }
0292         }
0293     }
0294 
0295     return false;
0296 }
0297 
0298 void HTMLWidget::setSelectionRectangle(const GeoCoordinates::Pair& searchCoordinates)
0299 {
0300     if (!searchCoordinates.first.hasCoordinates())
0301     {
0302         runScript(QLatin1String("kgeomapRemoveSelectionRectangle();"));
0303         return;
0304     }
0305 
0306     qreal West  = searchCoordinates.first.lon();
0307     qreal North = searchCoordinates.first.lat();
0308     qreal East  = searchCoordinates.second.lon();
0309     qreal South = searchCoordinates.second.lat();
0310 
0311     runScript(QString::fromLatin1("kgeomapSetSelectionRectangle(%1, %2, %3, %4);")
0312               .arg(West).arg(North).arg(East).arg(South));
0313 }
0314 
0315 void HTMLWidget::removeSelectionRectangle()
0316 {
0317     runScript(QLatin1String("kgeomapRemoveSelectionRectangle();"));
0318 }
0319 
0320 void HTMLWidget::mouseModeChanged(const GeoMouseModes mouseMode)
0321 {
0322     const bool inSelectionMode = (mouseMode == MouseModeRegionSelection);
0323 
0324     if (inSelectionMode)
0325     {
0326         d->firstSelectionPoint.clear();
0327         d->intermediateSelectionPoint.clear();
0328         runScript(QString::fromLatin1("kgeomapSelectionModeStatus(%1);").arg(inSelectionMode));
0329     }
0330     else
0331     {
0332         runScript(QString::fromLatin1("kgeomapSelectionModeStatus(%1);").arg(inSelectionMode));
0333     }
0334 }
0335 
0336 void HTMLWidget::centerOn(const qreal west, const qreal north,
0337                           const qreal east, const qreal south,
0338                           const bool useSaneZoomLevel)
0339 {
0340 /*
0341     qCDebug(DIGIKAM_GEOIFACE_LOG) << "West:" << west
0342                                   << " North:" << north
0343                                   << " East:" << east
0344                                   << " South:" << south;
0345 */
0346     runScript(QString::fromLatin1("kgeomapSetMapBoundaries(%1, %2, %3, %4, %5);")
0347               .arg(west)
0348               .arg(north)
0349               .arg(east)
0350               .arg(south)
0351               .arg(useSaneZoomLevel ? 1 : 0));
0352 }
0353 
0354 void HTMLWidget::setSharedGeoIfaceObject(GeoIfaceSharedData* const sharedData)
0355 {
0356     s = sharedData;
0357 }
0358 
0359 } // namespace Digikam
0360 
0361 #include "moc_htmlwidget_qwebkit.cpp"