File indexing completed on 2024-04-28 04:21:03

0001 // SPDX-FileCopyrightText: 2003 - 2020 The KPhotoAlbum Development Team
0002 // SPDX-FileCopyrightText: 2021 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0003 // SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
0004 //
0005 // SPDX-License-Identifier: GPL-2.0-or-later
0006 
0007 #include "SearchDialog.h"
0008 
0009 #include <kpaexif/Database.h>
0010 
0011 #include <KConfigGroup>
0012 #include <KLocalizedString>
0013 #include <QDialogButtonBox>
0014 #include <QGridLayout>
0015 #include <QGroupBox>
0016 #include <QHBoxLayout>
0017 #include <QPushButton>
0018 #include <QScrollArea>
0019 #include <QVBoxLayout>
0020 #include <qcheckbox.h>
0021 #include <qlabel.h>
0022 #include <qlayout.h>
0023 #include <qspinbox.h>
0024 
0025 using namespace Exif;
0026 
0027 Exif::SearchDialog::SearchDialog(const Database *exifDB, QWidget *parent)
0028     : KPageDialog(parent)
0029     , m_exifDB(exifDB)
0030 {
0031     setWindowTitle(i18nc("@title:window", "Exif Search"));
0032     setFaceType(Tabbed);
0033 
0034     QWidget *settings = new QWidget;
0035     KPageWidgetItem *page = new KPageWidgetItem(settings, i18n("Settings"));
0036 
0037     addPage(page);
0038     QVBoxLayout *vlay = new QVBoxLayout(settings);
0039 
0040     // Iso, Exposure, FNumber
0041     QHBoxLayout *hlay = new QHBoxLayout;
0042     vlay->addLayout(hlay);
0043     QGridLayout *gridLayout = new QGridLayout;
0044     gridLayout->setSpacing(6);
0045     hlay->addLayout(gridLayout);
0046     hlay->addStretch(1);
0047 
0048     makeISO(gridLayout);
0049     makeExposureTime(gridLayout);
0050     hlay->addSpacing(30);
0051 
0052     gridLayout = new QGridLayout;
0053     gridLayout->setSpacing(6);
0054     hlay->addLayout(gridLayout);
0055     hlay->addStretch(1);
0056     m_fNumber = makeFNumber(i18n("Aperture (F Number)"), QString::fromLatin1("Exif_Photo_FNumber"), gridLayout, 1);
0057 
0058     hlay->addSpacing(30);
0059 
0060     // Focal length
0061     QHBoxLayout *focalLayout = new QHBoxLayout;
0062     focalLayout->setSpacing(6);
0063     hlay->addLayout(focalLayout);
0064     hlay->addStretch(1);
0065 
0066     QLabel *label = new QLabel(i18n("Focal Length"));
0067     focalLayout->addWidget(label);
0068 
0069     m_fromFocalLength = new QSpinBox;
0070     focalLayout->addWidget(m_fromFocalLength);
0071     m_fromFocalLength->setRange(0, 10000);
0072     m_fromFocalLength->setSingleStep(10);
0073 
0074     label = new QLabel(i18nc("As in 'A range from x to y'", "to"));
0075     focalLayout->addWidget(label);
0076 
0077     m_toFocalLength = new QSpinBox;
0078     focalLayout->addWidget(m_toFocalLength);
0079     m_toFocalLength->setRange(0, 10000);
0080     m_toFocalLength->setSingleStep(10);
0081 
0082     m_toFocalLength->setValue(10000);
0083     QString suffix = i18nc("This is millimeter for focal length, like 35mm", "mm");
0084     m_fromFocalLength->setSuffix(suffix);
0085     m_toFocalLength->setSuffix(suffix);
0086 
0087     connect(m_fromFocalLength, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &SearchDialog::fromFocalLengthChanged);
0088     connect(m_toFocalLength, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &SearchDialog::toFocalLengthChanged);
0089 
0090     // exposure program and Metring mode
0091     hlay = new QHBoxLayout;
0092     vlay->addLayout(hlay);
0093     hlay->addWidget(makeExposureProgram(settings));
0094     hlay->addWidget(makeMeteringMode(settings));
0095 
0096     vlay->addStretch(1);
0097 
0098     // ------------------------------------------------------------ Camera
0099     page = new KPageWidgetItem(makeCamera(), i18n("Camera"));
0100     addPage(page);
0101 
0102     // ------------------------------------------------------------ Lens
0103     page = new KPageWidgetItem(makeLens(), i18n("Lens"));
0104     addPage(page);
0105 
0106     // ------------------------------------------------------------ Misc
0107     QWidget *misc = new QWidget;
0108     addPage(new KPageWidgetItem(misc, i18n("Miscellaneous")));
0109     vlay = new QVBoxLayout(misc);
0110     vlay->addWidget(makeOrientation(misc), 1);
0111 
0112     hlay = new QHBoxLayout;
0113     vlay->addLayout(hlay);
0114     hlay->addWidget(makeContrast(misc));
0115     hlay->addWidget(makeSharpness(misc));
0116     hlay->addWidget(makeSaturation(misc));
0117     vlay->addStretch(1);
0118 }
0119 
0120 void Exif::SearchDialog::makeISO(QGridLayout *layout)
0121 {
0122     Exif::RangeWidget::ValueList list;
0123     list << Exif::RangeWidget::Value(100, QString::fromLatin1("100"))
0124          << Exif::RangeWidget::Value(200, QString::fromLatin1("200"))
0125          << Exif::RangeWidget::Value(400, QString::fromLatin1("400"))
0126          << Exif::RangeWidget::Value(800, QString::fromLatin1("800"))
0127          << Exif::RangeWidget::Value(1600, QString::fromLatin1("1600"))
0128          << Exif::RangeWidget::Value(3200, QString::fromLatin1("3200"))
0129          << Exif::RangeWidget::Value(6400, QString::fromLatin1("6400"))
0130          << Exif::RangeWidget::Value(12800, QString::fromLatin1("12800"))
0131          << Exif::RangeWidget::Value(25600, QString::fromLatin1("25600"))
0132          << Exif::RangeWidget::Value(51200, QString::fromLatin1("51200"));
0133 
0134     m_iso = new RangeWidget(i18n("Iso setting"), QString::fromLatin1("Exif_Photo_ISOSpeedRatings"), list, layout, 0, this);
0135 }
0136 
0137 void Exif::SearchDialog::makeExposureTime(QGridLayout *layout)
0138 {
0139     QString secs = i18nc("Example 1.6 secs (as in seconds)", "secs.");
0140     Exif::RangeWidget::ValueList list;
0141     list
0142         << Exif::RangeWidget::Value(1.0 / 4000, QString::fromLatin1("1/4000"))
0143         << Exif::RangeWidget::Value(1.0 / 3200, QString::fromLatin1("1/3200"))
0144         << Exif::RangeWidget::Value(1.0 / 2500, QString::fromLatin1("1/2500"))
0145         << Exif::RangeWidget::Value(1.0 / 2000, QString::fromLatin1("1/2000"))
0146         << Exif::RangeWidget::Value(1.0 / 1600, QString::fromLatin1("1/1600"))
0147         << Exif::RangeWidget::Value(1.0 / 1250, QString::fromLatin1("1/1250"))
0148         << Exif::RangeWidget::Value(1.0 / 1000, QString::fromLatin1("1/1000"))
0149         << Exif::RangeWidget::Value(1.0 / 800, QString::fromLatin1("1/800"))
0150         << Exif::RangeWidget::Value(1.0 / 640, QString::fromLatin1("1/640"))
0151         << Exif::RangeWidget::Value(1.0 / 500, QString::fromLatin1("1/500"))
0152         << Exif::RangeWidget::Value(1.0 / 400, QString::fromLatin1("1/400"))
0153         << Exif::RangeWidget::Value(1.0 / 320, QString::fromLatin1("1/320"))
0154         << Exif::RangeWidget::Value(1.0 / 250, QString::fromLatin1("1/250"))
0155         << Exif::RangeWidget::Value(1.0 / 200, QString::fromLatin1("1/200"))
0156         << Exif::RangeWidget::Value(1.0 / 160, QString::fromLatin1("1/160"))
0157         << Exif::RangeWidget::Value(1.0 / 125, QString::fromLatin1("1/125"))
0158         << Exif::RangeWidget::Value(1.0 / 100, QString::fromLatin1("1/100"))
0159         << Exif::RangeWidget::Value(1.0 / 80, QString::fromLatin1("1/80"))
0160         << Exif::RangeWidget::Value(1.0 / 60, QString::fromLatin1("1/60"))
0161         << Exif::RangeWidget::Value(1.0 / 50, QString::fromLatin1("1/50"))
0162         << Exif::RangeWidget::Value(1.0 / 40, QString::fromLatin1("1/40"))
0163         << Exif::RangeWidget::Value(1.0 / 30, QString::fromLatin1("1/30"))
0164         << Exif::RangeWidget::Value(1.0 / 25, QString::fromLatin1("1/25"))
0165         << Exif::RangeWidget::Value(1.0 / 20, QString::fromLatin1("1/20"))
0166         << Exif::RangeWidget::Value(1.0 / 15, QString::fromLatin1("1/15"))
0167         << Exif::RangeWidget::Value(1.0 / 13, QString::fromLatin1("1/13"))
0168         << Exif::RangeWidget::Value(1.0 / 10, QString::fromLatin1("1/10"))
0169         << Exif::RangeWidget::Value(1.0 / 8, QString::fromLatin1("1/8"))
0170         << Exif::RangeWidget::Value(1.0 / 6, QString::fromLatin1("1/6"))
0171         << Exif::RangeWidget::Value(1.0 / 5, QString::fromLatin1("1/5"))
0172         << Exif::RangeWidget::Value(1.0 / 4, QString::fromLatin1("1/4"))
0173         << Exif::RangeWidget::Value(0.3, QString::fromLatin1("0.3 %1").arg(secs))
0174         << Exif::RangeWidget::Value(0.4, QString::fromLatin1("0.4 %1").arg(secs))
0175         << Exif::RangeWidget::Value(0.5, QString::fromLatin1("0.5 %1").arg(secs))
0176         << Exif::RangeWidget::Value(0.6, QString::fromLatin1("0.6 %1").arg(secs))
0177         << Exif::RangeWidget::Value(0.8, QString::fromLatin1("0.8 %1").arg(secs))
0178         << Exif::RangeWidget::Value(1, i18n("1 second"))
0179         << Exif::RangeWidget::Value(1.3, QString::fromLatin1("1.3 %1").arg(secs))
0180         << Exif::RangeWidget::Value(1.6, QString::fromLatin1("1.6 %1").arg(secs))
0181         << Exif::RangeWidget::Value(2, QString::fromLatin1("2 %1").arg(secs))
0182         << Exif::RangeWidget::Value(2.5, QString::fromLatin1("2.5 %1").arg(secs))
0183         << Exif::RangeWidget::Value(3.2, QString::fromLatin1("3.2 %1").arg(secs))
0184         << Exif::RangeWidget::Value(4, QString::fromLatin1("4 %1").arg(secs))
0185         << Exif::RangeWidget::Value(5, QString::fromLatin1("5 %1").arg(secs))
0186         << Exif::RangeWidget::Value(6, QString::fromLatin1("6 %1").arg(secs))
0187         << Exif::RangeWidget::Value(8, QString::fromLatin1("8 %1").arg(secs))
0188         << Exif::RangeWidget::Value(10, QString::fromLatin1("10 %1").arg(secs))
0189         << Exif::RangeWidget::Value(13, QString::fromLatin1("13 %1").arg(secs))
0190         << Exif::RangeWidget::Value(15, QString::fromLatin1("15 %1").arg(secs))
0191         << Exif::RangeWidget::Value(20, QString::fromLatin1("20 %1").arg(secs))
0192         << Exif::RangeWidget::Value(25, QString::fromLatin1("25 %1").arg(secs))
0193         << Exif::RangeWidget::Value(30, QString::fromLatin1("30 %1").arg(secs));
0194 
0195     m_exposureTime = new RangeWidget(i18n("Exposure time"), QString::fromLatin1("Exif_Photo_ExposureTime"), list, layout, 1, this);
0196 }
0197 
0198 RangeWidget *Exif::SearchDialog::makeFNumber(const QString &text, const QString &key, QGridLayout *layout, int row)
0199 {
0200     Exif::RangeWidget::ValueList list;
0201     list
0202         << Exif::RangeWidget::Value(1.4, QString::fromLatin1("1.4"))
0203         << Exif::RangeWidget::Value(1.8, QString::fromLatin1("1.8"))
0204         << Exif::RangeWidget::Value(2.0, QString::fromLatin1("2.0"))
0205         << Exif::RangeWidget::Value(2.2, QString::fromLatin1("2.2"))
0206         << Exif::RangeWidget::Value(2.5, QString::fromLatin1("2.5"))
0207         << Exif::RangeWidget::Value(2.8, QString::fromLatin1("2.8"))
0208         << Exif::RangeWidget::Value(3.2, QString::fromLatin1("3.2"))
0209         << Exif::RangeWidget::Value(3.5, QString::fromLatin1("3.5"))
0210         << Exif::RangeWidget::Value(4.0, QString::fromLatin1("4.0"))
0211         << Exif::RangeWidget::Value(4.5, QString::fromLatin1("4.5"))
0212         << Exif::RangeWidget::Value(5.0, QString::fromLatin1("5.0"))
0213         << Exif::RangeWidget::Value(5.6, QString::fromLatin1("5.6"))
0214         << Exif::RangeWidget::Value(6.3, QString::fromLatin1("6.3"))
0215         << Exif::RangeWidget::Value(7.1, QString::fromLatin1("7.1"))
0216         << Exif::RangeWidget::Value(8.0, QString::fromLatin1("8.0"))
0217         << Exif::RangeWidget::Value(9.0, QString::fromLatin1("9.0"))
0218         << Exif::RangeWidget::Value(10, QString::fromLatin1("10"))
0219         << Exif::RangeWidget::Value(11, QString::fromLatin1("11"))
0220         << Exif::RangeWidget::Value(13, QString::fromLatin1("13"))
0221         << Exif::RangeWidget::Value(14, QString::fromLatin1("14"))
0222         << Exif::RangeWidget::Value(16, QString::fromLatin1("16"))
0223         << Exif::RangeWidget::Value(18, QString::fromLatin1("18"))
0224         << Exif::RangeWidget::Value(20, QString::fromLatin1("20"))
0225         << Exif::RangeWidget::Value(22, QString::fromLatin1("22"))
0226         << Exif::RangeWidget::Value(25, QString::fromLatin1("25"))
0227         << Exif::RangeWidget::Value(29, QString::fromLatin1("29"))
0228         << Exif::RangeWidget::Value(32, QString::fromLatin1("32"))
0229         << Exif::RangeWidget::Value(36, QString::fromLatin1("36"))
0230         << Exif::RangeWidget::Value(40, QString::fromLatin1("40"))
0231         << Exif::RangeWidget::Value(45, QString::fromLatin1("45"));
0232 
0233     return new RangeWidget(text, key, list, layout, row, this);
0234 }
0235 
0236 #define addSetting(settings, text, num)                 \
0237     {                                                   \
0238         QCheckBox *cb = new QCheckBox(i18n(text), box); \
0239         settings.append(Setting<int>(cb, num));         \
0240         layout->addWidget(cb);                          \
0241     }
0242 
0243 QWidget *Exif::SearchDialog::makeExposureProgram(QWidget *parent)
0244 {
0245     QGroupBox *box = new QGroupBox(i18n("Exposure Program"), parent);
0246     QVBoxLayout *layout = new QVBoxLayout(box);
0247 
0248     addSetting(m_exposureProgram, "Not defined", 0);
0249     addSetting(m_exposureProgram, "Manual", 1);
0250     addSetting(m_exposureProgram, "Normal program", 2);
0251     addSetting(m_exposureProgram, "Aperture priority", 3);
0252     addSetting(m_exposureProgram, "Shutter priority", 4);
0253     addSetting(m_exposureProgram, "Creative program (biased toward depth of field)", 5);
0254     addSetting(m_exposureProgram, "Action program (biased toward fast shutter speed)", 6);
0255     addSetting(m_exposureProgram, "Portrait mode (for closeup photos with the background out of focus)", 7);
0256     addSetting(m_exposureProgram, "Landscape mode (for landscape photos with the background in focus)", 8);
0257     return box;
0258 }
0259 
0260 QWidget *Exif::SearchDialog::makeOrientation(QWidget *parent)
0261 {
0262     QGroupBox *box = new QGroupBox(i18n("Orientation"), parent);
0263     QVBoxLayout *layout = new QVBoxLayout(box);
0264 
0265     addSetting(m_orientation, "Not rotated", 0);
0266     addSetting(m_orientation, "Rotated counterclockwise", 6);
0267     addSetting(m_orientation, "Rotated clockwise", 8);
0268     addSetting(m_orientation, "Rotated 180 degrees", 3);
0269     return box;
0270 }
0271 
0272 QWidget *Exif::SearchDialog::makeMeteringMode(QWidget *parent)
0273 {
0274     QGroupBox *box = new QGroupBox(i18n("Metering Mode"), parent);
0275     QVBoxLayout *layout = new QVBoxLayout(box);
0276 
0277     addSetting(m_meteringMode, "Unknown", 0);
0278     addSetting(m_meteringMode, "Average", 1);
0279     addSetting(m_meteringMode, "CenterWeightedAverage", 2);
0280     addSetting(m_meteringMode, "Spot", 3);
0281     addSetting(m_meteringMode, "MultiSpot", 4);
0282     addSetting(m_meteringMode, "Pattern", 5);
0283     addSetting(m_meteringMode, "Partial", 6);
0284     addSetting(m_meteringMode, "Other", 255);
0285     return box;
0286 }
0287 
0288 QWidget *Exif::SearchDialog::makeContrast(QWidget *parent)
0289 {
0290     QGroupBox *box = new QGroupBox(i18n("Contrast"), parent);
0291     QVBoxLayout *layout = new QVBoxLayout(box);
0292 
0293     addSetting(m_contrast, "Normal", 0);
0294     addSetting(m_contrast, "Soft", 1);
0295     addSetting(m_contrast, "Hard", 2);
0296     return box;
0297 }
0298 
0299 QWidget *Exif::SearchDialog::makeSharpness(QWidget *parent)
0300 {
0301     QGroupBox *box = new QGroupBox(i18n("Sharpness"), parent);
0302     QVBoxLayout *layout = new QVBoxLayout(box);
0303 
0304     addSetting(m_sharpness, "Normal", 0);
0305     addSetting(m_sharpness, "Soft", 1);
0306     addSetting(m_sharpness, "Hard", 2);
0307     return box;
0308 }
0309 
0310 QWidget *Exif::SearchDialog::makeSaturation(QWidget *parent)
0311 {
0312     QGroupBox *box = new QGroupBox(i18n("Saturation"), parent);
0313     QVBoxLayout *layout = new QVBoxLayout(box);
0314 
0315     addSetting(m_saturation, "Normal", 0);
0316     addSetting(m_saturation, "Low", 1);
0317     addSetting(m_saturation, "High", 2);
0318     return box;
0319 }
0320 
0321 Exif::SearchInfo Exif::SearchDialog::info()
0322 {
0323     Exif::SearchInfo result(m_exifDB);
0324     result.addSearchKey(QString::fromLatin1("Exif_Photo_MeteringMode"), m_meteringMode.selected());
0325     result.addSearchKey(QString::fromLatin1("Exif_Photo_ExposureProgram"), m_exposureProgram.selected());
0326     result.addSearchKey(QString::fromLatin1("Exif_Image_Orientation"), m_orientation.selected());
0327     result.addSearchKey(QString::fromLatin1("Exif_Photo_MeteringMode"), m_meteringMode.selected());
0328     result.addSearchKey(QString::fromLatin1("Exif_Photo_Contrast"), m_contrast.selected());
0329     result.addSearchKey(QString::fromLatin1("Exif_Photo_Sharpness"), m_sharpness.selected());
0330     result.addSearchKey(QString::fromLatin1("Exif_Photo_Saturation"), m_saturation.selected());
0331     result.addCamera(m_cameras.selected());
0332     result.addLens(m_lenses.selected());
0333     result.addRangeKey(m_iso->range());
0334     result.addRangeKey(m_exposureTime->range());
0335     result.addRangeKey(m_fNumber->range());
0336 
0337     SearchInfo::Range focalRange(QString::fromLatin1("Exif_Photo_FocalLength"));
0338     focalRange.min = m_fromFocalLength->value();
0339     focalRange.max = m_toFocalLength->value();
0340     result.addRangeKey(focalRange);
0341     return result;
0342 }
0343 
0344 QWidget *Exif::SearchDialog::makeCamera()
0345 {
0346     QScrollArea *view = new QScrollArea;
0347     view->setWidgetResizable(true);
0348 
0349     QWidget *w = new QWidget;
0350     view->setWidget(w);
0351     QVBoxLayout *layout = new QVBoxLayout(w);
0352 
0353     QList<QPair<QString, QString>> cameras = m_exifDB->cameras();
0354     std::sort(cameras.begin(), cameras.end());
0355 
0356     for (QList<QPair<QString, QString>>::ConstIterator cameraIt = cameras.constBegin(); cameraIt != cameras.constEnd(); ++cameraIt) {
0357         QCheckBox *cb = new QCheckBox(QString::fromUtf8("%1 - %2").arg((*cameraIt).first.trimmed(), (*cameraIt).second.trimmed()));
0358         layout->addWidget(cb);
0359         m_cameras.append(Setting<QPair<QString, QString>>(cb, *cameraIt));
0360     }
0361 
0362     if (cameras.isEmpty()) {
0363         QLabel *label = new QLabel(i18n("No cameras found in the database"));
0364         layout->addWidget(label);
0365     }
0366 
0367     return view;
0368 }
0369 
0370 QWidget *Exif::SearchDialog::makeLens()
0371 {
0372     QScrollArea *view = new QScrollArea;
0373     view->setWidgetResizable(true);
0374 
0375     QWidget *w = new QWidget;
0376     view->setWidget(w);
0377     QVBoxLayout *layout = new QVBoxLayout(w);
0378 
0379     QList<QString> lenses = m_exifDB->lenses();
0380     std::sort(lenses.begin(), lenses.end());
0381 
0382     if (lenses.isEmpty()) {
0383         QLabel *label = new QLabel(i18n("No lenses found in the database"));
0384         layout->addWidget(label);
0385     } else {
0386         // add option "None" first
0387         lenses.prepend(i18nc("As in No persons, no locations etc.", "None"));
0388 
0389         for (QList<QString>::ConstIterator lensIt = lenses.constBegin(); lensIt != lenses.constEnd(); ++lensIt) {
0390             QCheckBox *cb = new QCheckBox(QString::fromUtf8("%1").arg((*lensIt).trimmed()));
0391             layout->addWidget(cb);
0392             m_lenses.append(Setting<QString>(cb, *lensIt));
0393         }
0394     }
0395 
0396     if (m_exifDB->DBFileVersionGuaranteed() < 3) {
0397         QLabel *label = new QLabel(
0398             i18n("Not all images in the database have lens information. "
0399                  "<note>Recreate the Exif search database to ensure lens data for all images.</note>"));
0400         layout->addWidget(label);
0401     }
0402 
0403     return view;
0404 }
0405 
0406 void Exif::SearchDialog::fromFocalLengthChanged(int val)
0407 {
0408     if (m_toFocalLength->value() < val)
0409         m_toFocalLength->setValue(val);
0410 }
0411 
0412 void Exif::SearchDialog::toFocalLengthChanged(int val)
0413 {
0414     if (m_fromFocalLength->value() > val)
0415         m_fromFocalLength->setValue(val);
0416 }
0417 
0418 // vi:expandtab:tabstop=4 shiftwidth=4:
0419 
0420 #include "moc_SearchDialog.cpp"