diff --git a/core/utilities/advancedrename/advancedrenamedialog.cpp b/core/utilities/advancedrename/advancedrenamedialog.cpp index 1c91c38787..c79b4f3838 100644 --- a/core/utilities/advancedrename/advancedrenamedialog.cpp +++ b/core/utilities/advancedrename/advancedrenamedialog.cpp @@ -1,589 +1,591 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2009-09-14 * Description : a rename dialog for the AdvancedRename utility * * Copyright (C) 2009-2012 by Andi Clemens * Copyright (C) 2013-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 "advancedrenamedialog.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "dxmlguiwindow.h" #include "advancedrenamewidget.h" #include "contextmenuhelper.h" #include "parser.h" #include "parsesettings.h" #include "advancedrenamemanager.h" #include "advancedrenameprocessdialog.h" #include "digikam_debug.h" namespace Digikam { class Q_DECL_HIDDEN AdvancedRenameListItem::Private { public: explicit Private() { } QUrl imageUrl; QString completeFileName; }; // -------------------------------------------------------- AdvancedRenameListItem::AdvancedRenameListItem(QTreeWidget* const view) : QTreeWidgetItem(view), d(new Private) { } AdvancedRenameListItem::AdvancedRenameListItem(QTreeWidget* const view, const QUrl& url) : QTreeWidgetItem(view), d(new Private) { setImageUrl(url); } AdvancedRenameListItem:: ~AdvancedRenameListItem() { delete d; } void AdvancedRenameListItem::setImageUrl(const QUrl& url) { d->imageUrl = url; QFileInfo fi(d->imageUrl.toLocalFile()); d->completeFileName = fi.fileName(); setName(d->completeFileName); setNewName(d->completeFileName); } QUrl AdvancedRenameListItem::imageUrl() const { return d->imageUrl; } void AdvancedRenameListItem::setName(const QString& name) { setText(OldName, name); } QString AdvancedRenameListItem::name() const { return text(OldName); } void AdvancedRenameListItem::setNewName(const QString& name) { setText(NewName, name); } QString AdvancedRenameListItem::newName() const { return text(NewName); } void AdvancedRenameListItem::markInvalid(bool invalid) { QColor normalText = qApp->palette().text().color(); setForeground(OldName, invalid ? Qt::red : normalText); setForeground(NewName, invalid ? Qt::red : normalText); } bool AdvancedRenameListItem::isNameEqual() const { return (name() == newName()); } // -------------------------------------------------------- class Q_DECL_HIDDEN AdvancedRenameDialog::Private { public: explicit Private() : singleFileMode(false), minSizeDialog(450), sortActionName(0), sortActionDate(0), sortActionSize(0), sortActionAscending(0), sortActionDescending(0), sortGroupActions(0), sortGroupDirections(0), listView(0), buttons(0), advancedRenameManager(0), advancedRenameWidget(0) { } static const QString configGroupName; static const QString configLastUsedRenamePatternEntry; static const QString configDialogSizeEntry; QString singleFileModeOldFilename; bool singleFileMode; int minSizeDialog; QAction* sortActionName; QAction* sortActionDate; QAction* sortActionSize; QAction* sortActionAscending; QAction* sortActionDescending; QActionGroup* sortGroupActions; QActionGroup* sortGroupDirections; QTreeWidget* listView; QDialogButtonBox* buttons; AdvancedRenameManager* advancedRenameManager; AdvancedRenameWidget* advancedRenameWidget; NewNamesList newNamesList; }; const QString AdvancedRenameDialog::Private::configGroupName(QLatin1String("AdvancedRename Dialog")); const QString AdvancedRenameDialog::Private::configLastUsedRenamePatternEntry(QLatin1String("Last Used Rename Pattern")); const QString AdvancedRenameDialog::Private::configDialogSizeEntry(QLatin1String("Dialog Size")); // -------------------------------------------------------- AdvancedRenameDialog::AdvancedRenameDialog(QWidget* const parent) : QDialog(parent), d(new Private) { - setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window | - Qt::WindowCloseButtonHint | - Qt::WindowMinMaxButtonsHint); + setWindowFlags((windowFlags() & ~Qt::Dialog) | + Qt::Window | + Qt::WindowCloseButtonHint | + Qt::WindowMinMaxButtonsHint); + setModal(true); setupWidgets(); setupConnections(); initDialog(); readSettings(); } AdvancedRenameDialog::~AdvancedRenameDialog() { writeSettings(); delete d->advancedRenameManager; delete d; } void AdvancedRenameDialog::setupWidgets() { d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); d->advancedRenameManager = new AdvancedRenameManager(); d->advancedRenameWidget = new AdvancedRenameWidget(this); d->advancedRenameManager->setWidget(d->advancedRenameWidget); // -------------------------------------------------------- d->sortActionName = new QAction(i18n("By Name"), this); d->sortActionDate = new QAction(i18n("By Date"), this); d->sortActionSize = new QAction(i18n("By File Size"), this); d->sortActionName->setCheckable(true); d->sortActionDate->setCheckable(true); d->sortActionSize->setCheckable(true); // -------------------------------------------------------- d->sortActionAscending = new QAction(i18n("Ascending"), this); d->sortActionDescending = new QAction(i18n("Descending"), this); d->sortActionAscending->setCheckable(true); d->sortActionDescending->setCheckable(true); d->sortActionAscending->setChecked(true); // -------------------------------------------------------- d->sortGroupActions = new QActionGroup(this); d->sortGroupDirections = new QActionGroup(this); d->sortGroupActions->addAction(d->sortActionName); d->sortGroupActions->addAction(d->sortActionDate); d->sortGroupActions->addAction(d->sortActionSize); d->sortGroupDirections->addAction(d->sortActionAscending); d->sortGroupDirections->addAction(d->sortActionDescending); // -------------------------------------------------------- d->listView = new QTreeWidget(this); d->listView->setRootIsDecorated(false); d->listView->setSelectionMode(QAbstractItemView::NoSelection); d->listView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); d->listView->setAllColumnsShowFocus(true); d->listView->setSortingEnabled(false); d->listView->setColumnCount(2); d->listView->setHeaderLabels(QStringList() << i18n("Current Name") << i18n("New Name")); d->listView->setContextMenuPolicy(Qt::CustomContextMenu); d->listView->header()->setSectionResizeMode(0, QHeaderView::Stretch); d->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch); d->listView->setWhatsThis(i18n("This list shows the results for your renaming pattern. Red items indicate a " "name collision, either because the new name is equal to the current name, " "or because the name has already been assigned to another item.")); // -------------------------------------------------------- QWidget* const mainWidget = new QWidget(this); QGridLayout* const mainLayout = new QGridLayout; mainLayout->addWidget(d->listView, 0, 0, 1, 1); mainLayout->addWidget(d->advancedRenameWidget, 1, 0, 1, 1); mainLayout->setRowStretch(0, 10); mainWidget->setLayout(mainLayout); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(mainWidget); vbx->addWidget(d->buttons); setLayout(vbx); setMinimumWidth(d->advancedRenameWidget->minimumWidth()); } void AdvancedRenameDialog::setupConnections() { connect(d->advancedRenameWidget, SIGNAL(signalTextChanged(QString)), this, SLOT(slotParseStringChanged(QString))); connect(d->advancedRenameWidget, SIGNAL(signalReturnPressed()), this, SLOT(slotReturnPressed())); connect(d->advancedRenameManager, SIGNAL(signalSortingChanged(QList)), this, SLOT(slotAddImages(QList))); connect(d->listView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotShowContextMenu(QPoint))); connect(d->sortGroupActions, SIGNAL(triggered(QAction*)), this, SLOT(slotSortActionTriggered(QAction*))); connect(d->sortGroupDirections, SIGNAL(triggered(QAction*)), this, SLOT(slotSortDirectionTriggered(QAction*))); connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); connect(d->buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotHelp())); } void AdvancedRenameDialog::initDialog() { QStringList fileList = d->advancedRenameManager->fileList(); int count = fileList.size(); QString title = i18np("Rename", "Rename (%1 images)", count); setWindowTitle(title); if (count < 1) { d->listView->clear(); return; } d->singleFileMode = count == 1; foreach(const QString& file, fileList) { QUrl url = QUrl::fromLocalFile(file); new AdvancedRenameListItem(d->listView, url); } // set current filename if only one image has been added if (d->singleFileMode) { QFileInfo info(fileList.first()); d->advancedRenameWidget->setParseString(info.completeBaseName()); d->advancedRenameWidget->setParseTimerDuration(50); d->advancedRenameWidget->focusLineEdit(); d->advancedRenameWidget->highlightLineEdit(); d->singleFileModeOldFilename = info.fileName(); } d->buttons->button(QDialogButtonBox::Ok)->setEnabled(checkNewNames()); } void AdvancedRenameDialog::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); QSize s = group.readEntry(d->configDialogSizeEntry, QSize(d->minSizeDialog, d->minSizeDialog)); resize(s); d->advancedRenameWidget->setParseString(group.readEntry(d->configLastUsedRenamePatternEntry, QString())); } void AdvancedRenameDialog::writeSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); group.writeEntry(d->configDialogSizeEntry, size()); if (d->singleFileMode) { d->advancedRenameWidget->clear(); } else { group.writeEntry(d->configLastUsedRenamePatternEntry, d->advancedRenameWidget->parseString()); } } void AdvancedRenameDialog::slotReturnPressed() { if (d->buttons->button(QDialogButtonBox::Ok)->isEnabled()) { accept(); } } void AdvancedRenameDialog::slotSortActionTriggered(QAction* action) { if (!action) { d->advancedRenameManager->setSortAction(AdvancedRenameManager::SortCustom); } else if (action == d->sortActionName) { d->advancedRenameManager->setSortAction(AdvancedRenameManager::SortName); } else if (action == d->sortActionDate) { d->advancedRenameManager->setSortAction(AdvancedRenameManager::SortDate); } else if (action == d->sortActionSize) { d->advancedRenameManager->setSortAction(AdvancedRenameManager::SortSize); } } void AdvancedRenameDialog::slotSortDirectionTriggered(QAction* direction) { if (direction == d->sortActionAscending) { d->advancedRenameManager->setSortDirection(AdvancedRenameManager::SortAscending); } else if (direction == d->sortActionDescending) { d->advancedRenameManager->setSortDirection(AdvancedRenameManager::SortDescending); } } void AdvancedRenameDialog::slotShowContextMenu(const QPoint& pos) { QMenu menu(this); menu.addSection(i18n("Sort Images")); ContextMenuHelper cmhelper(&menu); cmhelper.addAction(d->sortActionName); cmhelper.addAction(d->sortActionDate); cmhelper.addAction(d->sortActionSize); cmhelper.addSeparator(); cmhelper.addAction(d->sortActionAscending); cmhelper.addAction(d->sortActionDescending); cmhelper.exec(d->listView->viewport()->mapToGlobal(pos)); } void AdvancedRenameDialog::slotParseStringChanged(const QString& parseString) { if (!d->advancedRenameManager) { return; } if (!d->singleFileMode) { QApplication::setOverrideCursor(Qt::WaitCursor); } d->newNamesList.clear(); // generate new file names ParseSettings settings; settings.useOriginalFileExtension = true; // settings.useOriginalFileExtension = d->singleFileMode ? false : true; d->advancedRenameManager->parseFiles(parseString, settings); // fill the tree widget with the updated files QTreeWidgetItemIterator it(d->listView); while (*it) { AdvancedRenameListItem* const item = dynamic_cast((*it)); if (item) { QString newName = d->advancedRenameManager->newName(item->imageUrl().toLocalFile()); item->setNewName(newName); d->newNamesList << NewNameInfo(item->imageUrl(), newName); } ++it; } bool enableBtn = checkNewNames() && !parseString.isEmpty(); d->buttons->button(QDialogButtonBox::Ok)->setEnabled(enableBtn); d->listView->viewport()->update(); if (!d->singleFileMode) { QApplication::restoreOverrideCursor(); } } void AdvancedRenameDialog::slotAddImages(const QList& urls) { if (urls.isEmpty()) { qCDebug(DIGIKAM_GENERAL_LOG) << "No item to process"; return; } d->listView->clear(); d->advancedRenameManager->reset(); QList files; foreach(const QUrl& url, urls) { ParseSettings ps; ps.fileUrl = url; files << ps; qCDebug(DIGIKAM_GENERAL_LOG) << url; } d->advancedRenameManager->addFiles(files); initDialog(); slotParseStringChanged(d->advancedRenameWidget->parseString()); } NewNamesList AdvancedRenameDialog::newNames() const { return filterNewNames(); } bool AdvancedRenameDialog::checkNewNames() const { int numNames = 0; int numEqualNames = 0; bool ok = true; QSet tmpNewNames; QTreeWidgetItemIterator it(d->listView); while (*it) { AdvancedRenameListItem* const item = dynamic_cast((*it)); if (item) { ++numNames; QFileInfo fi(item->imageUrl().toLocalFile()); QString completeNewName = fi.path(); completeNewName.append(QLatin1Char('/')); completeNewName.append(item->newName()); bool invalid = tmpNewNames.contains(completeNewName); tmpNewNames << completeNewName; item->markInvalid(invalid); ok &= !invalid; if (item->isNameEqual()) { ++ numEqualNames; } } ++it; } return (ok && !(numNames == numEqualNames)); } NewNamesList AdvancedRenameDialog::filterNewNames() const { NewNamesList filteredNames; QTreeWidgetItemIterator it(d->listView); while (*it) { AdvancedRenameListItem* const item = dynamic_cast((*it)); if (item && !item->isNameEqual()) { filteredNames << NewNameInfo(item->imageUrl(), item->newName()); } ++it; } return filteredNames; } void AdvancedRenameDialog::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/core/utilities/assistants/webservices/common/wstooldialog.cpp b/core/utilities/assistants/webservices/common/wstooldialog.cpp index 69790bbbef..aad98ac542 100644 --- a/core/utilities/assistants/webservices/common/wstooldialog.cpp +++ b/core/utilities/assistants/webservices/common/wstooldialog.cpp @@ -1,151 +1,156 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-04-04 * Description : Web Service Tool 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 "wstooldialog.h" // Qt includes #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" namespace Digikam { class Q_DECL_HIDDEN WSToolDialog::Private { public: explicit Private() : buttonBox(0), startButton(0), mainWidget(0), propagateReject(true) { } QDialogButtonBox* buttonBox; QPushButton* startButton; QWidget* mainWidget; bool propagateReject; }; WSToolDialog::WSToolDialog(QWidget* const parent) : QDialog(parent), d(new Private) { + setWindowFlags((windowFlags() & ~Qt::Dialog) | + Qt::Window | + Qt::WindowCloseButtonHint | + Qt::WindowMinMaxButtonsHint); + d->buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this); d->startButton = new QPushButton(i18nc("@action:button", "&Start"), this); d->startButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start"))); d->buttonBox->addButton(d->startButton, QDialogButtonBox::ActionRole); d->buttonBox->button(QDialogButtonBox::Close)->setDefault(true); QVBoxLayout* const mainLayout = new QVBoxLayout(this); mainLayout->addWidget(d->buttonBox); setLayout(mainLayout); connect(d->buttonBox, &QDialogButtonBox::rejected, this, &WSToolDialog::slotCloseClicked); } WSToolDialog::~WSToolDialog() { delete d; } void WSToolDialog::setMainWidget(QWidget* const widget) { if (d->mainWidget == widget) { return; } layout()->removeWidget(d->buttonBox); if (d->mainWidget) { // Replace existing widget layout()->removeWidget(d->mainWidget); delete d->mainWidget; } d->mainWidget = widget; layout()->addWidget(d->mainWidget); layout()->addWidget(d->buttonBox); } void WSToolDialog::setRejectButtonMode(QDialogButtonBox::StandardButton button) { if (button == QDialogButtonBox::Close) { d->buttonBox->button(QDialogButtonBox::Close)->setText(i18n("Close")); d->buttonBox->button(QDialogButtonBox::Close)->setIcon(QIcon::fromTheme(QLatin1String("window-close"))); d->buttonBox->button(QDialogButtonBox::Close)->setToolTip(i18n("Close window")); d->propagateReject = true; } else if (button == QDialogButtonBox::Cancel) { d->buttonBox->button(QDialogButtonBox::Close)->setText(i18n("Cancel")); d->buttonBox->button(QDialogButtonBox::Close)->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel"))); d->buttonBox->button(QDialogButtonBox::Close)->setToolTip(i18n("Cancel current operation")); d->propagateReject = false; } else { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Unexpected button mode passed"; } } QPushButton* WSToolDialog::startButton() const { return d->startButton; } void WSToolDialog::addButton(QAbstractButton* button, QDialogButtonBox::ButtonRole role) { d->buttonBox->addButton(button, role); } void WSToolDialog::slotCloseClicked() { if (d->propagateReject) { reject(); } else { emit cancelClicked(); } } } // namespace Digikam diff --git a/core/utilities/geolocation/editor/dialog/geolocationedit.cpp b/core/utilities/geolocation/editor/dialog/geolocationedit.cpp index 9eeb8abfce..94ebe4396e 100644 --- a/core/utilities/geolocation/editor/dialog/geolocationedit.cpp +++ b/core/utilities/geolocation/editor/dialog/geolocationedit.cpp @@ -1,1097 +1,1099 @@ /* ============================================================ * * 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: explicit 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: explicit 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 Q_DECL_HIDDEN GeolocationEdit::Private { public: explicit 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) { - setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window | - Qt::WindowCloseButtonHint | - Qt::WindowMinMaxButtonsHint); + setWindowFlags((windowFlags() & ~Qt::Dialog) | + Qt::Window | + Qt::WindowCloseButtonHint | + Qt::WindowMinMaxButtonsHint); + setAttribute(Qt::WA_DeleteOnClose, true); setWindowTitle(i18n("Geolocation Editor")); setMinimumSize(300, 400); setModal(true); 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) << 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"); // -------------------------- // 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/core/utilities/maintenance/maintenancedlg.cpp b/core/utilities/maintenance/maintenancedlg.cpp index c64bf100b7..9c9be666b7 100644 --- a/core/utilities/maintenance/maintenancedlg.cpp +++ b/core/utilities/maintenance/maintenancedlg.cpp @@ -1,575 +1,576 @@ /* ============================================================ * * 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 // 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 Q_DECL_HIDDEN MaintenanceDlg::Private { public: enum Operation { Options = 0, NewItems, DbCleanup, Thumbnails, FingerPrints, Duplicates, FaceManagement, ImageQualitySorter, MetadataSync, Stretch }; public: explicit 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) { setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowMinMaxButtonsHint); + setWindowTitle(i18n("Maintenance")); setModal(true); 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/core/utilities/mediaserver/dmediaserverdlg.cpp b/core/utilities/mediaserver/dmediaserverdlg.cpp index 94f4b2915c..014a75791a 100644 --- a/core/utilities/mediaserver/dmediaserverdlg.cpp +++ b/core/utilities/mediaserver/dmediaserverdlg.cpp @@ -1,368 +1,370 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2012-05-28 * Description : Media Server configuration dialog to share a single list of files * * Copyright (C) 2012-2018 by Gilles Caulier * Copyright (C) 2017 by Ahmed Fathy * * 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 "dmediaserverdlg.h" // Qt includes #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "dinfointerface.h" #include "dimageslist.h" #include "dmediaservermngr.h" #include "dxmlguiwindow.h" #include "workingwidget.h" namespace Digikam { class Q_DECL_HIDDEN DMediaServerDlg::Private { public: explicit Private() : dirty(false), mngr(DMediaServerMngr::instance()), srvButton(0), srvStatus(0), progress(0), aStats(0), separator(0), iStats(0), startOnStartup(0), albumSupport(false), albumSelector(0), listView(0), iface(0), page(0), buttons(0) { } bool dirty; DMediaServerMngr* mngr; QPushButton* srvButton; QLabel* srvStatus; WorkingWidget* progress; QLabel* aStats; QLabel* separator; QLabel* iStats; QCheckBox* startOnStartup; bool albumSupport; QWidget* albumSelector; DImagesList* listView; DInfoInterface* iface; QWidget* page; QDialogButtonBox* buttons; }; DMediaServerDlg::DMediaServerDlg(QObject* const /*parent*/, DInfoInterface* const iface) : QDialog(), d(new Private) { - setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window | - Qt::WindowCloseButtonHint | - Qt::WindowMinMaxButtonsHint); + setWindowFlags((windowFlags() & ~Qt::Dialog) | + Qt::Window | + Qt::WindowCloseButtonHint | + Qt::WindowMinMaxButtonsHint); + setWindowTitle(i18nc("@title:window", "Share Files with DLNA Media Server")); d->iface = iface; d->buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); d->page = new QWidget(this); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(d->page); vbx->addWidget(d->buttons); setLayout(vbx); setModal(false); // ------------------- QGridLayout* const grid = new QGridLayout(d->page); d->albumSupport = (d->iface && d->iface->supportAlbums()); if (d->albumSupport) { d->albumSelector = d->iface->albumChooser(this); grid->addWidget(d->albumSelector, 0, 0, 1, 6); connect(d->iface, SIGNAL(signalAlbumChooserSelectionChanged()), this, SLOT(slotSelectionChanged())); } else { d->listView = new DImagesList(d->page); d->listView->setControlButtonsPlacement(DImagesList::ControlButtonsRight); d->listView->setIface(d->iface); // Add all items currently loaded in application. d->listView->loadImagesFromCurrentSelection(); // Replug the previous shared items list. d->listView->slotAddImages(d->mngr->itemsList()); grid->addWidget(d->listView, 0, 0, 1, 6); connect(d->listView, SIGNAL(signalImageListChanged()), this, SLOT(slotSelectionChanged())); } // ------------------- const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); d->startOnStartup = new QCheckBox(i18n("Start Server at Startup")); d->startOnStartup->setWhatsThis(i18n("Set this option to turn-on the DLNA server at application start-up automatically")); d->startOnStartup->setChecked(true); d->srvButton = new QPushButton(this); d->srvStatus = new QLabel(this); d->progress = new WorkingWidget(this); d->aStats = new QLabel(this); d->separator = new QLabel(QLatin1String(" / "), this); d->iStats = new QLabel(this); QLabel* const explanation = new QLabel(this); explanation->setOpenExternalLinks(true); explanation->setWordWrap(true); explanation->setFrameStyle(QFrame::Box | QFrame::Plain); QString txt; explanation->setText(i18n("The media server permit to share items through the local network " "using DLNA " "standard and UPNP " "protocol. Many kind of electronic devices can support DLNA, as tablets, cellulars, TV, etc." "
Note: depending of the network features and the configuration, " "the delay to discover the server on client devices can take a while.")); grid->addWidget(d->startOnStartup, 1, 0, 1, 6); grid->addWidget(d->srvButton, 2, 0, 1, 1); grid->addWidget(d->srvStatus, 2, 1, 1, 1); grid->addWidget(d->aStats, 2, 2, 1, 1); grid->addWidget(d->separator, 2, 3, 1, 1); grid->addWidget(d->iStats, 2, 4, 1, 1); grid->addWidget(d->progress, 2, 5, 1, 1); grid->addWidget(explanation, 3, 0, 1, 6); grid->setColumnStretch(1, 10); grid->setRowStretch(0, 10); grid->setSpacing(spacing); // -------------------------------------------------------- connect(d->srvButton, SIGNAL(clicked()), this, SLOT(slotToggleMediaServer())); connect(d->buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &DMediaServerDlg::reject); connect(d->buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &DMediaServerDlg::accept); // ------------------- readSettings(); } DMediaServerDlg::~DMediaServerDlg() { delete d; } void DMediaServerDlg::accept() { if (d->dirty) { bool empty = false; if (d->albumSupport) { empty = d->iface->albumChooserItems().isEmpty(); } else { empty = d->listView->imageUrls().isEmpty(); } if (!empty) { int rc = QMessageBox::question(this, i18n("Media Server Contents"), i18n("The items list to share has changed. " "Do you want to start now the media server with this contents?")); if (rc == QMessageBox::Yes) { startMediaServer(); } } } saveSettings(); QDialog::accept(); } void DMediaServerDlg::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->mngr->configGroupName()); d->startOnStartup->setChecked(group.readEntry(d->mngr->configStartServerOnStartupEntry(), false)); winId(); DXmlGuiWindow::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); updateServerStatus(); } void DMediaServerDlg::saveSettings() { setMediaServerContents(); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->mngr->configGroupName()); group.writeEntry(d->mngr->configStartServerOnStartupEntry(), d->startOnStartup->isChecked()); DXmlGuiWindow::saveWindowSize(windowHandle(), group); config->sync(); } void DMediaServerDlg::updateServerStatus() { if (d->mngr->isRunning()) { d->srvStatus->setText(i18n("Server is running")); d->aStats->setText(i18np("1 album shared", "%1 albums shared", d->mngr->albumsShared())); d->separator->setVisible(true); d->iStats->setText(i18np("1 item shared", "%1 items shared", d->mngr->itemsShared())); d->srvButton->setText(i18n("Stop")); d->srvButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-stop"))); d->progress->toggleTimer(true); d->progress->setVisible(true); } else { d->srvStatus->setText(i18n("Server is not running")); d->aStats->clear(); d->separator->setVisible(false); d->iStats->clear(); d->srvButton->setText(i18n("Start")); d->srvButton->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start"))); d->progress->toggleTimer(false); d->progress->setVisible(false); } } bool DMediaServerDlg::setMediaServerContents() { if (d->albumSupport) { DInfoInterface::DAlbumIDs albums = d->iface->albumChooserItems(); MediaServerMap map; foreach(int id, albums) { DAlbumInfo anf(d->iface->albumInfo(id)); map.insert(anf.title(), d->iface->albumItems(id)); } if (map.isEmpty()) { QMessageBox::information(this, i18n("Media Server Contents"), i18n("There is no collection to share with the current selection...")); return false; } d->mngr->setCollectionMap(map); } else { QList urls = d->listView->imageUrls(); if (urls.isEmpty()) { QMessageBox::information(this, i18n("Media Server Contents"), i18n("There is no item to share with the current selection...")); return false; } d->mngr->setItemsList(i18n("Shared Items"), urls); } return true; } void DMediaServerDlg::startMediaServer() { if (d->dirty) d->dirty = false; if (!setMediaServerContents()) return; if (!d->mngr->startMediaServer()) { QMessageBox::warning(this, i18n("Starting Media Server"), i18n("An error occurs while to start Media Server...")); } else { d->mngr->mediaServerNotification(true); } updateServerStatus(); } void DMediaServerDlg::slotSelectionChanged() { d->dirty = true; } void DMediaServerDlg::slotToggleMediaServer() { if (!d->mngr->isRunning()) { startMediaServer(); } else { d->mngr->cleanUp(); updateServerStatus(); } } } // namespace Digikam diff --git a/core/utilities/metadataedit/dialog/metadataedit.cpp b/core/utilities/metadataedit/dialog/metadataedit.cpp index e1f9e9e793..57e56f6675 100644 --- a/core/utilities/metadataedit/dialog/metadataedit.cpp +++ b/core/utilities/metadataedit/dialog/metadataedit.cpp @@ -1,378 +1,380 @@ /* ============================================================ * * This file is a part of digiKam project * http://www.digikam.org * * Date : 2011-03-14 * Description : a dialog to edit EXIF,IPTC and XMP metadata * * Copyright (C) 2011 by Victor Dodon * Copyright (C) 2006-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 "metadataedit.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "exifeditwidget.h" #include "iptceditwidget.h" #include "xmpeditwidget.h" #include "thumbnailloadthread.h" #include "dxmlguiwindow.h" namespace Digikam { class Q_DECL_HIDDEN MetadataEditDialog::Private { public: explicit Private() { isReadOnly = false; tabWidget = 0; buttons = 0; tabExif = 0; tabIptc = 0; tabXmp = 0; catcher = 0; } bool isReadOnly; QString preview; QList urls; QList::iterator currItem; QTabWidget* tabWidget; QDialogButtonBox* buttons; EXIFEditWidget* tabExif; IPTCEditWidget* tabIptc; XMPEditWidget* tabXmp; ThumbnailImageCatcher* catcher; }; MetadataEditDialog::MetadataEditDialog(QWidget* const parent, const QList& urls) : QDialog(parent), d(new Private) { - setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window | - Qt::WindowCloseButtonHint | - Qt::WindowMinMaxButtonsHint); + setWindowFlags((windowFlags() & ~Qt::Dialog) | + Qt::Window | + Qt::WindowCloseButtonHint | + Qt::WindowMinMaxButtonsHint); + setWindowTitle(i18n("Metadata Editor")); setModal(true); ThumbnailLoadThread* const thread = new ThumbnailLoadThread; thread->setThumbnailSize(48); thread->setPixmapRequested(false); d->catcher = new ThumbnailImageCatcher(thread, this); d->urls = urls; d->currItem = d->urls.begin(); updatePreview(); QDialogButtonBox::StandardButtons btns = QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Close | QDialogButtonBox::No | // NextPrevious item QDialogButtonBox::Yes; // Previous item d->buttons = new QDialogButtonBox(btns, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); d->buttons->button(QDialogButtonBox::Apply)->setEnabled(false); if (d->urls.count() > 1) { d->buttons->button(QDialogButtonBox::No)->setText(i18nc("@action:button", "Next")); d->buttons->button(QDialogButtonBox::No)->setIcon(QIcon::fromTheme(QLatin1String("go-next"))); d->buttons->button(QDialogButtonBox::Yes)->setText(i18nc("@action:button", "Previous")); d->buttons->button(QDialogButtonBox::Yes)->setIcon(QIcon::fromTheme(QLatin1String("go-previous"))); } else { d->buttons->button(QDialogButtonBox::No)->setVisible(false); d->buttons->button(QDialogButtonBox::Yes)->setVisible(false); } d->tabWidget = new QTabWidget(this); d->tabExif = new EXIFEditWidget(this); d->tabIptc = new IPTCEditWidget(this); d->tabXmp = new XMPEditWidget(this); d->tabWidget->addTab(d->tabExif, i18n("Edit EXIF")); d->tabWidget->addTab(d->tabIptc, i18n("Edit IPTC")); d->tabWidget->addTab(d->tabXmp, i18n("Edit XMP")); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(d->tabWidget); vbx->addWidget(d->buttons); setLayout(vbx); //---------------------------------------------------------- connect(d->tabExif, SIGNAL(signalModified()), this, SLOT(slotModified())); connect(d->tabIptc, SIGNAL(signalModified()), this, SLOT(slotModified())); connect(d->tabXmp, SIGNAL(signalModified()), this, SLOT(slotModified())); connect(d->tabExif, SIGNAL(signalSetReadOnly(bool)), this, SLOT(slotSetReadOnly(bool))); connect(d->tabIptc, SIGNAL(signalSetReadOnly(bool)), this, SLOT(slotSetReadOnly(bool))); connect(d->tabXmp, SIGNAL(signalSetReadOnly(bool)), this, SLOT(slotSetReadOnly(bool))); connect(d->buttons->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotApply())); connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(slotOk())); connect(d->buttons->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(slotClose())); connect(d->buttons->button(QDialogButtonBox::No), SIGNAL(clicked()), this, SLOT(slotNext())); connect(d->buttons->button(QDialogButtonBox::Yes), SIGNAL(clicked()), this, SLOT(slotPrevious())); //---------------------------------------------------------- readSettings(); slotItemChanged(); } MetadataEditDialog::~MetadataEditDialog() { d->catcher->thread()->stopAllTasks(); d->catcher->cancel(); delete d->catcher->thread(); delete d->catcher; delete d; } QString MetadataEditDialog::currentItemTitleHeader(const QString& title) const { QString start = QLatin1String(""); QString end = QLatin1String("
"); return QString::fromLatin1("%1%2%3%4").arg(start).arg(d->preview).arg(title).arg(end); } void MetadataEditDialog::updatePreview() { d->catcher->setActive(true); d->catcher->thread()->find(ThumbnailIdentifier(d->currItem->toLocalFile())); d->catcher->enqueue(); QList images = d->catcher->waitForThumbnails(); QImage img(48, 48, QImage::Format_ARGB32); QImage thm = images.first(); QPainter p(&img); p.fillRect(img.rect(), QPalette().window()); p.setPen(Qt::black); p.drawRect(img.rect().left(), img.rect().top(), img.rect().right()-1, img.rect().bottom()-1); p.drawImage((img.width() - thm.width())/2, (img.height() - thm.height())/2, thm); QByteArray byteArray; QBuffer buffer(&byteArray); img.save(&buffer, "PNG"); d->preview = QString::fromLatin1(" ").arg(QLatin1String(byteArray.toBase64().data())); d->catcher->setActive(false); } QList::iterator MetadataEditDialog::currentItem() const { return d->currItem; } void MetadataEditDialog::slotModified() { bool modified = false; switch (d->tabWidget->currentIndex()) { case 0: modified = d->tabExif->isModified(); break; case 1: modified = d->tabIptc->isModified(); break; case 2: modified = d->tabXmp->isModified(); break; } d->buttons->button(QDialogButtonBox::Apply)->setEnabled(modified); } void MetadataEditDialog::slotOk() { slotApply(); saveSettings(); accept(); } void MetadataEditDialog::slotClose() { saveSettings(); close(); } void MetadataEditDialog::slotApply() { d->tabExif->apply(); d->tabIptc->apply(); d->tabXmp->apply(); slotItemChanged(); } void MetadataEditDialog::slotNext() { slotApply(); ++d->currItem; slotItemChanged(); } void MetadataEditDialog::slotPrevious() { slotApply(); --d->currItem; slotItemChanged(); } void MetadataEditDialog::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Metadata Edit Dialog")); d->tabWidget->setCurrentIndex(group.readEntry(QLatin1String("Tab Index"), 0)); winId(); DXmlGuiWindow::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); } void MetadataEditDialog::saveSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Metadata Edit Dialog")); group.writeEntry(QLatin1String("Tab Index"), d->tabWidget->currentIndex()); DXmlGuiWindow::saveWindowSize(windowHandle(), group); d->tabExif->saveSettings(); d->tabIptc->saveSettings(); d->tabXmp->saveSettings(); } void MetadataEditDialog::slotItemChanged() { updatePreview(); d->tabExif->slotItemChanged(); d->tabIptc->slotItemChanged(); d->tabXmp->slotItemChanged(); setWindowTitle(i18n("%1 (%2/%3) - Edit Metadata", (*d->currItem).fileName(), d->urls.indexOf(*(d->currItem))+1, d->urls.count())); d->buttons->button(QDialogButtonBox::No)->setEnabled(*(d->currItem) != d->urls.last()); d->buttons->button(QDialogButtonBox::Yes)->setEnabled(*(d->currItem) != d->urls.first()); d->buttons->button(QDialogButtonBox::Apply)->setEnabled(!d->isReadOnly); } bool MetadataEditDialog::eventFilter(QObject*, QEvent* e) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent* const k = (QKeyEvent*)e; if (k->modifiers() == Qt::ControlModifier && (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return)) { slotApply(); if (d->buttons->button(QDialogButtonBox::No)->isEnabled()) slotNext(); return true; } else if (k->modifiers() == Qt::ShiftModifier && (k->key() == Qt::Key_Enter || k->key() == Qt::Key_Return)) { slotApply(); if (d->buttons->button(QDialogButtonBox::Yes)->isEnabled()) slotPrevious(); return true; } return false; } return false; } void MetadataEditDialog::closeEvent(QCloseEvent* e) { if (!e) return; saveSettings(); e->accept(); } void MetadataEditDialog::slotSetReadOnly(bool state) { d->isReadOnly = state; } } // namespace Digikam diff --git a/core/utilities/setup/setup.cpp b/core/utilities/setup/setup.cpp index d2636e1315..8d3a6bb346 100644 --- a/core/utilities/setup/setup.cpp +++ b/core/utilities/setup/setup.cpp @@ -1,574 +1,576 @@ /* ============================================================ * * 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 Q_DECL_HIDDEN Setup::Private { public: explicit 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) { - setWindowFlags((windowFlags() & ~Qt::Dialog) | Qt::Window | - Qt::WindowCloseButtonHint | - Qt::WindowMinMaxButtonsHint); + setWindowFlags((windowFlags() & ~Qt::Dialog) | + Qt::Window | + Qt::WindowCloseButtonHint | + Qt::WindowMinMaxButtonsHint); + setWindowTitle(i18n("Configure")); setStandardButtons(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel); button(QDialogButtonBox::Ok)->setDefault(true); setFaceType(List); 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