File indexing completed on 2024-04-28 15:39:04
0001 // SPDX-FileCopyrightText: 2020-2022 Tobias Leupold <tl at stonemx dot de> 0002 // 0003 // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 0005 // Local includes 0006 #include "AutomaticMatchingWidget.h" 0007 #include "Settings.h" 0008 0009 // KDE includes 0010 #include <KLocalizedString> 0011 0012 // Qt includes 0013 #include <QVBoxLayout> 0014 #include <QHBoxLayout> 0015 #include <QGridLayout> 0016 #include <QDebug> 0017 #include <QLabel> 0018 #include <QPushButton> 0019 #include <QSpinBox> 0020 #include <QCheckBox> 0021 #include <QGroupBox> 0022 #include <QApplication> 0023 #include <QStyle> 0024 #include <QMessageBox> 0025 #include <QMenu> 0026 #include <QAction> 0027 #include <QDebug> 0028 0029 // C++ includes 0030 #include <functional> 0031 0032 AutomaticMatchingWidget::AutomaticMatchingWidget(Settings *settings, QWidget *parent) 0033 : QWidget(parent), m_settings(settings) 0034 { 0035 auto *layout = new QVBoxLayout(this); 0036 0037 // Exact matching 0038 0039 auto *exactMatchBox = new QGroupBox(i18n("Search for exact matches")); 0040 exactMatchBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); 0041 auto *exactMatchBoxLayout = new QVBoxLayout(exactMatchBox); 0042 layout->addWidget(exactMatchBox); 0043 0044 auto *exactMatchToleranceLabel = new QLabel(i18n( 0045 "Maximum deviation of the image's time from a GPS point's time to be considered an exact " 0046 "match:")); 0047 exactMatchToleranceLabel->setWordWrap(true); 0048 exactMatchBoxLayout->addWidget(exactMatchToleranceLabel); 0049 0050 auto *secondsLayout = new QHBoxLayout; 0051 exactMatchBoxLayout->addLayout(secondsLayout); 0052 0053 m_exactMatchTolerance = new QSpinBox; 0054 m_exactMatchTolerance->setMinimum(0); 0055 m_exactMatchTolerance->setMaximum(300); 0056 m_exactMatchTolerance->setValue(m_settings->exactMatchTolerance()); 0057 secondsLayout->addWidget(m_exactMatchTolerance); 0058 0059 secondsLayout->addWidget(new QLabel(i18n("seconds"))); 0060 0061 secondsLayout->addStretch(); 0062 0063 // Interpolated matching 0064 0065 auto *interpolatedMatchBox = new QGroupBox(i18n("Search for interpolated matches")); 0066 interpolatedMatchBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); 0067 auto *interpolatedMatchBoxLayout = new QVBoxLayout(interpolatedMatchBox); 0068 layout->addWidget(interpolatedMatchBox); 0069 0070 auto *interpolatedMatchLabel = new QLabel(i18n( 0071 "Spatial and temporal boundaries for two coordinates used to calculate an interpolated " 0072 "match:")); 0073 interpolatedMatchLabel->setWordWrap(true); 0074 interpolatedMatchBoxLayout->addWidget(interpolatedMatchLabel); 0075 0076 auto boundariesWrapperLayout = new QHBoxLayout; 0077 interpolatedMatchBoxLayout->addLayout(boundariesWrapperLayout); 0078 0079 auto *boundariesLayout = new QGridLayout; 0080 boundariesWrapperLayout->addLayout(boundariesLayout); 0081 0082 m_enableMaximumInterpolationInterval = new QCheckBox(i18n("Maximum interval:")); 0083 boundariesLayout->addWidget(m_enableMaximumInterpolationInterval, 0, 0); 0084 0085 m_maximumInterpolationInterval = new QSpinBox; 0086 m_maximumInterpolationInterval->setMinimum(0); 0087 m_maximumInterpolationInterval->setMaximum(86400); 0088 boundariesLayout->addWidget(m_maximumInterpolationInterval, 0, 1); 0089 0090 boundariesLayout->addWidget(new QLabel(i18n("seconds")), 0, 2); 0091 0092 const int interval = m_settings->maximumInterpolationInterval(); 0093 if (interval == -1) { 0094 enableMaximumInterpolationInterval(false); 0095 } else { 0096 m_enableMaximumInterpolationInterval->setChecked(true); 0097 m_maximumInterpolationInterval->setValue(interval); 0098 } 0099 0100 connect(m_enableMaximumInterpolationInterval, &QCheckBox::toggled, 0101 this, &AutomaticMatchingWidget::enableMaximumInterpolationInterval); 0102 0103 m_enableMaximumInterpolationDistance = new QCheckBox(i18n("Maximum distance:")); 0104 boundariesLayout->addWidget(m_enableMaximumInterpolationDistance, 1, 0); 0105 0106 m_maximumInterpolationDistance = new QSpinBox; 0107 m_maximumInterpolationDistance->setRange(0, 1000000); 0108 boundariesLayout->addWidget(m_maximumInterpolationDistance, 1, 1); 0109 0110 boundariesLayout->addWidget(new QLabel(i18n("meters")), 1, 2); 0111 0112 const int distance = m_settings->maximumInterpolationDistance(); 0113 if (distance == -1) { 0114 enableMaximumInterpolationDistance(false); 0115 } else { 0116 m_enableMaximumInterpolationDistance->setChecked(true); 0117 m_maximumInterpolationDistance->setValue(distance); 0118 } 0119 0120 connect(m_enableMaximumInterpolationDistance, &QCheckBox::toggled, 0121 this, &AutomaticMatchingWidget::enableMaximumInterpolationDistance); 0122 0123 boundariesWrapperLayout->addStretch(); 0124 0125 // Bottom buttons 0126 0127 layout->addStretch(); 0128 0129 auto *buttonsLayout = new QHBoxLayout; 0130 layout->addLayout(buttonsLayout); 0131 0132 auto *saveButton = new QPushButton(i18n("Save settings")); 0133 saveButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogSaveButton)); 0134 connect(saveButton, &QPushButton::clicked, this, &AutomaticMatchingWidget::saveSettings); 0135 buttonsLayout->addWidget(saveButton); 0136 0137 buttonsLayout->addStretch(); 0138 0139 auto *reassignButton = new QPushButton(i18n("(Re)Assign all images")); 0140 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) 0141 // FIXME: 0142 // QStyle::SP_DialogRetryButton wasn't there until Qt 5.14. KGeoTag actually can be built 0143 // against Qt 5.12, which is included in Ubuntu LTS 20.04. Let's keep this until the last-ish 0144 // Ubuntu LTS version has Qt 5.15. 0145 reassignButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogRetryButton)); 0146 #endif 0147 0148 auto *reassignMenu = new QMenu(this); 0149 0150 auto *combinedSearch = reassignMenu->addAction(i18n("Combined match search")); 0151 connect(combinedSearch, &QAction::triggered, 0152 this, std::bind(&AutomaticMatchingWidget::requestReassignment, this, 0153 KGeoTag::CombinedMatchSearch)); 0154 0155 reassignMenu->addSeparator(); 0156 0157 auto *exactSearch = reassignMenu->addAction(i18n("Search exact matches only")); 0158 connect(exactSearch, &QAction::triggered, 0159 this, std::bind(&AutomaticMatchingWidget::requestReassignment, this, 0160 KGeoTag::ExactMatchSearch)); 0161 0162 auto *interpolatedSearch = reassignMenu->addAction(i18n("Search interpolated matches only")); 0163 connect(interpolatedSearch, &QAction::triggered, 0164 this, std::bind(&AutomaticMatchingWidget::requestReassignment, this, 0165 KGeoTag::InterpolatedMatchSearch)); 0166 0167 reassignMenu->addSeparator(); 0168 0169 m_excludeManuallyTagged = reassignMenu->addAction(i18n("Exclude manually tagged images")); 0170 m_excludeManuallyTagged->setCheckable(true); 0171 m_excludeManuallyTagged->setChecked(m_settings->excludeManuallyTaggedWhenReassigning()); 0172 0173 reassignButton->setMenu(reassignMenu); 0174 buttonsLayout->addWidget(reassignButton); 0175 } 0176 0177 void AutomaticMatchingWidget::enableMaximumInterpolationInterval(bool state) 0178 { 0179 m_maximumInterpolationInterval->setEnabled(state); 0180 if (! state) { 0181 m_maximumInterpolationInterval->setValue(3600); 0182 } 0183 } 0184 0185 void AutomaticMatchingWidget::enableMaximumInterpolationDistance(bool state) 0186 { 0187 m_maximumInterpolationDistance->setEnabled(state); 0188 if (! state) { 0189 m_maximumInterpolationDistance->setValue(500); 0190 } 0191 } 0192 0193 void AutomaticMatchingWidget::saveSettings() 0194 { 0195 m_settings->saveExactMatchTolerance(m_exactMatchTolerance->value()); 0196 m_settings->saveMaximumInterpolationInterval(m_enableMaximumInterpolationInterval->isChecked() 0197 ? m_maximumInterpolationInterval->value() : -1); 0198 m_settings->saveMaximumInterpolationDistance(m_enableMaximumInterpolationDistance->isChecked() 0199 ? m_maximumInterpolationDistance->value() : -1); 0200 m_settings->saveExcludeManuallyTaggedWhenReassigning(m_excludeManuallyTagged->isChecked()); 0201 0202 QMessageBox::information(this, i18n("Save as default"), i18n("Settings saved!")); 0203 } 0204 0205 bool AutomaticMatchingWidget::excludeManuallyTagged() const 0206 { 0207 return m_excludeManuallyTagged->isChecked(); 0208 } 0209 0210 int AutomaticMatchingWidget::exactMatchTolerance() const 0211 { 0212 return m_exactMatchTolerance->value(); 0213 } 0214 0215 int AutomaticMatchingWidget::maximumInterpolationInterval() const 0216 { 0217 return m_enableMaximumInterpolationInterval->isChecked() 0218 ? m_maximumInterpolationInterval->value() 0219 : -1; 0220 } 0221 0222 int AutomaticMatchingWidget::maximumInterpolationDistance() const 0223 { 0224 return m_enableMaximumInterpolationDistance->isChecked() 0225 ? m_maximumInterpolationDistance->value() 0226 : -1; 0227 }