diff --git a/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.cpp b/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.cpp index 74df2a0404..d4dfff5f4c 100644 --- a/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.cpp +++ b/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.cpp @@ -1,1091 +1,1122 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-05-16 * Description : A tool to edit geolocation * * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2010-2014 by Michael G. Hansen * Copyright (C) 2010 by Gabriel Voicu * Copyright (C) 2014 by Justus Schwartz * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "geolocationedit.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "dlayoutbox.h" #include "digikam_config.h" #include "itemmarkertiler.h" #include "trackmanager.h" #include "gpscommon.h" #include "gpsitemmodel.h" #include "mapdragdrophandler.h" #include "gpsitemlist.h" #include "gpsitemlistdragdrophandler.h" #include "gpsitemlistcontextmenu.h" #include "gpscorrelatorwidget.h" #include "digikam_debug.h" #include "dmessagebox.h" #include "rgwidget.h" #include "kmlwidget.h" #include "statusprogressbar.h" #include "searchwidget.h" #include "backend-rg.h" #include "gpsitemdetails.h" #include "gpsgeoifacemodelhelper.h" #include "dxmlguiwindow.h" #include "gpsbookmarkowner.h" #include "gpsbookmarkmodelhelper.h" #ifdef GPSSYNC_MODELTEST # include #endif using namespace Digikam; namespace DigikamGenericGeolocationEditPlugin { struct SaveChangedImagesHelper { public: explicit SaveChangedImagesHelper(GPSItemModel* const model) : imageModel(model) { } QPair operator()(const QPersistentModelIndex& itemIndex) { GPSItemContainer* const item = imageModel->itemFromIndex(itemIndex); if (!item) + { return QPair(QUrl(), QString()); + } return QPair(item->url(), item->saveChanges()); } public: typedef QPair result_type; GPSItemModel* const imageModel; }; // --------------------------------------------------------------------------------- struct LoadFileMetadataHelper { public: explicit LoadFileMetadataHelper(GPSItemModel* const model) : imageModel(model) { } QPair operator()(const QPersistentModelIndex& itemIndex) { GPSItemContainer* const item = imageModel->itemFromIndex(itemIndex); if (!item) + { return QPair(QUrl(), QString()); + } item->loadImageData(); return QPair(item->url(), QString()); } public: typedef QPair result_type; - GPSItemModel* const imageModel; + GPSItemModel* const imageModel; }; // --------------------------------------------------------------------------------- class Q_DECL_HIDDEN GeolocationEdit::Private { public: explicit Private() { imageModel = nullptr; selectionModel = nullptr; uiEnabled = true; listViewContextMenu = nullptr; trackManager = nullptr; fileIOFutureWatcher = nullptr; fileIOCountDone = 0; fileIOCountTotal = 0; fileIOCloseAfterSaving = false; buttonBox = nullptr; VSplitter = nullptr; HSplitter = nullptr; treeView = nullptr; stackedWidget = nullptr; tabBar = nullptr; splitterSize = 0; undoStack = nullptr; undoView = nullptr; progressBar = nullptr; progressCancelButton = nullptr; progressCancelObject = nullptr; detailsWidget = nullptr; correlatorWidget = nullptr; rgWidget = nullptr; searchWidget = nullptr; kmlWidget = nullptr; mapSplitter = nullptr; mapWidget = nullptr; mapWidget2 = nullptr; mapDragDropHandler = nullptr; mapModelHelper = nullptr; geoifaceMarkerModel = nullptr; sortActionOldestFirst = nullptr; sortActionYoungestFirst = nullptr; sortMenu = nullptr; mapLayout = MapLayoutOne; cbMapLayout = nullptr; bookmarkOwner = nullptr; actionBookmarkVisibility = nullptr; iface = nullptr; } // General things GPSItemModel* imageModel; QItemSelectionModel* selectionModel; bool uiEnabled; GPSItemListContextMenu* listViewContextMenu; TrackManager* trackManager; // Loading and saving QFuture > fileIOFuture; QFutureWatcher >* fileIOFutureWatcher; int fileIOCountDone; int fileIOCountTotal; bool fileIOCloseAfterSaving; // UI QDialogButtonBox* buttonBox; QSplitter* VSplitter; QSplitter* HSplitter; GPSItemList* treeView; QStackedWidget* stackedWidget; QTabBar* tabBar; int splitterSize; QUndoStack* undoStack; QUndoView* undoView; // UI: progress StatusProgressBar* progressBar; QPushButton* progressCancelButton; QObject* progressCancelObject; QString progressCancelSlot; // UI: tab widgets GPSItemDetails* detailsWidget; GPSCorrelatorWidget* correlatorWidget; RGWidget* rgWidget; SearchWidget* searchWidget; KmlWidget* kmlWidget; // map: UI MapLayout mapLayout; QSplitter* mapSplitter; MapWidget* mapWidget; MapWidget* mapWidget2; // map: helpers MapDragDropHandler* mapDragDropHandler; GPSGeoIfaceModelHelper* mapModelHelper; ItemMarkerTiler* geoifaceMarkerModel; // map: actions QAction* sortActionOldestFirst; QAction* sortActionYoungestFirst; QMenu* sortMenu; QComboBox* cbMapLayout; GPSBookmarkOwner* bookmarkOwner; QAction* actionBookmarkVisibility; DInfoInterface* iface; }; GeolocationEdit::GeolocationEdit(QWidget* const parent, DInfoInterface* const iface) : DPluginDialog(parent, QLatin1String("Geolocation Edit Settings")), d(new Private) { setAttribute(Qt::WA_DeleteOnClose, true); setWindowTitle(i18n("Geolocation Editor")); setMinimumSize(300, 400); setModal(true); d->iface = iface; d->imageModel = new GPSItemModel(this); d->selectionModel = new QItemSelectionModel(d->imageModel); d->trackManager = new TrackManager(this); #ifdef GPSSYNC_MODELTEST new ModelTest(d->imageModel, this); #endif d->bookmarkOwner = new GPSBookmarkOwner(d->imageModel, this); d->undoStack = new QUndoStack(this); d->stackedWidget = new QStackedWidget(); d->searchWidget = new SearchWidget(d->bookmarkOwner, d->imageModel, d->selectionModel, d->stackedWidget); GPSItemContainer::setHeaderData(d->imageModel); d->mapModelHelper = new GPSGeoIfaceModelHelper(d->imageModel, d->selectionModel, this); d->mapModelHelper->addUngroupedModelHelper(d->bookmarkOwner->bookmarkModelHelper()); d->mapModelHelper->addUngroupedModelHelper(d->searchWidget->getModelHelper()); d->mapDragDropHandler = new MapDragDropHandler(d->imageModel, d->mapModelHelper); d->geoifaceMarkerModel = new ItemMarkerTiler(d->mapModelHelper, this); d->actionBookmarkVisibility = new QAction(this); d->actionBookmarkVisibility->setIcon(QIcon::fromTheme(QLatin1String("bookmark-new"))); d->actionBookmarkVisibility->setToolTip(i18n("Display bookmarked positions on the map.")); d->actionBookmarkVisibility->setCheckable(true); connect(d->actionBookmarkVisibility, SIGNAL(changed()), this, SLOT(slotBookmarkVisibilityToggled())); QVBoxLayout* const mainLayout = new QVBoxLayout(this); setLayout(mainLayout); DHBox* const hboxMain = new DHBox(this); mainLayout->addWidget(hboxMain, 10); d->HSplitter = new QSplitter(Qt::Horizontal, hboxMain); d->HSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // ------------------------------------------------------------------------------------------------ DHBox* const hbox = new DHBox(this); QLabel* const labelMapLayout = new QLabel(i18n("Layout:"), hbox); d->cbMapLayout = new QComboBox(hbox); d->cbMapLayout->addItem(i18n("One map"), QVariant::fromValue(MapLayoutOne)); d->cbMapLayout->addItem(i18n("Two maps - horizontal"), QVariant::fromValue(MapLayoutHorizontal)); d->cbMapLayout->addItem(i18n("Two maps - vertical"), QVariant::fromValue(MapLayoutVertical)); labelMapLayout->setBuddy(d->cbMapLayout); d->progressBar = new StatusProgressBar(hbox); d->progressBar->setVisible(false); d->progressBar->setProgressBarMode(StatusProgressBar::ProgressBarMode); d->progressBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); d->progressCancelButton = new QPushButton(hbox); d->progressCancelButton->setVisible(false); d->progressCancelButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); d->progressCancelButton->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel"))); connect(d->progressCancelButton, SIGNAL(clicked()), this, SLOT(slotProgressCancelButtonClicked())); m_buttons->addButton(QDialogButtonBox::Apply); m_buttons->addButton(QDialogButtonBox::Close); m_buttons->setParent(hbox); connect(m_buttons->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &GeolocationEdit::slotApplyClicked); connect(m_buttons->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &GeolocationEdit::close); mainLayout->addWidget(hbox, 0); // ------------------------------------------------------------------------------------------------ d->VSplitter = new QSplitter(Qt::Vertical, d->HSplitter); d->HSplitter->addWidget(d->VSplitter); d->HSplitter->setStretchFactor(0, 10); d->sortMenu = new QMenu(this); d->sortMenu->setTitle(i18n("Sorting")); QActionGroup* const sortOrderExclusive = new QActionGroup(d->sortMenu); sortOrderExclusive->setExclusive(true); connect(sortOrderExclusive, SIGNAL(triggered(QAction*)), this, SLOT(slotSortOptionTriggered(QAction*))); d->sortActionOldestFirst = new QAction(i18n("Show oldest first"), sortOrderExclusive); d->sortActionOldestFirst->setCheckable(true); d->sortMenu->addAction(d->sortActionOldestFirst); d->sortActionYoungestFirst = new QAction(i18n("Show youngest first"), sortOrderExclusive); d->sortMenu->addAction(d->sortActionYoungestFirst); d->sortActionYoungestFirst->setCheckable(true); QWidget* mapVBox = nullptr; d->mapWidget = makeMapWidget(&mapVBox); d->searchWidget->setPrimaryMapWidget(d->mapWidget); d->mapSplitter = new QSplitter(this); d->mapSplitter->addWidget(mapVBox); d->VSplitter->addWidget(d->mapSplitter); d->treeView = new GPSItemList(this); d->treeView->setModelAndSelectionModel(d->imageModel, d->selectionModel); d->treeView->setDragDropHandler(new GPSItemListDragDropHandler(this)); d->treeView->setDragEnabled(true); - // TODO: save and restore the state of the header - // TODO: add a context menu to the header to select which columns should be visible - // TODO: add sorting by column + + /** + * TODO: save and restore the state of the header + * TODO: add a context menu to the header to select which columns should be visible + * TODO: add sorting by column + */ + d->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); d->treeView->setSortingEnabled(true); d->VSplitter->addWidget(d->treeView); d->listViewContextMenu = new GPSItemListContextMenu(d->treeView, d->bookmarkOwner); d->HSplitter->addWidget(d->stackedWidget); d->HSplitter->setCollapsible(1, true); d->splitterSize = 0; DVBox* const vboxTabBar = new DVBox(hboxMain); vboxTabBar->layout()->setContentsMargins(QMargins()); vboxTabBar->layout()->setSpacing(0); d->tabBar = new QTabBar(vboxTabBar); d->tabBar->setShape(QTabBar::RoundedEast); dynamic_cast(vboxTabBar->layout())->addStretch(200); d->tabBar->addTab(i18n("Details")); d->tabBar->addTab(i18n("GPS Correlator")); d->tabBar->addTab(i18n("Undo/Redo")); d->tabBar->addTab(i18n("Reverse Geocoding")); d->tabBar->addTab(i18n("Search")); d->tabBar->addTab(i18n("KML Export")); d->tabBar->installEventFilter(this); d->detailsWidget = new GPSItemDetails(d->stackedWidget, d->imageModel); d->stackedWidget->addWidget(d->detailsWidget); d->correlatorWidget = new GPSCorrelatorWidget(d->stackedWidget, d->imageModel, d->trackManager); d->stackedWidget->addWidget(d->correlatorWidget); d->undoView = new QUndoView(d->undoStack, d->stackedWidget); d->stackedWidget->addWidget(d->undoView); d->rgWidget = new RGWidget(d->imageModel, d->selectionModel, d->iface->tagFilterModel(), d->stackedWidget); d->stackedWidget->addWidget(d->rgWidget); d->stackedWidget->addWidget(d->searchWidget); d->kmlWidget = new KmlWidget(this, d->imageModel, d->iface); d->stackedWidget->addWidget(d->kmlWidget); // --------------------------------------------------------------- connect(d->treeView, SIGNAL(signalImageActivated(QModelIndex)), this, SLOT(slotImageActivated(QModelIndex))); connect(d->correlatorWidget, SIGNAL(signalSetUIEnabled(bool)), this, SLOT(slotSetUIEnabled(bool))); connect(d->correlatorWidget, SIGNAL(signalSetUIEnabled(bool,QObject*const,QString)), this, SLOT(slotSetUIEnabled(bool,QObject*const,QString))); connect(d->correlatorWidget, SIGNAL(signalProgressSetup(int,QString)), this, SLOT(slotProgressSetup(int,QString))); connect(d->correlatorWidget, SIGNAL(signalProgressChanged(int)), this, SLOT(slotProgressChanged(int))); connect(d->correlatorWidget, SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->mapModelHelper, SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->rgWidget, SIGNAL(signalSetUIEnabled(bool)), this, SLOT(slotSetUIEnabled(bool))); connect(d->rgWidget, SIGNAL(signalSetUIEnabled(bool,QObject*const,QString)), this, SLOT(slotSetUIEnabled(bool,QObject*const,QString))); connect(d->rgWidget, SIGNAL(signalProgressSetup(int,QString)), this, SLOT(slotProgressSetup(int,QString))); connect(d->rgWidget, SIGNAL(signalProgressChanged(int)), this, SLOT(slotProgressChanged(int))); connect(d->rgWidget, SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->searchWidget, SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->listViewContextMenu, SIGNAL(signalSetUIEnabled(bool)), this, SLOT(slotSetUIEnabled(bool))); connect(d->listViewContextMenu, SIGNAL(signalSetUIEnabled(bool,QObject*const,QString)), this, SLOT(slotSetUIEnabled(bool,QObject*const,QString))); connect(d->listViewContextMenu, SIGNAL(signalProgressSetup(int,QString)), this, SLOT(slotProgressSetup(int,QString))); connect(d->listViewContextMenu, SIGNAL(signalProgressChanged(int)), this, SLOT(slotProgressChanged(int))); connect(d->listViewContextMenu, SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->tabBar, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabChanged(int))); connect(d->bookmarkOwner->bookmarkModelHelper(), SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->detailsWidget, SIGNAL(signalUndoCommand(GPSUndoCommand*)), this, SLOT(slotGPSUndoCommand(GPSUndoCommand*))); connect(d->cbMapLayout, SIGNAL(activated(int)), this, SLOT(slotLayoutChanged(int))); connect(this, SIGNAL(signalMetadataChangedForUrl(QUrl)), d->iface, SLOT(slotMetadataChangedForUrl(QUrl))); readSettings(); d->mapWidget->setActive(true); setItems(d->iface->currentGPSItems()); } GeolocationEdit::~GeolocationEdit() { delete d; } bool GeolocationEdit::eventFilter(QObject* const o, QEvent* const e) { if ((o == d->tabBar) && (e->type() == QEvent::MouseButtonPress)) { QMouseEvent const* m = static_cast(e); QPoint p (m->x(), m->y()); const int var = d->tabBar->tabAt(p); if (var < 0) { return false; } QList sizes = d->HSplitter->sizes(); if (d->splitterSize == 0) { - if (sizes.at(1) == 0) + if (sizes.at(1) == 0) { sizes[1] = d->stackedWidget->widget(var)->minimumSizeHint().width(); } else if (d->tabBar->currentIndex() == var) { d->splitterSize = sizes.at(1); sizes[1] = 0; } } else { sizes[1] = d->splitterSize; d->splitterSize = 0; } d->tabBar->setCurrentIndex(var); d->stackedWidget->setCurrentIndex(var); d->HSplitter->setSizes(sizes); d->detailsWidget->slotSetActive((d->stackedWidget->currentWidget() == d->detailsWidget) && (d->splitterSize == 0)); return true; } return QWidget::eventFilter(o, e); } void GeolocationEdit::slotCurrentTabChanged(int index) { d->tabBar->setCurrentIndex(index); d->stackedWidget->setCurrentIndex(index); d->detailsWidget->slotSetActive(d->stackedWidget->currentWidget() == d->detailsWidget); } void GeolocationEdit::setCurrentTab(int index) { d->tabBar->setCurrentIndex(index); d->stackedWidget->setCurrentIndex(index); QList sizes = d->HSplitter->sizes(); if (d->splitterSize >= 0) { sizes[1] = d->splitterSize; d->splitterSize = 0; } d->HSplitter->setSizes(sizes); d->detailsWidget->slotSetActive((d->stackedWidget->currentWidget() == d->detailsWidget) && (d->splitterSize == 0)); } void GeolocationEdit::setImages(const QList& images) { QList items; foreach (const QUrl& u, images) { items << new GPSItemContainer(u); } setItems(items); } void GeolocationEdit::setItems(const QList& items) { foreach (GPSItemContainer* const newItem, items) { newItem->loadImageData(); d->imageModel->addItem(newItem); } QList imagesToLoad; for (int i = 0 ; i < d->imageModel->rowCount() ; ++i) { imagesToLoad << d->imageModel->index(i, 0); } slotSetUIEnabled(false); slotProgressSetup(imagesToLoad.count(), i18n("Loading metadata -")); // initiate the saving + d->fileIOCountDone = 0; d->fileIOCountTotal = imagesToLoad.count(); d->fileIOFutureWatcher = new QFutureWatcher >(this); connect(d->fileIOFutureWatcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(slotFileMetadataLoaded(int,int))); d->fileIOFuture = QtConcurrent::mapped(imagesToLoad, LoadFileMetadataHelper(d->imageModel)); d->fileIOFutureWatcher->setFuture(d->fileIOFuture); } void GeolocationEdit::slotFileMetadataLoaded(int beginIndex, int endIndex) { qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << beginIndex << endIndex; d->fileIOCountDone += (endIndex-beginIndex); slotProgressChanged(d->fileIOCountDone); if (d->fileIOCountDone == d->fileIOCountTotal) { slotSetUIEnabled(true); } } void GeolocationEdit::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); - KConfigGroup group = config->group("Geolocation Edit Settings"); + KConfigGroup group = config->group("Geolocation Edit Settings"); // -------------------------- // TODO: sanely determine a default backend + const KConfigGroup groupMapWidget = KConfigGroup(&group, "Map Widget"); d->mapWidget->readSettingsFromGroup(&groupMapWidget); const KConfigGroup groupCorrelatorWidget = KConfigGroup(&group, "Correlator Widget"); d->correlatorWidget->readSettingsFromGroup(&groupCorrelatorWidget); const KConfigGroup groupTreeView = KConfigGroup(&group, "Tree View"); d->treeView->readSettingsFromGroup(&groupTreeView); const KConfigGroup groupSearchWidget = KConfigGroup(&group, "Search Widget"); d->searchWidget->readSettingsFromGroup(&groupSearchWidget); const KConfigGroup groupRGWidget = KConfigGroup(&group, "Reverse Geocoding Widget"); d->rgWidget->readSettingsFromGroup(&groupRGWidget); const KConfigGroup groupDialog = KConfigGroup(&group, "Dialog"); // -------------------------- setCurrentTab(group.readEntry("Current Tab", 0)); const bool showOldestFirst = group.readEntry("Show oldest images first", false); if (showOldestFirst) { d->sortActionOldestFirst->setChecked(true); d->mapWidget->setSortKey(1); } else { d->sortActionYoungestFirst->setChecked(true); d->mapWidget->setSortKey(0); } d->actionBookmarkVisibility->setChecked(group.readEntry("Bookmarks visible", false)); slotBookmarkVisibilityToggled(); if (group.hasKey("SplitterState V1")) { const QByteArray splitterState = QByteArray::fromBase64(group.readEntry("SplitterState V1", QByteArray())); if (!splitterState.isEmpty()) { d->VSplitter->restoreState(splitterState); } } if (group.hasKey("SplitterState H1")) { const QByteArray splitterState = QByteArray::fromBase64(group.readEntry("SplitterState H1", QByteArray())); if (!splitterState.isEmpty()) { d->HSplitter->restoreState(splitterState); } } d->splitterSize = group.readEntry("Splitter H1 CollapsedSize", 0); // ---------------------------------- d->mapLayout = MapLayout(group.readEntry("Map Layout", QVariant::fromValue(int(MapLayoutOne))).value()); d->cbMapLayout->setCurrentIndex(d->mapLayout); adjustMapLayout(false); if (d->mapWidget2) { - const KConfigGroup groupMapWidget = KConfigGroup(&group, "Map Widget 2"); - d->mapWidget2->readSettingsFromGroup(&groupMapWidget); + const KConfigGroup groupMapWidget2 = KConfigGroup(&group, "Map Widget 2"); + d->mapWidget2->readSettingsFromGroup(&groupMapWidget2); d->mapWidget2->setActive(true); } } void GeolocationEdit::saveSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group("Geolocation Edit Settings"); // -------------------------- KConfigGroup groupMapWidget = KConfigGroup(&group, "Map Widget"); d->mapWidget->saveSettingsToGroup(&groupMapWidget); if (d->mapWidget2) { - KConfigGroup groupMapWidget = KConfigGroup(&group, "Map Widget 2"); - d->mapWidget2->saveSettingsToGroup(&groupMapWidget); + KConfigGroup groupMapWidget2 = KConfigGroup(&group, "Map Widget 2"); + d->mapWidget2->saveSettingsToGroup(&groupMapWidget2); } KConfigGroup groupCorrelatorWidget = KConfigGroup(&group, "Correlator Widget"); d->correlatorWidget->saveSettingsToGroup(&groupCorrelatorWidget); KConfigGroup groupTreeView = KConfigGroup(&group, "Tree View"); d->treeView->saveSettingsToGroup(&groupTreeView); KConfigGroup groupSearchWidget = KConfigGroup(&group, "Search Widget"); d->searchWidget->saveSettingsToGroup(&groupSearchWidget); KConfigGroup groupRGWidget = KConfigGroup(&group, "Reverse Geocoding Widget"); d->rgWidget->saveSettingsToGroup(&groupRGWidget); // -------------------------- group.writeEntry("Current Tab", d->tabBar->currentIndex()); group.writeEntry("Show oldest images first", d->sortActionOldestFirst->isChecked()); group.writeEntry("SplitterState V1", d->VSplitter->saveState().toBase64()); group.writeEntry("SplitterState H1", d->HSplitter->saveState().toBase64()); group.writeEntry("Splitter H1 CollapsedSize", d->splitterSize); group.writeEntry("Map Layout", QVariant::fromValue(int(d->mapLayout))); group.writeEntry("Bookmarks visible", d->actionBookmarkVisibility->isChecked()); config->sync(); } void GeolocationEdit::closeEvent(QCloseEvent *e) { if (!e) return; // is the UI locked? + if (!d->uiEnabled) { // please wait until we are done ... + return; } // are there any modified images? + int dirtyImagesCount = 0; for (int i = 0 ; i < d->imageModel->rowCount() ; ++i) { const QModelIndex itemIndex = d->imageModel->index(i, 0); GPSItemContainer* const item = d->imageModel->itemFromIndex(itemIndex); if (item->isDirty() || item->isTagListDirty()) { ++dirtyImagesCount; } } if (dirtyImagesCount > 0) { const QString message = i18np( "You have 1 modified image.", "You have %1 modified images.", dirtyImagesCount ); const int chosenAction = DMessageBox::showYesNo(QMessageBox::Warning, this, i18n("Unsaved changes"), i18n("%1 Would you like to save the changes you made to them?", message) ); if (chosenAction == QMessageBox::No) { saveSettings(); e->accept(); return; } if (chosenAction == QMessageBox::Yes) { // the user wants to save his changes. // this will initiate the saving process and then close the dialog. + saveChanges(true); } // do not close the dialog for now + e->ignore(); return; } saveSettings(); e->accept(); } void GeolocationEdit::slotImageActivated(const QModelIndex& index) { d->detailsWidget->slotSetCurrentImage(index); if (!index.isValid()) + { return; + } GPSItemContainer* const item = d->imageModel->itemFromIndex(index); if (!item) + { return; + } const GeoCoordinates imageCoordinates = item->coordinates(); if (imageCoordinates.hasCoordinates()) { d->mapWidget->setCenter(imageCoordinates); } } void GeolocationEdit::slotSetUIEnabled(const bool enabledState, QObject* const cancelObject, const QString& cancelSlot) { if (enabledState) { // hide the progress bar + d->progressBar->setVisible(false); d->progressCancelButton->setVisible(false); d->progressBar->setProgressValue(d->progressBar->progressTotalSteps()); } - // TODO: disable the worldmapwidget and the images list (at least disable editing operations) + /// TODO: disable the worldmapwidget and the images list (at least disable editing operations) + d->progressCancelObject = cancelObject; d->progressCancelSlot = cancelSlot; d->uiEnabled = enabledState; m_buttons->setEnabled(enabledState); d->correlatorWidget->setUIEnabledExternal(enabledState); d->detailsWidget->setUIEnabledExternal(enabledState); d->rgWidget->setUIEnabled(enabledState); d->treeView->setEditEnabled(enabledState); d->listViewContextMenu->setEnabled(enabledState); d->mapWidget->setAllowModifications(enabledState); } void GeolocationEdit::slotSetUIEnabled(const bool enabledState) { slotSetUIEnabled(enabledState, nullptr, QString()); } void GeolocationEdit::saveChanges(const bool closeAfterwards) { - // TODO: actually save the changes - // are there any modified images? + /** + * TODO: actually save the changes are there any modified images? + */ + QList dirtyImages; for (int i = 0 ; i < d->imageModel->rowCount() ; ++i) { const QModelIndex itemIndex = d->imageModel->index(i, 0); GPSItemContainer* const item = d->imageModel->itemFromIndex(itemIndex); if (item->isDirty() || item->isTagListDirty()) { dirtyImages << itemIndex; } } if (dirtyImages.isEmpty()) { if (closeAfterwards) { close(); } return; } - // TODO: disable the UI and provide progress and cancel information + /// TODO: disable the UI and provide progress and cancel information + slotSetUIEnabled(false); slotProgressSetup(dirtyImages.count(), i18n("Saving changes -")); // initiate the saving + d->fileIOCountDone = 0; d->fileIOCountTotal = dirtyImages.count(); d->fileIOCloseAfterSaving = closeAfterwards; d->fileIOFutureWatcher = new QFutureWatcher >(this); connect(d->fileIOFutureWatcher, SIGNAL(resultsReadyAt(int,int)), this, SLOT(slotFileChangesSaved(int,int))); d->fileIOFuture = QtConcurrent::mapped(dirtyImages, SaveChangedImagesHelper(d->imageModel)); d->fileIOFutureWatcher->setFuture(d->fileIOFuture); } void GeolocationEdit::slotFileChangesSaved(int beginIndex, int endIndex) { qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << beginIndex << endIndex; d->fileIOCountDone += (endIndex-beginIndex); slotProgressChanged(d->fileIOCountDone); if (d->fileIOCountDone == d->fileIOCountTotal) { slotSetUIEnabled(true); // any errors? + QList > errorList; for (int i = 0 ; i < d->fileIOFuture.resultCount() ; ++i) { if (!d->fileIOFuture.resultAt(i).second.isEmpty()) + { errorList << d->fileIOFuture.resultAt(i); + } // To rescan item metadata from host. + emit signalMetadataChangedForUrl(d->fileIOFuture.resultAt(i).first); } if (!errorList.isEmpty()) { QStringList errorStrings; for (int i = 0 ; i < errorList.count() ; ++i) { errorStrings << QString::fromLatin1("%1: %2") .arg(errorList.at(i).first.toLocalFile()) .arg(errorList.at(i).second); } DMessageBox::showInformationList(QMessageBox::Critical, this, i18n("Error"), i18n("Failed to save some information:"), errorStrings); } // done saving files + if (d->fileIOCloseAfterSaving) { close(); } } } void GeolocationEdit::slotApplyClicked() { // save the changes, but do not close afterwards + saveChanges(false); } void GeolocationEdit::slotProgressChanged(const int currentProgress) { d->progressBar->setProgressValue(currentProgress); } void GeolocationEdit::slotProgressSetup(const int maxProgress, const QString& progressText) { d->progressBar->setProgressText(progressText); d->progressBar->setProgressTotalSteps(maxProgress); d->progressBar->setProgressValue(0); d->progressBar->setNotify(true); d->progressBar->setNotificationTitle(i18n("Edit Geolocation"), QIcon::fromTheme(QLatin1String("globe"))); d->progressBar->setVisible(true); d->progressCancelButton->setVisible(d->progressCancelObject != nullptr); } void GeolocationEdit::slotGPSUndoCommand(GPSUndoCommand* undoCommand) { d->undoStack->push(undoCommand); } void GeolocationEdit::slotSortOptionTriggered(QAction* /*sortAction*/) { int newSortKey = 0; if (d->sortActionOldestFirst->isChecked()) { newSortKey |= 1; } d->mapWidget->setSortKey(newSortKey); } void GeolocationEdit::slotProgressCancelButtonClicked() { if (d->progressCancelObject) { QTimer::singleShot(0, d->progressCancelObject, d->progressCancelSlot.toUtf8().constData()); d->progressBar->setProgressValue(d->progressBar->progressTotalSteps()); } } void GeolocationEdit::slotBookmarkVisibilityToggled() { d->bookmarkOwner->bookmarkModelHelper()->setVisible(d->actionBookmarkVisibility->isChecked()); } void GeolocationEdit::slotLayoutChanged(int lay) { d->mapLayout = (MapLayout)lay; adjustMapLayout(true); } MapWidget* GeolocationEdit::makeMapWidget(QWidget** const pvbox) { QWidget* const dummyWidget = new QWidget(this); QVBoxLayout* const vbox = new QVBoxLayout(dummyWidget); MapWidget* const mapWidget = new MapWidget(dummyWidget); mapWidget->setAvailableMouseModes(MouseModePan | MouseModeZoomIntoGroup | MouseModeSelectThumbnail); mapWidget->setVisibleMouseModes(MouseModePan | MouseModeZoomIntoGroup | MouseModeSelectThumbnail); mapWidget->setMouseMode(MouseModeSelectThumbnail); mapWidget->setGroupedModel(d->geoifaceMarkerModel); mapWidget->setDragDropHandler(d->mapDragDropHandler); mapWidget->addUngroupedModel(d->bookmarkOwner->bookmarkModelHelper()); mapWidget->addUngroupedModel(d->searchWidget->getModelHelper()); mapWidget->setTrackManager(d->trackManager); mapWidget->setSortOptionsMenu(d->sortMenu); vbox->addWidget(mapWidget); vbox->addWidget(mapWidget->getControlWidget()); QToolButton* const bookmarkVisibilityButton = new QToolButton(mapWidget); bookmarkVisibilityButton->setDefaultAction(d->actionBookmarkVisibility); mapWidget->addWidgetToControlWidget(bookmarkVisibilityButton); *pvbox = dummyWidget; return mapWidget; } void GeolocationEdit::adjustMapLayout(const bool syncSettings) { if (d->mapLayout == MapLayoutOne) { if (d->mapSplitter->count() > 1) { delete d->mapSplitter->widget(1); d->mapWidget2 = nullptr; } } else { if (d->mapSplitter->count() == 1) { QWidget* mapHolder = nullptr; d->mapWidget2 = makeMapWidget(&mapHolder); d->mapSplitter->addWidget(mapHolder); if (syncSettings) { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group("Geolocation Edit Settings"); const KConfigGroup groupMapWidget = KConfigGroup(&group, "Map Widget"); d->mapWidget2->readSettingsFromGroup(&groupMapWidget); d->mapWidget2->setActive(true); } } if (d->mapLayout == MapLayoutHorizontal) { d->mapSplitter->setOrientation(Qt::Horizontal); } else { d->mapSplitter->setOrientation(Qt::Vertical); } } } } // namespace DigikamGenericGeolocationEditPlugin diff --git a/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.h b/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.h index 8cb11e4b2a..278b2a2522 100644 --- a/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.h +++ b/core/dplugins/generic/metadata/geolocationedit/dialog/geolocationedit.h @@ -1,115 +1,116 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-05-16 * Description : A tool to edit geolocation * * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2010-2014 by Michael G. Hansen * Copyright (C) 2010 by Gabriel Voicu * Copyright (C) 2014 by Justus Schwartz * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_GEO_LOCATION_EDIT_H #define DIGIKAM_GEO_LOCATION_EDIT_H // Qt includes #include #include #include // Local includes #include "dplugindialog.h" #include "geoifacetypes.h" #include "geomodelhelper.h" #include "trackmanager.h" #include "gpsitemcontainer.h" #include "dinfointerface.h" #include "mapwidget.h" #include "gpsundocommand.h" class QAbstractItemModel; using namespace Digikam; namespace DigikamGenericGeolocationEditPlugin { class GeolocationEdit : public DPluginDialog { Q_OBJECT public: explicit GeolocationEdit(QWidget* const parent, DInfoInterface* const iface); ~GeolocationEdit(); - /* + /** * Populate items in dialog list based on url. To be used in case of non database as with Showfoto. */ void setImages(const QList& images); - /* Populate items in dialog list based dedicated GPSItemContainer instances filled with DB info + /** + * Populate items in dialog list based dedicated GPSItemContainer instances filled with DB info */ void setItems(const QList& items); Q_SIGNALS: void signalMetadataChangedForUrl(const QUrl&); protected: void closeEvent(QCloseEvent* e) override; bool eventFilter(QObject*, QEvent*) override; private: void readSettings(); void saveSettings(); void saveChanges(const bool closeAfterwards); MapWidget* makeMapWidget(QWidget** const pvbox); void adjustMapLayout(const bool syncSettings); private Q_SLOTS: void slotImageActivated(const QModelIndex& index); void slotSetUIEnabled(const bool enabledState, QObject* const cancelObject, const QString& cancelSlot); void slotSetUIEnabled(const bool enabledState); void slotApplyClicked(); void slotFileChangesSaved(int beginIndex, int endIndex); void slotFileMetadataLoaded(int beginIndex, int endIndex); void slotProgressChanged(const int currentProgress); void slotProgressSetup(const int maxProgress, const QString& progressText); void slotGPSUndoCommand(GPSUndoCommand* undoCommand); void slotSortOptionTriggered(QAction* sortAction); void setCurrentTab(const int index); void slotProgressCancelButtonClicked(); void slotCurrentTabChanged(int); void slotBookmarkVisibilityToggled(); void slotLayoutChanged(int); private: class Private; Private* const d; }; } // namespace DigikamGenericGeolocationEditPlugin #endif // DIGIKAM_GEO_LOCATION_EDIT_H diff --git a/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.cpp b/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.cpp index 9529ed8f2d..ff21d6abbc 100644 --- a/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.cpp +++ b/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.cpp @@ -1,715 +1,736 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-10-13 * Description : IPTC origin settings page. * * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "iptcorigin.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "squeezedcombobox.h" #include "metadatacheckbox.h" #include "timezonecombobox.h" #include "multivaluesedit.h" #include "dmetadata.h" #include "countryselector.h" #include "dexpanderbox.h" using namespace Digikam; namespace DigikamGenericMetadataEditPlugin { class Q_DECL_HIDDEN IPTCOrigin::Private { public: explicit Private() + : dateCreatedCheck(nullptr), + dateDigitalizedCheck(nullptr), + timeCreatedCheck(nullptr), + timeDigitalizedCheck(nullptr), + syncEXIFDateCheck(nullptr), + cityCheck(nullptr), + sublocationCheck(nullptr), + provinceCheck(nullptr), + timeCreatedSel(nullptr), + timeDigitalizedSel(nullptr), + zoneCreatedSel(nullptr), + zoneDigitalizedSel(nullptr), + setTodayCreatedBtn(nullptr), + setTodayDigitalizedBtn(nullptr), + dateCreatedSel(nullptr), + dateDigitalizedSel(nullptr), + cityEdit(nullptr), + sublocationEdit(nullptr), + provinceEdit(nullptr), + locationEdit(nullptr), + countryCheck(nullptr), + countryCB(nullptr) { - cityEdit = nullptr; - sublocationEdit = nullptr; - provinceEdit = nullptr; - locationEdit = nullptr; - cityCheck = nullptr; - sublocationCheck = nullptr; - provinceCheck = nullptr; - countryCheck = nullptr; - dateCreatedSel = nullptr; - dateDigitalizedSel = nullptr; - timeCreatedSel = nullptr; - timeDigitalizedSel = nullptr; - zoneCreatedSel = nullptr; - zoneDigitalizedSel = nullptr; - dateCreatedCheck = nullptr; - dateDigitalizedCheck = nullptr; - timeCreatedCheck = nullptr; - timeDigitalizedCheck = nullptr; - syncEXIFDateCheck = nullptr; - setTodayCreatedBtn = nullptr; - setTodayDigitalizedBtn = nullptr; - countryCB = nullptr; } QCheckBox* dateCreatedCheck; QCheckBox* dateDigitalizedCheck; QCheckBox* timeCreatedCheck; QCheckBox* timeDigitalizedCheck; QCheckBox* syncEXIFDateCheck; QCheckBox* cityCheck; QCheckBox* sublocationCheck; QCheckBox* provinceCheck; QTimeEdit* timeCreatedSel; QTimeEdit* timeDigitalizedSel; TimeZoneComboBox* zoneCreatedSel; TimeZoneComboBox* zoneDigitalizedSel; QPushButton* setTodayCreatedBtn; QPushButton* setTodayDigitalizedBtn; QDateEdit* dateCreatedSel; QDateEdit* dateDigitalizedSel; QLineEdit* cityEdit; QLineEdit* sublocationEdit; QLineEdit* provinceEdit; MultiValuesEdit* locationEdit; MetadataCheckBox* countryCheck; CountrySelector* countryCB; }; IPTCOrigin::IPTCOrigin(QWidget* const parent) : QWidget(parent), d(new Private) { QGridLayout* const grid = new QGridLayout(this); // IPTC only accept printable Ascii char. + QRegExp asciiRx(QLatin1String("[\x20-\x7F]+$")); QValidator* const asciiValidator = new QRegExpValidator(asciiRx, this); QString dateFormat = QLocale().dateFormat(QLocale::ShortFormat); if (!dateFormat.contains(QLatin1String("yyyy"))) { dateFormat.replace(QLatin1String("yy"), QLatin1String("yyyy")); } QString timeFormat = QLatin1String("hh:mm:ss"); // -------------------------------------------------------- d->dateDigitalizedCheck = new QCheckBox(i18n("Digitization date"), this); d->timeDigitalizedCheck = new QCheckBox(i18n("Digitization time"), this); d->zoneDigitalizedSel = new TimeZoneComboBox(this); d->dateDigitalizedSel = new QDateEdit(this); d->dateDigitalizedSel->setDisplayFormat(dateFormat); d->timeDigitalizedSel = new QTimeEdit(this); d->timeDigitalizedSel->setDisplayFormat(timeFormat); d->setTodayDigitalizedBtn = new QPushButton(); d->setTodayDigitalizedBtn->setIcon(QIcon::fromTheme(QLatin1String("go-jump-today"))); d->setTodayDigitalizedBtn->setWhatsThis(i18n("Set digitization date to today")); d->dateDigitalizedSel->setWhatsThis(i18n("Set here the creation date of " "digital representation.")); d->timeDigitalizedSel->setWhatsThis(i18n("Set here the creation time of " "digital representation.")); d->zoneDigitalizedSel->setWhatsThis(i18n("Set here the time zone of " "digital representation.")); slotSetTodayDigitalized(); // -------------------------------------------------------- d->dateCreatedCheck = new QCheckBox(i18n("Creation date"), this); d->timeCreatedCheck = new QCheckBox(i18n("Creation time"), this); d->zoneCreatedSel = new TimeZoneComboBox(this); d->dateCreatedSel = new QDateEdit(this); d->dateCreatedSel->setDisplayFormat(dateFormat); d->timeCreatedSel = new QTimeEdit(this); d->timeCreatedSel->setDisplayFormat(timeFormat); d->syncEXIFDateCheck = new QCheckBox(i18n("Sync EXIF creation date"), this); d->setTodayCreatedBtn = new QPushButton(); d->setTodayCreatedBtn->setIcon(QIcon::fromTheme(QLatin1String("go-jump-today"))); d->setTodayCreatedBtn->setWhatsThis(i18n("Set creation date to today")); d->dateCreatedSel->setWhatsThis(i18n("Set here the creation date of " "intellectual content.")); d->timeCreatedSel->setWhatsThis(i18n("Set here the creation time of " "intellectual content.")); d->zoneCreatedSel->setWhatsThis(i18n("Set here the time zone of " "intellectual content.")); slotSetTodayCreated(); // -------------------------------------------------------- d->locationEdit = new MultiValuesEdit(this, i18n("Location:"), i18n("Set here the full country name referenced by the content.")); // -------------------------------------------------------- d->cityCheck = new QCheckBox(i18n("City:"), this); d->cityEdit = new QLineEdit(this); d->cityEdit->setClearButtonEnabled(true); d->cityEdit->setValidator(asciiValidator); d->cityEdit->setMaxLength(32); d->cityEdit->setWhatsThis(i18n("Set here the city of content origin. " "This field is limited to 32 ASCII characters.")); // -------------------------------------------------------- d->sublocationCheck = new QCheckBox(i18n("Sublocation:"), this); d->sublocationEdit = new QLineEdit(this); d->sublocationEdit->setClearButtonEnabled(true); d->sublocationEdit->setValidator(asciiValidator); d->sublocationEdit->setMaxLength(32); d->sublocationEdit->setWhatsThis(i18n("Set here the content location within city. " "This field is limited to 32 ASCII characters.")); // -------------------------------------------------------- d->provinceCheck = new QCheckBox(i18n("State/Province:"), this); d->provinceEdit = new QLineEdit(this); d->provinceEdit->setClearButtonEnabled(true); d->provinceEdit->setValidator(asciiValidator); d->provinceEdit->setMaxLength(32); d->provinceEdit->setWhatsThis(i18n("Set here the Province or State of content origin. " "This field is limited to 32 ASCII characters.")); // -------------------------------------------------------- d->countryCheck = new MetadataCheckBox(i18n("Country:"), this); d->countryCB = new CountrySelector(this); d->countryCB->setWhatsThis(i18n("Select here country name of content origin.")); + // Remove 2 last items for the list (separator + Unknown item) + d->countryCB->removeItem(d->countryCB->count()-1); d->countryCB->removeItem(d->countryCB->count()-1); QStringList list; for (int i = 0 ; i < d->countryCB->count() ; ++i) + { list.append(d->countryCB->itemText(i)); + } d->locationEdit->setData(list); // -------------------------------------------------------- QLabel* const note = new QLabel(i18n("Note: " "IPTC " "text tags only support the printable " "ASCII " "characters and limit string sizes. " "Use contextual help for details."), this); note->setOpenExternalLinks(true); note->setWordWrap(true); note->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); // -------------------------------------------------------- grid->addWidget(d->dateDigitalizedCheck, 0, 0, 1, 2); grid->addWidget(d->timeDigitalizedCheck, 0, 2, 1, 2); grid->addWidget(d->dateDigitalizedSel, 1, 0, 1, 2); grid->addWidget(d->timeDigitalizedSel, 1, 2, 1, 1); grid->addWidget(d->zoneDigitalizedSel, 1, 3, 1, 1); grid->addWidget(d->setTodayDigitalizedBtn, 1, 5, 1, 1); grid->addWidget(d->dateCreatedCheck, 2, 0, 1, 2); grid->addWidget(d->timeCreatedCheck, 2, 2, 1, 2); grid->addWidget(d->dateCreatedSel, 3, 0, 1, 2); grid->addWidget(d->timeCreatedSel, 3, 2, 1, 1); grid->addWidget(d->zoneCreatedSel, 3, 3, 1, 1); grid->addWidget(d->setTodayCreatedBtn, 3, 5, 1, 1); grid->addWidget(d->syncEXIFDateCheck, 5, 0, 1, 6); grid->addWidget(d->locationEdit, 6, 0, 1, 6); - grid->addWidget(new DLineWidget(Qt::Horizontal, this), 7, 0, 1, 6); + grid->addWidget(new DLineWidget(Qt::Horizontal, this), 7, 0, 1, 6); grid->addWidget(d->cityCheck, 8, 0, 1, 1); grid->addWidget(d->cityEdit, 8, 1, 1, 5); grid->addWidget(d->sublocationCheck, 9, 0, 1, 1); grid->addWidget(d->sublocationEdit, 9, 1, 1, 5); grid->addWidget(d->provinceCheck, 10, 0, 1, 1); grid->addWidget(d->provinceEdit, 10, 1, 1, 5); grid->addWidget(d->countryCheck, 11, 0, 1, 1); grid->addWidget(d->countryCB, 11, 1, 1, 5); grid->addWidget(note, 12, 0, 1, 6); grid->setColumnStretch(4, 10); grid->setRowStretch(13, 10); grid->setContentsMargins(QMargins()); grid->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); // -------------------------------------------------------- connect(d->dateCreatedCheck, SIGNAL(toggled(bool)), d->dateCreatedSel, SLOT(setEnabled(bool))); connect(d->dateDigitalizedCheck, SIGNAL(toggled(bool)), d->dateDigitalizedSel, SLOT(setEnabled(bool))); connect(d->timeCreatedCheck, SIGNAL(toggled(bool)), d->timeCreatedSel, SLOT(setEnabled(bool))); connect(d->timeDigitalizedCheck, SIGNAL(toggled(bool)), d->timeDigitalizedSel, SLOT(setEnabled(bool))); connect(d->timeCreatedCheck, SIGNAL(toggled(bool)), d->zoneCreatedSel, SLOT(setEnabled(bool))); connect(d->timeDigitalizedCheck, SIGNAL(toggled(bool)), d->zoneDigitalizedSel, SLOT(setEnabled(bool))); connect(d->dateCreatedCheck, SIGNAL(toggled(bool)), d->syncEXIFDateCheck, SLOT(setEnabled(bool))); connect(d->cityCheck, SIGNAL(toggled(bool)), d->cityEdit, SLOT(setEnabled(bool))); connect(d->sublocationCheck, SIGNAL(toggled(bool)), d->sublocationEdit, SLOT(setEnabled(bool))); connect(d->provinceCheck, SIGNAL(toggled(bool)), d->provinceEdit, SLOT(setEnabled(bool))); connect(d->countryCheck, SIGNAL(toggled(bool)), d->countryCB, SLOT(setEnabled(bool))); // -------------------------------------------------------- connect(d->dateCreatedCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->dateDigitalizedCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->timeCreatedCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->timeDigitalizedCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->cityCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->sublocationCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->provinceCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->countryCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->locationEdit, SIGNAL(signalModified()), this, SIGNAL(signalModified())); // -------------------------------------------------------- connect(d->dateCreatedSel, SIGNAL(dateChanged(QDate)), this, SIGNAL(signalModified())); connect(d->dateDigitalizedSel, SIGNAL(dateChanged(QDate)), this, SIGNAL(signalModified())); connect(d->timeCreatedSel, SIGNAL(timeChanged(QTime)), this, SIGNAL(signalModified())); connect(d->timeDigitalizedSel, SIGNAL(timeChanged(QTime)), this, SIGNAL(signalModified())); connect(d->zoneCreatedSel, SIGNAL(currentIndexChanged(QString)), this, SIGNAL(signalModified())); connect(d->zoneDigitalizedSel, SIGNAL(currentIndexChanged(QString)), this, SIGNAL(signalModified())); // -------------------------------------------------------- connect(d->setTodayCreatedBtn, SIGNAL(clicked()), this, SLOT(slotSetTodayCreated())); connect(d->setTodayDigitalizedBtn, SIGNAL(clicked()), this, SLOT(slotSetTodayDigitalized())); // -------------------------------------------------------- connect(d->countryCB, SIGNAL(activated(int)), this, SIGNAL(signalModified())); connect(d->cityEdit, SIGNAL(textChanged(QString)), this, SIGNAL(signalModified())); connect(d->sublocationEdit, SIGNAL(textChanged(QString)), this, SIGNAL(signalModified())); connect(d->provinceEdit, SIGNAL(textChanged(QString)), this, SIGNAL(signalModified())); } IPTCOrigin::~IPTCOrigin() { delete d; } void IPTCOrigin::slotSetTodayCreated() { d->dateCreatedSel->setDate(QDate::currentDate()); d->timeCreatedSel->setTime(QTime::currentTime()); d->zoneCreatedSel->setToUTC(); } void IPTCOrigin::slotSetTodayDigitalized() { d->dateDigitalizedSel->setDate(QDate::currentDate()); d->timeDigitalizedSel->setTime(QTime::currentTime()); d->zoneDigitalizedSel->setToUTC(); } bool IPTCOrigin::syncEXIFDateIsChecked() const { return d->syncEXIFDateCheck->isChecked(); } void IPTCOrigin::setCheckedSyncEXIFDate(bool c) { d->syncEXIFDateCheck->setChecked(c); } QDateTime IPTCOrigin::getIPTCCreationDate() const { return QDateTime(d->dateCreatedSel->date(), d->timeCreatedSel->time()); } void IPTCOrigin::readMetadata(QByteArray& iptcData) { blockSignals(true); DMetadata meta; meta.setIptc(iptcData); QString data; QStringList code, list; QDate date; QTime time; QString dateStr, timeStr; dateStr = meta.getIptcTagString("Iptc.Application2.DateCreated", false); timeStr = meta.getIptcTagString("Iptc.Application2.TimeCreated", false); d->dateCreatedSel->setDate(QDate::currentDate()); d->dateCreatedCheck->setChecked(false); if (!dateStr.isEmpty()) { date = QDate::fromString(dateStr, Qt::ISODate); if (date.isValid()) { d->dateCreatedSel->setDate(date); d->dateCreatedCheck->setChecked(true); } } d->dateCreatedSel->setEnabled(d->dateCreatedCheck->isChecked()); d->syncEXIFDateCheck->setEnabled(d->dateCreatedCheck->isChecked()); d->timeCreatedSel->setTime(QTime::currentTime()); d->timeCreatedCheck->setChecked(false); d->zoneCreatedSel->setToUTC(); if (!timeStr.isEmpty()) { time = QTime::fromString(timeStr, Qt::ISODate); if (time.isValid()) { d->timeCreatedSel->setTime(time); d->timeCreatedCheck->setChecked(true); d->zoneCreatedSel->setTimeZone(timeStr); } } d->timeCreatedSel->setEnabled(d->timeCreatedCheck->isChecked()); d->zoneCreatedSel->setEnabled(d->timeCreatedCheck->isChecked()); dateStr = meta.getIptcTagString("Iptc.Application2.DigitizationDate", false); timeStr = meta.getIptcTagString("Iptc.Application2.DigitizationTime", false); d->dateDigitalizedSel->setDate(QDate::currentDate()); d->dateDigitalizedCheck->setChecked(false); if (!dateStr.isEmpty()) { date = QDate::fromString(dateStr, Qt::ISODate); if (date.isValid()) { d->dateDigitalizedSel->setDate(date); d->dateDigitalizedCheck->setChecked(true); } } d->dateDigitalizedSel->setEnabled(d->dateDigitalizedCheck->isChecked()); d->timeDigitalizedSel->setTime(QTime::currentTime()); d->timeDigitalizedCheck->setChecked(false); d->zoneDigitalizedSel->setToUTC(); if (!timeStr.isEmpty()) { time = QTime::fromString(timeStr, Qt::ISODate); if (time.isValid()) { d->timeDigitalizedSel->setTime(time); d->timeDigitalizedCheck->setChecked(true); d->zoneDigitalizedSel->setTimeZone(timeStr); } } d->timeDigitalizedSel->setEnabled(d->timeDigitalizedCheck->isChecked()); d->zoneDigitalizedSel->setEnabled(d->timeDigitalizedCheck->isChecked()); code = meta.getIptcTagsStringList("Iptc.Application2.LocationCode", false); for (QStringList::Iterator it = code.begin(); it != code.end(); ++it) { - QStringList data = d->locationEdit->getData(); + QStringList lst = d->locationEdit->getData(); QStringList::Iterator it2; - for (it2 = data.begin(); it2 != data.end(); ++it2) + for (it2 = lst.begin() ; it2 != lst.end() ; ++it2) { if ((*it2).left(3) == (*it)) { list.append(*it2); break; } } - if (it2 == data.end()) + if (it2 == lst.end()) + { d->locationEdit->setValid(false); + } } d->locationEdit->setValues(list); d->cityEdit->clear(); d->cityCheck->setChecked(false); data = meta.getIptcTagString("Iptc.Application2.City", false); if (!data.isNull()) { d->cityEdit->setText(data); d->cityCheck->setChecked(true); } d->cityEdit->setEnabled(d->cityCheck->isChecked()); d->sublocationEdit->clear(); d->sublocationCheck->setChecked(false); data = meta.getIptcTagString("Iptc.Application2.SubLocation", false); if (!data.isNull()) { d->sublocationEdit->setText(data); d->sublocationCheck->setChecked(true); } d->sublocationEdit->setEnabled(d->sublocationCheck->isChecked()); d->provinceEdit->clear(); d->provinceCheck->setChecked(false); data = meta.getIptcTagString("Iptc.Application2.ProvinceState", false); if (!data.isNull()) { d->provinceEdit->setText(data); d->provinceCheck->setChecked(true); } d->provinceEdit->setEnabled(d->provinceCheck->isChecked()); d->countryCB->setCurrentIndex(0); d->countryCheck->setChecked(false); data = meta.getIptcTagString("Iptc.Application2.CountryCode", false); if (!data.isNull()) { int item = -1; for (int i = 0 ; i < d->countryCB->count() ; ++i) { if (d->countryCB->itemText(i).left(3) == data) + { item = i; + } } if (item != -1) { d->countryCB->setCurrentIndex(item); d->countryCheck->setChecked(true); } else { d->countryCheck->setValid(false); } } d->countryCB->setEnabled(d->countryCheck->isChecked()); blockSignals(false); } void IPTCOrigin::applyMetadata(QByteArray& exifData, QByteArray& iptcData) { DMetadata meta; meta.setExif(exifData); meta.setIptc(iptcData); if (d->dateCreatedCheck->isChecked()) { meta.setIptcTagString("Iptc.Application2.DateCreated", getIPTCCreationDate().toString(Qt::ISODate)); if (syncEXIFDateIsChecked()) { meta.setExifTagString("Exif.Image.DateTime", getIPTCCreationDate().toString(QLatin1String("yyyy:MM:dd hh:mm:ss"))); } } else { meta.removeIptcTag("Iptc.Application2.DateCreated"); } if (d->dateDigitalizedCheck->isChecked()) { meta.setIptcTagString("Iptc.Application2.DigitizationDate", d->dateDigitalizedSel->date().toString(Qt::ISODate)); } else { meta.removeIptcTag("Iptc.Application2.DigitizationDate"); } if (d->timeCreatedCheck->isChecked()) { meta.setIptcTagString("Iptc.Application2.TimeCreated", d->timeCreatedSel->time().toString(Qt::ISODate) + d->zoneCreatedSel->getTimeZone()); } else { meta.removeIptcTag("Iptc.Application2.TimeCreated"); } if (d->timeDigitalizedCheck->isChecked()) { meta.setIptcTagString("Iptc.Application2.DigitizationTime", d->timeDigitalizedSel->time().toString(Qt::ISODate) + d->zoneDigitalizedSel->getTimeZone()); } else { meta.removeIptcTag("Iptc.Application2.DigitizationTime"); } QStringList oldList, newList; if (d->locationEdit->getValues(oldList, newList)) { QStringList oldCode, newCode, oldName, newName; - for (QStringList::Iterator it = oldList.begin(); it != oldList.end(); ++it) + for (QStringList::Iterator it = oldList.begin() ; it != oldList.end() ; ++it) { oldCode.append((*it).left(3)); oldName.append((*it).mid(6)); } - for (QStringList::Iterator it2 = newList.begin(); it2 != newList.end(); ++it2) + for (QStringList::Iterator it2 = newList.begin() ; it2 != newList.end() ; ++it2) { newCode.append((*it2).left(3)); newName.append((*it2).mid(6)); } meta.setIptcTagsStringList("Iptc.Application2.LocationCode", 3, oldCode, newCode); meta.setIptcTagsStringList("Iptc.Application2.LocationName", 64, oldName, newName); } else { meta.removeIptcTag("Iptc.Application2.LocationCode"); meta.removeIptcTag("Iptc.Application2.LocationName"); } if (d->cityCheck->isChecked()) + { meta.setIptcTagString("Iptc.Application2.City", d->cityEdit->text()); + } else + { meta.removeIptcTag("Iptc.Application2.City"); + } if (d->sublocationCheck->isChecked()) + { meta.setIptcTagString("Iptc.Application2.SubLocation", d->sublocationEdit->text()); + } else + { meta.removeIptcTag("Iptc.Application2.SubLocation"); + } if (d->provinceCheck->isChecked()) + { meta.setIptcTagString("Iptc.Application2.ProvinceState", d->provinceEdit->text()); + } else + { meta.removeIptcTag("Iptc.Application2.ProvinceState"); + } - if (d->countryCheck->isChecked()) + if (d->countryCheck->isChecked()) { QString countryName = d->countryCB->currentText().mid(6); QString countryCode = d->countryCB->currentText().left(3); meta.setIptcTagString("Iptc.Application2.CountryCode", countryCode); meta.setIptcTagString("Iptc.Application2.CountryName", countryName); } else if (d->countryCheck->isValid()) { meta.removeIptcTag("Iptc.Application2.CountryCode"); meta.removeIptcTag("Iptc.Application2.CountryName"); } exifData = meta.getExifEncoded(); iptcData = meta.getIptc(); } } // namespace DigikamGenericMetadataEditPlugin diff --git a/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.h b/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.h index 1ad822491b..62579d036b 100644 --- a/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.h +++ b/core/dplugins/generic/metadata/metadataedit/iptc/iptcorigin.h @@ -1,70 +1,70 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-10-13 * Description : IPTC origin settings page. * * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_IPTC_ORIGIN_H #define DIGIKAM_IPTC_ORIGIN_H // Qt includes #include #include #include namespace DigikamGenericMetadataEditPlugin { class IPTCOrigin : public QWidget { Q_OBJECT public: explicit IPTCOrigin(QWidget* const parent); ~IPTCOrigin(); void applyMetadata(QByteArray& exifData, QByteArray& iptcData); void readMetadata(QByteArray& iptcData); - bool syncEXIFDateIsChecked() const; + bool syncEXIFDateIsChecked() const; void setCheckedSyncEXIFDate(bool c); - QDateTime getIPTCCreationDate() const; + QDateTime getIPTCCreationDate() const; Q_SIGNALS: void signalModified(); private Q_SLOTS: void slotSetTodayCreated(); void slotSetTodayDigitalized(); private: class Private; Private* const d; }; } // namespace DigikamGenericMetadataEditPlugin #endif // DIGIKAM_IPTC_ORIGIN_H diff --git a/core/dplugins/generic/metadata/metadataedit/metadataeditplugin.h b/core/dplugins/generic/metadata/metadataedit/metadataeditplugin.h index b1f644d29b..d03f292c53 100644 --- a/core/dplugins/generic/metadata/metadataedit/metadataeditplugin.h +++ b/core/dplugins/generic/metadata/metadataedit/metadataeditplugin.h @@ -1,64 +1,64 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2018-07-30 * Description : a plugin to edit items metadata. * * Copyright (C) 2018-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_METADATA_EDIT_PLUGIN_H #define DIGIKAM_METADATA_EDIT_PLUGIN_H // Local includes #include "dplugingeneric.h" #define DPLUGIN_IID "org.kde.digikam.plugin.generic.MetadataEdit" using namespace Digikam; namespace DigikamGenericMetadataEditPlugin { class MetadataEditPlugin : public DPluginGeneric { Q_OBJECT Q_PLUGIN_METADATA(IID DPLUGIN_IID) Q_INTERFACES(Digikam::DPluginGeneric) public: explicit MetadataEditPlugin(QObject* const parent = nullptr); ~MetadataEditPlugin(); QString name() const override; QString iid() const override; QIcon icon() const override; QString details() const override; QString description() const override; QList authors() const override; - void setup(QObject* const) override; + void setup(QObject* const) override; private Q_SLOTS: void slotEditMetadata(); }; } // namespace DigikamGenericMetadataEditPlugin #endif // DIGIKAM_METADATA_EDIT_PLUGIN_H diff --git a/core/dplugins/generic/metadata/metadataedit/xmp/xmpproperties.cpp b/core/dplugins/generic/metadata/metadataedit/xmp/xmpproperties.cpp index f1987457f5..b853af982e 100644 --- a/core/dplugins/generic/metadata/metadataedit/xmp/xmpproperties.cpp +++ b/core/dplugins/generic/metadata/metadataedit/xmp/xmpproperties.cpp @@ -1,550 +1,579 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-10-24 * Description : XMP workflow status properties settings page. * * Copyright (C) 2007-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "xmpproperties.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "squeezedcombobox.h" #include "digikam_debug.h" #include "altlangstringedit.h" #include "metadatacheckbox.h" #include "multivaluesedit.h" #include "objectattributesedit.h" #include "dmetadata.h" #include "dexpanderbox.h" using namespace Digikam; namespace DigikamGenericMetadataEditPlugin { class Q_DECL_HIDDEN XMPProperties::Private { public: explicit Private() + : originalTransCheck(nullptr), + priorityCB(nullptr), + objectTypeCB(nullptr), + objectAttributeEdit(nullptr), + originalTransEdit(nullptr), + priorityCheck(nullptr), + objectAttributeCheck(nullptr), + sceneEdit(nullptr), + objectTypeEdit(nullptr), + languageEdit(nullptr), + objectAttributeCB(nullptr) { - priorityCB = nullptr; - objectTypeCB = nullptr; - priorityCheck = nullptr; - objectAttributeCheck = nullptr; - sceneEdit = nullptr; - objectTypeEdit = nullptr; - objectAttributeEdit = nullptr; - objectAttributeCB = nullptr; - languageEdit = nullptr; - originalTransEdit = nullptr; - originalTransCheck = nullptr; - sceneCodeMap.insert( QLatin1String("010100"), i18n("Headshot") ); sceneCodeMap.insert( QLatin1String("010200"), i18n("Half-length") ); sceneCodeMap.insert( QLatin1String("010300"), i18n("Full-length") ); sceneCodeMap.insert( QLatin1String("010400"), i18nc("Side view of a person", "Profile") ); sceneCodeMap.insert( QLatin1String("010500"), i18n("Rear view") ); sceneCodeMap.insert( QLatin1String("010600"), i18n("Single") ); sceneCodeMap.insert( QLatin1String("010700"), i18n("Couple") ); sceneCodeMap.insert( QLatin1String("010800"), i18n("Two") ); sceneCodeMap.insert( QLatin1String("010900"), i18nc("group of people", "Group") ); sceneCodeMap.insert( QLatin1String("011000"), i18n("General view") ); sceneCodeMap.insert( QLatin1String("011100"), i18n("Panoramic view") ); sceneCodeMap.insert( QLatin1String("011200"), i18n("Aerial view") ); sceneCodeMap.insert( QLatin1String("011300"), i18n("Under-water") ); sceneCodeMap.insert( QLatin1String("011400"), i18n("Night scene") ); sceneCodeMap.insert( QLatin1String("011500"), i18n("Satellite") ); sceneCodeMap.insert( QLatin1String("011600"), i18n("Exterior view") ); sceneCodeMap.insert( QLatin1String("011700"), i18n("Interior view") ); sceneCodeMap.insert( QLatin1String("011800"), i18n("Close-up") ); sceneCodeMap.insert( QLatin1String("011900"), i18n("Action") ); sceneCodeMap.insert( QLatin1String("012000"), i18n("Performing") ); sceneCodeMap.insert( QLatin1String("012100"), i18n("Posing") ); sceneCodeMap.insert( QLatin1String("012200"), i18n("Symbolic") ); sceneCodeMap.insert( QLatin1String("012300"), i18n("Off-beat") ); sceneCodeMap.insert( QLatin1String("012400"), i18n("Movie scene") ); typeCodeMap.insert( QLatin1String("Advisory"), i18n("Advisory") ); typeCodeMap.insert( QLatin1String("Alert"), i18n("Alert") ); typeCodeMap.insert( QLatin1String("Catalog"), i18n("Catalog") ); typeCodeMap.insert( QLatin1String("Data"), i18n("Data") ); typeCodeMap.insert( QLatin1String("Document"), i18nc("type is a document", "Document") ); typeCodeMap.insert( QLatin1String("DTD"), i18n("DTD") ); typeCodeMap.insert( QLatin1String("Maintenance"), i18n("Maintenance") ); typeCodeMap.insert( QLatin1String("News"), i18n("News") ); typeCodeMap.insert( QLatin1String("NewsManagementMode"), i18n("News Management Mode") ); typeCodeMap.insert( QLatin1String("Package"), i18n("Package") ); typeCodeMap.insert( QLatin1String("Schema"), i18n("Schema") ); typeCodeMap.insert( QLatin1String("Topic"), i18n("Topic") ); typeCodeMap.insert( QLatin1String("TopicSet"), i18n("Topic Set") ); DMetadata::CountryCodeMap map = DMetadata::countryCodeMap(); for (DMetadata::CountryCodeMap::Iterator it = map.begin() ; it != map.end() ; ++it) { languageCodeMap.insert(it.key(), it.value()); } } typedef QMap SceneCodeMap; typedef QMap TypeCodeMap; typedef QMap LanguageCodeMap; SceneCodeMap sceneCodeMap; TypeCodeMap typeCodeMap; LanguageCodeMap languageCodeMap; QCheckBox* originalTransCheck; QComboBox* priorityCB; QComboBox* objectTypeCB; QLineEdit* objectAttributeEdit; QLineEdit* originalTransEdit; MetadataCheckBox* priorityCheck; MetadataCheckBox* objectAttributeCheck; MultiValuesEdit* sceneEdit; MultiValuesEdit* objectTypeEdit; MultiValuesEdit* languageEdit; SqueezedComboBox* objectAttributeCB; }; XMPProperties::XMPProperties(QWidget* const parent) : QWidget(parent), d(new Private) { QGridLayout* const grid = new QGridLayout(this); // -------------------------------------------------------- d->languageEdit = new MultiValuesEdit(this, i18n("Language:"), i18n("Select here the language of content.")); QStringList list; - for (Private::LanguageCodeMap::Iterator it = d->languageCodeMap.begin(); - it != d->languageCodeMap.end(); ++it) + for (Private::LanguageCodeMap::Iterator it = d->languageCodeMap.begin() ; + it != d->languageCodeMap.end() ; ++it) + { list.append(QString::fromUtf8("%1 - %2").arg(it.key()).arg(it.value())); + } d->languageEdit->setData(list); // -------------------------------------------------------- d->priorityCheck = new MetadataCheckBox(i18n("Priority:"), this); d->priorityCB = new QComboBox(this); d->priorityCB->insertItem(0, i18nc("editorial urgency of content", "0: None")); d->priorityCB->insertItem(1, i18nc("editorial urgency of content", "1: High")); d->priorityCB->insertItem(2, QLatin1String("2")); d->priorityCB->insertItem(3, QLatin1String("3")); d->priorityCB->insertItem(4, QLatin1String("4")); d->priorityCB->insertItem(5, i18nc("editorial urgency of content", "5: Normal")); d->priorityCB->insertItem(6, QLatin1String("6")); d->priorityCB->insertItem(7, QLatin1String("7")); d->priorityCB->insertItem(8, i18nc("editorial urgency of content", "8: Low")); d->priorityCB->insertItem(9, i18nc("editorial urgency of content", "9: User-defined")); d->priorityCB->setWhatsThis(i18n("Select here the editorial urgency of content.")); // -------------------------------------------------------- d->sceneEdit = new MultiValuesEdit(this, i18n("Scene:"), i18n("Select here the scene type of the content.")); QStringList list2; - for (Private::SceneCodeMap::Iterator it = d->sceneCodeMap.begin(); - it != d->sceneCodeMap.end(); ++it) + for (Private::SceneCodeMap::Iterator it = d->sceneCodeMap.begin() ; + it != d->sceneCodeMap.end() ; ++it) + { list2.append(QString::fromUtf8("%1 - %2").arg(it.key()).arg(it.value())); + } d->sceneEdit->setData(list2); // -------------------------------------------------------- d->objectTypeEdit = new MultiValuesEdit(this, i18n("Type:"), i18n("Select here the editorial type of the content.")); QStringList list3; - for (Private::TypeCodeMap::Iterator it = d->typeCodeMap.begin(); - it != d->typeCodeMap.end(); ++it) + for (Private::TypeCodeMap::Iterator it = d->typeCodeMap.begin() ; + it != d->typeCodeMap.end() ; ++it) + { list3.append(it.value()); + } d->objectTypeEdit->setData(list3); // -------------------------------------------------------- d->objectAttributeCheck = new MetadataCheckBox(i18n("Attribute:"), this); d->objectAttributeCB = new SqueezedComboBox(this); d->objectAttributeEdit = new QLineEdit(this); d->objectAttributeEdit->setClearButtonEnabled(true); d->objectAttributeEdit->setWhatsThis(i18n("Set here the editorial attribute description of the content.")); d->objectAttributeCB->setWhatsThis(i18n("Select here the editorial attribute of the content.")); d->objectAttributeCB->addSqueezedItem(QLatin1String("001 - ") + i18nc("editorial content attribute", "Current")); d->objectAttributeCB->addSqueezedItem(QLatin1String("002 - ") + i18nc("editorial content attribute", "Analysis")); d->objectAttributeCB->addSqueezedItem(QLatin1String("003 - ") + i18nc("editorial content attribute", "Archive material")); d->objectAttributeCB->addSqueezedItem(QLatin1String("004 - ") + i18nc("editorial content attribute", "Background")); d->objectAttributeCB->addSqueezedItem(QLatin1String("005 - ") + i18nc("editorial content attribute", "Feature")); d->objectAttributeCB->addSqueezedItem(QLatin1String("006 - ") + i18nc("editorial content attribute", "Forecast")); d->objectAttributeCB->addSqueezedItem(QLatin1String("007 - ") + i18nc("editorial content attribute", "History")); d->objectAttributeCB->addSqueezedItem(QLatin1String("008 - ") + i18nc("editorial content attribute", "Obituary")); d->objectAttributeCB->addSqueezedItem(QLatin1String("009 - ") + i18nc("editorial content attribute", "Opinion")); d->objectAttributeCB->addSqueezedItem(QLatin1String("010 - ") + i18nc("editorial content attribute", "Polls & Surveys")); d->objectAttributeCB->addSqueezedItem(QLatin1String("011 - ") + i18nc("editorial content attribute", "Profile")); d->objectAttributeCB->addSqueezedItem(QLatin1String("012 - ") + i18nc("editorial content attribute", "Results Listings & Table")); d->objectAttributeCB->addSqueezedItem(QLatin1String("013 - ") + i18nc("editorial content attribute", "Side bar & Supporting information")); d->objectAttributeCB->addSqueezedItem(QLatin1String("014 - ") + i18nc("editorial content attribute", "Summary")); d->objectAttributeCB->addSqueezedItem(QLatin1String("015 - ") + i18nc("editorial content attribute", "Transcript & Verbatim")); d->objectAttributeCB->addSqueezedItem(QLatin1String("016 - ") + i18nc("editorial content attribute", "Interview")); d->objectAttributeCB->addSqueezedItem(QLatin1String("017 - ") + i18nc("editorial content attribute", "From the Scene")); d->objectAttributeCB->addSqueezedItem(QLatin1String("018 - ") + i18nc("editorial content attribute", "Retrospective")); d->objectAttributeCB->addSqueezedItem(QLatin1String("019 - ") + i18nc("editorial content attribute", "Statistics")); d->objectAttributeCB->addSqueezedItem(QLatin1String("020 - ") + i18nc("editorial content attribute", "Update")); d->objectAttributeCB->addSqueezedItem(QLatin1String("021 - ") + i18nc("editorial content attribute", "Wrap-up")); d->objectAttributeCB->addSqueezedItem(QLatin1String("022 - ") + i18nc("editorial content attribute", "Press Release")); // -------------------------------------------------------- d->originalTransCheck = new QCheckBox(i18n("Reference:"), this); d->originalTransEdit = new QLineEdit(this); d->originalTransEdit->setClearButtonEnabled(true); d->originalTransEdit->setWhatsThis(i18n("Set here the original content transmission reference.")); // -------------------------------------------------------- grid->addWidget(d->languageEdit, 0, 0, 1, 5); grid->addWidget(d->priorityCheck, 1, 0, 1, 1); grid->addWidget(d->priorityCB, 1, 1, 1, 1); grid->addWidget(d->sceneEdit, 2, 0, 1, 5); grid->addWidget(d->objectTypeEdit, 3, 0, 1, 5); grid->addWidget(new DLineWidget(Qt::Horizontal, this), 4, 0, 1, 5); grid->addWidget(d->objectAttributeCheck, 5, 0, 1, 1); grid->addWidget(d->objectAttributeCB, 5, 1, 1, 2); grid->addWidget(d->objectAttributeEdit, 5, 3, 1, 2); grid->addWidget(new DLineWidget(Qt::Horizontal, this), 6, 0, 1, 5); grid->addWidget(d->originalTransCheck, 7, 0, 1, 1); grid->addWidget(d->originalTransEdit, 7, 1, 1, 4); grid->setRowStretch(8, 10); grid->setColumnStretch(4, 10); grid->setContentsMargins(QMargins()); grid->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); // -------------------------------------------------------- connect(d->priorityCheck, SIGNAL(toggled(bool)), d->priorityCB, SLOT(setEnabled(bool))); connect(d->objectAttributeCheck, SIGNAL(toggled(bool)), d->objectAttributeCB, SLOT(setEnabled(bool))); connect(d->objectAttributeCheck, SIGNAL(toggled(bool)), d->objectAttributeEdit, SLOT(setEnabled(bool))); connect(d->originalTransCheck, SIGNAL(toggled(bool)), d->originalTransEdit, SLOT(setEnabled(bool))); // -------------------------------------------------------- connect(d->languageEdit, SIGNAL(signalModified()), this, SIGNAL(signalModified())); connect(d->priorityCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->sceneEdit, SIGNAL(signalModified()), this, SIGNAL(signalModified())); connect(d->objectTypeEdit, SIGNAL(signalModified()), this, SIGNAL(signalModified())); connect(d->objectAttributeCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); connect(d->originalTransCheck, SIGNAL(toggled(bool)), this, SIGNAL(signalModified())); // -------------------------------------------------------- connect(d->priorityCB, SIGNAL(activated(int)), this, SIGNAL(signalModified())); connect(d->objectAttributeCB, SIGNAL(activated(int)), this, SIGNAL(signalModified())); connect(d->objectAttributeEdit, SIGNAL(textChanged(QString)), this, SIGNAL(signalModified())); connect(d->originalTransEdit, SIGNAL(textChanged(QString)), this, SIGNAL(signalModified())); } XMPProperties::~XMPProperties() { delete d; } void XMPProperties::readMetadata(QByteArray& xmpData) { blockSignals(true); DMetadata meta; meta.setXmp(xmpData); int val; QString data; QStringList code, list, list2; QString dateStr, timeStr; DMetadata::AltLangMap map; // --------------------------------------------------------------- code = meta.getXmpTagStringBag("Xmp.dc.language", false); - for (QStringList::Iterator it = code.begin(); it != code.end(); ++it) + for (QStringList::Iterator it = code.begin() ; it != code.end() ; ++it) { - QStringList data = d->languageEdit->getData(); + QStringList lst1 = d->languageEdit->getData(); QStringList::Iterator it2; - for (it2 = data.begin(); it2 != data.end(); ++it2) + for (it2 = lst1.begin() ; it2 != lst1.end() ; ++it2) { if ((*it2).left(2) == (*it)) { list.append(*it2); break; } } - if (it2 == data.end()) + if (it2 == lst1.end()) + { d->languageEdit->setValid(false); + } } d->languageEdit->setValues(list); // --------------------------------------------------------------- d->priorityCB->setCurrentIndex(0); d->priorityCheck->setChecked(false); data = meta.getXmpTagString("Xmp.photoshop.Urgency", false); if (!data.isNull()) { val = data.toInt(); - if (val >= 0 && val <= 9) + if ((val >= 0) && (val <= 9)) { d->priorityCB->setCurrentIndex(val); d->priorityCheck->setChecked(true); } else d->priorityCheck->setValid(false); } d->priorityCB->setEnabled(d->priorityCheck->isChecked()); // --------------------------------------------------------------- code = meta.getXmpTagStringBag("Xmp.iptc.Scene", false); - for (QStringList::Iterator it = code.begin(); it != code.end(); ++it) + for (QStringList::Iterator it = code.begin() ; it != code.end() ; ++it) { - QStringList data = d->sceneEdit->getData(); + QStringList lst2 = d->sceneEdit->getData(); QStringList::Iterator it2; - for (it2 = data.begin(); it2 != data.end(); ++it2) + for (it2 = lst2.begin() ; it2 != lst2.end() ; ++it2) { if ((*it2).left(6) == (*it)) { list.append(*it2); break; } } - if (it2 == data.end()) + if (it2 == lst2.end()) + { d->sceneEdit->setValid(false); + } } d->sceneEdit->setValues(list); // --------------------------------------------------------------- code = meta.getXmpTagStringBag("Xmp.dc.type", false); - for (QStringList::Iterator it3 = code.begin(); it3 != code.end(); ++it3) + for (QStringList::Iterator it3 = code.begin() ; it3 != code.end() ; ++it3) { - QStringList data = d->objectTypeEdit->getData(); + QStringList lst3 = d->objectTypeEdit->getData(); QStringList::Iterator it4; - for (it4 = data.begin(); it4 != data.end(); ++it4) + for (it4 = lst3.begin() ; it4 != lst3.end() ; ++it4) { if ((*it4) == (*it3)) { list2.append(*it4); break; } } - if (it4 == data.end()) + if (it4 == lst3.end()) + { d->objectTypeEdit->setValid(false); + } } d->objectTypeEdit->setValues(list2); // --------------------------------------------------------------- d->objectAttributeCB->setCurrentIndex(0); d->objectAttributeEdit->clear(); d->objectAttributeCheck->setChecked(false); data = meta.getXmpTagString("Xmp.iptc.IntellectualGenre", false); if (!data.isNull()) { QString attrSec = data.section(QLatin1Char(':'), 0, 0); if (!attrSec.isEmpty()) { int attr = attrSec.toInt()-1; - if (attr >= 0 && attr < 23) + if ((attr >= 0) && (attr < 23)) { d->objectAttributeCB->setCurrentIndex(attr); d->objectAttributeEdit->setText(data.section(QLatin1Char(':'), -1)); d->objectAttributeCheck->setChecked(true); } else + { d->objectAttributeCheck->setValid(false); + } } } d->objectAttributeCB->setEnabled(d->objectAttributeCheck->isChecked()); d->objectAttributeEdit->setEnabled(d->objectAttributeCheck->isChecked()); // --------------------------------------------------------------- d->originalTransEdit->clear(); d->originalTransCheck->setChecked(false); data = meta.getXmpTagString("Xmp.photoshop.TransmissionReference", false); if (!data.isNull()) { d->originalTransEdit->setText(data); d->originalTransCheck->setChecked(true); } d->originalTransEdit->setEnabled(d->originalTransCheck->isChecked()); // --------------------------------------------------------------- blockSignals(false); } void XMPProperties::applyMetadata(QByteArray& xmpData) { QStringList oldList, newList; DMetadata meta; meta.setXmp(xmpData); // --------------------------------------------------------------- if (d->languageEdit->getValues(oldList, newList)) { QStringList newCode; - for (QStringList::Iterator it2 = newList.begin(); it2 != newList.end(); ++it2) + for (QStringList::Iterator it2 = newList.begin() ; it2 != newList.end() ; ++it2) + { newCode.append((*it2).left(2)); + } meta.setXmpTagStringBag("Xmp.dc.language", newCode); } else { meta.removeXmpTag("Xmp.dc.language"); } // --------------------------------------------------------------- - if (d->priorityCheck->isChecked()) + if (d->priorityCheck->isChecked()) + { meta.setXmpTagString("Xmp.photoshop.Urgency", QString::number(d->priorityCB->currentIndex())); + } else if (d->priorityCheck->isValid()) + { meta.removeXmpTag("Xmp.photoshop.Urgency"); + } // --------------------------------------------------------------- if (d->sceneEdit->getValues(oldList, newList)) { QStringList newCode; - for (QStringList::Iterator it2 = newList.begin(); it2 != newList.end(); ++it2) + for (QStringList::Iterator it2 = newList.begin() ; it2 != newList.end() ; ++it2) + { newCode.append((*it2).left(6)); + } meta.setXmpTagStringBag("Xmp.iptc.Scene", newCode); } else { meta.removeXmpTag("Xmp.iptc.Scene"); } // --------------------------------------------------------------- if (d->objectTypeEdit->getValues(oldList, newList)) + { meta.setXmpTagStringBag("Xmp.dc.type", newList); + } else + { meta.removeXmpTag("Xmp.dc.type"); + } // --------------------------------------------------------------- - if (d->objectAttributeCheck->isChecked()) + if (d->objectAttributeCheck->isChecked()) { QString objectAttribute; objectAttribute.asprintf("%3d", d->objectAttributeCB->currentIndex()+1); objectAttribute.append(QString::fromUtf8(":%1").arg(d->objectAttributeEdit->text())); meta.setXmpTagString("Xmp.iptc.IntellectualGenre", objectAttribute); } else if (d->objectAttributeCheck->isValid()) { meta.removeXmpTag("Xmp.iptc.IntellectualGenre"); } // --------------------------------------------------------------- if (d->originalTransCheck->isChecked()) + { meta.setXmpTagString("Xmp.photoshop.TransmissionReference", d->originalTransEdit->text()); + } else + { meta.removeXmpTag("Xmp.photoshop.TransmissionReference"); + } xmpData = meta.getXmp(); } } // namespace DigikamGenericMetadataEditPlugin diff --git a/core/utilities/setup/metadata/setupmetadata.cpp b/core/utilities/setup/metadata/setupmetadata.cpp index 877526c386..a5cb7cb466 100644 --- a/core/utilities/setup/metadata/setupmetadata.cpp +++ b/core/utilities/setup/metadata/setupmetadata.cpp @@ -1,921 +1,921 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-08-03 * Description : setup Metadata tab. * * Copyright (C) 2003-2004 by Ralf Holzer * Copyright (C) 2003-2020 by Gilles Caulier * Copyright (C) 2009-2012 by Marcel Wiesweg * Copyright (C) 2017 by Simon Frei * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupmetadata.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "advancedmetadatatab.h" #include "applicationsettings.h" #include "dactivelabel.h" #include "digikam_config.h" #include "digikam_debug.h" #include "metaengine.h" #include "metadatapanel.h" #include "metaenginesettings.h" #include "setuputils.h" namespace Digikam { class Q_DECL_HIDDEN SetupMetadata::Private { public: explicit Private() : exifAutoRotateOriginal(false), exifAutoRotateShowedInfo(false), clearMetadataShowedInfo(false), fieldsGroup(nullptr), readWriteGroup(nullptr), rotationGroup(nullptr), rotationAdvGroup(nullptr), saveTagsBox(nullptr), saveCommentsBox(nullptr), saveRatingBox(nullptr), savePickLabelBox(nullptr), saveColorLabelBox(nullptr), saveDateTimeBox(nullptr), saveTemplateBox(nullptr), saveFaceTags(nullptr), useLazySync(nullptr), writeRawFilesBox(nullptr), writeXMPSidecarBox(nullptr), readXMPSidecarBox(nullptr), sidecarFileNameBox(nullptr), updateFileTimeStampBox(nullptr), rescanImageIfModifiedBox(nullptr), clearMetadataIfRescanBox(nullptr), writingModeCombo(nullptr), rotateByFlag(nullptr), rotateByContents(nullptr), allowRotateByMetadata(nullptr), allowLossyRotate(nullptr), exifRotateBox(nullptr), exifSetOrientationBox(nullptr), saveToBalooBox(nullptr), readFromBalooBox(nullptr), tab(nullptr), displaySubTab(nullptr), tagsCfgPanel(nullptr), advTab(nullptr), extensionsEdit(nullptr) { } bool exifAutoRotateOriginal; bool exifAutoRotateShowedInfo; bool clearMetadataShowedInfo; QGroupBox* fieldsGroup; QGroupBox* readWriteGroup; QGroupBox* rotationGroup; QGroupBox* rotationAdvGroup; QCheckBox* saveTagsBox; QCheckBox* saveCommentsBox; QCheckBox* saveRatingBox; QCheckBox* savePickLabelBox; QCheckBox* saveColorLabelBox; QCheckBox* saveDateTimeBox; QCheckBox* saveTemplateBox; QCheckBox* saveFaceTags; QCheckBox* useLazySync; QCheckBox* writeRawFilesBox; QCheckBox* writeXMPSidecarBox; QCheckBox* readXMPSidecarBox; QCheckBox* sidecarFileNameBox; QCheckBox* updateFileTimeStampBox; QCheckBox* rescanImageIfModifiedBox; QCheckBox* clearMetadataIfRescanBox; QComboBox* writingModeCombo; QRadioButton* rotateByFlag; QRadioButton* rotateByContents; QCheckBox* allowRotateByMetadata; QCheckBox* allowLossyRotate; QCheckBox* exifRotateBox; QCheckBox* exifSetOrientationBox; QCheckBox* saveToBalooBox; QCheckBox* readFromBalooBox; QTabWidget* tab; QTabWidget* displaySubTab; MetadataPanel* tagsCfgPanel; AdvancedMetadataTab* advTab; QLineEdit* extensionsEdit; }; SetupMetadata::SetupMetadata(QWidget* const parent) : QScrollArea(parent), d(new Private) { d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); QWidget* const panel = new QWidget; QVBoxLayout* const mainLayout = new QVBoxLayout; // -------------------------------------------------------- d->fieldsGroup = new QGroupBox; QGridLayout* const fieldsLayout = new QGridLayout; d->fieldsGroup->setWhatsThis(xi18nc("@info:whatsthis", "In addition to the pixel content, image files usually " "contain a variety of metadata. A lot of the parameters you can use " "in digiKam to manage files, such as rating or comment, can be written " "to the files' metadata. " "Storing in metadata allows one to preserve this information " "when moving or sending the files to different systems.")); QLabel* const fieldsIconLabel = new QLabel; fieldsIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("format-list-unordered")).pixmap(32)); QLabel* const fieldsLabel = new QLabel(i18nc("@label", "Write This Information to the Metadata")); d->saveTagsBox = new QCheckBox; d->saveTagsBox->setText(i18nc("@option:check", "Image tags")); d->saveTagsBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item tags " "in the XMP and IPTC tags.")); d->saveCommentsBox = new QCheckBox; d->saveCommentsBox->setText(i18nc("@option:check", "Captions and title")); d->saveCommentsBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store item caption and title " "in the JFIF Comment section, the EXIF tag, the XMP tag, " "and the IPTC tag.")); d->saveRatingBox = new QCheckBox; d->saveRatingBox->setText(i18nc("@option:check", "Rating")); d->saveRatingBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item rating " "in the EXIF tag and the XMP tags.")); d->savePickLabelBox = new QCheckBox; d->savePickLabelBox->setText(i18nc("@option:check", "Pick label")); d->savePickLabelBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item pick label " "in the XMP tags.")); d->saveColorLabelBox = new QCheckBox; d->saveColorLabelBox->setText(i18nc("@option:check", "Color label")); d->saveColorLabelBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item color label " "in the XMP tags.")); d->saveDateTimeBox = new QCheckBox; d->saveDateTimeBox->setText(i18nc("@option:check", "Timestamps")); d->saveDateTimeBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item date and time " "in the EXIF, XMP, and IPTC tags.")); d->saveTemplateBox = new QCheckBox; d->saveTemplateBox->setText(i18nc("@option:check", "Metadata templates (Copyright etc.)")); d->saveTemplateBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the metadata " "template in the XMP and the IPTC tags. " "You can set template values to Template setup page.")); d->saveFaceTags = new QCheckBox; d->saveFaceTags->setText(i18nc("@option:check", "Face Tags (including face areas)")); d->saveFaceTags->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store face tags " "with face rectangles in the XMP tags.")); fieldsLayout->addWidget(fieldsIconLabel, 0, 0, 2, 3); fieldsLayout->addWidget(fieldsLabel, 0, 1, 2, 3); fieldsLayout->addWidget(d->saveTagsBox, 2, 0, 1, 3); fieldsLayout->addWidget(d->saveCommentsBox, 3, 0, 1, 3); fieldsLayout->addWidget(d->saveRatingBox, 4, 0, 1, 3); fieldsLayout->addWidget(d->savePickLabelBox, 5, 0, 1, 3); fieldsLayout->addWidget(d->saveColorLabelBox, 6, 0, 1, 3); fieldsLayout->addWidget(d->saveDateTimeBox, 7, 0, 1, 3); fieldsLayout->addWidget(d->saveTemplateBox, 8, 0, 1, 3); fieldsLayout->addWidget(d->saveFaceTags, 9 ,0, 1, 3); fieldsLayout->setColumnStretch(3, 10); d->fieldsGroup->setLayout(fieldsLayout); // -------------------------------------------------------- d->readWriteGroup = new QGroupBox; QGridLayout* const readWriteLayout = new QGridLayout; QLabel* const readWriteIconLabel = new QLabel; readWriteIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("document-open")).pixmap(32)); QLabel* const readWriteLabel = new QLabel(i18nc("@label", "Reading and Writing Metadata")); d->useLazySync = new QCheckBox; d->useLazySync->setText(i18nc("@option:check", "Use lazy synchronization")); d->useLazySync->setWhatsThis(i18nc("@info:whatsthis", "Instead of synchronizing metadata, just schedule it for synchronization." "Synchronization can be done later by triggering the apply pending, or at digikam exit")); d->writeRawFilesBox = new QCheckBox; d->writeRawFilesBox->setText(i18nc("@option:check", "If possible write Metadata to RAW files (experimental)")); d->writeRawFilesBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to write metadata into RAW TIFF/EP files. " "This feature requires the Exiv2 shared library, version >= 0.18.0. It is still " "experimental, and is disabled by default.")); d->writeRawFilesBox->setEnabled(MetaEngine::supportMetadataWritting(QLatin1String("image/x-raw"))); d->updateFileTimeStampBox = new QCheckBox; d->updateFileTimeStampBox->setText(i18nc("@option:check", "&Update file modification timestamp when files are modified")); d->updateFileTimeStampBox->setWhatsThis(i18nc("@info:whatsthis", "Turn off this option to not update file timestamps when files are changed as " "when you update metadata or image data. Note: disabling this option can " "introduce some dysfunctions with applications which use file timestamps " "properties to detect file modifications automatically.")); d->rescanImageIfModifiedBox = new QCheckBox; d->rescanImageIfModifiedBox->setText(i18nc("@option:check", "&Rescan file when files are modified")); d->rescanImageIfModifiedBox->setWhatsThis(i18nc("@info:whatsthis", "Turning this option on, will force digiKam to rescan files that has been " "modified outside digiKam. If a file has changed it is file size or if " "the last modified timestamp has changed, a rescan of that " "file will be performed when digiKam starts.")); d->clearMetadataIfRescanBox = new QCheckBox; d->clearMetadataIfRescanBox->setText(i18nc("@option:check", "&Clean up the metadata from the database when rescan files")); d->clearMetadataIfRescanBox->setWhatsThis(i18nc("@info:whatsthis", "Turning this option on, will force digiKam to delete the file metadata " "contained in the database before the file is rescanned. WARNING: " "if your metadata has been written to the database only and not " "to the file or sidecar, you will be able to lose inserted " "metadata such as tags, keywords, or geographic coordinates.")); readWriteLayout->addWidget(readWriteIconLabel, 0, 0, 2, 3); readWriteLayout->addWidget(readWriteLabel, 0, 1, 2, 3); readWriteLayout->addWidget(d->useLazySync, 2, 0, 1, 3); readWriteLayout->addWidget(d->writeRawFilesBox, 3, 0, 1, 3); readWriteLayout->addWidget(d->updateFileTimeStampBox, 4, 0, 1, 3); readWriteLayout->addWidget(d->rescanImageIfModifiedBox, 5, 0, 1, 3); readWriteLayout->addWidget(d->clearMetadataIfRescanBox, 6, 0, 1, 3); readWriteLayout->setColumnStretch(3, 10); d->readWriteGroup->setLayout(readWriteLayout); // -------------------------------------------------------- QFrame* const infoBox = new QFrame; QGridLayout* const infoBoxGrid = new QGridLayout; infoBox->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); DActiveLabel* const exiv2LogoLabel = new DActiveLabel(QUrl(QLatin1String("https://www.exiv2.org")), QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/logo-exiv2.png")), infoBox); exiv2LogoLabel->setWhatsThis(i18n("Visit Exiv2 project website")); QLabel* const explanation = new QLabel(infoBox); explanation->setOpenExternalLinks(true); explanation->setWordWrap(true); QString txt; txt.append(i18n("

EXIF - " "a standard used by most digital cameras today to store technical " "information (like aperture and shutter speed) about an image.

")); txt.append(i18n("

IPTC - " "an older standard used in digital photography to store " "photographer information in images.

")); if (MetaEngine::supportXmp()) { txt.append(i18n("

XMP - " "a new standard used in digital photography, designed to replace IPTC.

")); } explanation->setText(txt); infoBoxGrid->addWidget(exiv2LogoLabel, 0, 0, 1, 1); infoBoxGrid->addWidget(explanation, 0, 1, 1, 2); infoBoxGrid->setColumnStretch(1, 10); infoBoxGrid->setRowStretch(1, 10); infoBoxGrid->setSpacing(0); infoBox->setLayout(infoBoxGrid); // -------------------------------------------------------- mainLayout->addWidget(d->fieldsGroup); mainLayout->addWidget(d->readWriteGroup); mainLayout->addWidget(infoBox); panel->setLayout(mainLayout); d->tab->insertTab(Behavior, panel, i18nc("@title:tab", "Behavior")); // -------------------------------------------------------- QWidget* const rotationPanel = new QWidget(d->tab); QVBoxLayout* const rotationLayout = new QVBoxLayout; d->rotationGroup = new QGroupBox; QGridLayout* const rotationGroupLayout = new QGridLayout; QLabel* const rotationExplanation = new QLabel(i18nc("@label", "When rotating a file")); QLabel* const rotationIcon = new QLabel; rotationIcon->setPixmap(QIcon::fromTheme(QLatin1String("transform-rotate")).pixmap(32)); d->rotateByFlag = new QRadioButton(i18nc("@option:radio", "Rotate by only setting a flag")); d->rotateByContents = new QRadioButton(i18nc("@option:radio", "Rotate by changing the content if possible")); d->allowLossyRotate = new QCheckBox(i18nc("@option:check", "Even allow lossy rotation if necessary")); d->allowRotateByMetadata = new QCheckBox(i18nc("@option:check", "Write flag to metadata if possible")); connect(d->rotateByContents, SIGNAL(toggled(bool)), d->allowLossyRotate, SLOT(setEnabled(bool))); d->rotateByFlag->setChecked(false); d->rotateByContents->setChecked(false); d->allowLossyRotate->setEnabled(false); d->allowLossyRotate->setChecked(false); d->allowRotateByMetadata->setChecked(true); d->rotateByFlag->setToolTip(i18nc("@info:tooltip", "Rotate files only by changing a flag, not touching the pixel data")); d->rotateByFlag->setWhatsThis(xi18nc("@info:whatsthis", "A file can be rotated in two ways: " "You can change the contents, rearranging the individual pixels of the image data. " "Or you can set a flag that the file is to be rotated before it is shown. " "Select this option if you always want to set only a flag. " "This is less obtrusive, but requires support if the file is accessed with another software. " "Ensure to allow setting the flag in the metadata if you want to share your files " "outside digiKam.")); d->rotateByContents->setToolTip(i18nc("@info:tooltip", "If possible rotate files by changing the pixel data")); d->rotateByContents->setWhatsThis(xi18nc("@info:whatsthis", "A file can be rotated in two ways: " "You can change the contents, rearranging the individual pixels of the image data. " "Or you can set a flag that the file is to be rotated before it is shown. " "Select this option if you want the file to be rotated by changing the content. " "This is a lossless operation for JPEG files. For other formats it is a lossy operation, " "which you need to enable explicitly. " "It is not support for RAW and other read-only formats, " "which will be rotated by flag only.")); d->allowLossyRotate->setToolTip(i18nc("@info:tooltip", "Rotate files by changing the pixel data even if the operation will incur quality loss")); d->allowLossyRotate->setWhatsThis(i18nc("@info:whatsthis", "For some file formats which apply lossy compression, " "data will be lost each time the content is rotated. " "Check this option to allow lossy rotation. " "If not enabled, these files will be rotated by flag.")); d->allowRotateByMetadata->setToolTip(i18nc("@info:tooltip", "When rotating a file by setting a flag, also change this flag in the file's metadata")); d->allowRotateByMetadata->setWhatsThis(i18nc("@info:whatsthis", "File metadata typically contains a flag describing " "that a file shall be shown rotated. " "Enable this option to allow editing this field. ")); rotationGroupLayout->addWidget(rotationIcon, 0, 0, 1, 1); rotationGroupLayout->addWidget(rotationExplanation, 0, 1, 1, 2); rotationGroupLayout->addWidget(d->rotateByFlag, 1, 0, 1, 3); rotationGroupLayout->addWidget(d->rotateByContents, 2, 0, 1, 3); rotationGroupLayout->addWidget(d->allowLossyRotate, 3, 2, 1, 1); rotationGroupLayout->addWidget(d->allowRotateByMetadata, 4, 0, 1, 3); rotationGroupLayout->setColumnStretch(3, 10); d->rotationGroup->setLayout(rotationGroupLayout); // -------------------------------------------------------- d->rotationAdvGroup = new QGroupBox; QGridLayout* const rotationAdvLayout = new QGridLayout; QLabel* const rotationAdvExpl = new QLabel(i18nc("@label", "Rotate actions")); QLabel* const rotationAdvIcon = new QLabel; rotationAdvIcon->setPixmap(QIcon::fromTheme(QLatin1String("configure")).pixmap(32)); d->exifRotateBox = new QCheckBox; d->exifRotateBox->setText(i18n("Show images/thumbnails &rotated according to orientation tag.")); d->exifSetOrientationBox = new QCheckBox; d->exifSetOrientationBox->setText(i18n("Set orientation tag to normal after rotate/flip.")); rotationAdvLayout->addWidget(rotationAdvIcon, 0, 0, 1, 1); rotationAdvLayout->addWidget(rotationAdvExpl, 0, 1, 1, 1); rotationAdvLayout->addWidget(d->exifRotateBox, 1, 0, 1, 3); rotationAdvLayout->addWidget(d->exifSetOrientationBox, 2, 0, 1, 3); rotationAdvLayout->setColumnStretch(2, 10); d->rotationAdvGroup->setLayout(rotationAdvLayout); // -------------------------------------------------------- QLabel* const rotationNote = new QLabel(i18n("Note: These settings affect the album view " "and not the image editor. The image editor always " "changes the image data during the rotation.")); rotationNote->setWordWrap(true); rotationNote->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); // -------------------------------------------------------- rotationLayout->addWidget(d->rotationGroup); rotationLayout->addWidget(d->rotationAdvGroup); rotationLayout->addWidget(rotationNote); rotationLayout->addStretch(); rotationPanel->setLayout(rotationLayout); d->tab->insertTab(Rotation, rotationPanel, i18nc("@title:tab", "Rotation")); // -------------------------------------------------------- QWidget* const displayPanel = new QWidget; QGridLayout* const displayLayout = new QGridLayout; QLabel* const displayLabel = new QLabel(i18nc("@info:label", "Select Metadata Fields to Be Displayed")); QLabel* const displayIcon = new QLabel; displayIcon->setPixmap(QIcon::fromTheme(QLatin1String("view-list-tree")).pixmap(32)); d->displaySubTab = new QTabWidget; d->tagsCfgPanel = new MetadataPanel(d->displaySubTab); displayLayout->addWidget(displayIcon, 0, 0); displayLayout->addWidget(displayLabel, 0, 1); displayLayout->addWidget(d->displaySubTab, 1, 0, 1, 3); displayLayout->setColumnStretch(2, 1); displayPanel->setLayout(displayLayout); d->tab->insertTab(Display, displayPanel, i18nc("@title:tab", "Views")); // -------------------------------------------------------- #ifdef HAVE_KFILEMETADATA QWidget* const balooPanel = new QWidget(d->tab); QVBoxLayout* const balooLayout = new QVBoxLayout(balooPanel); QGroupBox* const balooGroup = new QGroupBox(i18n("Baloo Desktop Search"), balooPanel); QVBoxLayout* const gLayout3 = new QVBoxLayout(balooGroup); d->saveToBalooBox = new QCheckBox; d->saveToBalooBox->setText(i18n("Store metadata from digiKam in Baloo")); d->saveToBalooBox->setWhatsThis(i18n("Turn on this option to push rating, comments and tags " "from digiKam into the Baloo storage")); d->readFromBalooBox = new QCheckBox; d->readFromBalooBox->setText(i18n("Read metadata from Baloo")); d->readFromBalooBox->setWhatsThis(i18n("Turn on this option if you want to apply changes to " "rating, comments and tags made in Baloo to digiKam's metadata storage. " "Please note that image metadata will not be edited automatically.")); gLayout3->addWidget(d->saveToBalooBox); gLayout3->addWidget(d->readFromBalooBox); d->tab->insertTab(Baloo, balooPanel, i18nc("@title:tab", "Baloo")); // -------------------------------------------------------- QFrame* const balooBox = new QFrame(balooPanel); QGridLayout* const balooGrid = new QGridLayout(balooBox); balooBox->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); QLabel* const balooLogoLabel = new QLabel; balooLogoLabel->setPixmap(QIcon::fromTheme(QLatin1String("baloo")).pixmap(48)); QLabel* const balooExplanation = new QLabel(balooBox); balooExplanation->setOpenExternalLinks(true); balooExplanation->setWordWrap(true); QString balootxt; balootxt.append(i18n("

Baloo " "provides the basis to handle all kinds of metadata on the KDE desktop in a generic fashion. " "It allows you to tag, rate and comment your files in KDE applications like Dolphin.

" "

Please set here if you want to synchronize the metadata stored by digiKam desktop-wide with the " "Baloo Desktop Search.

")); balooExplanation->setText(balootxt); balooGrid->addWidget(balooLogoLabel, 0, 0, 1, 1); balooGrid->addWidget(balooExplanation, 0, 1, 1, 2); balooGrid->setColumnStretch(1, 10); balooGrid->setSpacing(0); // -------------------------------------------------------- balooLayout->addWidget(balooGroup); balooLayout->addWidget(balooBox); /* balooLayout->addWidget(d->resyncButton, 0, Qt::AlignRight); */ balooLayout->addStretch(); #endif // HAVE_KFILEMETADATA //--------------Advanced Metadata Configuration -------------- d->advTab = new AdvancedMetadataTab(this); d->tab->insertTab(AdvancedConfig, d->advTab, i18nc("@title:tab", "Advanced")); //------------------------Sidecars------------------------- QWidget* const sidecarsPanel = new QWidget(d->tab); QVBoxLayout* const sidecarsLayout = new QVBoxLayout(sidecarsPanel); // -------------------------------------------------------- QGroupBox* rwSidecarsGroup = new QGroupBox; QGridLayout* const rwSidecarsLayout = new QGridLayout; QLabel* const rwSidecarsLabel = new QLabel(i18nc("@label", "Reading and Writing to Sidecars")); d->readXMPSidecarBox = new QCheckBox; d->readXMPSidecarBox->setText(i18nc("@option:check", "Read from sidecar files")); d->readXMPSidecarBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to read metadata from XMP sidecar files when reading metadata.")); d->readXMPSidecarBox->setEnabled(MetaEngine::supportXmp()); d->writeXMPSidecarBox = new QCheckBox; d->writeXMPSidecarBox->setText(i18nc("@option:check", "Write to sidecar files")); d->writeXMPSidecarBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to save, as specified, metadata to XMP sidecar files.")); d->writeXMPSidecarBox->setEnabled(MetaEngine::supportXmp()); d->writingModeCombo = new QComboBox; d->writingModeCombo->addItem(i18n("Write to XMP sidecar for read-only item only"), MetaEngine::WRITE_TO_SIDECAR_ONLY_FOR_READ_ONLY_FILES); d->writingModeCombo->addItem(i18n("Write to XMP sidecar only"), MetaEngine::WRITE_TO_SIDECAR_ONLY); d->writingModeCombo->addItem(i18n("Write to item and XMP Sidecar"), MetaEngine::WRITE_TO_SIDECAR_AND_FILE); d->writingModeCombo->setToolTip(i18nc("@info:tooltip", "Specify the exact mode of XMP sidecar writing")); d->writingModeCombo->setEnabled(false); d->sidecarFileNameBox = new QCheckBox; d->sidecarFileNameBox->setText(i18nc("@option:check", "Sidecar file names are compatible with commercial programs")); d->sidecarFileNameBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to create the XMP sidecar files with a compatible " "file name (BASENAME.xmp) used by many commercial programs. " "For Darktable do not enable this option.")); d->sidecarFileNameBox->setEnabled(false); connect(d->writeXMPSidecarBox, SIGNAL(toggled(bool)), d->writingModeCombo, SLOT(setEnabled(bool))); connect(d->writeXMPSidecarBox, SIGNAL(toggled(bool)), d->sidecarFileNameBox, SLOT(setEnabled(bool))); rwSidecarsLayout->addWidget(rwSidecarsLabel, 0, 0, 1, 3); rwSidecarsLayout->addWidget(d->readXMPSidecarBox, 1, 0, 1, 3); rwSidecarsLayout->addWidget(d->writeXMPSidecarBox, 2, 0, 1, 3); rwSidecarsLayout->addWidget(d->writingModeCombo, 3, 1, 1, 2); rwSidecarsLayout->addWidget(d->sidecarFileNameBox, 4, 0, 1, 3); rwSidecarsLayout->setColumnStretch(3, 10); rwSidecarsGroup->setLayout(rwSidecarsLayout); // -------------------------------------------------------- QGroupBox* const extensionsGroup = new QGroupBox(sidecarsPanel); QGridLayout* const extensionsGrid = new QGridLayout(extensionsGroup); QLabel* extensionsGroupLabel = new QLabel( i18n("

Add file types to be recognised as sidecars.

" "

digiKam (optionally) writes metadata to *.xmp sidecar " "files. Other programs might use different types, which " "can be specified below. digiKam will neither display these " "nor read from or write to them. But whenever a matching album " "item (e.g. \"image.dng\" for \"image.dng.pp3\") is renamed, " "moved, copied or deleted, the same operation will be done " "on these sidecar files.

" "

Multiple extensions must be separated by a semicolon " "or a space.

")); extensionsGroupLabel->setWordWrap(true); QLabel* const extensionsLogo = new QLabel(extensionsGroup); extensionsLogo->setPixmap(QIcon::fromTheme(QLatin1String("text-x-texinfo")).pixmap(48)); d->extensionsEdit = new QLineEdit(extensionsGroup); d->extensionsEdit->setWhatsThis(i18n("

Here you can add extra extensions " "of sidecars files to be processed alongside " "regular items. These files will not be visible, " "but regarded as an extension of the main file. " "Just write \"xyz abc\" to support files with " "the *.xyz and *.abc extensions. The internally " "used sidecars type *.xmp is always included.

")); d->extensionsEdit->setClearButtonEnabled(true); d->extensionsEdit->setPlaceholderText(i18n("Enter additional sidecars file extensions.")); QLabel* const extensionsLabel = new QLabel(extensionsGroup); extensionsLabel->setText(i18n("Additional &sidecar file extensions")); extensionsLabel->setBuddy(d->extensionsEdit); extensionsGrid->addWidget(extensionsGroupLabel, 0, 0, 1, -1); extensionsGrid->addWidget(extensionsLogo, 1, 0, 2, 1); extensionsGrid->addWidget(extensionsLabel, 1, 1, 1, -1); extensionsGrid->addWidget(d->extensionsEdit, 2, 1, 1, -1); extensionsGrid->setColumnStretch(1, 10); // -------------------------------------------------------- sidecarsLayout->addWidget(rwSidecarsGroup); sidecarsLayout->addWidget(extensionsGroup); sidecarsLayout->addStretch(); d->tab->insertTab(Sidecars, sidecarsPanel, i18nc("@title:tab", "Sidecars")); // -------------------------------------------------------- readSettings(); connect(d->exifRotateBox, SIGNAL(toggled(bool)), this, SLOT(slotExifAutoRotateToggled(bool))); connect(d->clearMetadataIfRescanBox, SIGNAL(toggled(bool)), this, SLOT(slotClearMetadataToggled(bool))); connect(d->writeRawFilesBox, SIGNAL(toggled(bool)), this, SLOT(slotWriteRawFilesToggled(bool))); } SetupMetadata::~SetupMetadata() { delete d; } void SetupMetadata::setActiveMainTab(MetadataTab tab) { d->tab->setCurrentIndex(tab); } void SetupMetadata::setActiveSubTab(int tab) { d->displaySubTab->setCurrentIndex(tab); } void SetupMetadata::applySettings() { MetaEngineSettings* const mSettings = MetaEngineSettings::instance(); if (!mSettings) { return; } MetaEngineSettingsContainer set; set.rotationBehavior = MetaEngineSettingsContainer::RotateByInternalFlag; if (d->allowRotateByMetadata->isChecked()) { set.rotationBehavior |= MetaEngineSettingsContainer::RotateByMetadataFlag; } if (d->rotateByContents->isChecked()) { set.rotationBehavior |= MetaEngineSettingsContainer::RotateByLosslessRotation; if (d->allowLossyRotate->isChecked()) { set.rotationBehavior |= MetaEngineSettingsContainer::RotateByLossyRotation; } } set.exifRotate = d->exifRotateBox->isChecked(); set.exifSetOrientation = d->exifSetOrientationBox->isChecked(); set.saveComments = d->saveCommentsBox->isChecked(); set.saveDateTime = d->saveDateTimeBox->isChecked(); set.savePickLabel = d->savePickLabelBox->isChecked(); set.saveColorLabel = d->saveColorLabelBox->isChecked(); set.saveRating = d->saveRatingBox->isChecked(); set.saveTags = d->saveTagsBox->isChecked(); set.saveTemplate = d->saveTemplateBox->isChecked(); set.saveFaceTags = d->saveFaceTags->isChecked(); set.useLazySync = d->useLazySync->isChecked(); set.writeRawFiles = d->writeRawFilesBox->isChecked(); set.useXMPSidecar4Reading = d->readXMPSidecarBox->isChecked(); set.useCompatibleFileName = d->sidecarFileNameBox->isChecked(); if (d->writeXMPSidecarBox->isChecked()) { set.metadataWritingMode = (MetaEngine::MetadataWritingMode) d->writingModeCombo->itemData(d->writingModeCombo->currentIndex()).toInt(); } else { set.metadataWritingMode = MetaEngine::WRITE_TO_FILE_ONLY; } set.updateFileTimeStamp = d->updateFileTimeStampBox->isChecked(); set.rescanImageIfModified = d->rescanImageIfModifiedBox->isChecked(); set.clearMetadataIfRescan = d->clearMetadataIfRescanBox->isChecked(); set.sidecarExtensions = cleanUserFilterString(d->extensionsEdit->text()); set.sidecarExtensions.removeAll(QLatin1String("xmp")); set.sidecarExtensions.removeDuplicates(); mSettings->setSettings(set); #ifdef HAVE_KFILEMETADATA ApplicationSettings* const aSettings = ApplicationSettings::instance(); if (!aSettings) { return; } aSettings->setSyncDigikamToBaloo(d->saveToBalooBox->isChecked()); aSettings->setSyncBalooToDigikam(d->readFromBalooBox->isChecked()); aSettings->saveSettings(); #endif // HAVE_KFILEMETADATA d->tagsCfgPanel->applySettings(); d->advTab->applySettings(); } void SetupMetadata::readSettings() { MetaEngineSettings* const mSettings = MetaEngineSettings::instance(); if (!mSettings) { return; } MetaEngineSettingsContainer set = mSettings->settings(); if (set.rotationBehavior & MetaEngineSettingsContainer::RotatingPixels) { d->rotateByContents->setChecked(true); } else { d->rotateByFlag->setChecked(true); } d->allowRotateByMetadata->setChecked(set.rotationBehavior & MetaEngineSettingsContainer::RotateByMetadataFlag); d->allowLossyRotate->setChecked(set.rotationBehavior & MetaEngineSettingsContainer::RotateByLossyRotation); d->exifAutoRotateOriginal = set.exifRotate; d->exifRotateBox->setChecked(d->exifAutoRotateOriginal); d->exifSetOrientationBox->setChecked(set.exifSetOrientation); d->saveTagsBox->setChecked(set.saveTags); d->saveCommentsBox->setChecked(set.saveComments); d->saveRatingBox->setChecked(set.saveRating); d->savePickLabelBox->setChecked(set.savePickLabel); d->saveColorLabelBox->setChecked(set.saveColorLabel); d->saveDateTimeBox->setChecked(set.saveDateTime); d->saveTemplateBox->setChecked(set.saveTemplate); d->saveFaceTags->setChecked(set.saveFaceTags); d->useLazySync->setChecked(set.useLazySync); d->writeRawFilesBox->setChecked(set.writeRawFiles); d->readXMPSidecarBox->setChecked(set.useXMPSidecar4Reading); d->sidecarFileNameBox->setChecked(set.useCompatibleFileName); d->updateFileTimeStampBox->setChecked(set.updateFileTimeStamp); d->rescanImageIfModifiedBox->setChecked(set.rescanImageIfModified); d->clearMetadataIfRescanBox->setChecked(set.clearMetadataIfRescan); if (set.metadataWritingMode == MetaEngine::WRITE_TO_FILE_ONLY) { d->writeXMPSidecarBox->setChecked(false); } else { d->writeXMPSidecarBox->setChecked(true); d->writingModeCombo->setCurrentIndex(d->writingModeCombo->findData(set.metadataWritingMode)); } d->extensionsEdit->setText(set.sidecarExtensions.join(QLatin1Char(' '))); #ifdef HAVE_KFILEMETADATA ApplicationSettings* const aSettings = ApplicationSettings::instance(); if (!aSettings) { return; } d->saveToBalooBox->setChecked(aSettings->getSyncDigikamToBaloo()); d->readFromBalooBox->setChecked(aSettings->getSyncBalooToDigikam()); #endif // HAVE_KFILEMETADATA } bool SetupMetadata::exifAutoRotateHasChanged() const { return (d->exifAutoRotateOriginal != d->exifRotateBox->isChecked()); } void SetupMetadata::slotExifAutoRotateToggled(bool b) { // Show info if rotation was switched off, and only once. if (!b && !d->exifAutoRotateShowedInfo && exifAutoRotateHasChanged()) { d->exifAutoRotateShowedInfo = true; QMessageBox::information(this, qApp->applicationName(), i18nc("@info", "Switching off exif auto rotation will most probably show " "your images in a wrong orientation, so only change this " "option if you explicitly require this.")); } } void SetupMetadata::slotClearMetadataToggled(bool b) { // Show info if delete metadata from the database was switched on, and only once. if (b && !d->clearMetadataShowedInfo) { d->clearMetadataShowedInfo = true; QMessageBox::information(this, qApp->applicationName(), i18nc("@info", "Switching on this option and your metadata has been written to the " "database only and not to the file or sidecar, you will be able to " "lose inserted metadata such as tags, keywords, or geographic " "coordinates.")); } } void SetupMetadata::slotWriteRawFilesToggled(bool b) { // Show info if write metadata to raw files was switched on if (b) { QApplication::beep(); - QPointer msgBox = new QMessageBox(QMessageBox::Warning, + QPointer msgBox1 = new QMessageBox(QMessageBox::Warning, qApp->applicationName(), i18n("

Do you really want to enable metadata writing to RAW files?

" "

DigiKam delegates this task to the Exiv2 library. With different RAW " "formats, problems are known which can lead to the destruction of RAW " "files. If you decide to do so, make a backup of your RAW files.

" "

We strongly recommend not to enable this option.

"), QMessageBox::Yes | QMessageBox::No, this); - msgBox->button(QMessageBox::Yes)->setText(i18n("Yes I understand")); - msgBox->setDefaultButton(QMessageBox::No); + msgBox1->button(QMessageBox::Yes)->setText(i18n("Yes I understand")); + msgBox1->setDefaultButton(QMessageBox::No); - int result1 = msgBox->exec(); - delete msgBox; + int result1 = msgBox1->exec(); + delete msgBox1; if (result1 == QMessageBox::Yes) { - QPointer msgBox = new QMessageBox(QMessageBox::Warning, + QPointer msgBox2 = new QMessageBox(QMessageBox::Warning, qApp->applicationName(), i18n("You would rather disable writing metadata to RAW files?"), QMessageBox::Yes | QMessageBox::No, this); - int result2 = msgBox->exec(); - delete msgBox; + int result2 = msgBox2->exec(); + delete msgBox2; if (result2 == QMessageBox::No) { return; } } d->writeRawFilesBox->setChecked(false); } } } // namespace Digikam diff --git a/project/bundles/mxe/config.sh b/project/bundles/mxe/config.sh index f0d0a23eb0..35a1282082 100644 --- a/project/bundles/mxe/config.sh +++ b/project/bundles/mxe/config.sh @@ -1,77 +1,77 @@ #!/bin/bash # Copyright (c) 2013-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. ######################################################################## # Absolute path where are downloaded all tarballs to compile. DOWNLOAD_DIR="`pwd`/temp.dwnld" # Absolute path where are compiled all tarballs BUILDING_DIR="`pwd`/temp.build" #------------------------------------------------------------------------------------------- # MXE configuration #------------ # IMPORTANT: Target Windows architecture to build installer. Possible values: 32 or 64 bits. MXE_ARCHBITS=32 #------------ if [[ $MXE_ARCHBITS == 32 ]]; then # Windows 32 bits shared MXE_BUILD_TARGETS="i686-w64-mingw32.shared" MXE_BUILDROOT="`pwd`/build.win32" elif [[ $MXE_ARCHBITS == 64 ]]; then # Windows 64 bits shared MXE_BUILD_TARGETS="x86_64-w64-mingw32.shared" MXE_BUILDROOT="`pwd`/build.win64" else echo "Unsupported or wrong target Windows architecture: $MXE_ARCHBITS bits." exit -1 fi echo "Target Windows architecture: $MXE_ARCHBITS bits." MXE_GIT_URL="https://github.com/mxe/mxe.git" MXE_GIT_REVISION=master MXE_INSTALL_PREFIX=${MXE_BUILDROOT}/usr/${MXE_BUILD_TARGETS}/ MXE_TOOLCHAIN=${MXE_INSTALL_PREFIX}/share/cmake/mxe-conf.cmake #------------------------------------------------------------------------------------------- # URL to git repository to checkout digiKam source code DK_GITURL="git@invent.kde.org:kde/digikam.git" # digiKam tarball information. DK_URL="http://download.kde.org/stable/digikam" # Location to build source code. DK_BUILDTEMP=~/dktemp # digiKam tag version from git. Official tarball do not include extra shared libraries. # The list of tags can be listed with this url: https://quickgit.kde.org/?p=digikam.git&a=tags # If you want to package current implemntation from git, use "master" as tag. #DK_VERSION=v7.0.0-beta2 DK_VERSION=master #DK_VERSION=development/dplugins # Installer sub version to differentiates newer updates of the installer itself, even if the underlying application hasn’t changed. #DK_EPOCH="-01" # Epoch with time-stamp for pre-release bundle in ISO format DK_EPOCH="-`date "+%Y%m%dT%H%M%S"`" # Installer will include or not digiKam debug symbols -DK_DEBUG=1 +DK_DEBUG=0 # Sign bundles with GPG. Passphrase must be hosted in ~/.gnupg/dkorg-gpg-pwd.txt DK_SIGN=0 # Upload automatically bundle to files.kde.org (pre-release only). DK_UPLOAD=1 DK_UPLOADURL="digikam@milonia.kde.org" DK_UPLOADDIR="/srv/archives/files/digikam/"