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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-05-12
0007  * Description : A widget to apply Reverse Geocoding
0008  *
0009  * SPDX-FileCopyrightText: 2010 by Michael G. Hansen <mike at mghansen dot de>
0010  * SPDX-FileCopyrightText: 2010 by Gabriel Voicu <ping dot gabi at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "rgwidget.h"
0017 
0018 // Qt includes
0019 
0020 #include <QCheckBox>
0021 #include <QContextMenuEvent>
0022 #include <QHBoxLayout>
0023 #include <QLabel>
0024 #include <QLineEdit>
0025 #include <QList>
0026 #include <QMap>
0027 #include <QPointer>
0028 #include <QPushButton>
0029 #include <QTreeView>
0030 #include <QVBoxLayout>
0031 #include <QMenu>
0032 #include <QInputDialog>
0033 #include <QAction>
0034 #include <QComboBox>
0035 #include <QApplication>
0036 #include <QMessageBox>
0037 
0038 // KDE includes
0039 
0040 #include <kconfiggroup.h>
0041 #include <klocalizedstring.h>
0042 
0043 // local includes
0044 
0045 #include "dlayoutbox.h"
0046 #include "gpsundocommand.h"
0047 #include "gpsitemmodel.h"
0048 #include "backend-geonames-rg.h"
0049 #include "backend-osm-rg.h"
0050 #include "backend-geonamesUS-rg.h"
0051 #include "parsetagstring.h"
0052 #include "rgtagmodel.h"
0053 #include "simpletreemodel.h"
0054 #include "dmessagebox.h"
0055 #include "dexpanderbox.h"
0056 #include "dmetadata.h"
0057 #include "digikam_debug.h"
0058 
0059 #ifdef GPSSYNC_MODELTEST
0060 #   include <modeltest.h>
0061 #endif // GPSSYNC_MODELTEST
0062 
0063 namespace Digikam
0064 {
0065 
0066 /**
0067  * @class RGWidget
0068  *
0069  * @brief The RGWidget class represents the main widget for reverse geocoding.
0070  */
0071 
0072 class Q_DECL_HIDDEN RGWidget::Private
0073 {
0074 public:
0075 
0076     explicit Private()
0077         : currentlyAskingCancelQuestion     (false),
0078           hideOptions                       (true),
0079           UIEnabled                         (true),
0080           label                             (nullptr),
0081           imageModel                        (nullptr),
0082           selectionModel                    (nullptr),
0083           buttonRGSelected                  (nullptr),
0084           undoCommand                       (nullptr),
0085           serviceComboBox                   (nullptr),
0086           languageEdit                      (nullptr),
0087           currentBackend                    (nullptr),
0088           requestedRGCount                  (0),
0089           receivedRGCount                   (0),
0090           buttonHideOptions                 (nullptr),
0091           tagsLoc                           (nullptr),
0092           metaLoc                           (nullptr),
0093           UGridContainer                    (nullptr),
0094           LGridContainer                    (nullptr),
0095           serviceLabel                      (nullptr),
0096           languageLabel                     (nullptr),
0097           separator                         (nullptr),
0098           tagModel                          (nullptr),
0099           tagTreeView                       (nullptr),
0100           tagSelectionModel                 (nullptr),
0101           actionAddCountry                  (nullptr),
0102           actionAddState                    (nullptr),
0103           actionAddStateDistrict            (nullptr),
0104           actionAddCounty                   (nullptr),
0105           actionAddCity                     (nullptr),
0106           actionAddCityDistrict             (nullptr),
0107           actionAddSuburb                   (nullptr),
0108           actionAddTown                     (nullptr),
0109           actionAddVillage                  (nullptr),
0110           actionAddHamlet                   (nullptr),
0111           actionAddStreet                   (nullptr),
0112           actionAddHouseNumber              (nullptr),
0113           actionAddPlace                    (nullptr),
0114           actionAddLAU2                     (nullptr),
0115           actionAddLAU1                     (nullptr),
0116           actionAddCustomizedSpacer         (nullptr),
0117           actionRemoveTag                   (nullptr),
0118           actionRemoveAllSpacers            (nullptr),
0119           actionAddAllAddressElementsToTag  (nullptr)
0120     {
0121     }
0122 
0123     bool                   currentlyAskingCancelQuestion;
0124     bool                   hideOptions;
0125     bool                   UIEnabled;
0126     QLabel*                label;
0127     GPSItemModel*          imageModel;
0128     QItemSelectionModel*   selectionModel;
0129     QPushButton*           buttonRGSelected;
0130 
0131     GPSUndoCommand*        undoCommand;
0132     QModelIndex            currentTagTreeIndex;
0133 
0134     QComboBox*             serviceComboBox;
0135     QComboBox*             languageEdit;
0136     QList<RGInfo>          photoList;
0137     QList<RGBackend*>      backendRGList;
0138     RGBackend*             currentBackend;
0139     int                    requestedRGCount;
0140     int                    receivedRGCount;
0141     QPushButton*           buttonHideOptions;
0142     QCheckBox*             tagsLoc;
0143     QCheckBox*             metaLoc;
0144     QWidget*               UGridContainer;
0145     QWidget*               LGridContainer;
0146     QLabel*                serviceLabel;
0147     QLabel*                languageLabel;
0148     DLineWidget*           separator;
0149 
0150     RGTagModel*            tagModel;
0151     QTreeView*             tagTreeView;
0152 
0153     QItemSelectionModel*   tagSelectionModel;
0154     QAction*               actionAddCountry;
0155     QAction*               actionAddState;
0156     QAction*               actionAddStateDistrict;
0157     QAction*               actionAddCounty;
0158     QAction*               actionAddCity;
0159     QAction*               actionAddCityDistrict;
0160     QAction*               actionAddSuburb;
0161     QAction*               actionAddTown;
0162     QAction*               actionAddVillage;
0163     QAction*               actionAddHamlet;
0164     QAction*               actionAddStreet;
0165     QAction*               actionAddHouseNumber;
0166     QAction*               actionAddPlace;
0167     QAction*               actionAddLAU2;
0168     QAction*               actionAddLAU1;
0169     QAction*               actionAddCustomizedSpacer;
0170     QAction*               actionRemoveTag;
0171     QAction*               actionRemoveAllSpacers;
0172     QAction*               actionAddAllAddressElementsToTag;
0173 
0174     QMap<QString, QString> countryCode;
0175 };
0176 
0177 /**
0178  * Constructor
0179  * @param imageModel image model
0180  * @param selectionModel image selection model
0181  * @param parent The parent object
0182  */
0183 RGWidget::RGWidget(GPSItemModel* const imageModel, QItemSelectionModel* const selectionModel,
0184                    QAbstractItemModel* externTagModel, QWidget* const parent)
0185     : QWidget(parent),
0186       d      (new Private())
0187 {
0188     d->imageModel     = imageModel;
0189     d->selectionModel = selectionModel;
0190 
0191     // we need to have a main layout and add QVBoxLayout
0192 
0193     QVBoxLayout* const vBoxLayout = new QVBoxLayout(this);
0194     d->UGridContainer             = new QWidget(this);
0195 
0196     vBoxLayout->addWidget(d->UGridContainer);
0197     d->tagTreeView                = new QTreeView(this);
0198     d->tagTreeView->setHeaderHidden(true);
0199     vBoxLayout->addWidget(d->tagTreeView);
0200 
0201     Q_ASSERT(d->tagTreeView != nullptr);
0202 
0203     if (!externTagModel)
0204     {
0205         externTagModel = new SimpleTreeModel(1, this);
0206     }
0207 
0208     d->tagModel = new RGTagModel(externTagModel, this);
0209     d->tagTreeView->setModel(d->tagModel);
0210 
0211 #ifdef GPSSYNC_MODELTEST
0212 
0213     new ModelTest(externTagModel, d->tagTreeView);
0214     new ModelTest(d->tagModel, d->tagTreeView);
0215 
0216 #endif // GPSSYNC_MODELTEST
0217 
0218     d->tagSelectionModel         = new QItemSelectionModel(d->tagModel);
0219     d->tagTreeView->setSelectionModel(d->tagSelectionModel);
0220 
0221     d->actionAddCountry          = new QAction(i18n("Add country tag"), this);
0222     d->actionAddCountry->setData(QLatin1String("{Country}"));
0223     d->actionAddState            = new QAction(i18n("Add state tag"), this);
0224     d->actionAddState->setData(QLatin1String("{State}"));
0225     d->actionAddStateDistrict    = new QAction(i18n("Add state district tag"), this);
0226     d->actionAddStateDistrict->setData(QLatin1String("{State district}"));
0227     d->actionAddCounty           = new QAction(i18n("Add county tag"), this);
0228     d->actionAddCounty->setData(QLatin1String("{County}"));
0229     d->actionAddCity             = new QAction(i18n("Add city tag"), this);
0230     d->actionAddCity->setData(QLatin1String("{City}"));
0231     d->actionAddCityDistrict     = new QAction(i18n("Add city district tag"), this);
0232     d->actionAddCityDistrict->setData(QLatin1String("{City district}"));
0233     d->actionAddSuburb           = new QAction(i18n("Add suburb tag"), this);
0234     d->actionAddSuburb->setData(QLatin1String("{Suburb}"));
0235     d->actionAddTown             = new QAction(i18n("Add town tag"), this);
0236     d->actionAddTown->setData(QLatin1String("{Town}"));
0237     d->actionAddVillage          = new QAction(i18n("Add village tag"), this);
0238     d->actionAddVillage->setData(QLatin1String("{Village}"));
0239     d->actionAddHamlet           = new QAction(i18n("Add hamlet tag"), this);
0240     d->actionAddHamlet->setData(QLatin1String("{Hamlet}"));
0241     d->actionAddStreet           = new QAction(i18n("Add street"), this);
0242     d->actionAddStreet->setData(QLatin1String("{Street}"));
0243     d->actionAddHouseNumber      = new QAction(i18n("Add house number tag"), this);
0244     d->actionAddHouseNumber->setData(QLatin1String("{House number}"));
0245     d->actionAddPlace            = new QAction(i18n("Add place"), this);
0246     d->actionAddPlace->setData(QLatin1String("{Place}"));
0247     d->actionAddLAU2             = new QAction(i18n("Add Local Administrative Area 2"), this);
0248     d->actionAddLAU2->setData(QLatin1String("{LAU2}"));
0249     d->actionAddLAU1             = new QAction(i18n("Add Local Administrative Area 1"), this);
0250     d->actionAddLAU1->setData(QLatin1String("{LAU1}"));
0251     d->actionAddCustomizedSpacer = new QAction(i18n("Add new tag"), this);
0252     d->actionRemoveTag           = new QAction(i18n("Remove selected tag"), this);
0253     d->actionRemoveAllSpacers    = new QAction(i18n("Remove all control tags below this tag"), this);
0254     d->actionRemoveAllSpacers->setData(QLatin1String("Remove all spacers"));
0255 
0256     d->actionAddAllAddressElementsToTag = new QAction(i18n("Add all address elements"), this);
0257     QGridLayout* const gridLayout       = new QGridLayout(d->UGridContainer);
0258 
0259     d->languageLabel = new QLabel(i18n("Select language:"), d->UGridContainer);
0260     d->languageEdit  = new QComboBox(d->UGridContainer);
0261 
0262     DMetadata::CountryCodeMap map = DMetadata::countryCodeMap();
0263 
0264     for (DMetadata::CountryCodeMap::Iterator it = map.begin() ; it != map.end() ; ++it)
0265     {
0266         d->languageEdit->addItem(QString::fromUtf8("%1 - %2").arg(it.key()).arg(it.value()), it.key().toLower());
0267     }
0268 
0269     d->serviceLabel    = new QLabel(i18n("Select service:"), d->UGridContainer);
0270     d->serviceComboBox = new QComboBox(d->UGridContainer);
0271 
0272     d->serviceComboBox->addItem(i18n("Open Street Map"));
0273     d->serviceComboBox->addItem(i18n("Geonames.org place name (non-US)"));
0274     d->serviceComboBox->addItem(i18n("Geonames.org full address (US only)"));
0275 
0276     gridLayout->addWidget(d->serviceLabel,    0, 0, 1, 2);
0277     gridLayout->addWidget(d->serviceComboBox, 1, 0, 1, 2);
0278     gridLayout->addWidget(d->languageLabel,   2, 0, 1, 1);
0279     gridLayout->addWidget(d->languageEdit,    2, 1, 1, 1);
0280 
0281     d->UGridContainer->setLayout(gridLayout);
0282 
0283     d->separator         = new DLineWidget(Qt::Horizontal, this);
0284     vBoxLayout->addWidget(d->separator);
0285 
0286     d->buttonHideOptions = new QPushButton(i18n("Less options"), this);
0287     vBoxLayout->addWidget(d->buttonHideOptions);
0288 
0289     d->LGridContainer              = new QWidget(this);
0290     vBoxLayout->addWidget(d->LGridContainer);
0291     QGridLayout* const LGridLayout = new QGridLayout(d->LGridContainer);
0292 
0293     d->tagsLoc = new QCheckBox(i18n("Write locations as tags"), d->LGridContainer);
0294     d->metaLoc = new QCheckBox(i18n("Write locations metadata"), d->LGridContainer);
0295 
0296     LGridLayout->addWidget(d->tagsLoc, 0, 0, 1, 3);
0297     LGridLayout->addWidget(d->metaLoc, 1, 0, 1, 3);
0298 
0299     d->LGridContainer->setLayout(LGridLayout);
0300 
0301     d->buttonRGSelected = new QPushButton(i18n("Process reverse geocoding"), this);
0302     vBoxLayout->addWidget(d->buttonRGSelected);
0303 
0304     d->backendRGList.append(new BackendOsmRG(this));
0305     d->backendRGList.append(new BackendGeonamesRG(this));
0306     d->backendRGList.append(new BackendGeonamesUSRG(this));
0307 
0308     d->tagTreeView->installEventFilter(this);
0309 
0310     createCountryCodeMap();
0311 
0312     updateUIState();
0313 
0314     connect(d->buttonRGSelected, SIGNAL(clicked()),
0315             this, SLOT(slotButtonRGSelected()));
0316 
0317     connect(d->buttonHideOptions, SIGNAL(clicked()),
0318             this, SLOT(slotHideOptions()));
0319 
0320     connect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
0321             this, SLOT(updateUIState()));
0322 
0323     connect(d->actionAddCountry, SIGNAL(triggered(bool)),
0324             this, SLOT(slotAddSingleSpacer()));
0325 
0326     connect(d->actionAddState, SIGNAL(triggered(bool)),
0327             this, SLOT(slotAddSingleSpacer()));
0328 
0329     connect(d->actionAddStateDistrict, SIGNAL(triggered(bool)),
0330             this, SLOT(slotAddSingleSpacer()));
0331 
0332     connect(d->actionAddCounty, SIGNAL(triggered(bool)),
0333             this, SLOT(slotAddSingleSpacer()));
0334 
0335     connect(d->actionAddCity, SIGNAL(triggered(bool)),
0336             this, SLOT(slotAddSingleSpacer()));
0337 
0338     connect(d->actionAddCityDistrict, SIGNAL(triggered(bool)),
0339             this, SLOT(slotAddSingleSpacer()));
0340 
0341     connect(d->actionAddSuburb, SIGNAL(triggered(bool)),
0342             this, SLOT(slotAddSingleSpacer()));
0343 
0344     connect(d->actionAddTown, SIGNAL(triggered(bool)),
0345             this, SLOT(slotAddSingleSpacer()));
0346 
0347     connect(d->actionAddVillage, SIGNAL(triggered(bool)),
0348             this, SLOT(slotAddSingleSpacer()));
0349 
0350     connect(d->actionAddHamlet, SIGNAL(triggered(bool)),
0351             this, SLOT(slotAddSingleSpacer()));
0352 
0353     connect(d->actionAddHouseNumber, SIGNAL(triggered(bool)),
0354             this, SLOT(slotAddSingleSpacer()));
0355 
0356     connect(d->actionAddStreet, SIGNAL(triggered(bool)),
0357             this, SLOT(slotAddSingleSpacer()));
0358 
0359     connect(d->actionAddPlace, SIGNAL(triggered(bool)),
0360             this, SLOT(slotAddSingleSpacer()));
0361 
0362     connect(d->actionAddLAU2, SIGNAL(triggered(bool)),
0363             this, SLOT(slotAddSingleSpacer()));
0364 
0365     connect(d->actionAddLAU1, SIGNAL(triggered(bool)),
0366             this, SLOT(slotAddSingleSpacer()));
0367 
0368     connect(d->actionAddCustomizedSpacer, SIGNAL(triggered(bool)),
0369             this, SLOT(slotAddCustomizedSpacer()));
0370 
0371     connect(d->actionAddAllAddressElementsToTag, SIGNAL(triggered(bool)),
0372             this, SLOT(slotAddAllAddressElementsToTag()));
0373 
0374     connect(d->imageModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0375             this, SLOT(slotRegenerateNewTags()));
0376 
0377     connect(d->actionRemoveTag, SIGNAL(triggered(bool)),
0378             this, SLOT(slotRemoveTag()));
0379 
0380     connect(d->actionRemoveAllSpacers, SIGNAL(triggered(bool)),
0381             this, SLOT(slotRemoveAllSpacers()));
0382 
0383     for (int i = 0 ; i < d->backendRGList.count() ; ++i)
0384     {
0385         connect(d->backendRGList[i], SIGNAL(signalRGReady(QList<RGInfo>&)),
0386                 this, SLOT(slotRGReady(QList<RGInfo>&)));
0387     }
0388 
0389     int currentServiceIndex = d->serviceComboBox->currentIndex();
0390     d->currentBackend       = d->backendRGList[currentServiceIndex];
0391 }
0392 
0393 /**
0394  * Destructor
0395  */
0396 RGWidget::~RGWidget()
0397 {
0398     delete d;
0399 }
0400 
0401 /**
0402  * Enables or disables the containing widgets.
0403  */
0404 void RGWidget::updateUIState()
0405 {
0406     const bool haveSelection = d->selectionModel->hasSelection();
0407 
0408     d->buttonRGSelected->setEnabled(d->UIEnabled && haveSelection);
0409     d->serviceLabel->setEnabled(d->UIEnabled);
0410     d->serviceComboBox->setEnabled(d->UIEnabled);
0411     d->languageLabel->setEnabled(d->UIEnabled);
0412     d->languageEdit->setEnabled(d->UIEnabled);
0413     d->buttonHideOptions->setEnabled(d->UIEnabled);
0414     d->tagsLoc->setEnabled(d->UIEnabled);
0415     d->metaLoc->setEnabled(d->UIEnabled);
0416 }
0417 
0418 /**
0419  * This slot triggers when the button that start the reverse geocoding process is pressed.
0420  */
0421 void RGWidget::slotButtonRGSelected()
0422 {
0423     // get the selected images
0424 
0425     const QModelIndexList selectedItems = d->selectionModel->selectedRows();
0426     int currentServiceIndex             = d->serviceComboBox->currentIndex();
0427     d->currentBackend                   = d->backendRGList[currentServiceIndex];
0428     d->undoCommand                      = new GPSUndoCommand();
0429     d->undoCommand->setText(i18n("Image tags are changed."));
0430 
0431     QList<RGInfo> photoList;
0432     QString wantedLanguage                 = d->languageEdit->itemData(d->languageEdit->currentIndex()).toString();
0433     QList<QList<TagData> > returnedSpacers = d->tagModel->getSpacers();
0434 
0435     for (int i = 0 ; i < selectedItems.count() ; ++i)
0436     {
0437         const QPersistentModelIndex itemIndex = selectedItems.at(i);
0438         GPSItemContainer* const selectedItem  = d->imageModel->itemFromIndex(itemIndex);
0439         const GPSDataContainer gpsData        = selectedItem->gpsData();
0440 
0441         if (!gpsData.hasCoordinates())
0442         {
0443             continue;
0444         }
0445 
0446         const qreal latitude  = gpsData.getCoordinates().lat();
0447         const qreal longitude = gpsData.getCoordinates().lon();
0448 
0449         RGInfo photoObj;
0450         photoObj.id           = itemIndex;
0451         photoObj.coordinates  = GeoCoordinates(latitude, longitude);
0452 
0453         photoList << photoObj;
0454 
0455         selectedItem->writeTagsToXmp(d->tagsLoc->isChecked());
0456         selectedItem->writeLocations(d->metaLoc->isChecked());
0457     }
0458 
0459     if (!photoList.isEmpty())
0460     {
0461         d->receivedRGCount  = 0;
0462         d->requestedRGCount = photoList.count();
0463 
0464         Q_EMIT signalSetUIEnabled(false, this, QString::fromUtf8(SLOT(slotRGCanceled())));
0465         Q_EMIT signalProgressSetup(d->requestedRGCount, i18n("Retrieving RG info -"));
0466 
0467         d->currentBackend->callRGBackend(photoList, wantedLanguage);
0468     }
0469 }
0470 
0471 /**
0472  * Hide or shows the extra options.
0473  */
0474 void RGWidget::slotHideOptions()
0475 {
0476     if (d->hideOptions)
0477     {
0478         d->LGridContainer->hide();
0479         d->hideOptions = false;
0480         d->buttonHideOptions->setText(i18n("More options"));
0481     }
0482     else
0483     {
0484         d->LGridContainer->show();
0485         d->hideOptions = true;
0486         d->buttonHideOptions->setText(i18n("Less options"));
0487     }
0488 }
0489 
0490 /**
0491  * The data has returned from backend and now it's processed here.
0492  * @param returnedRGList Contains the data returned by backend.
0493  */
0494 void RGWidget::slotRGReady(QList<RGInfo>& returnedRGList)
0495 {
0496     const QString errorString = d->currentBackend->getErrorMessage();
0497 
0498     if (!errorString.isEmpty())
0499     {
0500         /// @todo This collides with the message box displayed if the user aborts the RG process
0501 
0502         QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Reverse Geo-coding Error"), errorString);
0503 
0504         d->receivedRGCount += returnedRGList.count();
0505 
0506         Q_EMIT signalSetUIEnabled(true);
0507 
0508         return;
0509     }
0510 
0511     QString address;
0512 
0513     for (int i = 0 ; i < returnedRGList.count() ; ++i)
0514     {
0515         QPersistentModelIndex currentImageIndex = returnedRGList[i].id;
0516 
0517         if (!returnedRGList[i].rgData.isEmpty())
0518         {
0519             QString addressElementsWantedFormat;
0520 
0521             if      (d->currentBackend->backendName() == QLatin1String("Geonames"))
0522             {
0523                 addressElementsWantedFormat.append(QLatin1String("/{Country}/{Country code}/{Place}"));
0524             }
0525             else if (d->currentBackend->backendName() == QLatin1String("GeonamesUS"))
0526             {
0527                 addressElementsWantedFormat.append(QLatin1String("/{LAU2}/{LAU1}/{City}"));
0528             }
0529             else
0530             {
0531                 addressElementsWantedFormat.append(QLatin1String("/{Country}/{Country code}/{State}/{State district}"
0532                                                                  "/{County}/{City}/{City district}/{Suburb}/{Town}"
0533                                                                  "/{Village}/{Hamlet}/{Street}/{House number}"));
0534             }
0535 
0536             QStringList combinedResult = makeTagString(returnedRGList[i],
0537                                                        addressElementsWantedFormat,
0538                                                        d->currentBackend->backendName());
0539 
0540             QString addressFormat      = combinedResult[0];
0541             QString addressElements    = combinedResult[1];
0542 
0543             // removes first "/" from tag addresses
0544 
0545             addressFormat.remove(0, 1);
0546             addressElements.remove(0, 1);
0547             addressElementsWantedFormat.remove(0, 1);
0548 
0549             const QStringList listAddressElementsWantedFormat = addressElementsWantedFormat.split(QLatin1Char('/'));
0550             const QStringList listAddressElements             = addressElements.split(QLatin1Char('/'));
0551             const QStringList listAddressFormat               = addressFormat.split(QLatin1Char('/'));
0552             QStringList elements, resultedData;
0553 
0554             for (int j = 0 ; j < listAddressElementsWantedFormat.count() ; ++j)
0555             {
0556                 QString currentAddressFormat = listAddressElementsWantedFormat.at(j);
0557                 int currentIndexFormat       = listAddressFormat.indexOf(currentAddressFormat);
0558 
0559                 if (currentIndexFormat != -1)
0560                 {
0561                     elements << currentAddressFormat;
0562                     resultedData << listAddressElements.at(currentIndexFormat);
0563                 }
0564             }
0565 
0566             QList<QList<TagData> > returnedTags = d->tagModel->addNewData(elements, resultedData);
0567 
0568             int countryCodeIndex = listAddressFormat.indexOf(QLatin1String("{Country code}"));
0569 
0570             if (countryCodeIndex != -1)
0571             {
0572                 TagData countryCode;
0573                 countryCode.tagName = d->countryCode.value(listAddressElements.at(countryCodeIndex).toUpper());
0574                 countryCode.tipName = QLatin1String("{Country code}");
0575                 returnedTags << (QList<TagData>() << countryCode);
0576             }
0577 
0578             GPSItemContainer* const currentItem = d->imageModel->itemFromIndex(currentImageIndex);
0579 
0580             GPSUndoCommand::UndoInfo undoInfo(currentImageIndex);
0581             undoInfo.readOldDataFromItem(currentItem);
0582 
0583             currentItem->setTagList(returnedTags);
0584 
0585             undoInfo.readNewDataFromItem(currentItem);
0586             d->undoCommand->addUndoInfo(undoInfo);
0587         }
0588     }
0589 
0590     d->receivedRGCount += returnedRGList.count();
0591 
0592     if (d->receivedRGCount >= d->requestedRGCount)
0593     {
0594         if (d->currentlyAskingCancelQuestion)
0595         {
0596             // if the user is currently answering the cancel question, do nothing, only report progress
0597 
0598             Q_EMIT signalProgressChanged(d->receivedRGCount);
0599         }
0600         else
0601         {
0602             Q_EMIT signalUndoCommand(d->undoCommand);
0603 
0604             d->undoCommand = nullptr;
0605 
0606             Q_EMIT signalSetUIEnabled(true);
0607         }
0608     }
0609     else
0610     {
0611         Q_EMIT signalProgressChanged(d->receivedRGCount);
0612     }
0613 }
0614 
0615 /**
0616  * Sets whether the containing widgets are enabled or disabled.
0617  * @param state If true, the controls are enabled.
0618  */
0619 void RGWidget::setUIEnabled(const bool state)
0620 {
0621     d->UIEnabled = state;
0622     updateUIState();
0623 }
0624 
0625 /**
0626  * Here are filtered the events.
0627  */
0628 bool RGWidget::eventFilter(QObject* watched, QEvent* event)
0629 {
0630     if (watched == d->tagTreeView)
0631     {
0632         if ((event->type() == QEvent::ContextMenu) && d->UIEnabled)
0633         {
0634             QMenu* const menu             = new QMenu(d->tagTreeView);
0635             const int currentServiceIndex = d->serviceComboBox->currentIndex();
0636             d->currentBackend             = d->backendRGList[currentServiceIndex];
0637             QString backendName           = d->currentBackend->backendName();
0638             QContextMenuEvent* const e    = static_cast<QContextMenuEvent*>(event);
0639             d->currentTagTreeIndex        = d->tagTreeView->indexAt(e->pos());
0640             const Type tagType            = d->tagModel->getTagType(d->currentTagTreeIndex);
0641 
0642             if      (backendName == QLatin1String("OSM"))
0643             {
0644                 menu->addAction(d->actionAddAllAddressElementsToTag);
0645                 menu->addSeparator();
0646                 menu->addAction(d->actionAddCountry);
0647                 menu->addAction(d->actionAddState);
0648                 menu->addAction(d->actionAddStateDistrict);
0649                 menu->addAction(d->actionAddCounty);
0650                 menu->addAction(d->actionAddCity);
0651                 menu->addAction(d->actionAddCityDistrict);
0652                 menu->addAction(d->actionAddSuburb);
0653                 menu->addAction(d->actionAddTown);
0654                 menu->addAction(d->actionAddVillage);
0655                 menu->addAction(d->actionAddHamlet);
0656                 menu->addAction(d->actionAddStreet);
0657                 menu->addAction(d->actionAddHouseNumber);
0658             }
0659             else if (backendName == QLatin1String("Geonames"))
0660             {
0661                 menu->addAction(d->actionAddAllAddressElementsToTag);
0662                 menu->addAction(d->actionAddCountry);
0663                 menu->addAction(d->actionAddPlace);
0664             }
0665             else if (backendName == QLatin1String("GeonamesUS"))
0666             {
0667                 menu->addAction(d->actionAddAllAddressElementsToTag);
0668                 menu->addAction(d->actionAddLAU2);
0669                 menu->addAction(d->actionAddLAU1);
0670                 menu->addAction(d->actionAddCity);
0671             }
0672 
0673             menu->addSeparator();
0674             menu->addAction(d->actionAddCustomizedSpacer);
0675             menu->addSeparator();
0676 
0677             if (tagType == TypeSpacer)
0678             {
0679                 menu->addAction(d->actionRemoveTag);
0680             }
0681 
0682             menu->addAction(d->actionRemoveAllSpacers);
0683             menu->exec(e->globalPos());
0684             delete menu;
0685         }
0686     }
0687 
0688     return QObject::eventFilter(watched, event);
0689 }
0690 
0691 /**
0692  * Saves the settings of widgets contained in reverse geocoding widget.
0693  * @param group Here are stored the settings.
0694  */
0695 void RGWidget::saveSettingsToGroup(KConfigGroup* const group)
0696 {
0697     group->writeEntry("RG Backend",        d->serviceComboBox->currentIndex());
0698     group->writeEntry("Language",          d->languageEdit->currentIndex());
0699     group->writeEntry("Hide options",      d->hideOptions);
0700     group->writeEntry("Tags location",     d->tagsLoc->isChecked());
0701     group->writeEntry("Metadata location", d->metaLoc->isChecked());
0702 
0703     QList<QList<TagData> > currentSpacerList = d->tagModel->getSpacers();
0704     const int spacerCount                    = currentSpacerList.count();
0705     group->writeEntry("Spacers count", spacerCount);
0706 
0707     for (int i = 0 ; i < currentSpacerList.count() ; ++i)
0708     {
0709         QString spacerName;
0710         spacerName.append(QString::fromLatin1("Spacerlistname %1").arg(i));
0711         QString spacerType;
0712         spacerType.append(QString::fromLatin1("Spacerlisttype %1").arg(i));
0713 
0714         QStringList spacerTagNames;
0715         QStringList spacerTypes;
0716 
0717         for (int j = 0 ; j < currentSpacerList[i].count() ; ++j)
0718         {
0719             spacerTagNames.append(currentSpacerList[i].at(j).tagName);
0720 
0721             if      (currentSpacerList[i].at(j).tagType == TypeSpacer)
0722             {
0723                 spacerTypes.append(QLatin1String("Spacer"));
0724             }
0725             else if (currentSpacerList[i].at(j).tagType == TypeNewChild)
0726             {
0727                 spacerTypes.append(QLatin1String("NewChild"));
0728             }
0729             else
0730             {
0731                 spacerTypes.append(QLatin1String("OldChild"));
0732             }
0733         }
0734 
0735         group->writeEntry(spacerName, spacerTagNames);
0736         group->writeEntry(spacerType, spacerTypes);
0737     }
0738 }
0739 
0740 /**
0741  * Restores the settings of widgets contained in reverse geocoding widget.
0742  * @param group Here are stored the settings.
0743  */
0744 void RGWidget::readSettingsFromGroup(const KConfigGroup* const group)
0745 {
0746     const int spacerCount = group->readEntry("Spacers count", 0);
0747     QList<QList<TagData> > spacersList;
0748 
0749     for (int i = 0 ; i < spacerCount ; ++i)
0750     {
0751         QStringList spacerTagNames = group->readEntry(QString::fromLatin1("Spacerlistname %1").arg(i), QStringList());
0752         QStringList spacerTypes    = group->readEntry(QString::fromLatin1("Spacerlisttype %1").arg(i), QStringList());
0753         QList<TagData> currentSpacerAddress;
0754 
0755         for (int j = 0 ; j < spacerTagNames.count() ; ++j)
0756         {
0757             TagData currentTagData;
0758             currentTagData.tagName = spacerTagNames.at(j);
0759             QString currentTagType = spacerTypes.at(j);
0760 
0761             if      (currentTagType == QLatin1String("Spacer"))
0762             {
0763                 currentTagData.tagType = TypeSpacer;
0764             }
0765             else if (currentTagType == QLatin1String("NewChild"))
0766             {
0767                 currentTagData.tagType = TypeNewChild;
0768             }
0769             else if (currentTagType == QLatin1String("OldChild"))
0770             {
0771                 currentTagData.tagType = TypeChild;
0772             }
0773             else
0774             {
0775                 qCWarning(DIGIKAM_GENERAL_LOG) << "Unknown tag type" << currentTagType;
0776                 continue;
0777             }
0778 
0779             currentSpacerAddress.append(currentTagData);
0780         }
0781 
0782         spacersList.append(currentSpacerAddress);
0783     }
0784 
0785     // this make sure that all external tags are added to tag tree view before spacers are re-added
0786 
0787     d->tagModel->addAllExternalTagsToTreeView();
0788     d->tagModel->readdNewTags(spacersList);
0789 
0790     d->serviceComboBox->setCurrentIndex(group->readEntry("RG Backend", 0));
0791     d->languageEdit->setCurrentIndex(group->readEntry("Language",      0));
0792 
0793     d->hideOptions = !(group->readEntry("Hide options",                false));
0794     slotHideOptions();
0795 
0796     d->tagsLoc->setChecked(group->readEntry("Tags location",           true));
0797     d->metaLoc->setChecked(group->readEntry("Metadata location",       false));
0798 }
0799 
0800 /**
0801  * Adds a tag to tag tree.
0802  */
0803 void RGWidget::slotAddSingleSpacer()
0804 {
0805 /*
0806     const QModelIndex baseIndex = d->tagSelectionModel->currentIndex();
0807 */
0808     QModelIndex baseIndex;
0809 
0810     if (!d->currentTagTreeIndex.isValid())
0811     {
0812         baseIndex = d->currentTagTreeIndex;
0813     }
0814     else
0815     {
0816         baseIndex = d->tagSelectionModel->currentIndex();
0817     }
0818 
0819     QAction* const senderAction = qobject_cast<QAction*>(sender());
0820     QString currentSpacerName   = senderAction->data().toString();
0821 
0822     d->tagModel->addSpacerTag(baseIndex, currentSpacerName);
0823 }
0824 
0825 /**
0826  * Adds a new tag to the tag tree.
0827  */
0828 void RGWidget::slotAddCustomizedSpacer()
0829 {
0830     QModelIndex baseIndex;
0831 
0832     if (!d->currentTagTreeIndex.isValid())
0833     {
0834         baseIndex = d->currentTagTreeIndex;
0835     }
0836     else
0837     {
0838         baseIndex = d->tagSelectionModel->currentIndex();
0839     }
0840 
0841     bool ok            = false;
0842     QString textString = QInputDialog::getText(this, i18nc("@title:window", "Add New Tag"),
0843                                                i18n("Select a name for the new tag:"),
0844                                                QLineEdit::Normal, QString(), &ok);
0845 
0846     if (ok && !textString.isEmpty())
0847     {
0848         d->tagModel->addSpacerTag(baseIndex, textString);
0849     }
0850 }
0851 
0852 /**
0853  * Removes a tag from tag tree.
0854  * Note: If the tag is an external, it is no more deleted.
0855  */
0856 void RGWidget::slotRemoveTag()
0857 {
0858     const QModelIndex baseIndex = d->tagSelectionModel->currentIndex();
0859     d->tagModel->deleteTag(baseIndex);
0860 }
0861 
0862 /**
0863  * Removes all spacers.
0864  */
0865 void RGWidget::slotRemoveAllSpacers()
0866 {
0867     QString whatShouldRemove = QLatin1String("Spacers");
0868     QModelIndex baseIndex;
0869 
0870     if (!d->currentTagTreeIndex.isValid())
0871     {
0872         baseIndex = d->currentTagTreeIndex;
0873     }
0874     else
0875     {
0876         baseIndex = d->tagSelectionModel->currentIndex();
0877     }
0878 
0879     d->tagModel->deleteAllSpacersOrNewTags(baseIndex, TypeSpacer);
0880 }
0881 
0882 /**
0883  * Re-adds all deleted tags based on Undo/Redo widget.
0884  */
0885 void RGWidget::slotReaddNewTags()
0886 {
0887     for (int row = 0 ; row < d->imageModel->rowCount() ; ++row)
0888     {
0889         GPSItemContainer* const currentItem = d->imageModel->itemFromIndex(d->imageModel->index(row, 0));
0890         QList<QList<TagData> > tagAddresses = currentItem->getTagList();
0891 
0892         if (!tagAddresses.isEmpty())
0893         {
0894             d->tagModel->readdNewTags(tagAddresses);
0895         }
0896     }
0897 }
0898 
0899 /**
0900  * Deletes and re-adds all new added tags.
0901  */
0902 void RGWidget::slotRegenerateNewTags()
0903 {
0904     QModelIndex baseIndex = QModelIndex();
0905     d->tagModel->deleteAllSpacersOrNewTags(baseIndex, TypeNewChild);
0906 
0907     slotReaddNewTags();
0908 }
0909 
0910 /**
0911  * Adds all address elements below the selected tag. The address ellements are order by area size.
0912  * For example: country > state > state district > city ...
0913  */
0914 void RGWidget::slotAddAllAddressElementsToTag()
0915 {
0916     QModelIndex baseIndex;
0917 
0918     if (!d->currentTagTreeIndex.isValid())
0919     {
0920         baseIndex = d->currentTagTreeIndex;
0921     }
0922     else
0923     {
0924         baseIndex = d->tagSelectionModel->currentIndex();
0925     }
0926 
0927     QStringList spacerList;
0928 
0929     if      (d->currentBackend->backendName() == QLatin1String("OSM"))
0930     {
0931         /// @todo Why are these wrapped in QString?
0932 
0933         spacerList.append(QLatin1String("{Country}"));
0934         spacerList.append(QLatin1String("{State}"));
0935         spacerList.append(QLatin1String("{State district}"));
0936         spacerList.append(QLatin1String("{County}"));
0937         spacerList.append(QLatin1String("{City}"));
0938         spacerList.append(QLatin1String("{City district}"));
0939         spacerList.append(QLatin1String("{Suburb}"));
0940         spacerList.append(QLatin1String("{Town}"));
0941         spacerList.append(QLatin1String("{Village}"));
0942         spacerList.append(QLatin1String("{Hamlet}"));
0943         spacerList.append(QLatin1String("{Street}"));
0944         spacerList.append(QLatin1String("{House number}"));
0945     }
0946     else if (d->currentBackend->backendName() == QLatin1String("Geonames"))
0947     {
0948         spacerList.append(QLatin1String("{Country}"));
0949         spacerList.append(QLatin1String("{Place}"));
0950     }
0951     else
0952     {
0953         spacerList.append(QLatin1String("{LAU1}"));
0954         spacerList.append(QLatin1String("{LAU2}"));
0955         spacerList.append(QLatin1String("{City}"));
0956     }
0957 
0958     d->tagModel->addAllSpacersToTag(baseIndex, spacerList,0);
0959 }
0960 
0961 void RGWidget::slotRGCanceled()
0962 {
0963     if (!d->undoCommand)
0964     {
0965         // the undo command object is not available, therefore
0966         // RG has probably been finished already
0967 
0968         return;
0969     }
0970 
0971     if (d->receivedRGCount > 0)
0972     {
0973         // Before we abort, ask the user whether he wants to discard
0974         // the information obtained so far.
0975 
0976         // ATTENTION: While we ask the question, the RG backend continues running
0977         //            and sends information about new images to this widget.
0978         //            This means that RG might finish while we ask the question!!!
0979 
0980         d->currentlyAskingCancelQuestion = true;
0981 
0982         QString question;
0983 
0984         if (d->receivedRGCount > 1)
0985         {
0986             question = i18n("%1 out of %2 images have been reverse geocoded. "
0987                             "Would you like to keep the tags which were "
0988                             "already obtained?",
0989                             d->receivedRGCount, d->requestedRGCount);
0990         }
0991         else
0992         {
0993             question = i18n("1 image have been reverse geocoded. "
0994                             "Would you like to keep the tags which were "
0995                             "already obtained?");
0996         }
0997 
0998         const int result = DMessageBox::showYesNo(QMessageBox::Warning, this,
0999                                                   i18nc("@title:window", "Abort reverse geocoding?"),
1000                                                   question);
1001 
1002         d->currentlyAskingCancelQuestion = false;
1003 
1004         if (result == QMessageBox::Cancel)
1005         {
1006             // continue
1007 
1008             // did RG finish while we asked the question?
1009 
1010             if (d->receivedRGCount==d->requestedRGCount)
1011             {
1012                 // the undo data was delayed, now send it
1013 
1014                 if (d->undoCommand)
1015                 {
1016                     Q_EMIT signalUndoCommand(d->undoCommand);
1017                     d->undoCommand = nullptr;
1018                 }
1019 
1020                 // unlock the UI
1021 
1022                 Q_EMIT signalSetUIEnabled(true);
1023             }
1024 
1025             return;
1026         }
1027 
1028         if (result == QMessageBox::No)
1029         {
1030             // discard the tags
1031 
1032             d->undoCommand->undo();
1033         }
1034 
1035         if (result == QMessageBox::Yes)
1036         {
1037             if (d->undoCommand)
1038             {
1039                 Q_EMIT signalUndoCommand(d->undoCommand);
1040                 d->undoCommand = nullptr;
1041             }
1042         }
1043     }
1044 
1045     // clean up the RG request:
1046 
1047     d->currentBackend->cancelRequests();
1048 
1049     if (d->undoCommand)
1050     {
1051         delete d->undoCommand;
1052         d->undoCommand = nullptr;
1053     }
1054 
1055     Q_EMIT signalSetUIEnabled(true);
1056 }
1057 
1058 void RGWidget::createCountryCodeMap()
1059 {
1060     // All ISO 3166-1 country codes to convert alpha2 to alpha3
1061     // https://en.wikipedia.org/wiki/ISO_3166-1
1062     // https://www.iban.com/country-codes
1063 
1064     d->countryCode.insert(QLatin1String("AF"), QLatin1String("AFG"));
1065     d->countryCode.insert(QLatin1String("AL"), QLatin1String("ALB"));
1066     d->countryCode.insert(QLatin1String("DZ"), QLatin1String("DZA"));
1067     d->countryCode.insert(QLatin1String("AS"), QLatin1String("ASM"));
1068     d->countryCode.insert(QLatin1String("AD"), QLatin1String("AND"));
1069     d->countryCode.insert(QLatin1String("AO"), QLatin1String("AGO"));
1070     d->countryCode.insert(QLatin1String("AI"), QLatin1String("AIA"));
1071     d->countryCode.insert(QLatin1String("AQ"), QLatin1String("ATA"));
1072     d->countryCode.insert(QLatin1String("AG"), QLatin1String("ATG"));
1073     d->countryCode.insert(QLatin1String("AR"), QLatin1String("ARG"));
1074     d->countryCode.insert(QLatin1String("AM"), QLatin1String("ARM"));
1075     d->countryCode.insert(QLatin1String("AW"), QLatin1String("ABW"));
1076     d->countryCode.insert(QLatin1String("AU"), QLatin1String("AUS"));
1077     d->countryCode.insert(QLatin1String("AT"), QLatin1String("AUT"));
1078     d->countryCode.insert(QLatin1String("AZ"), QLatin1String("AZE"));
1079     d->countryCode.insert(QLatin1String("BS"), QLatin1String("BHS"));
1080     d->countryCode.insert(QLatin1String("BH"), QLatin1String("BHR"));
1081     d->countryCode.insert(QLatin1String("BD"), QLatin1String("BGD"));
1082     d->countryCode.insert(QLatin1String("BB"), QLatin1String("BRB"));
1083     d->countryCode.insert(QLatin1String("BY"), QLatin1String("BLR"));
1084     d->countryCode.insert(QLatin1String("BE"), QLatin1String("BEL"));
1085     d->countryCode.insert(QLatin1String("BZ"), QLatin1String("BLZ"));
1086     d->countryCode.insert(QLatin1String("BJ"), QLatin1String("BEN"));
1087     d->countryCode.insert(QLatin1String("BM"), QLatin1String("BMU"));
1088     d->countryCode.insert(QLatin1String("BT"), QLatin1String("BTN"));
1089     d->countryCode.insert(QLatin1String("BO"), QLatin1String("BOL"));
1090     d->countryCode.insert(QLatin1String("BQ"), QLatin1String("BES"));
1091     d->countryCode.insert(QLatin1String("BA"), QLatin1String("BIH"));
1092     d->countryCode.insert(QLatin1String("BW"), QLatin1String("BWA"));
1093     d->countryCode.insert(QLatin1String("BV"), QLatin1String("BVT"));
1094     d->countryCode.insert(QLatin1String("BR"), QLatin1String("BRA"));
1095     d->countryCode.insert(QLatin1String("IO"), QLatin1String("IOT"));
1096     d->countryCode.insert(QLatin1String("BN"), QLatin1String("BRN"));
1097     d->countryCode.insert(QLatin1String("BG"), QLatin1String("BGR"));
1098     d->countryCode.insert(QLatin1String("BF"), QLatin1String("BFA"));
1099     d->countryCode.insert(QLatin1String("BI"), QLatin1String("BDI"));
1100     d->countryCode.insert(QLatin1String("CV"), QLatin1String("CPV"));
1101     d->countryCode.insert(QLatin1String("KH"), QLatin1String("KHM"));
1102     d->countryCode.insert(QLatin1String("CM"), QLatin1String("CMR"));
1103     d->countryCode.insert(QLatin1String("CA"), QLatin1String("CAN"));
1104     d->countryCode.insert(QLatin1String("KY"), QLatin1String("CYM"));
1105     d->countryCode.insert(QLatin1String("CF"), QLatin1String("CAF"));
1106     d->countryCode.insert(QLatin1String("TD"), QLatin1String("TCD"));
1107     d->countryCode.insert(QLatin1String("CL"), QLatin1String("CHL"));
1108     d->countryCode.insert(QLatin1String("CN"), QLatin1String("CHN"));
1109     d->countryCode.insert(QLatin1String("CX"), QLatin1String("CXR"));
1110     d->countryCode.insert(QLatin1String("CC"), QLatin1String("CCK"));
1111     d->countryCode.insert(QLatin1String("CO"), QLatin1String("COL"));
1112     d->countryCode.insert(QLatin1String("KM"), QLatin1String("COM"));
1113     d->countryCode.insert(QLatin1String("CD"), QLatin1String("COD"));
1114     d->countryCode.insert(QLatin1String("CG"), QLatin1String("COG"));
1115     d->countryCode.insert(QLatin1String("CK"), QLatin1String("COK"));
1116     d->countryCode.insert(QLatin1String("CR"), QLatin1String("CRI"));
1117     d->countryCode.insert(QLatin1String("HR"), QLatin1String("HRV"));
1118     d->countryCode.insert(QLatin1String("CU"), QLatin1String("CUB"));
1119     d->countryCode.insert(QLatin1String("CW"), QLatin1String("CUW"));
1120     d->countryCode.insert(QLatin1String("CY"), QLatin1String("CYP"));
1121     d->countryCode.insert(QLatin1String("CZ"), QLatin1String("CZE"));
1122     d->countryCode.insert(QLatin1String("CI"), QLatin1String("CIV"));
1123     d->countryCode.insert(QLatin1String("DK"), QLatin1String("DNK"));
1124     d->countryCode.insert(QLatin1String("DJ"), QLatin1String("DJI"));
1125     d->countryCode.insert(QLatin1String("DM"), QLatin1String("DMA"));
1126     d->countryCode.insert(QLatin1String("DO"), QLatin1String("DOM"));
1127     d->countryCode.insert(QLatin1String("EC"), QLatin1String("ECU"));
1128     d->countryCode.insert(QLatin1String("EG"), QLatin1String("EGY"));
1129     d->countryCode.insert(QLatin1String("SV"), QLatin1String("SLV"));
1130     d->countryCode.insert(QLatin1String("GQ"), QLatin1String("GNQ"));
1131     d->countryCode.insert(QLatin1String("ER"), QLatin1String("ERI"));
1132     d->countryCode.insert(QLatin1String("EE"), QLatin1String("EST"));
1133     d->countryCode.insert(QLatin1String("SZ"), QLatin1String("SWZ"));
1134     d->countryCode.insert(QLatin1String("ET"), QLatin1String("ETH"));
1135     d->countryCode.insert(QLatin1String("FK"), QLatin1String("FLK"));
1136     d->countryCode.insert(QLatin1String("FO"), QLatin1String("FRO"));
1137     d->countryCode.insert(QLatin1String("FJ"), QLatin1String("FJI"));
1138     d->countryCode.insert(QLatin1String("FI"), QLatin1String("FIN"));
1139     d->countryCode.insert(QLatin1String("FR"), QLatin1String("FRA"));
1140     d->countryCode.insert(QLatin1String("GF"), QLatin1String("GUF"));
1141     d->countryCode.insert(QLatin1String("PF"), QLatin1String("PYF"));
1142     d->countryCode.insert(QLatin1String("TF"), QLatin1String("ATF"));
1143     d->countryCode.insert(QLatin1String("GA"), QLatin1String("GAB"));
1144     d->countryCode.insert(QLatin1String("GM"), QLatin1String("GMB"));
1145     d->countryCode.insert(QLatin1String("GE"), QLatin1String("GEO"));
1146     d->countryCode.insert(QLatin1String("DE"), QLatin1String("DEU"));
1147     d->countryCode.insert(QLatin1String("GH"), QLatin1String("GHA"));
1148     d->countryCode.insert(QLatin1String("GI"), QLatin1String("GIB"));
1149     d->countryCode.insert(QLatin1String("GR"), QLatin1String("GRC"));
1150     d->countryCode.insert(QLatin1String("GL"), QLatin1String("GRL"));
1151     d->countryCode.insert(QLatin1String("GD"), QLatin1String("GRD"));
1152     d->countryCode.insert(QLatin1String("GP"), QLatin1String("GLP"));
1153     d->countryCode.insert(QLatin1String("GU"), QLatin1String("GUM"));
1154     d->countryCode.insert(QLatin1String("GT"), QLatin1String("GTM"));
1155     d->countryCode.insert(QLatin1String("GG"), QLatin1String("GGY"));
1156     d->countryCode.insert(QLatin1String("GN"), QLatin1String("GIN"));
1157     d->countryCode.insert(QLatin1String("GW"), QLatin1String("GNB"));
1158     d->countryCode.insert(QLatin1String("GY"), QLatin1String("GUY"));
1159     d->countryCode.insert(QLatin1String("HT"), QLatin1String("HTI"));
1160     d->countryCode.insert(QLatin1String("HM"), QLatin1String("HMD"));
1161     d->countryCode.insert(QLatin1String("VA"), QLatin1String("VAT"));
1162     d->countryCode.insert(QLatin1String("HN"), QLatin1String("HND"));
1163     d->countryCode.insert(QLatin1String("HK"), QLatin1String("HKG"));
1164     d->countryCode.insert(QLatin1String("HU"), QLatin1String("HUN"));
1165     d->countryCode.insert(QLatin1String("IS"), QLatin1String("ISL"));
1166     d->countryCode.insert(QLatin1String("IN"), QLatin1String("IND"));
1167     d->countryCode.insert(QLatin1String("ID"), QLatin1String("IDN"));
1168     d->countryCode.insert(QLatin1String("IR"), QLatin1String("IRN"));
1169     d->countryCode.insert(QLatin1String("IQ"), QLatin1String("IRQ"));
1170     d->countryCode.insert(QLatin1String("IE"), QLatin1String("IRL"));
1171     d->countryCode.insert(QLatin1String("IM"), QLatin1String("IMN"));
1172     d->countryCode.insert(QLatin1String("IL"), QLatin1String("ISR"));
1173     d->countryCode.insert(QLatin1String("IT"), QLatin1String("ITA"));
1174     d->countryCode.insert(QLatin1String("JM"), QLatin1String("JAM"));
1175     d->countryCode.insert(QLatin1String("JP"), QLatin1String("JPN"));
1176     d->countryCode.insert(QLatin1String("JE"), QLatin1String("JEY"));
1177     d->countryCode.insert(QLatin1String("JO"), QLatin1String("JOR"));
1178     d->countryCode.insert(QLatin1String("KZ"), QLatin1String("KAZ"));
1179     d->countryCode.insert(QLatin1String("KE"), QLatin1String("KEN"));
1180     d->countryCode.insert(QLatin1String("KI"), QLatin1String("KIR"));
1181     d->countryCode.insert(QLatin1String("KP"), QLatin1String("PRK"));
1182     d->countryCode.insert(QLatin1String("KR"), QLatin1String("KOR"));
1183     d->countryCode.insert(QLatin1String("KW"), QLatin1String("KWT"));
1184     d->countryCode.insert(QLatin1String("KG"), QLatin1String("KGZ"));
1185     d->countryCode.insert(QLatin1String("LA"), QLatin1String("LAO"));
1186     d->countryCode.insert(QLatin1String("LV"), QLatin1String("LVA"));
1187     d->countryCode.insert(QLatin1String("LB"), QLatin1String("LBN"));
1188     d->countryCode.insert(QLatin1String("LS"), QLatin1String("LSO"));
1189     d->countryCode.insert(QLatin1String("LR"), QLatin1String("LBR"));
1190     d->countryCode.insert(QLatin1String("LY"), QLatin1String("LBY"));
1191     d->countryCode.insert(QLatin1String("LI"), QLatin1String("LIE"));
1192     d->countryCode.insert(QLatin1String("LT"), QLatin1String("LTU"));
1193     d->countryCode.insert(QLatin1String("LU"), QLatin1String("LUX"));
1194     d->countryCode.insert(QLatin1String("MO"), QLatin1String("MAC"));
1195     d->countryCode.insert(QLatin1String("MG"), QLatin1String("MDG"));
1196     d->countryCode.insert(QLatin1String("MW"), QLatin1String("MWI"));
1197     d->countryCode.insert(QLatin1String("MY"), QLatin1String("MYS"));
1198     d->countryCode.insert(QLatin1String("MV"), QLatin1String("MDV"));
1199     d->countryCode.insert(QLatin1String("ML"), QLatin1String("MLI"));
1200     d->countryCode.insert(QLatin1String("MT"), QLatin1String("MLT"));
1201     d->countryCode.insert(QLatin1String("MH"), QLatin1String("MHL"));
1202     d->countryCode.insert(QLatin1String("MQ"), QLatin1String("MTQ"));
1203     d->countryCode.insert(QLatin1String("MR"), QLatin1String("MRT"));
1204     d->countryCode.insert(QLatin1String("MU"), QLatin1String("MUS"));
1205     d->countryCode.insert(QLatin1String("YT"), QLatin1String("MYT"));
1206     d->countryCode.insert(QLatin1String("MX"), QLatin1String("MEX"));
1207     d->countryCode.insert(QLatin1String("FM"), QLatin1String("FSM"));
1208     d->countryCode.insert(QLatin1String("MD"), QLatin1String("MDA"));
1209     d->countryCode.insert(QLatin1String("MC"), QLatin1String("MCO"));
1210     d->countryCode.insert(QLatin1String("MN"), QLatin1String("MNG"));
1211     d->countryCode.insert(QLatin1String("ME"), QLatin1String("MNE"));
1212     d->countryCode.insert(QLatin1String("MS"), QLatin1String("MSR"));
1213     d->countryCode.insert(QLatin1String("MA"), QLatin1String("MAR"));
1214     d->countryCode.insert(QLatin1String("MZ"), QLatin1String("MOZ"));
1215     d->countryCode.insert(QLatin1String("MM"), QLatin1String("MMR"));
1216     d->countryCode.insert(QLatin1String("NA"), QLatin1String("NAM"));
1217     d->countryCode.insert(QLatin1String("NR"), QLatin1String("NRU"));
1218     d->countryCode.insert(QLatin1String("NP"), QLatin1String("NPL"));
1219     d->countryCode.insert(QLatin1String("NL"), QLatin1String("NLD"));
1220     d->countryCode.insert(QLatin1String("NC"), QLatin1String("NCL"));
1221     d->countryCode.insert(QLatin1String("NZ"), QLatin1String("NZL"));
1222     d->countryCode.insert(QLatin1String("NI"), QLatin1String("NIC"));
1223     d->countryCode.insert(QLatin1String("NE"), QLatin1String("NER"));
1224     d->countryCode.insert(QLatin1String("NG"), QLatin1String("NGA"));
1225     d->countryCode.insert(QLatin1String("NU"), QLatin1String("NIU"));
1226     d->countryCode.insert(QLatin1String("NF"), QLatin1String("NFK"));
1227     d->countryCode.insert(QLatin1String("MP"), QLatin1String("MNP"));
1228     d->countryCode.insert(QLatin1String("NO"), QLatin1String("NOR"));
1229     d->countryCode.insert(QLatin1String("OM"), QLatin1String("OMN"));
1230     d->countryCode.insert(QLatin1String("PK"), QLatin1String("PAK"));
1231     d->countryCode.insert(QLatin1String("PW"), QLatin1String("PLW"));
1232     d->countryCode.insert(QLatin1String("PS"), QLatin1String("PSE"));
1233     d->countryCode.insert(QLatin1String("PA"), QLatin1String("PAN"));
1234     d->countryCode.insert(QLatin1String("PG"), QLatin1String("PNG"));
1235     d->countryCode.insert(QLatin1String("PY"), QLatin1String("PRY"));
1236     d->countryCode.insert(QLatin1String("PE"), QLatin1String("PER"));
1237     d->countryCode.insert(QLatin1String("PH"), QLatin1String("PHL"));
1238     d->countryCode.insert(QLatin1String("PN"), QLatin1String("PCN"));
1239     d->countryCode.insert(QLatin1String("PL"), QLatin1String("POL"));
1240     d->countryCode.insert(QLatin1String("PT"), QLatin1String("PRT"));
1241     d->countryCode.insert(QLatin1String("PR"), QLatin1String("PRI"));
1242     d->countryCode.insert(QLatin1String("QA"), QLatin1String("QAT"));
1243     d->countryCode.insert(QLatin1String("MK"), QLatin1String("MKD"));
1244     d->countryCode.insert(QLatin1String("RO"), QLatin1String("ROU"));
1245     d->countryCode.insert(QLatin1String("RU"), QLatin1String("RUS"));
1246     d->countryCode.insert(QLatin1String("RW"), QLatin1String("RWA"));
1247     d->countryCode.insert(QLatin1String("RE"), QLatin1String("REU"));
1248     d->countryCode.insert(QLatin1String("BL"), QLatin1String("BLM"));
1249     d->countryCode.insert(QLatin1String("SH"), QLatin1String("SHN"));
1250     d->countryCode.insert(QLatin1String("KN"), QLatin1String("KNA"));
1251     d->countryCode.insert(QLatin1String("LC"), QLatin1String("LCA"));
1252     d->countryCode.insert(QLatin1String("MF"), QLatin1String("MAF"));
1253     d->countryCode.insert(QLatin1String("PM"), QLatin1String("SPM"));
1254     d->countryCode.insert(QLatin1String("VC"), QLatin1String("VCT"));
1255     d->countryCode.insert(QLatin1String("WS"), QLatin1String("WSM"));
1256     d->countryCode.insert(QLatin1String("SM"), QLatin1String("SMR"));
1257     d->countryCode.insert(QLatin1String("ST"), QLatin1String("STP"));
1258     d->countryCode.insert(QLatin1String("SA"), QLatin1String("SAU"));
1259     d->countryCode.insert(QLatin1String("SN"), QLatin1String("SEN"));
1260     d->countryCode.insert(QLatin1String("RS"), QLatin1String("SRB"));
1261     d->countryCode.insert(QLatin1String("SC"), QLatin1String("SYC"));
1262     d->countryCode.insert(QLatin1String("SL"), QLatin1String("SLE"));
1263     d->countryCode.insert(QLatin1String("SG"), QLatin1String("SGP"));
1264     d->countryCode.insert(QLatin1String("SX"), QLatin1String("SXM"));
1265     d->countryCode.insert(QLatin1String("SK"), QLatin1String("SVK"));
1266     d->countryCode.insert(QLatin1String("SI"), QLatin1String("SVN"));
1267     d->countryCode.insert(QLatin1String("SB"), QLatin1String("SLB"));
1268     d->countryCode.insert(QLatin1String("SO"), QLatin1String("SOM"));
1269     d->countryCode.insert(QLatin1String("ZA"), QLatin1String("ZAF"));
1270     d->countryCode.insert(QLatin1String("GS"), QLatin1String("SGS"));
1271     d->countryCode.insert(QLatin1String("SS"), QLatin1String("SSD"));
1272     d->countryCode.insert(QLatin1String("ES"), QLatin1String("ESP"));
1273     d->countryCode.insert(QLatin1String("LK"), QLatin1String("LKA"));
1274     d->countryCode.insert(QLatin1String("SD"), QLatin1String("SDN"));
1275     d->countryCode.insert(QLatin1String("SR"), QLatin1String("SUR"));
1276     d->countryCode.insert(QLatin1String("SJ"), QLatin1String("SJM"));
1277     d->countryCode.insert(QLatin1String("SE"), QLatin1String("SWE"));
1278     d->countryCode.insert(QLatin1String("CH"), QLatin1String("CHE"));
1279     d->countryCode.insert(QLatin1String("SY"), QLatin1String("SYR"));
1280     d->countryCode.insert(QLatin1String("TW"), QLatin1String("TWN"));
1281     d->countryCode.insert(QLatin1String("TJ"), QLatin1String("TJK"));
1282     d->countryCode.insert(QLatin1String("TZ"), QLatin1String("TZA"));
1283     d->countryCode.insert(QLatin1String("TH"), QLatin1String("THA"));
1284     d->countryCode.insert(QLatin1String("TL"), QLatin1String("TLS"));
1285     d->countryCode.insert(QLatin1String("TG"), QLatin1String("TGO"));
1286     d->countryCode.insert(QLatin1String("TK"), QLatin1String("TKL"));
1287     d->countryCode.insert(QLatin1String("TO"), QLatin1String("TON"));
1288     d->countryCode.insert(QLatin1String("TT"), QLatin1String("TTO"));
1289     d->countryCode.insert(QLatin1String("TN"), QLatin1String("TUN"));
1290     d->countryCode.insert(QLatin1String("TR"), QLatin1String("TUR"));
1291     d->countryCode.insert(QLatin1String("TM"), QLatin1String("TKM"));
1292     d->countryCode.insert(QLatin1String("TC"), QLatin1String("TCA"));
1293     d->countryCode.insert(QLatin1String("TV"), QLatin1String("TUV"));
1294     d->countryCode.insert(QLatin1String("UG"), QLatin1String("UGA"));
1295     d->countryCode.insert(QLatin1String("UA"), QLatin1String("UKR"));
1296     d->countryCode.insert(QLatin1String("AE"), QLatin1String("ARE"));
1297     d->countryCode.insert(QLatin1String("GB"), QLatin1String("GBR"));
1298     d->countryCode.insert(QLatin1String("UM"), QLatin1String("UMI"));
1299     d->countryCode.insert(QLatin1String("US"), QLatin1String("USA"));
1300     d->countryCode.insert(QLatin1String("UY"), QLatin1String("URY"));
1301     d->countryCode.insert(QLatin1String("UZ"), QLatin1String("UZB"));
1302     d->countryCode.insert(QLatin1String("VU"), QLatin1String("VUT"));
1303     d->countryCode.insert(QLatin1String("VE"), QLatin1String("VEN"));
1304     d->countryCode.insert(QLatin1String("VN"), QLatin1String("VNM"));
1305     d->countryCode.insert(QLatin1String("VG"), QLatin1String("VGB"));
1306     d->countryCode.insert(QLatin1String("VI"), QLatin1String("VIR"));
1307     d->countryCode.insert(QLatin1String("WF"), QLatin1String("WLF"));
1308     d->countryCode.insert(QLatin1String("EH"), QLatin1String("ESH"));
1309     d->countryCode.insert(QLatin1String("YE"), QLatin1String("YEM"));
1310     d->countryCode.insert(QLatin1String("ZM"), QLatin1String("ZMB"));
1311     d->countryCode.insert(QLatin1String("ZW"), QLatin1String("ZWE"));
1312     d->countryCode.insert(QLatin1String("AX"), QLatin1String("ALA"));
1313 }
1314 
1315 } // namespace Digikam
1316 
1317 #include "moc_rgwidget.cpp"