File indexing completed on 2025-01-19 03:53:04
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2021-03-20 0007 * Description : a tool to export images to iNaturalist web service 0008 * 0009 * SPDX-FileCopyrightText: 2021 by Joerg Lohse <joergmlpts at gmail dot com> 0010 * SPDX-FileCopyrightText: 2005-2008 by Vardhman Jain <vardhman at gmail dot com> 0011 * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0012 * SPDX-FileCopyrightText: 2009 by Luka Renko <lure at kubuntu dot org> 0013 * 0014 * SPDX-License-Identifier: GPL-2.0-or-later 0015 * 0016 * ============================================================ */ 0017 0018 #include "inatwidget_p.h" 0019 0020 namespace DigikamGenericINatPlugin 0021 { 0022 0023 const DItemsListView::ColumnType ItemDate = DItemsListView::ColumnType::User1; 0024 const DItemsListView::ColumnType ItemLocation = DItemsListView::ColumnType::User2; 0025 0026 INatWidget::INatWidget(QWidget* const parent, 0027 DInfoInterface* const iface, 0028 const QString& serviceName) 0029 : WSSettingsWidget(parent, iface, serviceName), 0030 d (new Private) 0031 { 0032 d->serviceName = serviceName; 0033 0034 // -- The account group. ---------------------------------------------- 0035 0036 // make room and insert a QLabel for an account icon 0037 0038 QWidget* const userNameLbl = getAccountBoxLayout()->itemAt(0)->widget(); 0039 getAccountBoxLayout()->removeWidget(userNameLbl); 0040 getAccountBoxLayout()->addWidget(userNameLbl, 0, 0, 1, 1); 0041 d->accountIcon = new QLabel(getAccountBox()); 0042 getAccountBoxLayout()->addWidget(d->accountIcon, 0, 1, 1, 1); 0043 0044 // change user and remove account buttons go the in the row 0045 0046 getAccountBoxLayout()->removeWidget(getChangeUserBtn()); 0047 QHBoxLayout* const changeRemoveUserLayout = new QHBoxLayout(); 0048 d->removeAccount = new QPushButton(getAccountBox()); 0049 d->removeAccount->setText(i18n("Remove Account")); 0050 changeRemoveUserLayout->addWidget(getChangeUserBtn()); 0051 changeRemoveUserLayout->addWidget(d->removeAccount); 0052 getAccountBoxLayout()->addLayout(changeRemoveUserLayout, 2, 0, 1, -1); 0053 0054 // -- The image list -------------------------------------------------- 0055 0056 d->imglst = new DItemsList(this); 0057 0058 0059 d->imglst->setAllowRAW(true); 0060 d->imglst->setIface(iface); 0061 d->imglst->loadImagesFromCurrentSelection(); 0062 0063 d->imglst->listView()->setWhatsThis(i18n("This is the list of images to " 0064 "upload to an iNaturalist observation.")); 0065 0066 d->imglst->listView()->setColumn(ItemDate, i18n("Date"), true); 0067 d->imglst->listView()->setColumn(ItemLocation, i18n("Location"), true); 0068 0069 // -- The observation group. ------------------------------------------ 0070 0071 QGroupBox* const idBox = new QGroupBox(i18n("Observation"), getSettingsBox()); 0072 QVBoxLayout* const idBoxLayout = new QVBoxLayout(idBox); 0073 0074 d->identificationImage = new QLabel(idBox); 0075 d->identificationLabel = new QLabel(i18n("<i>no identification</i>"), idBox); 0076 d->identificationLabel->setWordWrap(true); 0077 QHBoxLayout* const identificationLayout = new QHBoxLayout(); 0078 identificationLayout->addWidget(d->identificationImage); 0079 identificationLayout->addWidget(d->identificationLabel, 1); 0080 idBoxLayout->addLayout(identificationLayout); 0081 0082 d->closestKnownObservation = new QLabel(idBox); 0083 d->closestKnownObservation->setWordWrap(true); 0084 d->closestKnownObservation->setOpenExternalLinks(true); 0085 idBoxLayout->addWidget(d->closestKnownObservation); 0086 0087 d->observationDescription = new DPlainTextEdit(0, idBox); 0088 d->observationDescription->setPlaceholderText(i18n("Optionally describe " 0089 "your observation or explain your identification here.")); 0090 QTextDocument* const pdoc = d->observationDescription->document(); 0091 QFontMetrics fm(pdoc->defaultFont()); 0092 QMargins margins = d->observationDescription->contentsMargins(); 0093 const int nRows = 3; 0094 d->observationDescription->setFixedHeight(nRows * fm.lineSpacing() + 0095 2 * (pdoc->documentMargin() + 0096 d->observationDescription->frameWidth()) + 0097 margins.top() + margins.bottom()); 0098 idBoxLayout->addWidget(d->observationDescription); 0099 d->observationDescription->hide(); 0100 0101 d->identificationEdit = new TaxonEdit(idBox); 0102 d->identificationEdit->setToolTip(i18n("Enter your identification here, " 0103 "popups will guide to a supported " 0104 "name.")); 0105 d->identificationEdit->setPlaceholderText(i18n("Enter your identification " 0106 "here; it is required.")); 0107 d->taxonPopup = new SuggestTaxonCompletion(d->identificationEdit); 0108 idBoxLayout->addWidget(d->identificationEdit); 0109 0110 QLabel* const placeLabel = new QLabel(i18n("Place:"), idBox); 0111 d->placesComboBox = new QComboBox(idBox); 0112 d->placesComboBox->setInsertPolicy(QComboBox::NoInsert); 0113 d->placesComboBox->setEditable(true); 0114 d->moreOptionsButton = new QPushButton(i18n("More options"), idBox); 0115 d->moreOptionsButton->setCheckable(true); 0116 d->moreOptionsButton->setChecked(false); 0117 idBoxLayout->addWidget(d->moreOptionsButton); 0118 QHBoxLayout* const placesLayout = new QHBoxLayout(); 0119 placesLayout->addWidget(placeLabel); 0120 placesLayout->addWidget(d->placesComboBox, 1); 0121 placesLayout->addWidget(d->moreOptionsButton); 0122 idBoxLayout->addLayout(placesLayout); 0123 0124 d->moreOptionsWidget = new QWidget(idBox); 0125 QVBoxLayout* const moreOptionsLayout = new QVBoxLayout(d->moreOptionsWidget); 0126 0127 QLabel* const warnTimeText1 = new QLabel(i18n("Photos should be taken within"), idBox); 0128 d->photoMaxTimeDiffSpB = new QSpinBox(idBox); 0129 d->photoMaxTimeDiffSpB->setMinimum(1); 0130 d->photoMaxTimeDiffSpB->setMaximum(9999); 0131 d->photoMaxTimeDiffSpB->setSingleStep(1); 0132 d->photoMaxTimeDiffSpB->setValue(5); 0133 d->photoMaxTimeDiffSpB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0134 d->photoMaxTimeDiffSpB->setEnabled(true); 0135 QLabel* const warnTimeText2 = new QLabel(i18n("minute(s) of observation."), idBox); 0136 QHBoxLayout* const warnTimeLayout = new QHBoxLayout(); 0137 warnTimeLayout->addWidget(warnTimeText1); 0138 warnTimeLayout->addWidget(d->photoMaxTimeDiffSpB); 0139 warnTimeLayout->addWidget(warnTimeText2, 1); 0140 moreOptionsLayout->addLayout(warnTimeLayout); 0141 0142 QLabel* const warnLocationText1 = new QLabel(i18n("Photos should be taken within"), idBox); 0143 d->photoMaxDistanceSpB = new QSpinBox(idBox); 0144 d->photoMaxDistanceSpB->setMinimum(1); 0145 d->photoMaxDistanceSpB->setMaximum(9999); 0146 d->photoMaxDistanceSpB->setSingleStep(1); 0147 d->photoMaxDistanceSpB->setValue(15); 0148 d->photoMaxDistanceSpB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0149 d->photoMaxDistanceSpB->setEnabled(true); 0150 QLabel* const warnLocationText2 = new QLabel(i18n("meter(s) of observation."), idBox); 0151 QHBoxLayout* warnLocationLayout = new QHBoxLayout(); 0152 warnLocationLayout->addWidget(warnLocationText1); 0153 warnLocationLayout->addWidget(d->photoMaxDistanceSpB); 0154 warnLocationLayout->addWidget(warnLocationText2, 1); 0155 moreOptionsLayout->addLayout(warnLocationLayout); 0156 0157 QLabel* const warnCloseObsText1 = new QLabel(i18n("Known observations should be within"), idBox); 0158 d->closestObservationMaxSpB = new QSpinBox(idBox); 0159 d->closestObservationMaxSpB->setMinimum(10); 0160 d->closestObservationMaxSpB->setMaximum(99999); 0161 d->closestObservationMaxSpB->setSingleStep(10); 0162 d->closestObservationMaxSpB->setValue(500); 0163 d->closestObservationMaxSpB->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0164 d->closestObservationMaxSpB->setEnabled(true); 0165 QLabel* const warnCloseObsText2 = new QLabel(i18n("meter(s) of observation."), idBox); 0166 QHBoxLayout* const warnCloseObsLayout = new QHBoxLayout(); 0167 warnCloseObsLayout->addWidget(warnCloseObsText1); 0168 warnCloseObsLayout->addWidget(d->closestObservationMaxSpB); 0169 warnCloseObsLayout->addWidget(warnCloseObsText2, 1); 0170 moreOptionsLayout->addLayout(warnCloseObsLayout); 0171 idBoxLayout->addWidget(d->moreOptionsWidget); 0172 d->moreOptionsWidget->hide(); 0173 0174 idBox->show(); 0175 getSettingsBoxLayout()->insertWidget(2, idBox); 0176 getSettingsBoxLayout()->setStretch(2, 5); 0177 0178 // -- The options group. ------------------------------------------------ 0179 0180 getPhotoIdCheckBox()->show(); 0181 0182 // hiding widgets not needed here. 0183 0184 getUploadBox()->hide(); 0185 getSizeBox()->hide(); 0186 getAlbumBox()->hide(); 0187 0188 replaceImageList(d->imglst); 0189 0190 this->updateLabels(QString()); 0191 } 0192 0193 INatWidget::~INatWidget() 0194 { 0195 delete d->taxonPopup; 0196 delete d; 0197 } 0198 0199 void INatWidget::updateLabels(const QString& name, const QString& /*url*/) 0200 { 0201 QString url = QLatin1String("https://www.inaturalist.org/"); 0202 0203 if (!name.isEmpty()) 0204 { 0205 url += QLatin1String("observations?place_id=any&user_id=") + name + 0206 QLatin1String("&verifiable=any"); 0207 } 0208 0209 getHeaderLbl()->setText(i18n("<b><h2><a href=\"%1\"><font color=\"#74ac00\"" 0210 ">iNaturalist</font></a> Export</h2></b>", 0211 url)); 0212 } 0213 0214 } // namespace DigikamGenericINatPlugin 0215 0216 #include "moc_inatwidget.cpp"