1 /* SPDX-FileCopyrightText: 2020-2021 Tobias Leupold <tl@l3u.de>
2
3 SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-KDE-Accepted-GPL
4 */
5
6 // Local includes
7 #include "SettingsDialog.h"
8 #include "Settings.h"
9
10 // KDE includes
11 #include <KLocalizedString>
12
13 // Qt includes
14 #include <QVBoxLayout>
15 #include <QDialogButtonBox>
16 #include <QDebug>
17 #include <QGroupBox>
18 #include <QGridLayout>
19 #include <QLabel>
20 #include <QComboBox>
21 #include <QSpinBox>
22 #include <QPushButton>
23 #include <QColorDialog>
24 #include <QCheckBox>
25 #include <QScrollArea>
26 #include <QScrollBar>
27 #include <QMessageBox>
28 #include <QHBoxLayout>
29
SettingsDialog(Settings * settings,QWidget * parent)30 SettingsDialog::SettingsDialog(Settings *settings, QWidget *parent)
31 : QDialog(parent), m_settings(settings)
32 {
33 setAttribute(Qt::WA_DeleteOnClose, true);
34 setWindowTitle(i18n("KGeoTag: Settings"));
35
36 auto *mainLayout = new QVBoxLayout(this);
37
38 // Header
39
40 auto *header = new QLabel(i18n("KGeoTag settings"));
41 header->setStyleSheet(QStringLiteral("QLabel { font-weight: bold; font-size: %1pt; }").arg(
42 (int) double(header->font().pointSize()) * 1.2));
43 header->setAlignment(Qt::AlignCenter);
44 mainLayout->addWidget(header);
45
46 // Settings
47
48 setStyleSheet(QStringLiteral("QGroupBox { font-weight: bold; }"));
49
50 auto *settingsWidget = new QWidget;
51
52 int row;
53
54 auto *layout = new QVBoxLayout(settingsWidget);
55
56 // Image lists
57
58 auto *listsBox = new QGroupBox(i18n("Image lists"));
59 layout->addWidget(listsBox);
60
61 auto *listsBoxLayout = new QVBoxLayout(listsBox);
62
63 auto *listsModeLabel = new QLabel(i18n(
64 "<p>Loaded images can either be listed in two different lists (one for all images without "
65 "and one for images with coordinates), or using a combined consecutive list for all images."
66 "</p>"
67 "<p>Use the following images list(s) mode:</p>"));
68 listsModeLabel->setWordWrap(true);
69 listsBoxLayout->addWidget(listsModeLabel);
70
71 m_imageListsMode = new QComboBox;
72 m_imageListsMode->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
73
74 m_imageListsMode->addItem(i18n("Separate \"Assigned\" and \"Unassigned\" list"));
75 m_imageListsMode->addItem(i18n("One combined list for all images"));
76
77 m_imageListsMode->setCurrentIndex(m_settings->splitImagesList() ? 0 : 1);
78
79 listsBoxLayout->addWidget(m_imageListsMode);
80
81 // Automatic matching
82
83 auto *searchMatchesBox = new QGroupBox(i18n("Image Assignment"));
84 layout->addWidget(searchMatchesBox);
85
86 auto *searchMatchesBoxLayout = new QVBoxLayout(searchMatchesBox);
87
88 auto *matchModeLabel = new QLabel(i18n("Search type for the main menu \"Assign images to GPS "
89 "data\" entry"));
90 matchModeLabel->setWordWrap(true);
91 searchMatchesBoxLayout->addWidget(matchModeLabel);
92
93 m_automaticMatchingMode = new QComboBox;
94 m_automaticMatchingMode->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding);
95
96 m_automaticMatchingMode->addItem(i18n("Combined match search"), KGeoTag::CombinedMatchSearch);
97 m_automaticMatchingMode->addItem(i18n("Search exact matches only"), KGeoTag::ExactMatchSearch);
98 m_automaticMatchingMode->addItem(i18n("Search interpolated matches only"),
99 KGeoTag::InterpolatedMatchSearch);
100
101 m_automaticMatchingMode->setCurrentIndex(
102 m_automaticMatchingMode->findData(m_settings->defaultMatchingMode()));
103
104 searchMatchesBoxLayout->addWidget(m_automaticMatchingMode);
105
106 auto *matchModeNoteLabel = new QLabel(i18n(
107 "This triggers an automatic (re-)assignment of all images, respecting the \"Exclude "
108 "manually tagged images\" setting from the \"Automatic assignment\" dock."));
109 matchModeNoteLabel->setWordWrap(true);
110 searchMatchesBoxLayout->addWidget(matchModeNoteLabel);
111
112 // Images
113
114 auto *imagesBox = new QGroupBox(i18n("Thumbnails and previews"));
115 auto *imagesBoxLayout = new QVBoxLayout(imagesBox);
116 layout->addWidget(imagesBox);
117
118 auto *sizesLayoutWrapper = new QHBoxLayout;
119 imagesBoxLayout->addLayout(sizesLayoutWrapper);
120 auto *sizesLayout = new QGridLayout;
121 sizesLayoutWrapper->addLayout(sizesLayout);
122 row = -1;
123
124 sizesLayout->addWidget(new QLabel(i18n("Thumbnail size:")), ++row, 0);
125 m_thumbnailSize = new QSpinBox;
126 m_thumbnailSize->setMinimum(16);
127 m_thumbnailSize->setMaximum(512);
128 m_originalThumbnailSizeValue = m_settings->thumbnailSize();
129 m_thumbnailSize->setValue(m_originalThumbnailSizeValue);
130 sizesLayout->addWidget(m_thumbnailSize, row, 1);
131 sizesLayout->addWidget(new QLabel(i18n("px")), row, 2);
132
133 sizesLayout->addWidget(new QLabel(i18n("Preview size:")), ++row, 0);
134 m_previewSize = new QSpinBox;
135 m_previewSize->setMinimum(100);
136 m_previewSize->setMaximum(1920);
137 m_originalPreviewSizeValue = m_settings->previewSize();
138 m_previewSize->setValue(m_originalPreviewSizeValue);
139 sizesLayout->addWidget(m_previewSize, row, 1);
140 sizesLayout->addWidget(new QLabel(i18n("px")), row, 2);
141
142 sizesLayoutWrapper->addStretch();
143
144 auto *imagesChangesLabel = new QLabel(i18n("Please restart the program after changes to these "
145 "values so that they are applied and become "
146 "visible."));
147 imagesChangesLabel->setWordWrap(true);
148 imagesBoxLayout->addWidget(imagesChangesLabel);
149
150 // GPX track rendering
151
152 auto *trackBox = new QGroupBox(i18n("GPX track rendering"));
153 auto *trackBoxLayout = new QHBoxLayout(trackBox);
154 layout->addWidget(trackBox);
155
156 auto *renderingLayout = new QGridLayout;
157 trackBoxLayout->addLayout(renderingLayout);
158 row = -1;
159
160 renderingLayout->addWidget(new QLabel(i18n("Color:")), ++row, 0);
161 m_trackColor = new QPushButton;
162 m_trackColor->setFlat(true);
163 m_currentTrackColor = m_settings->trackColor();
164 connect(m_trackColor, &QPushButton::clicked, this, &SettingsDialog::setTrackColor);
165 renderingLayout->addWidget(m_trackColor, row, 1);
166
167 m_trackOpacity = new QLabel;
168 renderingLayout->addWidget(m_trackOpacity, row, 2);
169
170 updateTrackColor();
171
172 renderingLayout->addWidget(new QLabel(i18n("Line width:")), ++row, 0);
173 m_trackWidth = new QSpinBox;
174 m_trackWidth->setMinimum(1);
175 m_trackWidth->setMaximum(50);
176 m_trackWidth->setValue(m_settings->trackWidth());
177 renderingLayout->addWidget(m_trackWidth, row, 1);
178
179 renderingLayout->addWidget(new QLabel(i18n("Line style:")), ++row, 0);
180 m_trackStyle = new QComboBox;
181 m_trackStyle->addItem(i18n("Solid"), static_cast<int>(Qt::SolidLine));
182 m_trackStyle->addItem(i18n("Dashes"), static_cast<int>(Qt::DashLine));
183 m_trackStyle->addItem(i18n("Dots"), static_cast<int>(Qt::DotLine));
184 m_trackStyle->addItem(i18n("Dash-Dot"), static_cast<int>(Qt::DashDotLine));
185 m_trackStyle->addItem(i18n("Dash-Dot-Dot"), static_cast<int>(Qt::DashDotDotLine));
186 m_trackStyle->setCurrentIndex(
187 m_trackStyle->findData(static_cast<int>(m_settings->trackStyle())));
188 renderingLayout->addWidget(m_trackStyle, row, 1);
189
190 trackBoxLayout->addStretch();
191
192 // Elevation lookup
193
194 auto *elevationBox = new QGroupBox(i18n("Elevation lookup"));
195 auto *elevationBoxLayout = new QVBoxLayout(elevationBox);
196 layout->addWidget(elevationBox);
197
198 auto *lookupLabel = new QLabel(i18n("Elevations can be looked up using opentopodata.org's web "
199 "API."));
200 lookupLabel->setWordWrap(true);
201 elevationBoxLayout->addWidget(lookupLabel);
202
203 auto *datasetLayout = new QHBoxLayout;
204 elevationBoxLayout->addLayout(datasetLayout);
205
206 datasetLayout->addWidget(new QLabel(i18n("Elevation dataset:")));
207
208 m_elevationDataset = new QComboBox;
209
210 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "ASTER"),
211 QStringLiteral("aster30m"));
212 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "ETOPO1"),
213 QStringLiteral("etopo1"));
214 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "EU-DEM"),
215 QStringLiteral("eudem25m"));
216 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "Mapzen"),
217 QStringLiteral("mapzen"));
218 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "NED"),
219 QStringLiteral("ned10m"));
220 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "NZ DEM"),
221 QStringLiteral("nzdem8m"));
222 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "SRTM (30 m)"),
223 QStringLiteral("srtm30m"));
224 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset", "SRTM (90 m)"),
225 QStringLiteral("srtm90m"));
226 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset",
227 "EMODnet 2018 Bathymetry"),
228 QStringLiteral("emod2018"));
229 m_elevationDataset->addItem(i18nc("opentopodata.org elevation dataset",
230 "GEBCO 2020 Bathymetry"),
231 QStringLiteral("gebco2020"));
232
233 m_elevationDataset->setCurrentIndex(
234 m_elevationDataset->findData(m_settings->elevationDataset()));
235
236 datasetLayout->addWidget(m_elevationDataset);
237
238 datasetLayout->addStretch();
239
240 auto *datasetInfoLabel = new QLabel(i18n("Cf. <a href=\"https://www.opentopodata.org/\">"
241 "https://www.opentopodata.org/</a> for further "
242 "information about the available datasets, like the "
243 "respective coverage!"));
244 datasetInfoLabel->setWordWrap(true);
245 datasetInfoLabel->setOpenExternalLinks(true);
246 elevationBoxLayout->addWidget(datasetInfoLabel);
247
248 m_lookupElevationAutomatically = new QCheckBox(i18n("Request and set altitudes automatically"));
249 m_lookupElevationAutomatically->setChecked(m_settings->lookupElevationAutomatically());
250 elevationBoxLayout->addWidget(m_lookupElevationAutomatically);
251
252 // Data saving
253
254 auto *saveBox = new QGroupBox(i18n("Saving"));
255 auto *saveBoxLayout = new QVBoxLayout(saveBox);
256 layout->addWidget(saveBox);
257
258 auto *saveTargetLayout = new QHBoxLayout;
259 saveBoxLayout->addLayout(saveTargetLayout);
260
261 saveTargetLayout->addWidget(new QLabel(i18n("Write changes to:")));
262
263 m_writeMode = new QComboBox;
264
265 m_writeMode->addItem(i18n("Exif header"),
266 QStringLiteral("WRITETOIMAGEONLY"));
267 m_writeMode->addItem(i18n("XMP sidecar file"),
268 QStringLiteral("WRITETOSIDECARONLY"));
269 m_writeMode->addItem(i18n("Exif header and XMP sidecar file"),
270 QStringLiteral("WRITETOSIDECARANDIMAGE"));
271
272 m_writeMode->setCurrentIndex(m_writeMode->findData(m_settings->writeMode()));
273
274 saveTargetLayout->addWidget(m_writeMode);
275
276 saveTargetLayout->addStretch();
277
278 m_createBackups = new QCheckBox(i18n("Create a backups before altering a file"));
279 m_createBackups->setChecked(m_settings->createBackups());
280 saveBoxLayout->addWidget(m_createBackups);
281
282 // Scroll area
283
284 auto *scrollArea = new QScrollArea;
285 scrollArea->setWidgetResizable(true);
286 const int styleAddition = scrollArea->width() - scrollArea->viewport()->width();
287 scrollArea->setWidget(settingsWidget);
288 mainLayout->addWidget(scrollArea);
289
290 show();
291 const int widgetWidth = settingsWidget->width() + scrollArea->verticalScrollBar()->width()
292 + styleAddition;
293 scrollArea->setMinimumWidth(widgetWidth);
294
295 // Button box
296
297 auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Close);
298 connect(buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::accept);
299 connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
300 mainLayout->addWidget(buttonBox);
301 }
302
updateTrackColor()303 void SettingsDialog::updateTrackColor()
304 {
305 m_trackColor->setStyleSheet(QStringLiteral("border: none; background-color: %1;").arg(
306 m_currentTrackColor.name()));
307 m_trackOpacity->setText(i18n("Opacity: %1%", int(m_currentTrackColor.alphaF() * 100.0)));
308 }
309
setTrackColor()310 void SettingsDialog::setTrackColor()
311 {
312 QColorDialog dialog(m_currentTrackColor);
313 dialog.setOption(QColorDialog::ShowAlphaChannel, true);
314
315 if (! dialog.exec()) {
316 return;
317 }
318
319 m_currentTrackColor = dialog.currentColor();
320 updateTrackColor();
321 }
322
accept()323 void SettingsDialog::accept()
324 {
325 const auto splitImagesList = m_imageListsMode->currentIndex() == 0;
326 m_settings->saveSplitImagesList(splitImagesList);
327
328 m_settings->saveDefaultMatchingMode(static_cast<KGeoTag::SearchType>(
329 m_automaticMatchingMode->currentData().toInt()));
330
331 const auto thumbnailSize = m_thumbnailSize->value();
332 m_settings->saveThumbnailSize(thumbnailSize);
333 const auto previewSize = m_previewSize->value();
334 m_settings->savePreviewSize(previewSize);
335
336 m_settings->saveTrackColor(m_currentTrackColor);
337 m_settings->saveTrackWidth(m_trackWidth->value());
338 m_settings->saveTrackStyle(static_cast<Qt::PenStyle>(m_trackStyle->currentData().toInt()));
339
340 m_settings->saveLookupElevationAutomatically(m_lookupElevationAutomatically->isChecked());
341 m_settings->saveElevationDataset(m_elevationDataset->currentData().toString());
342
343 m_settings->saveWriteMode(m_writeMode->currentData().toString());
344 m_settings->saveCreateBackups(m_createBackups->isChecked());
345
346 if ( thumbnailSize != m_originalThumbnailSizeValue
347 || previewSize != m_originalPreviewSizeValue) {
348
349 QMessageBox::information(this, i18n("Settings changed"),
350 i18n("Please restart KGeoTag to apply the changed settings and make them visible!"));
351 }
352
353 if (splitImagesList != m_originalSplitImagesListValue) {
354 emit imagesListsModeChanged();
355 }
356
357 QDialog::accept();
358 }
359