diff --git a/utilities/geolocation/editor/dialog/geolocationedit.cpp b/utilities/geolocation/editor/dialog/geolocationedit.cpp index ca18bfeefe..49d95ddff2 100644 --- a/utilities/geolocation/editor/dialog/geolocationedit.cpp +++ b/utilities/geolocation/editor/dialog/geolocationedit.cpp @@ -1,1093 +1,1093 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2006-05-16 * Description : A tool to edit geolocation * * Copyright (C) 2006-2018 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 // Local includes #include "dlayoutbox.h" #include "digikam_config.h" #include "mapwidget.h" #include "itemmarkertiler.h" #include "trackmanager.h" #include "gpscommon.h" #include "gpsimagemodel.h" #include "mapdragdrophandler.h" #include "gpsimagelist.h" #include "gpsimagelistdragdrophandler.h" #include "gpsimagelistcontextmenu.h" #include "gpscorrelatorwidget.h" #include "digikam_debug.h" #include "dmessagebox.h" #include "gpsundocommand.h" #include "rgwidget.h" #include "kmlwidget.h" #include "statusprogressbar.h" #include "searchwidget.h" #include "backend-rg.h" #include "gpsimagedetails.h" #include "gpsgeoifacemodelhelper.h" #include "dxmlguiwindow.h" #include "gpsbookmarkowner.h" #include "gpsbookmarkmodelhelper.h" #include "dinfointerface.h" #ifdef GPSSYNC_MODELTEST # include #endif namespace Digikam { struct SaveChangedImagesHelper { public: SaveChangedImagesHelper(GPSImageModel* const model) : imageModel(model) { } QPair operator()(const QPersistentModelIndex& itemIndex) { GPSImageItem* const item = imageModel->itemFromIndex(itemIndex); if (!item) return QPair(QUrl(), QString()); return QPair(item->url(), item->saveChanges()); } public: typedef QPair result_type; GPSImageModel* const imageModel; }; // --------------------------------------------------------------------------------- struct LoadFileMetadataHelper { public: LoadFileMetadataHelper(GPSImageModel* const model) : imageModel(model) { } QPair operator()(const QPersistentModelIndex& itemIndex) { GPSImageItem* const item = imageModel->itemFromIndex(itemIndex); if (!item) return QPair(QUrl(), QString()); item->loadImageData(); return QPair(item->url(), QString()); } public: typedef QPair result_type; GPSImageModel* const imageModel; }; // --------------------------------------------------------------------------------- class GeolocationEdit::Private { public: Private() { imageModel = 0; selectionModel = 0; uiEnabled = true; listViewContextMenu = 0; trackManager = 0; fileIOFutureWatcher = 0; fileIOCountDone = 0; fileIOCountTotal = 0; fileIOCloseAfterSaving = false; buttonBox = 0; VSplitter = 0; HSplitter = 0; treeView = 0; stackedWidget = 0; tabBar = 0; splitterSize = 0; undoStack = 0; undoView = 0; progressBar = 0; progressCancelButton = 0; progressCancelObject = 0; detailsWidget = 0; correlatorWidget = 0; rgWidget = 0; searchWidget = 0; kmlWidget = 0; mapSplitter = 0; mapWidget = 0; mapWidget2 = 0; mapDragDropHandler = 0; mapModelHelper = 0; geoifaceMarkerModel = 0; sortActionOldestFirst = 0; sortActionYoungestFirst = 0; sortMenu = 0; mapLayout = MapLayoutOne; cbMapLayout = 0; bookmarkOwner = 0; actionBookmarkVisibility = 0; iface = 0; } // General things GPSImageModel* imageModel; QItemSelectionModel* selectionModel; bool uiEnabled; GPSImageListContextMenu* listViewContextMenu; TrackManager* trackManager; // Loading and saving QFuture > fileIOFuture; QFutureWatcher >* fileIOFutureWatcher; int fileIOCountDone; int fileIOCountTotal; bool fileIOCloseAfterSaving; // UI QDialogButtonBox* buttonBox; QSplitter* VSplitter; QSplitter* HSplitter; GPSImageList* treeView; QStackedWidget* stackedWidget; QTabBar* tabBar; int splitterSize; QUndoStack* undoStack; QUndoView* undoView; // UI: progress StatusProgressBar* progressBar; QPushButton* progressCancelButton; QObject* progressCancelObject; QString progressCancelSlot; // UI: tab widgets GPSImageDetails* 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(QAbstractItemModel* const externTagModel, DInfoInterface* const iface, QWidget* const parent) : QDialog(parent), d(new Private) { setAttribute(Qt::WA_DeleteOnClose, true); setWindowTitle(i18n("Geolocation Editor")); setMinimumSize(300, 400); - resize(800, 600); d->iface = iface; d->imageModel = new GPSImageModel(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); GPSImageItem::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())); d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Apply | QDialogButtonBox::Close, hbox); connect(d->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &GeolocationEdit::slotApplyClicked); connect(d->buttonBox->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 = 0; 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 GPSImageList(this); d->treeView->setModelAndSelectionModel(d->imageModel, d->selectionModel); d->treeView->setDragDropHandler(new GPSImageListDragDropHandler(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 d->treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); d->treeView->setSortingEnabled(true); d->VSplitter->addWidget(d->treeView); d->listViewContextMenu = new GPSImageListContextMenu(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 GPSImageDetails(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, externTagModel, 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))); readSettings(); d->mapWidget->setActive(true); // Workaround for a drag & drop problem of images to the map for Qt>=5.9.2 show(); } 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) { 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 GPSImageItem(u); } setItems(items); } void GeolocationEdit::setItems(const QList& items) { foreach(GPSImageItem* 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_GENERAL_LOG)<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"); // -------------------------- // 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"); winId(); + windowHandle()->resize(800, 600); DXmlGuiWindow::restoreWindowSize(windowHandle(), groupDialog); resize(windowHandle()->size()); // -------------------------- 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); 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 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); KConfigGroup groupDialog = KConfigGroup(&group, "Dialog"); DXmlGuiWindow::saveWindowSize(windowHandle(), groupDialog); // -------------------------- 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); GPSImageItem* 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; GPSImageItem* 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) d->progressCancelObject = cancelObject; d->progressCancelSlot = cancelSlot; d->uiEnabled = enabledState; d->buttonBox->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, 0, QString()); } void GeolocationEdit::saveChanges(const bool closeAfterwards) { // 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); GPSImageItem* 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 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_GENERAL_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); } if (!errorList.isEmpty()) { QStringList errorStrings; for (int i = 0; i < errorList.count(); ++i) { // TODO: how to do kurl->qstring? 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 != 0); } 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 = 0; } } else { if (d->mapSplitter->count()==1) { QWidget* mapHolder = 0; 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 Digikam diff --git a/utilities/maintenance/maintenancedlg.cpp b/utilities/maintenance/maintenancedlg.cpp index a5dfb92030..0781d056d7 100644 --- a/utilities/maintenance/maintenancedlg.cpp +++ b/utilities/maintenance/maintenancedlg.cpp @@ -1,571 +1,571 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-01-30 * Description : maintenance dialog * * Copyright (C) 2012-2018 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 "maintenancedlg.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "dexpanderbox.h" #include "dnuminput.h" #include "digikam_config.h" #include "setup.h" #include "albumselectors.h" #include "facescansettings.h" #include "imagequalitysettings.h" #include "metadatasynchronizer.h" #include "dxmlguiwindow.h" #include "applicationsettings.h" #include "drangebox.h" namespace Digikam { class MaintenanceDlg::Private { public: enum Operation { Options = 0, NewItems, DbCleanup, Thumbnails, FingerPrints, Duplicates, FaceManagement, ImageQualitySorter, MetadataSync, Stretch }; public: Private() : buttons(0), logo(0), title(0), scanThumbs(0), scanFingerPrints(0), useMutiCoreCPU(0), cleanThumbsDb(0), cleanFacesDb(0), shrinkDatabases(0), qualityScanMode(0), metadataSetup(0), qualitySetup(0), syncDirection(0), similarityRangeBox(0), dupeRestrictionBox(0), vbox(0), vbox2(0), vbox3(0), duplicatesBox(0), hbox3(0), similarityRange(0), faceScannedHandling(0), searchResultRestriction(0), expanderBox(0), albumSelectors(0) { } static const QString configGroupName; static const QString configUseMutiCoreCPU; static const QString configNewItems; static const QString configThumbnails; static const QString configScanThumbs; static const QString configFingerPrints; static const QString configScanFingerPrints; static const QString configDuplicates; static const QString configMinSimilarity; static const QString configMaxSimilarity; static const QString configDuplicatesRestriction; static const QString configFaceManagement; static const QString configFaceScannedHandling; static const QString configImageQualitySorter; static const QString configQualityScanMode; static const QString configMetadataSync; static const QString configCleanupDatabase; static const QString configCleanupThumbDatabase; static const QString configCleanupFacesDatabase; static const QString configShrinkDatabases; static const QString configSyncDirection; QDialogButtonBox* buttons; QLabel* logo; QLabel* title; QCheckBox* scanThumbs; QCheckBox* scanFingerPrints; QCheckBox* useMutiCoreCPU; QCheckBox* cleanThumbsDb; QCheckBox* cleanFacesDb; QCheckBox* shrinkDatabases; QComboBox* qualityScanMode; QPushButton* metadataSetup; QPushButton* qualitySetup; QComboBox* syncDirection; DHBox* similarityRangeBox; DHBox* dupeRestrictionBox; DVBox* vbox; DVBox* vbox2; DVBox* vbox3; DVBox* duplicatesBox; DHBox* hbox3; DIntRangeBox* similarityRange; QComboBox* faceScannedHandling; QComboBox* searchResultRestriction; DExpanderBox* expanderBox; AlbumSelectors* albumSelectors; }; const QString MaintenanceDlg::Private::configGroupName(QLatin1String("MaintenanceDlg Settings")); const QString MaintenanceDlg::Private::configUseMutiCoreCPU(QLatin1String("UseMutiCoreCPU")); const QString MaintenanceDlg::Private::configNewItems(QLatin1String("NewItems")); const QString MaintenanceDlg::Private::configThumbnails(QLatin1String("Thumbnails")); const QString MaintenanceDlg::Private::configScanThumbs(QLatin1String("ScanThumbs")); const QString MaintenanceDlg::Private::configFingerPrints(QLatin1String("FingerPrints")); const QString MaintenanceDlg::Private::configScanFingerPrints(QLatin1String("ScanFingerPrints")); const QString MaintenanceDlg::Private::configDuplicates(QLatin1String("Duplicates")); const QString MaintenanceDlg::Private::configMinSimilarity(QLatin1String("minSimilarity")); const QString MaintenanceDlg::Private::configMaxSimilarity(QLatin1String("maxSimilarity")); const QString MaintenanceDlg::Private::configDuplicatesRestriction(QLatin1String("duplicatesRestriction")); const QString MaintenanceDlg::Private::configFaceManagement(QLatin1String("FaceManagement")); const QString MaintenanceDlg::Private::configFaceScannedHandling(QLatin1String("FaceScannedHandling")); const QString MaintenanceDlg::Private::configImageQualitySorter(QLatin1String("ImageQualitySorter")); const QString MaintenanceDlg::Private::configQualityScanMode(QLatin1String("QualityScanMode")); const QString MaintenanceDlg::Private::configMetadataSync(QLatin1String("MetadataSync")); const QString MaintenanceDlg::Private::configSyncDirection(QLatin1String("SyncDirection")); const QString MaintenanceDlg::Private::configCleanupDatabase(QLatin1String("CleanupDatabase")); const QString MaintenanceDlg::Private::configCleanupThumbDatabase(QLatin1String("CleanupThumbDatabase")); const QString MaintenanceDlg::Private::configCleanupFacesDatabase(QLatin1String("CleanupFacesDatabase")); const QString MaintenanceDlg::Private::configShrinkDatabases(QLatin1String("ShrinkDatabases")); MaintenanceDlg::MaintenanceDlg(QWidget* const parent) : QDialog(parent), d(new Private) { setWindowTitle(i18n("Maintenance")); - resize(800, 600); d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Cancel)->setDefault(true); QScrollArea* const main = new QScrollArea(this); QWidget* const page = new QWidget(main->viewport()); main->setWidget(page); main->setWidgetResizable(true); QGridLayout* const grid = new QGridLayout(page); d->logo = new QLabel(page); d->logo->setPixmap(QIcon::fromTheme(QLatin1String("digikam")).pixmap(QSize(48,48))); d->title = new QLabel(i18n("Select Maintenance Operations to Process"), page); d->expanderBox = new DExpanderBox(page); // -------------------------------------------------------------------------------------- DVBox* const options = new DVBox; d->albumSelectors = new AlbumSelectors(i18nc("@label", "Process items from:"), d->configGroupName, options); d->useMutiCoreCPU = new QCheckBox(i18nc("@option:check", "Work on all processor cores (when it possible)"), options); d->expanderBox->insertItem(Private::Options, options, QIcon::fromTheme(QLatin1String("configure")), i18n("Common Options"), QLatin1String("Options"), true); // -------------------------------------------------------------------------------------- d->expanderBox->insertItem(Private::NewItems, new QLabel(i18n("No option
" "Note: only Albums Collection are processed by this tool.
")), QIcon::fromTheme(QLatin1String("view-refresh")), i18n("Scan for new items"), QLatin1String("NewItems"), false); d->expanderBox->setCheckBoxVisible(Private::NewItems, true); // -------------------------------------------------------------------------------------- d->vbox3 = new DVBox; new QLabel(i18n("Note: If activated, the Core DB is always cleaned. You can select additional databases for cleaning.
" " If you select one of the options below, the process may take much time and can freeze digiKam temporarily
" " in order to make sure that no database corruption occurs.
"), d->vbox3); d->cleanThumbsDb = new QCheckBox(i18n("Also clean up the thumbnail database."), d->vbox3); d->cleanFacesDb = new QCheckBox(i18n("Also clean up the faces database."), d->vbox3); d->shrinkDatabases = new QCheckBox(i18n("Also shrink all databases if possible."), d->vbox3); d->shrinkDatabases->setToolTip(i18n("This option leads to the vacuuming (shrinking) of the databases." " Vacuuming is supported both for SQLite and MySQL.")); d->expanderBox->insertItem(Private::DbCleanup, d->vbox3, QIcon::fromTheme(QLatin1String("run-build")), i18n("Perform database cleaning"), QLatin1String("DbCleanup"), false); d->expanderBox->setCheckBoxVisible(Private::DbCleanup, true); // -------------------------------------------------------------------------------------- d->scanThumbs = new QCheckBox(i18n("Scan for changed or non-cataloged items (faster)")); d->expanderBox->insertItem(Private::Thumbnails, d->scanThumbs, QIcon::fromTheme(QLatin1String("view-process-all")), i18n("Rebuild Thumbnails"), QLatin1String("Thumbnails"), false); d->expanderBox->setCheckBoxVisible(Private::Thumbnails, true); // -------------------------------------------------------------------------------------- d->scanFingerPrints = new QCheckBox(i18n("Scan for changed or non-cataloged items (faster)")); d->expanderBox->insertItem(Private::FingerPrints, d->scanFingerPrints, QIcon::fromTheme(QLatin1String("run-build")), i18n("Rebuild Finger-prints"), QLatin1String("Fingerprints"), false); d->expanderBox->setCheckBoxVisible(Private::FingerPrints, true); // -------------------------------------------------------------------------------------- const ApplicationSettings * settings = ApplicationSettings::instance(); d->duplicatesBox = new DVBox; d->similarityRangeBox = new DHBox(d->duplicatesBox); new QLabel(i18n("Similarity range (in percents): "), d->similarityRangeBox); QWidget* const space = new QWidget(d->similarityRangeBox); d->similarityRangeBox->setStretchFactor(space, 10); d->similarityRange = new DIntRangeBox(d->similarityRangeBox); d->similarityRange->setSuffix(QLatin1String("%")); if (settings) { d->similarityRange->setRange(settings->getMinimumSimilarityBound(), 100); d->similarityRange->setInterval(settings->getDuplicatesSearchLastMinSimilarity(), settings->getDuplicatesSearchLastMaxSimilarity()); } else { d->similarityRange->setRange(40, 100); d->similarityRange->setInterval(90, 100); } d->dupeRestrictionBox = new DHBox(d->duplicatesBox); new QLabel(i18n("Restriction on duplicates:"), d->dupeRestrictionBox); QWidget* const space4 = new QWidget(d->dupeRestrictionBox); d->dupeRestrictionBox->setStretchFactor(space4, 10); d->searchResultRestriction = new QComboBox(d->dupeRestrictionBox); d->searchResultRestriction->addItem(i18n("No restriction"), HaarIface::DuplicatesSearchRestrictions::None); d->searchResultRestriction->addItem(i18n("Restrict to album of reference image"), HaarIface::DuplicatesSearchRestrictions::SameAlbum); d->searchResultRestriction->addItem(i18n("Exclude album of reference image"), HaarIface::DuplicatesSearchRestrictions::DifferentAlbum); // Load the last choice from application settings. HaarIface::DuplicatesSearchRestrictions restrictions = HaarIface::DuplicatesSearchRestrictions::None; if (settings) { restrictions = (HaarIface::DuplicatesSearchRestrictions) settings->getDuplicatesSearchRestrictions(); } d->searchResultRestriction->setCurrentIndex(d->searchResultRestriction->findData(restrictions)); d->expanderBox->insertItem(Private::Duplicates, d->duplicatesBox, QIcon::fromTheme(QLatin1String("tools-wizard")), i18n("Find Duplicate Items"), QLatin1String("Duplicates"), false); d->expanderBox->setCheckBoxVisible(Private::Duplicates, true); // -------------------------------------------------------------------------------------- d->hbox3 = new DHBox; new QLabel(i18n("Faces data management: "), d->hbox3); QWidget* const space3 = new QWidget(d->hbox3); d->hbox3->setStretchFactor(space3, 10); d->faceScannedHandling = new QComboBox(d->hbox3); d->faceScannedHandling->addItem(i18n("Skip images already scanned"), FaceScanSettings::Skip); d->faceScannedHandling->addItem(i18n("Scan again and merge results"), FaceScanSettings::Merge); d->faceScannedHandling->addItem(i18n("Clear unconfirmed results and rescan"), FaceScanSettings::Rescan); d->expanderBox->insertItem(Private::FaceManagement, d->hbox3, QIcon::fromTheme(QLatin1String("edit-image-face-detect")), i18n("Detect and recognize Faces (experimental)"), QLatin1String("FaceManagement"), false); d->expanderBox->setCheckBoxVisible(Private::FaceManagement, true); // -------------------------------------------------------------------------------------- d->vbox = new DVBox; DHBox* const hbox11 = new DHBox(d->vbox); new QLabel(i18n("Scan Mode: "), hbox11); QWidget* const space7 = new QWidget(hbox11); hbox11->setStretchFactor(space7, 10); d->qualityScanMode = new QComboBox(hbox11); d->qualityScanMode->addItem(i18n("Clean all and re-scan"), ImageQualitySorter::AllItems); d->qualityScanMode->addItem(i18n("Scan non-assigned only"), ImageQualitySorter::NonAssignedItems); DHBox* const hbox12 = new DHBox(d->vbox); new QLabel(i18n("Check quality sorter setup panel for details: "), hbox12); QWidget* const space2 = new QWidget(hbox12); hbox12->setStretchFactor(space2, 10); d->qualitySetup = new QPushButton(i18n("Settings..."), hbox12); d->expanderBox->insertItem(Private::ImageQualitySorter, d->vbox, QIcon::fromTheme(QLatin1String("flag-green")), i18n("Image Quality Sorter"), QLatin1String("ImageQualitySorter"), false); d->expanderBox->setCheckBoxVisible(Private::ImageQualitySorter, true); // -------------------------------------------------------------------------------------- d->vbox2 = new DVBox; DHBox* const hbox21 = new DHBox(d->vbox2); new QLabel(i18n("Sync Direction: "), hbox21); QWidget* const space5 = new QWidget(hbox21); hbox21->setStretchFactor(space5, 10); d->syncDirection = new QComboBox(hbox21); d->syncDirection->addItem(i18n("From database to image metadata"), MetadataSynchronizer::WriteFromDatabaseToFile); d->syncDirection->addItem(i18n("From image metadata to database"), MetadataSynchronizer::ReadFromFileToDatabase); DHBox* const hbox22 = new DHBox(d->vbox2); new QLabel(i18n("Check metadata setup panel for details: "), hbox22); QWidget* const space6 = new QWidget(hbox22); hbox22->setStretchFactor(space6, 10); d->metadataSetup = new QPushButton(i18n("Settings..."), hbox22); d->expanderBox->insertItem(Private::MetadataSync, d->vbox2, QIcon::fromTheme(QLatin1String("run-build-file")), i18n("Sync Metadata and Database"), QLatin1String("MetadataSync"), false); d->expanderBox->setCheckBoxVisible(Private::MetadataSync, true); d->expanderBox->insertStretch(Private::Stretch); // -------------------------------------------------------------------------------------- grid->addWidget(d->logo, 0, 0, 1, 1); grid->addWidget(d->title, 0, 1, 1, 1); grid->addWidget(d->expanderBox, 5, 0, 3, 2); grid->setSpacing(style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); grid->setContentsMargins(QMargins()); grid->setColumnStretch(1, 10); grid->setRowStretch(5, 10); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(main); vbx->addWidget(d->buttons); setLayout(vbx); // -------------------------------------------------------------------------------------- connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(slotOk())); connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); connect(d->buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotHelp())); connect(d->expanderBox, SIGNAL(signalItemToggled(int,bool)), this, SLOT(slotItemToggled(int,bool))); connect(d->metadataSetup, SIGNAL(clicked()), this, SLOT(slotMetadataSetup())); connect(d->qualitySetup, SIGNAL(clicked()), this, SLOT(slotQualitySetup())); // -------------------------------------------------------------------------------------- readSettings(); } MaintenanceDlg::~MaintenanceDlg() { delete d; } void MaintenanceDlg::slotOk() { writeSettings(); accept(); } MaintenanceSettings MaintenanceDlg::settings() const { MaintenanceSettings prm; prm.wholeAlbums = d->albumSelectors->wholeAlbumsChecked(); prm.wholeTags = d->albumSelectors->wholeTagsChecked(); prm.albums = d->albumSelectors->selectedAlbums(); prm.tags = d->albumSelectors->selectedTags(); prm.useMutiCoreCPU = d->useMutiCoreCPU->isChecked(); prm.newItems = d->expanderBox->isChecked(Private::NewItems); prm.databaseCleanup = d->expanderBox->isChecked(Private::DbCleanup); prm.cleanThumbDb = d->cleanThumbsDb->isChecked(); prm.cleanFacesDb = d->cleanFacesDb->isChecked(); prm.shrinkDatabases = d->shrinkDatabases->isChecked(); prm.thumbnails = d->expanderBox->isChecked(Private::Thumbnails); prm.scanThumbs = d->scanThumbs->isChecked(); prm.fingerPrints = d->expanderBox->isChecked(Private::FingerPrints); prm.scanFingerPrints = d->scanFingerPrints->isChecked(); prm.duplicates = d->expanderBox->isChecked(Private::Duplicates); prm.minSimilarity = d->similarityRange->minValue(); prm.maxSimilarity = d->similarityRange->maxValue(); prm.duplicatesRestriction = (HaarIface::DuplicatesSearchRestrictions)d->searchResultRestriction->itemData(d->searchResultRestriction->currentIndex()).toInt(); prm.faceManagement = d->expanderBox->isChecked(Private::FaceManagement); prm.faceSettings.alreadyScannedHandling = (FaceScanSettings::AlreadyScannedHandling)d->faceScannedHandling->itemData(d->faceScannedHandling->currentIndex()).toInt(); prm.faceSettings.albums = d->albumSelectors->selectedAlbums(); prm.qualitySort = d->expanderBox->isChecked(Private::ImageQualitySorter); prm.qualityScanMode = d->qualityScanMode->itemData(d->qualityScanMode->currentIndex()).toInt(); ImageQualitySettings imgq; imgq.readFromConfig(); prm.quality = imgq; prm.metadataSync = d->expanderBox->isChecked(Private::MetadataSync); prm.syncDirection = d->syncDirection->itemData(d->syncDirection->currentIndex()).toInt(); return prm; } void MaintenanceDlg::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); d->expanderBox->readSettings(group); d->albumSelectors->loadState(); MaintenanceSettings prm; d->useMutiCoreCPU->setChecked(group.readEntry(d->configUseMutiCoreCPU, prm.useMutiCoreCPU)); d->expanderBox->setChecked(Private::NewItems, group.readEntry(d->configNewItems, prm.newItems)); d->expanderBox->setChecked(Private::DbCleanup, group.readEntry(d->configCleanupDatabase, prm.databaseCleanup)); d->cleanThumbsDb->setChecked(group.readEntry(d->configCleanupThumbDatabase, prm.cleanThumbDb)); d->cleanFacesDb->setChecked(group.readEntry(d->configCleanupFacesDatabase, prm.cleanFacesDb)); d->shrinkDatabases->setChecked(group.readEntry(d->configShrinkDatabases, prm.shrinkDatabases)); d->expanderBox->setChecked(Private::Thumbnails, group.readEntry(d->configThumbnails, prm.thumbnails)); d->scanThumbs->setChecked(group.readEntry(d->configScanThumbs, prm.scanThumbs)); d->expanderBox->setChecked(Private::FingerPrints, group.readEntry(d->configFingerPrints, prm.fingerPrints)); d->scanFingerPrints->setChecked(group.readEntry(d->configScanFingerPrints, prm.scanFingerPrints)); d->expanderBox->setChecked(Private::Duplicates, group.readEntry(d->configDuplicates, prm.duplicates)); d->similarityRange->setInterval(group.readEntry(d->configMinSimilarity, prm.minSimilarity), group.readEntry(d->configMaxSimilarity, prm.maxSimilarity)); int restrictions = d->searchResultRestriction->findData(group.readEntry(d->configDuplicatesRestriction, (int)prm.duplicatesRestriction)); d->searchResultRestriction->setCurrentIndex(restrictions); d->expanderBox->setChecked(Private::FaceManagement, group.readEntry(d->configFaceManagement, prm.faceManagement)); d->faceScannedHandling->setCurrentIndex(group.readEntry(d->configFaceScannedHandling, (int)prm.faceSettings.alreadyScannedHandling)); d->expanderBox->setChecked(Private::ImageQualitySorter, group.readEntry(d->configImageQualitySorter, prm.qualitySort)); d->qualityScanMode->setCurrentIndex(group.readEntry(d->configQualityScanMode, prm.qualityScanMode)); d->expanderBox->setChecked(Private::MetadataSync, group.readEntry(d->configMetadataSync, prm.metadataSync)); d->syncDirection->setCurrentIndex(group.readEntry(d->configSyncDirection, prm.syncDirection)); for (int i = Private::NewItems ; i < Private::Stretch ; ++i) { slotItemToggled(i, d->expanderBox->isChecked(i)); } winId(); + windowHandle()->resize(800, 600); DXmlGuiWindow::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); } void MaintenanceDlg::writeSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); d->expanderBox->writeSettings(group); d->albumSelectors->saveState(); MaintenanceSettings prm = settings(); group.writeEntry(d->configUseMutiCoreCPU, prm.useMutiCoreCPU); group.writeEntry(d->configNewItems, prm.newItems); group.writeEntry(d->configCleanupDatabase, prm.databaseCleanup); group.writeEntry(d->configCleanupThumbDatabase, prm.cleanThumbDb); group.writeEntry(d->configCleanupFacesDatabase, prm.cleanFacesDb); group.writeEntry(d->configShrinkDatabases, prm.shrinkDatabases); group.writeEntry(d->configThumbnails, prm.thumbnails); group.writeEntry(d->configScanThumbs, prm.scanThumbs); group.writeEntry(d->configFingerPrints, prm.fingerPrints); group.writeEntry(d->configScanFingerPrints, prm.scanFingerPrints); group.writeEntry(d->configDuplicates, prm.duplicates); group.writeEntry(d->configMinSimilarity, prm.minSimilarity); group.writeEntry(d->configMaxSimilarity, prm.maxSimilarity); group.writeEntry(d->configDuplicatesRestriction, (int)prm.duplicatesRestriction); group.writeEntry(d->configFaceManagement, prm.faceManagement); group.writeEntry(d->configFaceScannedHandling, (int)prm.faceSettings.alreadyScannedHandling); group.writeEntry(d->configImageQualitySorter, prm.qualitySort); group.writeEntry(d->configQualityScanMode, prm.qualityScanMode); group.writeEntry(d->configMetadataSync, prm.metadataSync); group.writeEntry(d->configSyncDirection, prm.syncDirection); DXmlGuiWindow::saveWindowSize(windowHandle(), group); } void MaintenanceDlg::slotItemToggled(int index, bool b) { switch (index) { case Private::Thumbnails: d->scanThumbs->setEnabled(b); break; case Private::FingerPrints: d->scanFingerPrints->setEnabled(b); break; case Private::Duplicates: d->duplicatesBox->setEnabled(b); break; case Private::FaceManagement: d->hbox3->setEnabled(b); break; case Private::ImageQualitySorter: d->vbox->setEnabled(b); break; case Private::MetadataSync: d->vbox2->setEnabled(b); break; case Private::DbCleanup: d->vbox3->setEnabled(b); break; default : // NewItems break; } } void MaintenanceDlg::slotMetadataSetup() { Setup::execSinglePage(this, Setup::MetadataPage); } void MaintenanceDlg::slotQualitySetup() { Setup::execSinglePage(this, Setup::ImageQualityPage); } void MaintenanceDlg::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/utilities/setup/setup.cpp b/utilities/setup/setup.cpp index 0c0762022f..578127fb98 100644 --- a/utilities/setup/setup.cpp +++ b/utilities/setup/setup.cpp @@ -1,571 +1,571 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2003-02-03 * Description : digiKam setup dialog. * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2003-2018 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU Album * 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 Album Public License for more details. * * ============================================================ */ #include "setup.h" // Qt includes #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "applicationsettings.h" #include "thumbsgenerator.h" #include "setupalbumview.h" #include "setupcamera.h" #include "setupcollections.h" #include "setupeditor.h" #include "setupicc.h" #include "setuplighttable.h" #include "setupmetadata.h" #include "setupmisc.h" #include "setupslideshow.h" #include "setupimagequalitysorter.h" #include "setuptooltip.h" #include "setupdatabase.h" #include "importsettings.h" #include "dxmlguiwindow.h" namespace Digikam { class Setup::Private { public: Private() : page_database(0), page_collections(0), page_albumView(0), page_tooltip(0), page_metadata(0), page_template(0), page_lighttable(0), page_editor(0), page_slideshow(0), page_imagequalitysorter(0), page_icc(0), page_camera(0), page_misc(0), databasePage(0), collectionsPage(0), albumViewPage(0), tooltipPage(0), metadataPage(0), templatePage(0), lighttablePage(0), editorPage(0), slideshowPage(0), imageQualitySorterPage(0), iccPage(0), cameraPage(0), miscPage(0) { } DConfigDlgWdgItem* page_database; DConfigDlgWdgItem* page_collections; DConfigDlgWdgItem* page_albumView; DConfigDlgWdgItem* page_tooltip; DConfigDlgWdgItem* page_metadata; DConfigDlgWdgItem* page_template; DConfigDlgWdgItem* page_lighttable; DConfigDlgWdgItem* page_editor; DConfigDlgWdgItem* page_slideshow; DConfigDlgWdgItem* page_imagequalitysorter; DConfigDlgWdgItem* page_icc; DConfigDlgWdgItem* page_camera; DConfigDlgWdgItem* page_misc; SetupDatabase* databasePage; SetupCollections* collectionsPage; SetupAlbumView* albumViewPage; SetupToolTip* tooltipPage; SetupMetadata* metadataPage; SetupTemplate* templatePage; SetupLightTable* lighttablePage; SetupEditor* editorPage; SetupSlideShow* slideshowPage; SetupImageQualitySorter* imageQualitySorterPage; SetupICC* iccPage; SetupCamera* cameraPage; SetupMisc* miscPage; public: DConfigDlgWdgItem* pageItem(Setup::Page page) const; }; Setup::Setup(QWidget* const parent) : DConfigDlg(parent), d(new Private) { setWindowTitle(i18n("Configure")); setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel); button(QDialogButtonBox::Ok)->setDefault(true); setFaceType(List); - resize(800, 600); setModal(true); d->databasePage = new SetupDatabase(); d->page_database = addPage(d->databasePage, i18n("Database")); d->page_database->setHeader(i18n("Database Settings
" "Customize database settings
")); d->page_database->setIcon(QIcon::fromTheme(QLatin1String("network-server-database"))); d->collectionsPage = new SetupCollections(); d->page_collections = addPage(d->collectionsPage, i18n("Collections")); d->page_collections->setHeader(i18n("Collections Settings
" "Set root albums locations
")); d->page_collections->setIcon(QIcon::fromTheme(QLatin1String("folder-pictures"))); d->albumViewPage = new SetupAlbumView(); d->page_albumView = addPage(d->albumViewPage, i18n("Views")); d->page_albumView->setHeader(i18n("Application Views Settings
" "Customize the look of the views
")); d->page_albumView->setIcon(QIcon::fromTheme(QLatin1String("view-list-icons"))); d->tooltipPage = new SetupToolTip(); d->page_tooltip = addPage(d->tooltipPage, i18n("Tool-Tip")); d->page_tooltip->setHeader(i18n("Items Tool-Tip Settings
" "Customize information in item tool-tips
")); d->page_tooltip->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->metadataPage = new SetupMetadata(); d->page_metadata = addPage(d->metadataPage, i18n("Metadata")); d->page_metadata->setHeader(i18n("Embedded Image Information Management
" "Setup relations between images and metadata
")); d->page_metadata->setIcon(QIcon::fromTheme(QLatin1String("format-text-code"))); // krazy:exclude=iconnames d->templatePage = new SetupTemplate(); d->page_template = addPage(d->templatePage, i18n("Templates")); d->page_template->setHeader(i18n("Metadata templates
" "Manage your collection of metadata templates
")); d->page_template->setIcon(QIcon::fromTheme(QLatin1String("im-user"))); d->editorPage = new SetupEditor(); d->page_editor = addPage(d->editorPage, i18n("Image Editor")); d->page_editor->setHeader(i18n("Image Editor Settings
" "Customize the image editor settings
")); d->page_editor->setIcon(QIcon::fromTheme(QLatin1String("document-edit"))); d->iccPage = new SetupICC(buttonBox()); d->page_icc = addPage(d->iccPage, i18n("Color Management")); d->page_icc->setHeader(i18n("Settings for Color Management
" "Customize the color management settings
")); d->page_icc->setIcon(QIcon::fromTheme(QLatin1String("preferences-desktop-display-color"))); d->lighttablePage = new SetupLightTable(); d->page_lighttable = addPage(d->lighttablePage, i18n("Light Table")); d->page_lighttable->setHeader(i18n("Light Table Settings
" "Customize tool used to compare images
")); d->page_lighttable->setIcon(QIcon::fromTheme(QLatin1String("lighttable"))); d->slideshowPage = new SetupSlideShow(); d->page_slideshow = addPage(d->slideshowPage, i18n("Slide Show")); d->page_slideshow->setHeader(i18n("Slide Show Settings
" "Customize slideshow settings
")); d->page_slideshow->setIcon(QIcon::fromTheme(QLatin1String("view-presentation"))); d->imageQualitySorterPage = new SetupImageQualitySorter(); d->page_imagequalitysorter = addPage(d->imageQualitySorterPage, i18n("Image Quality Sorter")); d->page_imagequalitysorter->setHeader(i18n("Image Quality Sorter Settings
")); d->page_imagequalitysorter->setIcon(QIcon::fromTheme(QLatin1String("flag-green"))); d->cameraPage = new SetupCamera(); d->page_camera = addPage(d->cameraPage, i18n("Cameras")); d->page_camera->setHeader(i18n("Camera Settings
" "Manage your camera devices
")); d->page_camera->setIcon(QIcon::fromTheme(QLatin1String("camera-photo"))); connect(d->cameraPage, SIGNAL(signalUseFileMetadataChanged(bool)), d->tooltipPage, SLOT(slotUseFileMetadataChanged(bool))); connect(buttonBox(), SIGNAL(helpRequested()), this, SLOT(slotHelp())); connect(buttonBox()->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &Setup::slotOkClicked); d->miscPage = new SetupMisc(); d->page_misc = addPage(d->miscPage, i18n("Miscellaneous")); d->page_misc->setHeader(i18n("Miscellaneous Settings
" "Customize behavior of the other parts of digiKam
")); d->page_misc->setIcon(QIcon::fromTheme(QLatin1String("preferences-other"))); for (int i = 0 ; i != SetupPageEnumLast ; ++i) { DConfigDlgWdgItem* const item = d->pageItem((Page)i); if (!item) { continue; } QWidget* const wgt = item->widget(); QScrollArea* const scrollArea = qobject_cast(wgt); if (scrollArea) { scrollArea->setFrameShape(QFrame::NoFrame); } } KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Setup Dialog")); winId(); + windowHandle()->resize(800, 600); DXmlGuiWindow::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); } Setup::~Setup() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Setup Dialog")); group.writeEntry(QLatin1String("Setup Page"), (int)activePageIndex()); DXmlGuiWindow::saveWindowSize(windowHandle(), group); config->sync(); delete d; } void Setup::slotHelp() { DXmlGuiWindow::openHandbook(); } void Setup::setTemplate(const Template& t) { if (d->templatePage) { d->templatePage->setTemplate(t); } } QSize Setup::sizeHint() const { // The minimum size is very small. But the default initial size is such // that some important tabs get a scroll bar, although the dialog could be larger // on a normal display (QScrollArea size hint does not take widget into account) // Adjust size hint here so that certain selected tabs are display full per default. QSize hint = DConfigDlg::sizeHint(); int maxHintHeight = 0; int maxWidgetHeight = 0; for (int page = 0 ; page != SetupPageEnumLast ; ++page) { // only take tabs into account here that should better be displayed without scrolling if (page == CollectionsPage || page == AlbumViewPage || page == TemplatePage || page == LightTablePage || page == EditorPage || page == MiscellaneousPage) { DConfigDlgWdgItem* const item = d->pageItem((Page)page); if (!item) { continue; } QWidget* const page = item->widget(); maxHintHeight = qMax(maxHintHeight, page->sizeHint().height()); QScrollArea* const scrollArea = qobject_cast(page); if (scrollArea) { maxWidgetHeight = qMax(maxWidgetHeight, scrollArea->widget()->sizeHint().height()); } } } // The additional 20 is a hack to make it work. // Don't know why, the largest page would have scroll bars without this if (maxWidgetHeight > maxHintHeight) { hint.setHeight(hint.height() + (maxWidgetHeight - maxHintHeight) + 20); } return hint; } bool Setup::execDialog(Page page) { return execDialog(0, page); } bool Setup::execDialog(QWidget* const parent, Page page) { QPointer setup = new Setup(parent); setup->showPage(page); bool success = (setup->DConfigDlg::exec() == QDialog::Accepted); delete setup; return success; } bool Setup::execSinglePage(Page page) { return execSinglePage(0, page); } bool Setup::execSinglePage(QWidget* const parent, Page page) { QPointer setup = new Setup(parent); setup->showPage(page); setup->setFaceType(Plain); bool success = (setup->DConfigDlg::exec() == QDialog::Accepted); delete setup; return success; } bool Setup::execTemplateEditor(QWidget* const parent, const Template& t) { QPointer setup = new Setup(parent); setup->showPage(TemplatePage); setup->setFaceType(Plain); setup->setTemplate(t); bool success = (setup->DConfigDlg::exec() == QDialog::Accepted); delete setup; return success; } bool Setup::execMetadataFilters(QWidget* const parent, int tab) { QPointer setup = new Setup(parent); setup->showPage(MetadataPage); setup->setFaceType(Plain); DConfigDlgWdgItem* const cur = setup->currentPage(); if (!cur) return false; SetupMetadata* const widget = dynamic_cast(cur->widget()); if (!widget) return false; widget->setActiveMainTab(SetupMetadata::Display); widget->setActiveSubTab(tab); bool success = (setup->DConfigDlg::exec() == QDialog::Accepted); delete setup; return success; } void Setup::slotOkClicked() { if (!d->cameraPage->checkSettings()) { showPage(CameraPage); return; } qApp->setOverrideCursor(Qt::WaitCursor); d->cameraPage->applySettings(); d->databasePage->applySettings(); d->collectionsPage->applySettings(); d->albumViewPage->applySettings(); d->tooltipPage->applySettings(); d->metadataPage->applySettings(); d->templatePage->applySettings(); d->lighttablePage->applySettings(); d->editorPage->applySettings(); d->slideshowPage->applySettings(); d->imageQualitySorterPage->applySettings(); d->iccPage->applySettings(); d->miscPage->applySettings(); ApplicationSettings::instance()->emitSetupChanged(); ImportSettings::instance()->emitSetupChanged(); qApp->restoreOverrideCursor(); if (d->metadataPage->exifAutoRotateHasChanged()) { QString msg = i18n("The Exif auto-rotate thumbnails option has been changed.\n" "Do you want to rebuild all albums' items' thumbnails now?\n\n" "Note: thumbnail processing can take a while. You can start " "this job later from the \"Tools-Maintenance\" menu."); int result = QMessageBox::warning(this, qApp->applicationName(), msg, QMessageBox::Yes | QMessageBox::No); if (result != QMessageBox::Yes) { return; } new ThumbsGenerator(true, -1); } accept(); } void Setup::showPage(Setup::Page page) { DConfigDlgWdgItem* item = 0; if (page == LastPageUsed) { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Setup Dialog")); item = d->pageItem((Page)group.readEntry(QLatin1String("Setup Page"), (int)CollectionsPage)); } else { item = d->pageItem(page); } if (!item) { item = d->pageItem(CollectionsPage); } setCurrentPage(item); } Setup::Page Setup::activePageIndex() const { DConfigDlgWdgItem* const cur = currentPage(); if (cur == d->page_collections) { return CollectionsPage; } if (cur == d->page_albumView) { return AlbumViewPage; } if (cur == d->page_tooltip) { return ToolTipPage; } if (cur == d->page_metadata) { return MetadataPage; } if (cur == d->page_template) { return TemplatePage; } if (cur == d->page_lighttable) { return LightTablePage; } if (cur == d->page_editor) { return EditorPage; } if (cur == d->page_slideshow) { return SlideshowPage; } if (cur == d->page_imagequalitysorter) { return ImageQualityPage; } if (cur == d->page_icc) { return ICCPage; } if (cur == d->page_camera) { return CameraPage; } if (cur == d->page_misc) { return MiscellaneousPage; } return DatabasePage; } DConfigDlgWdgItem* Setup::Private::pageItem(Setup::Page page) const { switch (page) { case Setup::DatabasePage: return page_database; case Setup::CollectionsPage: return page_collections; case Setup::AlbumViewPage: return page_albumView; case Setup::ToolTipPage: return page_tooltip; case Setup::MetadataPage: return page_metadata; case Setup::TemplatePage: return page_template; case Setup::LightTablePage: return page_lighttable; case Setup::EditorPage: return page_editor; case Setup::SlideshowPage: return page_slideshow; case Setup::ImageQualityPage: return page_imagequalitysorter; case Setup::ICCPage: return page_icc; case Setup::CameraPage: return page_camera; case Setup::MiscellaneousPage: return page_misc; default: return 0; } } } // namespace Digikam