File indexing completed on 2025-01-05 03:59:34

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2023-12-21
0007  * Description : Marble Settings View.
0008  *
0009  * SPDX-FileCopyrightText: 2009      by Bastian Holst <bastianholst at gmx dot de>
0010  * SPDX-FileCopyrightText: 2012      by Mohammed Nafees <nafees dot technocool at gmail dot com>
0011  * SPDX-FileCopyrightText: 2022-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: LGPL-2.1-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "MarbleConfigView.h"
0018 
0019 // Qt includes
0020 
0021 #include <QApplication>
0022 #include <QPushButton>
0023 #include <QVBoxLayout>
0024 #include <QGridLayout>
0025 #include <QFontComboBox>
0026 #include <QComboBox>
0027 #include <QGroupBox>
0028 #include <QWidget>
0029 #include <QSpinBox>
0030 #include <QCheckBox>
0031 #include <QDateTime>
0032 #include <QTimer>
0033 #include <QLabel>
0034 
0035 // KDE includes
0036 
0037 #include <klocalizedstring.h>
0038 
0039 // Local includes
0040 
0041 #include "MarbleDirs.h"
0042 #include "MarbleWidget.h"
0043 #include "MarbleModel.h"
0044 #include "MarbleLocale.h"
0045 #include "MarbleGlobal.h"
0046 #include "RenderPlugin.h"
0047 #include "RenderPluginModel.h"
0048 #include "ParseRunnerPlugin.h"
0049 #include "MarbleClock.h"
0050 #include "MarblePluginSettingsWidget.h"
0051 
0052 #include "geolocationsettings.h"
0053 #include "digikam_debug.h"
0054 #include "dexpanderbox.h"
0055 
0056 using namespace Digikam;
0057 
0058 namespace Marble
0059 {
0060 
0061 class Q_DECL_HIDDEN MarbleConfigView::Private
0062 {
0063 
0064 public:
0065 
0066     explicit Private(MarbleWidget* const marbleWidget)
0067         : marbleWidget(marbleWidget),
0068           pluginModel ()
0069     {
0070     }
0071 
0072     MarblePluginSettingsWidget*        pluginSettings   = nullptr;
0073 
0074     QComboBox*                         distCb           = nullptr;
0075     QComboBox*                         angleCb          = nullptr;
0076     QComboBox*                         stillCb          = nullptr;
0077     QComboBox*                         aniCb            = nullptr;
0078 
0079     QCheckBox*                         inertialRotation = nullptr;
0080     QCheckBox*                         viewRotation     = nullptr;
0081 
0082     QSpinBox*                          phySb            = nullptr;
0083     QSpinBox*                          discSb           = nullptr;
0084 
0085     QFontComboBox*                     mapFont          = nullptr;
0086     QCheckBox*                         showGrid         = nullptr;
0087     QCheckBox*                         showCross        = nullptr;
0088     QCheckBox*                         showAtmos        = nullptr;
0089     QCheckBox*                         showSunShading   = nullptr;
0090     QCheckBox*                         showCities       = nullptr;
0091     QCheckBox*                         showRelief       = nullptr;
0092 
0093     MarbleWidget* const                marbleWidget;
0094 
0095     RenderPluginModel                  pluginModel;
0096 };
0097 
0098 MarbleConfigView::MarbleConfigView(MarbleWidget* const marbleWidget,
0099                                    QWidget* const parent)
0100     : QTabWidget(parent),
0101       d         (new Private(marbleWidget))
0102 {
0103     // View page
0104 
0105     QWidget* const viewSettings  = new QWidget(this);
0106 
0107     // --- Unit Settings
0108 
0109     QGroupBox* const grpUnits    = new QGroupBox(i18n("Units"), viewSettings);
0110     QGridLayout* const gridUnits = new QGridLayout(grpUnits);
0111     QLabel* const distLbl        = new QLabel(i18n("Distance:"), grpUnits);
0112     d->distCb                    = new QComboBox(grpUnits);
0113     d->distCb->insertItem(MarbleLocale::MetricSystem,   i18n("Kilometer, Meter"));
0114     d->distCb->insertItem(MarbleLocale::ImperialSystem, i18n("Miles, Feet"));
0115     d->distCb->insertItem(MarbleLocale::NauticalSystem, i18n("Nautical miles, Knots"));
0116     d->distCb->setToolTip(i18n("The unit that gets used to measure altitude, lengths and distances (e.g. km, mi, ft)."));
0117 
0118     QLabel* const angleLbl       = new QLabel(i18n("Angle:"), grpUnits);
0119     d->angleCb                   = new QComboBox(grpUnits);
0120     d->angleCb->insertItem(Marble::DMSDegree,     i18n("Degree (DMS)"));
0121     d->angleCb->insertItem(Marble::DecimalDegree, i18n("Degree (Decimal)"));
0122     d->angleCb->insertItem(Marble::UTM,           i18n("Universal Transverse Mercator (UTM)"));
0123     d->angleCb->setToolTip(i18n("Specifies the notation of angles in coordinates.\n"
0124                                 "By default the Degree-Minute-Second notation (e.g. 54\302\26030'00\" ) gets used.\n"
0125                                 "As an alternative you can choose decimal degrees (e.g. 54.5\302\260)."));
0126 
0127     gridUnits->addWidget(distLbl,    0, 0, 1, 1);
0128     gridUnits->addWidget(d->distCb,  0, 1, 1, 1);
0129     gridUnits->addWidget(angleLbl,   1, 0, 1, 1);
0130     gridUnits->addWidget(d->angleCb, 1, 1, 1, 1);
0131 
0132     // --- Map quality settings
0133 
0134     QGroupBox* const grpQa       = new QGroupBox(i18n("Map Quality"), viewSettings);
0135     QGridLayout* const gridQa    = new QGridLayout(grpQa);
0136     QLabel* const stillLbl       = new QLabel(i18n("Still Image:"), grpQa);
0137     d->stillCb                   = new QComboBox(grpQa);
0138     d->stillCb->insertItem(Marble::OutlineQuality,   i18n("Outline Quality"));
0139     d->stillCb->insertItem(Marble::LowQuality,       i18n("Low Quality"));
0140     d->stillCb->insertItem(Marble::NormalQuality,    i18n("Normal"));
0141     d->stillCb->insertItem(Marble::HighQuality,      i18n("High Quality"));
0142     d->stillCb->insertItem(Marble::PrintQuality,     i18n("Print Quality"));
0143     d->stillCb->setToolTip(i18n("Specifies the map quality that gets displayed while there is no user input.\n"
0144                                 "Usually this allows for high map quality as speed is no concern."));
0145 
0146     QLabel* const aniLbl         = new QLabel(i18n("During Animations:"), grpQa);
0147     d->aniCb                     = new QComboBox(grpQa);
0148     d->aniCb->insertItem(Marble::OutlineQuality,   i18n("Outline Quality"));
0149     d->aniCb->insertItem(Marble::LowQuality,       i18n("Low Quality"));
0150     d->aniCb->insertItem(Marble::NormalQuality,    i18n("Normal"));
0151     d->aniCb->insertItem(Marble::HighQuality,      i18n("High Quality"));
0152     d->aniCb->insertItem(Marble::PrintQuality,     i18n("Print Quality"));
0153     d->aniCb->setToolTip(i18n("Specifies the map quality that gets displayed during map animations\n"
0154                               "(e.g. while dragging the globe). Especially on slow machines it is\n"
0155                               "advisable to set this option to \"low quality\" as this will give better speed."));
0156 
0157     gridQa->addWidget(stillLbl,    0, 0, 1, 1);
0158     gridQa->addWidget(d->stillCb,  0, 1, 1, 1);
0159     gridQa->addWidget(aniLbl,      1, 0, 1, 1);
0160     gridQa->addWidget(d->aniCb,    1, 1, 1, 1);
0161 
0162     // --- Mouse behavior settings
0163 
0164     QGroupBox* const grpMouse    = new QGroupBox(i18n("Mouse Behavior"), viewSettings);
0165     QGridLayout* const gridMouse = new QGridLayout(grpMouse);
0166     d->inertialRotation          = new QCheckBox(i18n("Inertial Globe Rotation"), grpMouse);
0167     d->inertialRotation->setToolTip(i18n("Use kinetic spinning when dragging the map"));
0168     d->viewRotation              = new QCheckBox(i18n("Mouse View Rotation"), grpMouse);
0169     d->viewRotation->setToolTip(i18n("Use right mouse button to rotate the camera around"));
0170 
0171     gridMouse->addWidget(d->inertialRotation, 0, 0, 1, 1);
0172     gridMouse->addWidget(d->viewRotation,     1, 0, 1, 1);
0173 
0174     // --- Cache settings
0175 
0176     QGroupBox* const grpCache    = new QGroupBox(i18n("Cache"), viewSettings);
0177     grpCache->setToolTip(i18n("There are two caches being used:\n"
0178                               "The \"physical memory\" which is needed to keep map data in the computer's memory.\n"
0179                               "Increasing the value will make the application more responsive.\n"
0180                               "The \"hard disc memory\" cache is used by download map data from the Internet.\n"
0181                               "Decrease this value if you want to save space on the hard disc\n"
0182                               "and if high usage of the Internet is not an issue."));
0183     QGridLayout* const gridCache = new QGridLayout(grpCache);
0184     QLabel* const phyLbl         = new QLabel(i18n("Physical Memory:"), grpCache);
0185     d->phySb                     = new QSpinBox(grpCache);
0186     d->phySb->setRange(10, 999999);
0187     d->phySb->setValue(100);
0188     d->phySb->setSuffix(i18n(" MB"));
0189     QPushButton* const phyBtn    = new QPushButton(i18n("Clear"), grpCache);
0190 
0191     QLabel* const discLbl        = new QLabel(i18n("Hard Disc:"), grpCache);
0192     d->discSb                    = new QSpinBox(grpCache);
0193     d->discSb->setRange(10, 999999);
0194     d->discSb->setValue(999999);
0195     d->discSb->setSuffix(i18n(" MB"));
0196     QPushButton* const discBtn   = new QPushButton(i18n("Clear"), grpCache);
0197 
0198     gridCache->addWidget(phyLbl,              0, 0, 1, 1);
0199     gridCache->addWidget(d->phySb,            0, 1, 1, 1);
0200     gridCache->addWidget(phyBtn,              0, 2, 1, 1);
0201     gridCache->addWidget(discLbl,             1, 0, 1, 1);
0202     gridCache->addWidget(d->discSb,           1, 1, 1, 1);
0203     gridCache->addWidget(discBtn,             1, 2, 1, 1);
0204 
0205     // --- Map content settings
0206 
0207     QGroupBox* const grpMap      = new QGroupBox(i18n("Map Contents"), viewSettings);
0208     QGridLayout* const gridMap   = new QGridLayout(grpMap);
0209     QLabel* const fntLbl         = new QLabel(i18n("Default Font:"), grpMap);
0210     d->mapFont                   = new QFontComboBox(grpMap);
0211     d->mapFont->setToolTip(i18n("The default font that gets used on the map.\n"
0212                                 "This setting take effect only with the Atlas and Satellite Maps\n"
0213                                 "not the Open-Street Map."));
0214 
0215     d->showGrid                  = new QCheckBox(i18n("Show Coordinate Grid"), grpMap);
0216     d->showGrid->setToolTip(i18n("Show the world-map coordinate grid overlay.\n"
0217                                  "This setting take effect only with the Atlas,\n"
0218                                  "the Satellite, and the Open-Street Maps."));
0219 
0220     d->showCross                 = new QCheckBox(i18n("Show Cross-Hair"), grpMap);
0221     d->showCross->setToolTip(i18n("Show cross-hair on a center of the map.\n"
0222                                   "This setting take effect only with the Atlas,\n"
0223                                   "the Satellite, and the Open-Street Maps."));
0224 
0225     d->showAtmos                 = new QCheckBox(i18n("Show Atmospheric Glow"), grpMap);
0226     d->showAtmos->setToolTip(i18n("Show the world-map atmospheric glow overlay.\n"
0227                                   "This setting take effect only with the Atlas,\n"
0228                                   "the Satellite, and the Open-Street Maps."));
0229 
0230     d->showSunShading            = new QCheckBox(i18n("Show Night Shadow"), grpMap);
0231     d->showSunShading->setToolTip(i18n("Show the world-map night shadow overlay.\n"
0232                                        "This setting take effect only with the Atlas,\n"
0233                                        "the Satellite, and the Open-Street Maps."));
0234 
0235     d->showCities                = new QCheckBox(i18n("Show City Place Mark"), grpMap);
0236     d->showCities->setToolTip(i18n("Show the world-map city place mark overlay.\n"
0237                                    "This setting take effect only with the Atlas and Satellite Maps\n"
0238                                    "not the Open-Street Map."));
0239 
0240     d->showRelief                = new QCheckBox(i18n("Show Relief"), grpMap);
0241     d->showRelief->setToolTip(i18n("Show the world-map relief overlay.\n"
0242                                    "This setting take effect only with the Atlas and Satellite Maps\n"
0243                                    "not the Open-Street Map."));
0244 
0245     // TODO:
0246     // Add IceLayer
0247     // Add Borders
0248     // Add Rivers       ==> Do not works!
0249     // Add Lakes
0250     // Add CityLights
0251     // Add Clouds ???
0252     // Add Terrain ???
0253     // Add Places ???
0254     // Add OtherPlaces ???
0255 
0256     gridMap->addWidget(d->showGrid,                             0, 0, 1, 1);
0257     gridMap->addWidget(d->showCross,                            0, 1, 1, 1);
0258     gridMap->addWidget(d->showAtmos,                            1, 0, 1, 1);
0259     gridMap->addWidget(d->showSunShading,                       1, 1, 1, 1);
0260     gridMap->addWidget(new DLineWidget(Qt::Horizontal, grpMap), 2, 0, 1, 2);
0261     gridMap->addWidget(d->showCities,                           3, 0, 1, 1);
0262     gridMap->addWidget(d->showRelief,                           3, 1, 1, 1);
0263     gridMap->addWidget(fntLbl,                                  4, 0, 1, 1);
0264     gridMap->addWidget(d->mapFont,                              4, 1, 1, 1);
0265 
0266     // ---
0267 
0268     QGridLayout* const viewGrid  = new QGridLayout(viewSettings);
0269     viewGrid->addWidget(grpUnits, 0, 0, 1, 1);
0270     viewGrid->addWidget(grpQa,    0, 1, 1, 1);
0271     viewGrid->addWidget(grpMouse, 1, 0, 1, 1);
0272     viewGrid->addWidget(grpCache, 1, 1, 1, 1);
0273     viewGrid->addWidget(grpMap,   2, 0, 1, 2);
0274 
0275     addTab(viewSettings, i18n("Map View"));
0276 
0277     if (d->marbleWidget)
0278     {
0279         connect(phyBtn, SIGNAL(clicked()),
0280                 d->marbleWidget, SLOT(clearVolatileTileCache()));
0281 
0282         connect(discBtn, SIGNAL(clicked()),
0283                 d->marbleWidget->model(), SLOT(clearPersistentTileCache()));
0284     }
0285 
0286     // Plugins page
0287 
0288 
0289     d->pluginSettings = new MarblePluginSettingsWidget(this);
0290 
0291     if (d->marbleWidget)
0292     {
0293         d->pluginModel.setRenderPlugins(d->marbleWidget->renderPlugins());
0294         d->pluginSettings->setRunnerPlugins(d->marbleWidget->runnerPlugins());
0295     }
0296 
0297     d->pluginSettings->setModel(&d->pluginModel);
0298     d->pluginSettings->setObjectName(QLatin1String("plugin_page"));
0299     addTab(d->pluginSettings, i18n("Map Plugins"));
0300 
0301     // Setting the icons for the plugin view.
0302 
0303     d->pluginSettings->setConfigIcon(QIcon::fromTheme(QLatin1String("configure")));
0304     d->pluginSettings->setAboutIcon(QIcon::fromTheme(QLatin1String("help-about")));
0305 }
0306 
0307 MarbleConfigView::~MarbleConfigView()
0308 {
0309     delete d;
0310 }
0311 
0312 void MarbleConfigView::cancel()
0313 {
0314     d->pluginModel.retrievePluginState();
0315 }
0316 
0317 void MarbleConfigView::readSettings()
0318 {
0319     // Read settings from config file.
0320 
0321     GeolocationSettingsContainer settings = GeolocationSettings::instance()->settings();
0322 
0323     // View
0324 
0325     d->distCb->setCurrentIndex(settings.distanceUnit);
0326     d->angleCb->setCurrentIndex(settings.angleUnit);
0327     d->stillCb->setCurrentIndex(settings.stillQuality);
0328     d->aniCb->setCurrentIndex(settings.animationQuality);
0329     d->inertialRotation->setChecked(settings.inertialRotation);
0330     d->viewRotation->setChecked(settings.mouseRotation);
0331     d->phySb->setValue(settings.volatileTileCacheLimit);
0332     d->discSb->setValue(settings.persistentTileCacheLimit);
0333     d->mapFont->setCurrentFont(settings.mapFont);
0334     d->showGrid->setChecked(settings.showGrid);
0335     d->showCross->setChecked(settings.showCross);
0336     d->showAtmos->setChecked(settings.showAtmos);
0337     d->showSunShading->setChecked(settings.showSunShading);
0338     d->showCities->setChecked(settings.showCities);
0339     d->showRelief->setChecked(settings.showRelief);
0340 
0341     // Read the settings of the plugins
0342 
0343     if (d->marbleWidget)
0344     {
0345         d->marbleWidget->readPluginSettings();
0346     }
0347 }
0348 
0349 void MarbleConfigView::applySettings()
0350 {
0351     d->pluginModel.applyPluginState();
0352 
0353     GeolocationSettingsContainer settings;
0354 
0355     settings.distanceUnit             = (Marble::MarbleLocale::MeasurementSystem)d->distCb->currentIndex();
0356     settings.angleUnit                = (Marble::AngleUnit)d->angleCb->currentIndex();
0357     settings.stillQuality             = (Marble::MapQuality)d->stillCb->currentIndex();
0358     settings.animationQuality         = (Marble::MapQuality)d->aniCb->currentIndex();
0359     settings.inertialRotation         = d->inertialRotation->isChecked();
0360     settings.mouseRotation            = d->viewRotation->isChecked();
0361     settings.volatileTileCacheLimit   = d->phySb->value();
0362     settings.persistentTileCacheLimit = d->discSb->value();
0363     settings.mapFont                  = d->mapFont->currentFont();
0364     settings.showGrid                 = d->showGrid->isChecked();
0365     settings.showCross                = d->showCross->isChecked();
0366     settings.showAtmos                = d->showAtmos->isChecked();
0367     settings.showSunShading           = d->showSunShading->isChecked();
0368     settings.showCities               = d->showCities->isChecked();
0369     settings.showRelief               = d->showRelief->isChecked();
0370 
0371     GeolocationSettings::instance()->setSettings(settings);
0372 
0373     // Plugins
0374 
0375     if (d->marbleWidget)
0376     {
0377         d->marbleWidget->writePluginSettings();
0378     }
0379 }
0380 
0381 } // namespace Marble
0382 
0383 #include "moc_MarbleConfigView.cpp"