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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-12-01
0007  * Description : world map widget library - Appearance management
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:      2014 by Justus Schwartz <justus at gmx dot li>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "mapwidget_p.h"
0018 
0019 namespace Digikam
0020 {
0021 
0022 void MapWidget::stopThumbnailTimer()
0023 {
0024     d->currentBackend->updateMarkers();
0025     d->thumbnailTimerCount++;
0026 
0027     if (d->thumbnailTimerCount == 10)
0028     {
0029         d->thumbnailTimer->stop();
0030         d->thumbnailsHaveBeenLoaded = true;
0031     }
0032 }
0033 
0034 void MapWidget::slotZoomIn()
0035 {
0036     if (!currentBackendReady())
0037     {
0038         return;
0039     }
0040 
0041     d->currentBackend->zoomIn();
0042 }
0043 
0044 void MapWidget::slotZoomOut()
0045 {
0046     if (!currentBackendReady())
0047     {
0048         return;
0049     }
0050 
0051     d->currentBackend->zoomOut();
0052 }
0053 
0054 void MapWidget::getColorInfos(const int clusterIndex,
0055                               QColor* fillColor,
0056                               QColor* strokeColor,
0057                               Qt::PenStyle* strokeStyle,
0058                               QString* labelText,
0059                               QColor* labelColor,
0060                               const GeoGroupState* const overrideSelection,
0061                               const int* const overrideCount) const
0062 {
0063     /// @todo Call the new getColorInfos function!
0064 
0065     const GeoIfaceCluster& cluster = s->clusterList.at(clusterIndex);
0066 
0067     /// @todo Check that this number is already valid!
0068 
0069     const int nMarkers             = overrideCount ? *overrideCount : cluster.markerCount;
0070 
0071     getColorInfos(overrideSelection ? *overrideSelection : cluster.groupState,
0072                   nMarkers,
0073                   fillColor, strokeColor, strokeStyle, labelText, labelColor);
0074 }
0075 
0076 void MapWidget::getColorInfos(const GeoGroupState groupState,
0077                               const int nMarkers,
0078                               QColor* fillColor, QColor* strokeColor,
0079                               Qt::PenStyle* strokeStyle, QString* labelText,
0080                               QColor* labelColor) const
0081 {
0082     if      (nMarkers < 1000)
0083     {
0084         *labelText = QString::number(nMarkers);
0085     }
0086     else if ((nMarkers >= 1000) && (nMarkers <= 1950))      // cppcheck-suppress knownConditionTrueFalse
0087     {
0088         *labelText = QString::fromLatin1("%L1k").arg(qreal(nMarkers)/1000.0, 0, 'f', 1);
0089     }
0090     else if ((nMarkers >= 1951) && (nMarkers < 19500))      // cppcheck-suppress knownConditionTrueFalse
0091     {
0092         *labelText = QString::fromLatin1("%L1k").arg(qreal(nMarkers)/1000.0, 0, 'f', 0);
0093     }
0094     else
0095     {
0096         // convert to "1E5" notation for numbers >=20k:
0097 
0098         qreal exponent           = floor(log((qreal)nMarkers)/log((qreal)10));
0099         qreal nMarkersFirstDigit = round(qreal(nMarkers)/pow(10, exponent));
0100 
0101         if (nMarkersFirstDigit >= 10)
0102         {
0103             nMarkersFirstDigit=round(nMarkersFirstDigit/10.0);
0104             exponent++;
0105         }
0106 
0107         *labelText = QString::fromLatin1("%1E%2").arg(int(nMarkersFirstDigit)).arg(int(exponent));
0108     }
0109 
0110     *labelColor  = QColor(Qt::black);
0111     *strokeStyle = Qt::NoPen;
0112 
0113     /// @todo On my system, digikam uses QColor(67, 172, 232) as the selection color. Or should we just use blue?
0114 
0115     switch (groupState & SelectedMask)
0116     {
0117         case SelectedNone:
0118         {
0119             *strokeStyle = Qt::SolidLine;
0120             *strokeColor = QColor(Qt::black);
0121             break;
0122         }
0123 
0124         case SelectedSome:
0125         {
0126             *strokeStyle = Qt::DotLine;
0127             *strokeColor = QColor(Qt::blue); // 67, 172, 232);
0128             break;
0129         }
0130 
0131         case SelectedAll:
0132         {
0133             *strokeStyle = Qt::SolidLine;
0134             *strokeColor = QColor(Qt::blue); // 67, 172, 232);
0135             break;
0136         }
0137     }
0138 
0139     /**
0140      * @todo These are the fill colors for the circles, for cases in which only some or all of the images
0141      * are positively filtered. Filtering is implemented in GeoIface, but the code here has not been adapted yet.
0142      */
0143     QColor fillAll, fillSome, fillNone;
0144 
0145     if      (nMarkers >= 100)
0146     {
0147         fillAll  = QColor(255, 0,   0);
0148         fillSome = QColor(255, 188, 125);
0149         fillNone = QColor(255, 185, 185);
0150     }
0151     else if (nMarkers >= 50)
0152     {
0153         fillAll  = QColor(255, 127, 0);
0154         fillSome = QColor(255, 190, 125);
0155         fillNone = QColor(255, 220, 185);
0156     }
0157     else if (nMarkers >= 10)
0158     {
0159         fillAll  = QColor(255, 255, 0);
0160         fillSome = QColor(255, 255, 105);
0161         fillNone = QColor(255, 255, 185);
0162     }
0163     else if (nMarkers >= 2)
0164     {
0165         fillAll  = QColor(0,   255, 0);
0166         fillSome = QColor(125, 255, 125);
0167         fillNone = QColor(185, 255, 255);
0168     }
0169     else
0170     {
0171         fillAll  = QColor(0,   255, 255);
0172         fillSome = QColor(125, 255, 255);
0173         fillNone = QColor(185, 255, 255);
0174     }
0175 
0176     *fillColor = fillAll;
0177 /*
0178     switch (groupState)
0179     {
0180         case PartialAll:
0181         {
0182             *fillColor = fillAll;
0183             break;
0184         }
0185 
0186         case PartialSome:
0187         {
0188             *fillColor = fillSome;
0189             break;
0190         }
0191 
0192         case PartialNone:
0193         {
0194             if (haveAnySolo)
0195             {
0196                 *fillColor = fillNone;
0197             }
0198             else
0199             {
0200                 *fillColor = fillAll;
0201             }
0202 
0203             break;
0204         }
0205     }
0206 */
0207 }
0208 
0209 QString MapWidget::convertZoomToBackendZoom(const QString& someZoom,
0210                                             const QString& targetBackend) const
0211 {
0212     const QStringList zoomParts = someZoom.split(QLatin1Char(':'));
0213     GEOIFACE_ASSERT(zoomParts.count() == 2);
0214     const QString sourceBackend = zoomParts.first();
0215 
0216     if (sourceBackend == targetBackend)
0217     {
0218         return someZoom;
0219     }
0220 
0221     const int sourceZoom = zoomParts.last().toInt();
0222     int targetZoom       = -1;
0223 
0224 #ifdef HAVE_GEOLOCATION
0225 
0226     // all of these values were found experimentally!
0227 
0228     if (targetBackend == QLatin1String("marble" ))
0229     {
0230         if      (sourceZoom == 0) { targetZoom =  900; }
0231         else if (sourceZoom == 1) { targetZoom =  970; }
0232         else if (sourceZoom == 2) { targetZoom = 1108; }
0233         else if (sourceZoom == 3) { targetZoom = 1250; }
0234         else if (sourceZoom == 4) { targetZoom = 1384; }
0235         else if (sourceZoom == 5) { targetZoom = 1520; }
0236         else if (sourceZoom == 6) { targetZoom = 1665; }
0237         else if (sourceZoom == 7) { targetZoom = 1800; }
0238         else if (sourceZoom == 8) { targetZoom = 1940; }
0239         else if (sourceZoom == 9) { targetZoom = 2070; }
0240         else if (sourceZoom ==10) { targetZoom = 2220; }
0241         else if (sourceZoom ==11) { targetZoom = 2357; }
0242         else if (sourceZoom ==12) { targetZoom = 2510; }
0243         else if (sourceZoom ==13) { targetZoom = 2635; }
0244         else if (sourceZoom ==14) { targetZoom = 2775; }
0245         else if (sourceZoom ==15) { targetZoom = 2900; }
0246         else if (sourceZoom ==16) { targetZoom = 3051; }
0247         else if (sourceZoom ==17) { targetZoom = 3180; }
0248         else if (sourceZoom ==18) { targetZoom = 3295; }
0249         else if (sourceZoom ==19) { targetZoom = 3450; }
0250         else                      { targetZoom = 3500; } /// @todo Find values for level 20 and up
0251     }
0252 
0253 #endif
0254 
0255     if (targetBackend == QLatin1String("googlemaps" ))
0256     {
0257         if      (sourceZoom <= 900) { targetZoom =  0; }
0258         else if (sourceZoom <= 970) { targetZoom =  1; }
0259         else if (sourceZoom <=1108) { targetZoom =  2; }
0260         else if (sourceZoom <=1250) { targetZoom =  3; }
0261         else if (sourceZoom <=1384) { targetZoom =  4; }
0262         else if (sourceZoom <=1520) { targetZoom =  5; }
0263         else if (sourceZoom <=1665) { targetZoom =  6; }
0264         else if (sourceZoom <=1800) { targetZoom =  7; }
0265         else if (sourceZoom <=1940) { targetZoom =  8; }
0266         else if (sourceZoom <=2070) { targetZoom =  9; }
0267         else if (sourceZoom <=2220) { targetZoom = 10; }
0268         else if (sourceZoom <=2357) { targetZoom = 11; }
0269         else if (sourceZoom <=2510) { targetZoom = 12; }
0270         else if (sourceZoom <=2635) { targetZoom = 13; }
0271         else if (sourceZoom <=2775) { targetZoom = 14; }
0272         else if (sourceZoom <=2900) { targetZoom = 15; }
0273         else if (sourceZoom <=3051) { targetZoom = 16; }
0274         else if (sourceZoom <=3180) { targetZoom = 17; }
0275         else if (sourceZoom <=3295) { targetZoom = 18; }
0276         else if (sourceZoom <=3450) { targetZoom = 19; }
0277         else                        { targetZoom = 20; } /// @todo Find values for level 20 and up
0278     }
0279 
0280     GEOIFACE_ASSERT(targetZoom >= 0);
0281 
0282     return QString::fromLatin1("%1:%2").arg(targetBackend).arg(targetZoom);
0283 }
0284 
0285 
0286 void MapWidget::setShowThumbnails(const bool state)
0287 {
0288     s->showThumbnails = state;
0289 
0290     rebuildConfigurationMenu();
0291     slotUpdateActionsEnabled();
0292     slotRequestLazyReclustering();
0293 }
0294 
0295 void MapWidget::slotShowThumbnailsChanged()
0296 {
0297     setShowThumbnails(d->actionShowThumbnails->isChecked());
0298 }
0299 
0300 void MapWidget::setSortKey(const int sortKey)
0301 {
0302     s->sortKey = sortKey;
0303 
0304     // this is probably faster than writing a function that changes all the clusters icons...
0305     /// @todo We just need to update the display, no need to recluster?
0306 
0307     slotRequestLazyReclustering();
0308 }
0309 
0310 void MapWidget::setThumnailSize(const int newThumbnailSize)
0311 {
0312     s->thumbnailSize = qMax(GeoIfaceMinThumbnailSize, newThumbnailSize);
0313 
0314     // make sure the grouping radius is larger than the thumbnail size
0315 
0316     if (2 * s->thumbnailGroupingRadius < newThumbnailSize)
0317     {
0318         /// @todo more straightforward way for this?
0319 
0320         s->thumbnailGroupingRadius = newThumbnailSize / 2 + newThumbnailSize % 2;
0321     }
0322 
0323     if (s->showThumbnails)
0324     {
0325         slotRequestLazyReclustering();
0326     }
0327 
0328     slotUpdateActionsEnabled();
0329 }
0330 
0331 void MapWidget::setThumbnailGroupingRadius(const int newGroupingRadius)
0332 {
0333     s->thumbnailGroupingRadius = qMax(GeoIfaceMinThumbnailGroupingRadius, newGroupingRadius);
0334 
0335     // make sure the thumbnails are smaller than the grouping radius
0336 
0337     if (2*s->thumbnailGroupingRadius < s->thumbnailSize)
0338     {
0339         s->thumbnailSize = 2 * newGroupingRadius;
0340     }
0341 
0342     if (s->showThumbnails)
0343     {
0344         slotRequestLazyReclustering();
0345     }
0346 
0347     slotUpdateActionsEnabled();
0348 }
0349 
0350 void MapWidget::setMarkerGroupingRadius(const int newGroupingRadius)
0351 {
0352     s->markerGroupingRadius = qMax(GeoIfaceMinMarkerGroupingRadius, newGroupingRadius);
0353 
0354     if (!s->showThumbnails)
0355     {
0356         slotRequestLazyReclustering();
0357     }
0358 
0359     slotUpdateActionsEnabled();
0360 }
0361 
0362 void MapWidget::slotDecreaseThumbnailSize()
0363 {
0364     if (!s->showThumbnails)
0365     {
0366         return;
0367     }
0368 
0369     if (s->thumbnailSize > GeoIfaceMinThumbnailSize)
0370     {
0371         const int newThumbnailSize = qMax(GeoIfaceMinThumbnailSize, s->thumbnailSize-5);
0372 
0373         // make sure the grouping radius is also decreased
0374         // this will automatically decrease the thumbnail size as well
0375 
0376         setThumbnailGroupingRadius(newThumbnailSize / 2);
0377     }
0378 }
0379 
0380 void MapWidget::slotIncreaseThumbnailSize()
0381 {
0382     if (!s->showThumbnails)
0383     {
0384         return;
0385     }
0386 
0387     setThumnailSize(s->thumbnailSize+5);
0388 }
0389 
0390 int MapWidget::getThumbnailSize() const
0391 {
0392     return s->thumbnailSize;
0393 }
0394 
0395 int MapWidget::getUndecoratedThumbnailSize() const
0396 {
0397     return s->thumbnailSize-2;
0398 }
0399 
0400 } // namespace Digikam