diff --git a/core/dplugins/generic/webservices/filecopy/fctask.cpp b/core/dplugins/generic/webservices/filecopy/fctask.cpp index db29ce332f..ca5acd12d3 100644 --- a/core/dplugins/generic/webservices/filecopy/fctask.cpp +++ b/core/dplugins/generic/webservices/filecopy/fctask.cpp @@ -1,141 +1,146 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2019-03-27 * Description : file copy actions using threads. * * Copyright (C) 2012 by Smit Mehta * Copyright (C) 2006-2020 by Gilles Caulier * Copyright (C) 2019 by Maik Qualmann * * 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 "fctask.h" // C ANSI includes extern "C" { #include #include } // Qt includes #include #include // Local includes #include "digikam_debug.h" +#include "digikam_config.h" #include "dinfointerface.h" namespace DigikamGenericFileCopyPlugin { class Q_DECL_HIDDEN FCTask::Private { public: explicit Private() : overwrite(false), symLinks(false) { } QUrl srcUrl; QUrl dstUrl; bool overwrite; bool symLinks; }; FCTask::FCTask(const QUrl& srcUrl, const QUrl& dstUrl, bool overwrite, bool symLinks) : ActionJob(), d(new Private) { d->srcUrl = srcUrl; d->dstUrl = dstUrl; d->overwrite = overwrite; d->symLinks = symLinks; } FCTask::~FCTask() { cancel(); delete d; } void FCTask::run() { if (m_cancel) { return; } QUrl dest = d->dstUrl.adjusted(QUrl::StripTrailingSlash); dest.setPath(dest.path() + QLatin1Char('/') + d->srcUrl.fileName()); if (d->overwrite && QFile::exists(dest.toLocalFile())) { QFile::remove(dest.toLocalFile()); } bool ok = false; if (d->symLinks) { +#ifdef Q_OS_WIN + dest.setPath(dest.path() + QLatin1String(".lnk")); +#endif + ok = QFile::link(d->srcUrl.toLocalFile(), dest.toLocalFile()); } else { ok = QFile::copy(d->srcUrl.toLocalFile(), dest.toLocalFile()); } // Since QFileInfo does not support timestamp updates, // we have to use the utime() system call. if (ok && !d->symLinks) { QT_STATBUF st; if (QT_STAT(QFile::encodeName(d->srcUrl.toLocalFile()).constData(), &st) == 0) { struct utimbuf ut; ut.modtime = st.st_mtime; ut.actime = st.st_atime; if (::utime(QFile::encodeName(dest.toLocalFile()).constData(), &ut) != 0) { qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Failed to restore modification time for file " << dest; } } } if (ok) { emit signalUrlProcessed(d->srcUrl, dest); } emit signalDone(); } } // namespace DigikamGenericFileCopyPlugin diff --git a/core/utilities/setup/album/setupalbumview.cpp b/core/utilities/setup/album/setupalbumview.cpp index 9625e49e9a..736681c827 100644 --- a/core/utilities/setup/album/setupalbumview.cpp +++ b/core/utilities/setup/album/setupalbumview.cpp @@ -1,521 +1,523 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-01 * Description : album view configuration setup tab * * Copyright (C) 2003-2004 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupalbumview.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_debug.h" #include "thumbnailsize.h" #include "applicationsettings.h" #include "dfontselect.h" #include "fullscreensettings.h" #include "dxmlguiwindow.h" #include "previewsettings.h" #include "setupcategory.h" #include "setupmime.h" namespace Digikam { class Q_DECL_HIDDEN SetupAlbumView::Private { public: explicit Private() : useLargeThumbsOriginal(false), useLargeThumbsShowedInfo(false), iconTreeThumbLabel(nullptr), iconShowNameBox(nullptr), iconShowSizeBox(nullptr), iconShowDateBox(nullptr), iconShowModDateBox(nullptr), iconShowResolutionBox(nullptr), iconShowAspectRatioBox(nullptr), iconShowTitleBox(nullptr), iconShowCommentsBox(nullptr), iconShowTagsBox(nullptr), iconShowOverlaysBox(nullptr), iconShowFullscreenBox(nullptr), iconShowRatingBox(nullptr), iconShowFormatBox(nullptr), iconShowCoordinatesBox(nullptr), previewFastPreview(nullptr), previewFullView(nullptr), previewRawMode(nullptr), previewConvertToEightBit(nullptr), previewShowIcons(nullptr), showFolderTreeViewItemsCount(nullptr), largeThumbsBox(nullptr), iconTreeThumbSize(nullptr), leftClickActionComboBox(nullptr), tab(nullptr), iconViewFontSelect(nullptr), treeViewFontSelect(nullptr), fullScreenSettings(nullptr), category(nullptr), mimetype(nullptr) { } bool useLargeThumbsOriginal; bool useLargeThumbsShowedInfo; QLabel* iconTreeThumbLabel; QCheckBox* iconShowNameBox; QCheckBox* iconShowSizeBox; QCheckBox* iconShowDateBox; QCheckBox* iconShowModDateBox; QCheckBox* iconShowResolutionBox; QCheckBox* iconShowAspectRatioBox; QCheckBox* iconShowTitleBox; QCheckBox* iconShowCommentsBox; QCheckBox* iconShowTagsBox; QCheckBox* iconShowOverlaysBox; QCheckBox* iconShowFullscreenBox; QCheckBox* iconShowRatingBox; QCheckBox* iconShowFormatBox; QCheckBox* iconShowCoordinatesBox; QRadioButton* previewFastPreview; QRadioButton* previewFullView; QComboBox* previewRawMode; QCheckBox* previewConvertToEightBit; QCheckBox* previewShowIcons; QCheckBox* showFolderTreeViewItemsCount; QCheckBox* largeThumbsBox; QComboBox* iconTreeThumbSize; QComboBox* leftClickActionComboBox; QTabWidget* tab; DFontSelect* iconViewFontSelect; DFontSelect* treeViewFontSelect; FullScreenSettings* fullScreenSettings; SetupCategory* category; SetupMime* mimetype; }; SetupAlbumView::SetupAlbumView(QWidget* const parent) : QScrollArea(parent), d(new Private) { - d->tab = new QTabWidget(viewport()); + d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); - QWidget* const iwpanel = new QWidget(d->tab); - const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); + QWidget* const iwpanel = new QWidget(d->tab); + const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); // -------------------------------------------------------- - QGridLayout* const grid = new QGridLayout(iwpanel); + QGridLayout* const grid = new QGridLayout(iwpanel); - d->iconShowNameBox = new QCheckBox(i18n("Show file&name"), iwpanel); + d->iconShowNameBox = new QCheckBox(i18n("Show file&name"), iwpanel); d->iconShowNameBox->setWhatsThis(i18n("Set this option to show the filename below the image thumbnail.")); - d->iconShowSizeBox = new QCheckBox(i18n("Show file si&ze"), iwpanel); + d->iconShowSizeBox = new QCheckBox(i18n("Show file si&ze"), iwpanel); d->iconShowSizeBox->setWhatsThis(i18n("Set this option to show the file size below the image thumbnail.")); - d->iconShowDateBox = new QCheckBox(i18n("Show camera creation &date"), iwpanel); + d->iconShowDateBox = new QCheckBox(i18n("Show camera creation &date"), iwpanel); d->iconShowDateBox->setWhatsThis(i18n("Set this option to show the camera creation date " "below the image thumbnail.")); - d->iconShowModDateBox = new QCheckBox(i18n("Show file &modification date"), iwpanel); + d->iconShowModDateBox = new QCheckBox(i18n("Show file &modification date"), iwpanel); d->iconShowModDateBox->setWhatsThis(i18n("Set this option to show the file modification date " "below the image thumbnail if it is different than camera creation date. " "This option is useful to identify quickly which items have been modified.")); - d->iconShowResolutionBox = new QCheckBox(i18n("Show ima&ge dimensions"), iwpanel); + d->iconShowResolutionBox = new QCheckBox(i18n("Show ima&ge dimensions"), iwpanel); d->iconShowResolutionBox->setWhatsThis(i18n("Set this option to show the image size in pixels " "below the image thumbnail.")); d->iconShowAspectRatioBox = new QCheckBox(i18n("Show image aspect ratio"), iwpanel); d->iconShowAspectRatioBox->setWhatsThis(i18n("Set this option to show the image aspect ratio " "below the image thumbnail.")); d->iconShowFormatBox = new QCheckBox(i18n("Show image format"), iwpanel); d->iconShowFormatBox->setWhatsThis(i18n("Set this option to show image mime type over image thumbnail.")); d->iconShowTitleBox = new QCheckBox(i18n("Show digiKam tit&le"), iwpanel); d->iconShowTitleBox->setWhatsThis(i18n("Set this option to show the digiKam title " "below the image thumbnail.")); d->iconShowCommentsBox = new QCheckBox(i18n("Show digiKam &captions"), iwpanel); d->iconShowCommentsBox->setWhatsThis(i18n("Set this option to show the digiKam captions " "below the image thumbnail.")); d->iconShowTagsBox = new QCheckBox(i18n("Show digiKam &tags"), iwpanel); d->iconShowTagsBox->setWhatsThis(i18n("Set this option to show the digiKam tags list " "below the image thumbnail.")); d->iconShowRatingBox = new QCheckBox(i18n("Show digiKam &rating"), iwpanel); d->iconShowRatingBox->setWhatsThis(i18n("Set this option to show the digiKam rating " "below the image thumbnail.")); d->iconShowOverlaysBox = new QCheckBox(i18n("Show rotation overlay buttons"), iwpanel); d->iconShowOverlaysBox->setWhatsThis(i18n("Set this option to show overlay buttons over " "the image thumbnail to be able to process left or right image rotation.")); d->iconShowFullscreenBox = new QCheckBox(i18n("Show fullscreen overlay button"), iwpanel); d->iconShowFullscreenBox->setWhatsThis(i18n("Set this option to show an overlay button over the " "image thumbnail to open it in fullscreen mode.")); d->iconShowCoordinatesBox = new QCheckBox(i18n("Show Geolocation Indicator"), iwpanel); d->iconShowCoordinatesBox->setWhatsThis(i18n("Set this option to show an icon over the image thumbnail if item has geolocation information.")); QLabel* leftClickLabel = new QLabel(i18n("Thumbnail click action:"), iwpanel); d->leftClickActionComboBox = new QComboBox(iwpanel); d->leftClickActionComboBox->addItem(i18n("Show preview"), ApplicationSettings::ShowPreview); d->leftClickActionComboBox->addItem(i18n("Start image editor"), ApplicationSettings::StartEditor); d->leftClickActionComboBox->setToolTip(i18n("Choose what should happen when you click on a thumbnail.")); d->iconViewFontSelect = new DFontSelect(i18n("Icon View font:"), iwpanel); d->iconViewFontSelect->setToolTip(i18n("Select here the font used to display text in icon views.")); - d->largeThumbsBox = new QCheckBox(i18n("Use large thumbnail size for high screen resolution"), iwpanel); + d->largeThumbsBox = new QCheckBox(i18n("Use large thumbnail size for high screen resolution"), iwpanel); d->largeThumbsBox->setWhatsThis(i18n("Set this option to render icon-view with large thumbnail size, for example in case of 4K monitor is used.\n" "By default this option is turned off and the maximum thumbnail size is limited to 256x256 pixels. " "When this option is enabled, thumbnail size can be extended to 512x512 pixels.\n" "This option will store more data in thumbnail database and will use more system memory. " "digiKam needs to be restarted to take effect, and Rebuild Thumbnails option from Maintenance tool " "needs to be processed over whole collections.")); grid->addWidget(d->iconShowNameBox, 0, 0, 1, 1); grid->addWidget(d->iconShowSizeBox, 1, 0, 1, 1); grid->addWidget(d->iconShowDateBox, 2, 0, 1, 1); grid->addWidget(d->iconShowModDateBox, 3, 0, 1, 1); grid->addWidget(d->iconShowResolutionBox, 4, 0, 1, 1); grid->addWidget(d->iconShowAspectRatioBox, 5, 0, 1, 1); grid->addWidget(d->iconShowFormatBox, 6, 0, 1, 1); grid->addWidget(d->iconShowTitleBox, 0, 1, 1, 1); grid->addWidget(d->iconShowCommentsBox, 1, 1, 1, 1); grid->addWidget(d->iconShowTagsBox, 2, 1, 1, 1); grid->addWidget(d->iconShowRatingBox, 3, 1, 1, 1); grid->addWidget(d->iconShowOverlaysBox, 4, 1, 1, 1); grid->addWidget(d->iconShowFullscreenBox, 5, 1, 1, 1); grid->addWidget(d->iconShowCoordinatesBox, 6, 1, 1, 1); grid->addWidget(leftClickLabel, 7, 0, 1, 1); grid->addWidget(d->leftClickActionComboBox, 7, 1, 1, 1); grid->addWidget(d->iconViewFontSelect, 8, 0, 1, 2); grid->addWidget(d->largeThumbsBox, 9, 0, 1, 2); grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); grid->setRowStretch(10, 10); d->tab->insertTab(IconView, iwpanel, i18nc("@title:tab", "Icons")); // -------------------------------------------------------- QWidget* const fwpanel = new QWidget(d->tab); QGridLayout* const grid2 = new QGridLayout(fwpanel); d->iconTreeThumbLabel = new QLabel(i18n("Tree View icon size:"), fwpanel); d->iconTreeThumbSize = new QComboBox(fwpanel); d->iconTreeThumbSize->addItem(QLatin1String("16")); d->iconTreeThumbSize->addItem(QLatin1String("22")); d->iconTreeThumbSize->addItem(QLatin1String("32")); d->iconTreeThumbSize->addItem(QLatin1String("48")); d->iconTreeThumbSize->addItem(QLatin1String("64")); d->iconTreeThumbSize->setToolTip(i18n("Set this option to configure the size in pixels of " "the Tree View icons in digiKam's sidebars.")); d->treeViewFontSelect = new DFontSelect(i18n("Tree View font:"), fwpanel); d->treeViewFontSelect->setToolTip(i18n("Select here the font used to display text in Tree Views.")); d->showFolderTreeViewItemsCount = new QCheckBox(i18n("Show a count of items in Tree Views"), fwpanel); d->showFolderTreeViewItemsCount->setToolTip(i18n("Set this option to display along the album name the number of icon-view items inside.")); grid2->addWidget(d->iconTreeThumbLabel, 0, 0, 1, 1); grid2->addWidget(d->iconTreeThumbSize, 0, 1, 1, 1); grid2->addWidget(d->treeViewFontSelect, 1, 0, 1, 2); grid2->addWidget(d->showFolderTreeViewItemsCount, 2, 0, 1, 2); grid2->setContentsMargins(spacing, spacing, spacing, spacing); grid2->setSpacing(spacing); grid2->setRowStretch(3, 10); d->tab->insertTab(FolderView, fwpanel, i18nc("@title:tab", "Tree-Views")); // -------------------------------------------------------- QWidget* const pwpanel = new QWidget(d->tab); QGridLayout* const grid3 = new QGridLayout(pwpanel); d->previewFastPreview = new QRadioButton(i18nc("@option:radio", "Preview shows embedded view if available (faster)")); d->previewFullView = new QRadioButton(i18nc("@option:radio", "Preview shows the full image")); QLabel* const rawPreviewLabel = new QLabel(i18nc("@label:listbox Mode of RAW preview decoding:", "Raw images:")); d->previewRawMode = new QComboBox; d->previewRawMode->addItem(i18nc("@option:inlistbox Automatic choice of RAW image preview source", "Automatic"), PreviewSettings::RawPreviewAutomatic); d->previewRawMode->addItem(i18nc("@option:inlistbox Embedded preview as RAW image preview source", "Embedded preview"), PreviewSettings::RawPreviewFromEmbeddedPreview); d->previewRawMode->addItem(i18nc("@option:inlistbox Original, half-size data as RAW image preview source", "Raw data in half size"), PreviewSettings::RawPreviewFromRawHalfSize); d->previewConvertToEightBit = new QCheckBox(i18n("Preview image is converted to 8 bits for a faster viewing"), pwpanel); d->previewConvertToEightBit->setWhatsThis(i18n("Uncheck this if you do not want to convert a 16 bits preview image to 8 bits.")); d->previewShowIcons = new QCheckBox(i18n("Show icons and text over preview"), pwpanel); d->previewShowIcons->setWhatsThis(i18n("Uncheck this if you do not want to see icons and text in the image preview.")); grid3->setContentsMargins(spacing, spacing, spacing, spacing); grid3->setSpacing(spacing); grid3->addWidget(d->previewFastPreview, 0, 0, 1, 2); grid3->addWidget(d->previewFullView, 1, 0, 1, 2); grid3->addWidget(rawPreviewLabel, 2, 0, 1, 1); grid3->addWidget(d->previewRawMode, 2, 1, 1, 1); grid3->addWidget(d->previewConvertToEightBit, 3, 0, 1, 2); grid3->addWidget(d->previewShowIcons, 4, 0, 1, 2); grid3->setRowStretch(5, 10); d->previewFastPreview->setChecked(true); d->previewRawMode->setCurrentIndex(0); d->previewRawMode->setEnabled(false); d->tab->insertTab(Preview, pwpanel, i18nc("@title:tab", "Preview")); // -------------------------------------------------------- QWidget* const fspanel = new QWidget(d->tab); QVBoxLayout* const layout = new QVBoxLayout(fspanel); d->fullScreenSettings = new FullScreenSettings(FS_ALBUMGUI, d->tab); d->fullScreenSettings->setTitle(QString()); d->fullScreenSettings->setFlat(true); layout->setContentsMargins(QMargins()); layout->setSpacing(spacing); layout->addWidget(d->fullScreenSettings); layout->addStretch(); d->tab->insertTab(FullScreen, fspanel, i18nc("@title:tab", "Full-Screen")); // -------------------------------------------------------- - d->mimetype = new SetupMime(); + d->mimetype = new SetupMime(); d->tab->insertTab(MimeType, d->mimetype, i18nc("@title:tab", "Mime Types")); - d->category = new SetupCategory(d->tab); + d->category = new SetupCategory(d->tab); d->tab->insertTab(Category, d->category, i18nc("@title:tab", "Categories")); // -------------------------------------------------------- readSettings(); adjustSize(); // -------------------------------------------------------- connect(d->previewFullView, SIGNAL(toggled(bool)), d->previewRawMode, SLOT(setEnabled(bool))); connect(d->largeThumbsBox, SIGNAL(toggled(bool)), this, SLOT(slotUseLargeThumbsToggled(bool))); // -------------------------------------------------------- } SetupAlbumView::~SetupAlbumView() { delete d; } void SetupAlbumView::applySettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setTreeViewIconSize(d->iconTreeThumbSize->currentText().toInt()); settings->setTreeViewFont(d->treeViewFontSelect->font()); settings->setIconShowName(d->iconShowNameBox->isChecked()); settings->setIconShowTags(d->iconShowTagsBox->isChecked()); settings->setIconShowSize(d->iconShowSizeBox->isChecked()); settings->setIconShowDate(d->iconShowDateBox->isChecked()); settings->setIconShowModDate(d->iconShowModDateBox->isChecked()); settings->setIconShowResolution(d->iconShowResolutionBox->isChecked()); settings->setIconShowAspectRatio(d->iconShowAspectRatioBox->isChecked()); settings->setIconShowTitle(d->iconShowTitleBox->isChecked()); settings->setIconShowComments(d->iconShowCommentsBox->isChecked()); settings->setIconShowOverlays(d->iconShowOverlaysBox->isChecked()); settings->setIconShowFullscreen(d->iconShowFullscreenBox->isChecked()); settings->setIconShowCoordinates(d->iconShowCoordinatesBox->isChecked()); settings->setIconShowRating(d->iconShowRatingBox->isChecked()); settings->setIconShowImageFormat(d->iconShowFormatBox->isChecked()); settings->setIconViewFont(d->iconViewFontSelect->font()); settings->setItemLeftClickAction((ApplicationSettings::ItemLeftClickAction) d->leftClickActionComboBox->currentIndex()); PreviewSettings previewSettings; previewSettings.quality = d->previewFastPreview->isChecked() ? PreviewSettings::FastPreview : PreviewSettings::HighQualityPreview; previewSettings.rawLoading = (PreviewSettings::RawLoading)d->previewRawMode->itemData(d->previewRawMode->currentIndex()).toInt(); previewSettings.convertToEightBit = d->previewConvertToEightBit->isChecked(); settings->setPreviewSettings(previewSettings); settings->setPreviewShowIcons(d->previewShowIcons->isChecked()); settings->setShowFolderTreeViewItemsCount(d->showFolderTreeViewItemsCount->isChecked()); settings->saveSettings(); KConfigGroup group = KSharedConfig::openConfig()->group(settings->generalConfigGroupName()); d->fullScreenSettings->saveSettings(group); d->category->applySettings(); d->mimetype->applySettings(); // Method ThumbnailSize::setUseLargeThumbs() is not called here to prevent // dysfunction between Thumbs DB and icon if // thumb size is over 256 and when large thumbs size support is disabled. // digiKam need to be restarted to take effect. + ThumbnailSize::saveSettings(group, d->largeThumbsBox->isChecked()); } void SetupAlbumView::readSettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } - if (settings->getTreeViewIconSize() == 16) + if (settings->getTreeViewIconSize() == 16) { d->iconTreeThumbSize->setCurrentIndex(0); } else if (settings->getTreeViewIconSize() == 22) { d->iconTreeThumbSize->setCurrentIndex(1); } else if (settings->getTreeViewIconSize() == 32) { d->iconTreeThumbSize->setCurrentIndex(2); } else if (settings->getTreeViewIconSize() == 48) { d->iconTreeThumbSize->setCurrentIndex(3); } else { d->iconTreeThumbSize->setCurrentIndex(4); } d->treeViewFontSelect->setFont(settings->getTreeViewFont()); d->iconShowNameBox->setChecked(settings->getIconShowName()); d->iconShowTagsBox->setChecked(settings->getIconShowTags()); d->iconShowSizeBox->setChecked(settings->getIconShowSize()); d->iconShowDateBox->setChecked(settings->getIconShowDate()); d->iconShowModDateBox->setChecked(settings->getIconShowModDate()); d->iconShowResolutionBox->setChecked(settings->getIconShowResolution()); d->iconShowAspectRatioBox->setChecked(settings->getIconShowAspectRatio()); d->iconShowTitleBox->setChecked(settings->getIconShowTitle()); d->iconShowCommentsBox->setChecked(settings->getIconShowComments()); d->iconShowOverlaysBox->setChecked(settings->getIconShowOverlays()); d->iconShowFullscreenBox->setChecked(settings->getIconShowFullscreen()); d->iconShowCoordinatesBox->setChecked(settings->getIconShowCoordinates()); d->iconShowRatingBox->setChecked(settings->getIconShowRating()); d->iconShowFormatBox->setChecked(settings->getIconShowImageFormat()); d->iconViewFontSelect->setFont(settings->getIconViewFont()); d->leftClickActionComboBox->setCurrentIndex((int)settings->getItemLeftClickAction()); PreviewSettings previewSettings = settings->getPreviewSettings(); if (previewSettings.quality == PreviewSettings::FastPreview) { d->previewFastPreview->setChecked(true); } else { d->previewFullView->setChecked(true); d->previewRawMode->setEnabled(true); } d->previewRawMode->setCurrentIndex(d->previewRawMode->findData(previewSettings.rawLoading)); d->previewShowIcons->setChecked(settings->getPreviewShowIcons()); d->previewConvertToEightBit->setChecked(previewSettings.convertToEightBit); d->showFolderTreeViewItemsCount->setChecked(settings->getShowFolderTreeViewItemsCount()); KConfigGroup group = KSharedConfig::openConfig()->group(settings->generalConfigGroupName()); d->fullScreenSettings->readSettings(group); ThumbnailSize::readSettings(group); d->useLargeThumbsOriginal = ThumbnailSize::getUseLargeThumbs(); d->largeThumbsBox->setChecked(d->useLargeThumbsOriginal); d->category->readSettings(); d->mimetype->readSettings(); } bool SetupAlbumView::useLargeThumbsHasChanged() const { - return d->largeThumbsBox->isChecked() != d->useLargeThumbsOriginal; + return (d->largeThumbsBox->isChecked() != d->useLargeThumbsOriginal); } void SetupAlbumView::slotUseLargeThumbsToggled(bool b) { // Show info if large thumbs were enabled, and only once. + if (b && d->useLargeThumbsShowedInfo && useLargeThumbsHasChanged()) { d->useLargeThumbsShowedInfo = true; QMessageBox::information(this, qApp->applicationName(), i18nc("@info", "This option changes the size in which thumbnails are generated. " "You need to restart digiKam for this option to take effect. " "Furthermore, you need to regenerate all already stored thumbnails via " "the Tools / Maintenance menu.")); } } } // namespace Digikam diff --git a/core/utilities/setup/album/setupcategory.cpp b/core/utilities/setup/album/setupcategory.cpp index 6392cda005..e7d9877a9d 100644 --- a/core/utilities/setup/album/setupcategory.cpp +++ b/core/utilities/setup/album/setupcategory.cpp @@ -1,257 +1,257 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-01-02 * Description : album category setup tab. * * Copyright (C) 2004-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupcategory.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "applicationsettings.h" #include "thumbnailsize.h" namespace Digikam { class Q_DECL_HIDDEN SetupCategory::Private { public: explicit Private() : addCategoryButton(nullptr), delCategoryButton(nullptr), repCategoryButton(nullptr), albumCategoryBox(nullptr), categoryEdit(nullptr) { } QPushButton* addCategoryButton; QPushButton* delCategoryButton; QPushButton* repCategoryButton; QListWidget* albumCategoryBox; QLineEdit* categoryEdit; }; SetupCategory::SetupCategory(QWidget* const parent) : QScrollArea(parent), d(new Private) { QWidget* const panel = new QWidget(viewport()); setWidget(panel); setWidgetResizable(true); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QGridLayout* const grid = new QGridLayout(panel); QLabel* const explanationLabel = new QLabel(panel); explanationLabel->setText(i18n("Manage categories to sort and re-arrange album tree-view.")); explanationLabel->setWordWrap(true); // -------------------------------------------------------- d->categoryEdit = new QLineEdit(panel); d->categoryEdit->setClearButtonEnabled(true); d->albumCategoryBox = new QListWidget(panel); d->albumCategoryBox->setWhatsThis(i18n("You can add or remove Album " "category types here to improve how " "your Albums are sorted in digiKam.")); d->albumCategoryBox->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->addCategoryButton = new QPushButton(i18n("&Add..."), panel); d->delCategoryButton = new QPushButton(i18n("&Remove"), panel); d->repCategoryButton = new QPushButton(i18n("&Replace"), panel); d->addCategoryButton->setIcon(QIcon::fromTheme(QLatin1String("list-add"))); d->delCategoryButton->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->repCategoryButton->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); d->delCategoryButton->setEnabled(false); d->repCategoryButton->setEnabled(false); grid->setAlignment(Qt::AlignTop); grid->addWidget(explanationLabel, 0, 0, 1, 1); grid->addWidget(d->categoryEdit, 1, 0, 1, 1); grid->addWidget(d->albumCategoryBox, 2, 0, 5, 1); grid->addWidget(d->addCategoryButton, 2, 1, 1, 1); grid->addWidget(d->delCategoryButton, 3, 1, 1, 1); grid->addWidget(d->repCategoryButton, 4, 1, 1, 1); grid->setRowStretch(5, 10); grid->setColumnStretch(0, 10); grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); // -------------------------------------------------------- connect(d->albumCategoryBox, SIGNAL(itemSelectionChanged()), this, SLOT(slotCategorySelectionChanged())); connect(d->addCategoryButton, SIGNAL(clicked()), this, SLOT(slotAddCategory())); connect(d->delCategoryButton, SIGNAL(clicked()), this, SLOT(slotDelCategory())); connect(d->repCategoryButton, SIGNAL(clicked()), this, SLOT(slotRepCategory())); // -------------------------------------------------------- adjustSize(); } SetupCategory::~SetupCategory() { delete d; } void SetupCategory::slotDelCategory() { QListWidgetItem* const item = d->albumCategoryBox->currentItem(); if (!item) { return; } d->albumCategoryBox->takeItem(d->albumCategoryBox->row(item)); delete item; } void SetupCategory::slotRepCategory() { QString newCategory = d->categoryEdit->text(); if (newCategory.isEmpty()) { return; } if (!d->albumCategoryBox->selectedItems().isEmpty()) { d->albumCategoryBox->selectedItems().at(0)->setText(newCategory); d->categoryEdit->clear(); } } void SetupCategory::slotCategorySelectionChanged() { if (!d->albumCategoryBox->selectedItems().isEmpty()) { d->categoryEdit->setText(d->albumCategoryBox->selectedItems().at(0)->text()); d->delCategoryButton->setEnabled(true); d->repCategoryButton->setEnabled(true); } else { d->delCategoryButton->setEnabled(false); d->repCategoryButton->setEnabled(false); } } void SetupCategory::slotAddCategory() { QString newCategory = d->categoryEdit->text(); if (newCategory.isEmpty()) { return; } bool found = false; - for (int i = 0 ; i < d->albumCategoryBox->count(); ++i) + for (int i = 0 ; i < d->albumCategoryBox->count() ; ++i) { QListWidgetItem* const item = d->albumCategoryBox->item(i); if (newCategory == item->text()) { found = true; break; } } if (!found) { d->albumCategoryBox->insertItem(d->albumCategoryBox->count(), newCategory); d->categoryEdit->clear(); } } void SetupCategory::applySettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } QStringList categoryList; - for (int i = 0 ; i < d->albumCategoryBox->count(); ++i) + for (int i = 0 ; i < d->albumCategoryBox->count() ; ++i) { QListWidgetItem* const item = d->albumCategoryBox->item(i); categoryList.append(item->text()); } settings->setAlbumCategoryNames(categoryList); settings->saveSettings(); } void SetupCategory::readSettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } d->albumCategoryBox->insertItems(0, settings->getAlbumCategoryNames()); } } // namespace Digikam diff --git a/core/utilities/setup/album/setupmime.cpp b/core/utilities/setup/album/setupmime.cpp index e36674c86c..248e5f43e0 100644 --- a/core/utilities/setup/album/setupmime.cpp +++ b/core/utilities/setup/album/setupmime.cpp @@ -1,337 +1,338 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-05-03 * Description : mime types setup tab * * Copyright (C) 2004-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupmime.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "applicationsettings.h" #include "coredb.h" #include "coredbaccess.h" #include "dlayoutbox.h" #include "scancontroller.h" #include "setuputils.h" namespace Digikam { class Q_DECL_HIDDEN SetupMime::Private { public: explicit Private() : imageFileFilterLabel(nullptr), movieFileFilterLabel(nullptr), audioFileFilterLabel(nullptr), imageFileFilterEdit(nullptr), movieFileFilterEdit(nullptr), audioFileFilterEdit(nullptr) { } QLabel* imageFileFilterLabel; QLabel* movieFileFilterLabel; QLabel* audioFileFilterLabel; QLineEdit* imageFileFilterEdit; QLineEdit* movieFileFilterEdit; QLineEdit* audioFileFilterEdit; }; SetupMime::SetupMime(QWidget* const parent) : QScrollArea(parent), d(new Private) { QWidget* const panel = new QWidget(viewport()); setWidget(panel); setWidgetResizable(true); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QVBoxLayout* const layout = new QVBoxLayout(panel); // -------------------------------------------------------- QLabel* const explanationLabel = new QLabel; explanationLabel->setText(i18n("

Add new file types to show as album items.

" "

digiKam attempts to support all of the image formats that digital cameras produce, " "while being able to handle a few other important video and audio formats.

" "

You can add to the already-appreciable list of formats that digiKam handles by " "adding the extension of the type you want to add. " "Multiple extensions need to be separated by a semicolon or space.

" "

Note: changes done in this view will perform " "a database rescan in the background.

")); explanationLabel->setWordWrap(true); // -------------------------------------------------------- QGroupBox* const imageFileFilterBox = new QGroupBox(i18n("Image Files"), panel); QGridLayout* const grid1 = new QGridLayout(imageFileFilterBox); QLabel* const logoLabel1 = new QLabel(imageFileFilterBox); logoLabel1->setPixmap(QIcon::fromTheme(QLatin1String("image-jpeg")).pixmap(48)); d->imageFileFilterLabel = new QLabel(imageFileFilterBox); d->imageFileFilterLabel->setText(i18n("Additional &image file extensions (Currently-supported types):")); DHBox* const hbox1 = new DHBox(imageFileFilterBox); d->imageFileFilterEdit = new QLineEdit(hbox1); d->imageFileFilterEdit->setWhatsThis(i18n("

Here you can add the extensions of image files (including RAW files) " "to be displayed in the Album view. Just put \"xyz abc\" " "to display files with the xyz and abc extensions in your Album view.

" "

You can also remove file formats that are shown by default " "by putting a minus sign in front of the extension: e.g. \"-gif\" would remove all GIF files " "from your Album view and any trace of them in your database. " "They would not be deleted, just not shown in digiKam.

" "

Warning: Removing files from the database means losing " "all of their tags and ratings.

")); d->imageFileFilterEdit->setClearButtonEnabled(true); d->imageFileFilterEdit->setPlaceholderText(i18n("Enter additional image file extensions.")); d->imageFileFilterLabel->setBuddy(d->imageFileFilterEdit); hbox1->setStretchFactor(d->imageFileFilterEdit, 10); grid1->addWidget(logoLabel1, 0, 0, 2, 1); grid1->addWidget(d->imageFileFilterLabel, 0, 1, 1, 1); grid1->addWidget(hbox1, 1, 1, 1, 1); grid1->setColumnStretch(1, 10); grid1->setSpacing(spacing); // -------------------------------------------------------- QGroupBox* const movieFileFilterBox = new QGroupBox(i18n("Video Files"), panel); QGridLayout* const grid2 = new QGridLayout(movieFileFilterBox); QLabel* const logoLabel2 = new QLabel(movieFileFilterBox); logoLabel2->setPixmap(QIcon::fromTheme(QLatin1String("video-x-matroska")).pixmap(48)); d->movieFileFilterLabel = new QLabel(movieFileFilterBox); d->movieFileFilterLabel->setText(i18n("Additional &video file extensions (Currently-supported types):")); DHBox* const hbox2 = new DHBox(movieFileFilterBox); d->movieFileFilterEdit = new QLineEdit(hbox2); d->movieFileFilterEdit->setWhatsThis(i18n("

Here you can add extra extensions of video files " "to be displayed in your Album view. Just write \"xyz abc\" " "to support files with the *.xyz and *.abc extensions. " "Clicking on these files will " "play them in an embedded video player.

" "

You can also remove file formats that are supported by default " "by putting a minus sign in front of the extension: e.g. \"-avi\" would remove " "all AVI files from your Album view and any trace of them in your database. " "They would not be deleted, just not shown in digiKam.

" "

Warning: Removing files from the database means losing " "all of their tags and ratings.

")); d->movieFileFilterEdit->setClearButtonEnabled(true); d->movieFileFilterEdit->setPlaceholderText(i18n("Enter additional video file extensions.")); d->movieFileFilterLabel->setBuddy(d->movieFileFilterEdit); hbox2->setStretchFactor(d->movieFileFilterEdit, 10); grid2->addWidget(logoLabel2, 0, 0, 2, 1); grid2->addWidget(d->movieFileFilterLabel, 0, 1, 1, 1); grid2->addWidget(hbox2, 1, 1, 1, 1); grid2->setColumnStretch(1, 10); grid2->setSpacing(spacing); // -------------------------------------------------------- QGroupBox* const audioFileFilterBox = new QGroupBox(i18n("Audio Files"), panel); QGridLayout* const grid3 = new QGridLayout(audioFileFilterBox); QLabel* const logoLabel3 = new QLabel(audioFileFilterBox); logoLabel3->setPixmap(QIcon::fromTheme(QLatin1String("audio-x-mpeg")).pixmap(48)); d->audioFileFilterLabel = new QLabel(audioFileFilterBox); d->audioFileFilterLabel->setText(i18n("Additional &audio file extensions (Currently-supported types):")); DHBox* const hbox3 = new DHBox(audioFileFilterBox); d->audioFileFilterEdit = new QLineEdit(hbox3); d->audioFileFilterEdit->setWhatsThis(i18n("

Here you can add extra extensions of audio files " "to be displayed in your Album view. Just write \"xyz abc\" " "to support files with the *.xyz and *.abc extensions. " "Clicking on these files will " "play them in an embedded audio player.

" "

You can also remove file formats that are supported by default " "by putting a minus sign in front of the extension: e.g. \"-ogg\" would " "remove all OGG files from your Album view and any trace of them in your database. " "They would not be deleted, just not shown in digiKam.

" "

Warning: Removing files from the database means losing " "all of their tags and ratings.

")); d->audioFileFilterEdit->setClearButtonEnabled(true); d->audioFileFilterEdit->setPlaceholderText(i18n("Enter additional audio file extensions.")); d->audioFileFilterLabel->setBuddy(d->audioFileFilterEdit); hbox3->setStretchFactor(d->audioFileFilterEdit, 10); grid3->addWidget(logoLabel3, 0, 0, 2, 1); grid3->addWidget(d->audioFileFilterLabel, 0, 1, 1, 1); grid3->addWidget(hbox3, 1, 1, 1, 1); grid3->setColumnStretch(1, 10); grid3->setSpacing(spacing); // -------------------------------------------------------- layout->setContentsMargins(spacing, spacing, spacing, spacing); layout->setSpacing(spacing); layout->addWidget(explanationLabel); layout->addWidget(imageFileFilterBox); layout->addWidget(movieFileFilterBox); layout->addWidget(audioFileFilterBox); layout->addStretch(); // -------------------------------------------------------- connect(d->imageFileFilterLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotShowCurrentImageSettings())); connect(d->movieFileFilterLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotShowCurrentMovieSettings())); connect(d->audioFileFilterLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotShowCurrentAudioSettings())); // -------------------------------------------------------- readSettings(); } SetupMime::~SetupMime() { delete d; } void SetupMime::applySettings() { // Display warning if user removes a core format + QStringList coreImageFormats, removedImageFormats; coreImageFormats << QLatin1String("jpg") << QLatin1String("jpeg") << QLatin1String("jpe") // JPEG << QLatin1String("tif") << QLatin1String("tiff") // TIFF << QLatin1String("png"); // PNG QString imageFilter = d->imageFileFilterEdit->text(); foreach (const QString& format, coreImageFormats) { if (imageFilter.contains(QLatin1Char('-') + format) || imageFilter.contains(QLatin1String("-*.") + format)) { removedImageFormats << format; } } if (!removedImageFormats.isEmpty()) { int result = QMessageBox::warning(this, qApp->applicationName(), i18n("

You have chosen to remove the following image formats " "from the list of supported formats: %1.

" "

These are very common formats. If you have images in your collection " "with these formats, they will be removed from the database and you will " "lose all information about them, including rating and tags.

" "

Are you sure you want to apply your changes and lose the support for these formats?

", removedImageFormats.join(QLatin1Char(' '))), QMessageBox::Yes | QMessageBox::No); if (result != QMessageBox::Yes) { return; } } QString imageFilterString; QString movieFilterString; QString audioFilterString; CoreDbAccess().db()->getUserFilterSettings(&imageFilterString, &movieFilterString, &audioFilterString); imageFilterString.replace(QLatin1Char(';'), QLatin1Char(' ')); movieFilterString.replace(QLatin1Char(';'), QLatin1Char(' ')); audioFilterString.replace(QLatin1Char(';'), QLatin1Char(' ')); - if (d->imageFileFilterEdit->text() != imageFilterString || - d->movieFileFilterEdit->text() != movieFilterString || - d->audioFileFilterEdit->text() != audioFilterString) + if ((d->imageFileFilterEdit->text() != imageFilterString) || + (d->movieFileFilterEdit->text() != movieFilterString) || + (d->audioFileFilterEdit->text() != audioFilterString)) { CoreDbAccess().db()->setUserFilterSettings(cleanUserFilterString(d->imageFileFilterEdit->text()), cleanUserFilterString(d->movieFileFilterEdit->text()), cleanUserFilterString(d->audioFileFilterEdit->text())); ScanController::instance()->completeCollectionScanInBackground(false); } } void SetupMime::readSettings() { QString image; QString audio; QString video; CoreDbAccess().db()->getUserFilterSettings(&image, &video, &audio); d->imageFileFilterEdit->setText(image.replace(QLatin1Char(';'), QLatin1Char(' '))); d->movieFileFilterEdit->setText(video.replace(QLatin1Char(';'), QLatin1Char(' '))); d->audioFileFilterEdit->setText(audio.replace(QLatin1Char(';'), QLatin1Char(' '))); } void SetupMime::slotShowCurrentImageSettings() { QStringList imageList; CoreDbAccess().db()->getFilterSettings(&imageList, nullptr, nullptr); QString text = i18n("

Files with these extensions will be recognized as images " "and included into the database:
%1

", imageList.join(QLatin1Char(' '))); QWhatsThis::showText(d->imageFileFilterLabel->mapToGlobal(QPoint(0, 0)), text, d->imageFileFilterLabel); } void SetupMime::slotShowCurrentMovieSettings() { QStringList movieList; CoreDbAccess().db()->getFilterSettings(nullptr, &movieList, nullptr); QString text = i18n("

Files with these extensions will be recognized as video files " "and included into the database:
%1

", movieList.join(QLatin1Char(' '))); QWhatsThis::showText(d->movieFileFilterLabel->mapToGlobal(QPoint(0, 0)), text, d->movieFileFilterLabel); } void SetupMime::slotShowCurrentAudioSettings() { QStringList audioList; CoreDbAccess().db()->getFilterSettings(nullptr, nullptr, &audioList); QString text = i18n("

Files with these extensions will be recognized as audio files " "and included into the database:
%1

", audioList.join(QLatin1Char(' '))); QWhatsThis::showText(d->audioFileFilterLabel->mapToGlobal(QPoint(0, 0)), text, d->audioFileFilterLabel); } } // namespace Digikam diff --git a/core/utilities/setup/camera/cameralist.cpp b/core/utilities/setup/camera/cameralist.cpp index b47392bbd9..d703af3b47 100644 --- a/core/utilities/setup/camera/cameralist.cpp +++ b/core/utilities/setup/camera/cameralist.cpp @@ -1,341 +1,351 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-03 * Description : Cameras list container * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "cameralist.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "cameratype.h" #include "gpcamera.h" #include "digikam_debug.h" namespace Digikam { CameraList* CameraList::m_defaultList = nullptr; CameraList* CameraList::defaultList() { return m_defaultList; } class Q_DECL_HIDDEN CameraList::Private { public: explicit Private() : modified(false) { } bool modified; QList clist; QString file; }; CameraList::CameraList(QObject* const parent, const QString& file) : QObject(parent), d(new Private) { d->file = file; qCDebug(DIGIKAM_GENERAL_LOG) << "Camera XML data: " << d->file; if (!m_defaultList) { m_defaultList = this; } } CameraList::~CameraList() { save(); clear(); delete d; if (m_defaultList == this) { m_defaultList = nullptr; } } bool CameraList::load() { d->modified = false; QFile cfile(d->file); if (!cfile.open(QIODevice::ReadOnly)) { return false; } QDomDocument doc(QLatin1String("cameralist")); if (!doc.setContent(&cfile)) { cfile.close(); + return false; } QDomElement docElem = doc.documentElement(); if (docElem.tagName() != QLatin1String("cameralist")) { cfile.close(); + return false; } - for (QDomNode n = docElem.firstChild(); !n.isNull(); n = n.nextSibling()) + for (QDomNode n = docElem.firstChild() ; !n.isNull() ; n = n.nextSibling()) { QDomElement e = n.toElement(); if (e.isNull()) { continue; } if (e.tagName() != QLatin1String("item")) { continue; } QString title = e.attribute(QLatin1String("title")); QString model = e.attribute(QLatin1String("model")); QString port = e.attribute(QLatin1String("port")); QString path = e.attribute(QLatin1String("path")); int sn = e.attribute(QLatin1String("startingnumber")).toInt(); CameraType* const ctype = new CameraType(title, model, port, path, sn); insertPrivate(ctype); } cfile.close(); + return true; } bool CameraList::save() { // If not modified don't save the file + if (!d->modified) { return true; } QDomDocument doc(QLatin1String("cameralist")); doc.setContent(QLatin1String("")); QDomElement docElem = doc.documentElement(); foreach (CameraType* const ctype, d->clist) { QDomElement elem = doc.createElement(QLatin1String("item")); elem.setAttribute(QLatin1String("title"), ctype->title()); elem.setAttribute(QLatin1String("model"), ctype->model()); elem.setAttribute(QLatin1String("port"), ctype->port()); elem.setAttribute(QLatin1String("path"), ctype->path()); elem.setAttribute(QLatin1String("startingnumber"), QString::number(ctype->startingNumber())); docElem.appendChild(elem); } QFile cfile(d->file); if (!cfile.open(QIODevice::WriteOnly)) { qCDebug(DIGIKAM_GENERAL_LOG) << "Cannot open Camera XML file to save data (" << d->file << ")"; return false; } QTextStream stream(&cfile); stream.setCodec(QTextCodec::codecForName("UTF-8")); stream.setAutoDetectUnicode(true); stream << doc.toString(); cfile.close(); d->modified = false; + return true; } void CameraList::insert(CameraType* const ctype) { if (!ctype) { return; } d->modified = true; insertPrivate(ctype); } void CameraList::remove(CameraType* const ctype) { if (!ctype) { return; } d->modified = true; removePrivate(ctype); } void CameraList::insertPrivate(CameraType* const ctype) { if (!ctype) { return; } d->clist.append(ctype); + emit signalCameraAdded(ctype); } void CameraList::removePrivate(CameraType* const ctype) { if (!ctype) { return; } emit signalCameraRemoved(ctype->action()); int i = d->clist.indexOf(ctype); if (i != -1) { delete d->clist.takeAt(i); } } void CameraList::clear() { while (!d->clist.isEmpty()) { d->modified = true; removePrivate(d->clist.first()); } } QList* CameraList::cameraList() const { return &d->clist; } CameraType* CameraList::find(const QString& title) const { foreach (CameraType* const ctype, d->clist) { if (ctype->title() == title) { return ctype; } } return nullptr; } CameraType* CameraList::autoDetect(bool& retry) { retry = false; QString model, port; if (GPCamera::autoDetect(model, port) != 0) { retry = (QMessageBox::warning(qApp->activeWindow(), qApp->applicationName(), i18n("Failed to auto-detect camera; " "please make sure it is connected " "properly and is turned on. " "Would you like to try again?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes); + return nullptr; } // Check if the camera is already in the list + foreach (CameraType* const ctype, d->clist) { // We can get away with checking only the model, as the auto-detection // works only for usb cameras. so the port is always usb: + if (ctype->model() == model) { return ctype; } } // Looks like a new camera // NOTE: libgphoto2 now (2.1.4+) expects port names to be // something like "usb:001,012". but on linux these port numbers // will change every time camera is reconnected. gphoto port funcs // also allow regexp match, so the safe bet is to just pass in // "usb:" and cross your fingers that user doesn't have multiple cameras // connected at the same time (whack them if they do). if (port.startsWith(QLatin1String("usb:"))) { port = QLatin1String("usb:"); } - CameraType* ctype = new CameraType(model, model, port, QLatin1String("/"), 1); + CameraType* const ctype = new CameraType(model, model, port, QLatin1String("/"), 1); insert(ctype); return ctype; } bool CameraList::findConnectedCamera(int vendorId, int productId, QString& model, QString& port) { return GPCamera::findConnectedUsbCamera(vendorId, productId, model, port); } bool CameraList::changeCameraStartIndex(const QString& cameraTitle, int startIndex) { CameraType* const cam = find(cameraTitle); if (cam) { cam->setStartingNumber(startIndex); d->modified = true; save(); + return true; } return false; } } // namespace Digikam diff --git a/core/utilities/setup/camera/cameralist.h b/core/utilities/setup/camera/cameralist.h index 976b00ba14..cb6d0bb47a 100644 --- a/core/utilities/setup/camera/cameralist.h +++ b/core/utilities/setup/camera/cameralist.h @@ -1,92 +1,92 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-03 * Description : Cameras list container * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_CAMERA_LIST_H #define DIGIKAM_CAMERA_LIST_H // Qt includes #include #include // Local includes #include "digikam_export.h" class QString; class QDateTime; class QAction; namespace Digikam { class CameraType; class DIGIKAM_EXPORT CameraList : public QObject { Q_OBJECT public: CameraList(QObject* const parent, const QString& file); ~CameraList(); bool load(); bool save(); void clear(); void insert(CameraType* const ctype); void remove(CameraType* const ctype); CameraType* autoDetect(bool& retry); CameraType* find(const QString& title) const; - QList* cameraList() const; + QList* cameraList() const; bool changeCameraStartIndex(const QString& cameraTitle, int startIndex); static bool findConnectedCamera(int vendorId, int productId, QString& model, QString& port); static CameraList* defaultList(); Q_SIGNALS: void signalCameraAdded(CameraType*); void signalCameraRemoved(QAction*); private: void insertPrivate(CameraType* const ctype); void removePrivate(CameraType* const ctype); private: static CameraList* m_defaultList; class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_CAMERA_LIST_H diff --git a/core/utilities/setup/camera/cameraselection.cpp b/core/utilities/setup/camera/cameraselection.cpp index ba7d15da06..1a5f1fc82e 100644 --- a/core/utilities/setup/camera/cameraselection.cpp +++ b/core/utilities/setup/camera/cameraselection.cpp @@ -1,703 +1,711 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-10 * Description : Camera type selection dialog * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "cameraselection.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "dfileselector.h" #include "digikam_config.h" #include "gpcamera.h" #include "dxmlguiwindow.h" namespace Digikam { class Q_DECL_HIDDEN CameraSelection::Private { public: explicit Private() : buttons(nullptr), portButtonGroup(nullptr), usbButton(nullptr), serialButton(nullptr), networkButton(nullptr), portPathComboBox(nullptr), listView(nullptr), titleEdit(nullptr), networkEdit(nullptr), umsMountURL(nullptr), searchBar(nullptr) { } QDialogButtonBox* buttons; QButtonGroup* portButtonGroup; QRadioButton* usbButton; QRadioButton* serialButton; QRadioButton* networkButton; QComboBox* portPathComboBox; QString UMSCameraNameActual; QString UMSCameraNameShown; QString PTPCameraNameShown; QString PTPIPCameraNameShown; QStringList serialPortList; QTreeWidget* listView; QLineEdit* titleEdit; QLineEdit* networkEdit; DFileSelector* umsMountURL; SearchTextBar* searchBar; }; CameraSelection::CameraSelection(QWidget* const parent) : QDialog(parent), d(new Private) { qApp->setOverrideCursor(Qt::WaitCursor); setWindowTitle(i18n("Camera Configuration")); setModal(true); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); d->UMSCameraNameActual = QLatin1String("Directory Browse"); // Don't be i18n! d->UMSCameraNameShown = i18n("Mounted Camera"); d->PTPCameraNameShown = QLatin1String("USB PTP Class Camera"); d->PTPIPCameraNameShown = QLatin1String("PTP/IP Camera"); QWidget* const page = new QWidget(this); QGridLayout* mainBoxLayout = new QGridLayout(page); // -------------------------------------------------------------- d->listView = new QTreeWidget(page); d->listView->setRootIsDecorated(false); d->listView->setSelectionMode(QAbstractItemView::SingleSelection); d->listView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); d->listView->setMinimumWidth(350); d->listView->setAllColumnsShowFocus(true); d->listView->setColumnCount(1); d->listView->setHeaderLabels(QStringList() << i18n("Camera List")); d->listView->setWhatsThis(i18n("

Select the camera name that you want to use here. All " "default settings on the right panel " "will be set automatically.

This list has been generated " "using the gphoto2 library installed on your computer.

")); d->searchBar = new SearchTextBar(page, QLatin1String("CameraSelectionSearchBar")); // -------------------------------------------------------------- QGroupBox* const titleBox = new QGroupBox(i18n("Camera Title"), page); QVBoxLayout* const gLayout1 = new QVBoxLayout(titleBox); d->titleEdit = new QLineEdit(titleBox); d->titleEdit->setWhatsThis(i18n("

Set here the name used in digiKam interface to " "identify this camera.

")); gLayout1->addWidget(d->titleEdit); gLayout1->setContentsMargins(spacing, spacing, spacing, spacing); gLayout1->setSpacing(spacing); // -------------------------------------------------------------- QGroupBox* const portPathBox = new QGroupBox(i18n("Camera Port Type"), page); QGridLayout* const gLayout2 = new QGridLayout(portPathBox); d->portButtonGroup = new QButtonGroup(portPathBox); d->portButtonGroup->setExclusive(true); d->usbButton = new QRadioButton(i18n("USB"), portPathBox); d->usbButton->setWhatsThis(i18n("

Select this option if your camera is connected to your " "computer using a USB cable.

")); d->serialButton = new QRadioButton(i18n("Serial"), portPathBox); d->serialButton->setWhatsThis(i18n("

Select this option if your camera is connected to your " "computer using a serial cable.

")); d->networkButton = new QRadioButton(i18n("Network"), portPathBox); d->networkButton->setWhatsThis(i18n("

Select this option if your camera is connected to your " "computer network.

")); d->portPathComboBox = new QComboBox(portPathBox); d->portPathComboBox->setDuplicatesEnabled(false); d->portPathComboBox->setWhatsThis(i18n("

Select the serial port to use on your computer here. " "This option is only required if you use a serial camera.

")); d->networkEdit = new QLineEdit(portPathBox); d->networkEdit->setWhatsThis(i18n("

Enter here the network address of your camera.

")); d->networkEdit->setInputMask(QLatin1String("000.000.000.000")); d->networkEdit->setText(QLatin1String("192.168.001.001")); d->portButtonGroup->addButton(d->usbButton); d->portButtonGroup->addButton(d->serialButton); d->portButtonGroup->addButton(d->networkButton); gLayout2->addWidget(d->usbButton, 0, 0, 1, 2); gLayout2->addWidget(d->serialButton, 1, 0, 1, 2); gLayout2->addWidget(d->portPathComboBox, 1, 1, 1, 2); gLayout2->addWidget(d->networkButton, 2, 0, 1, 2); gLayout2->addWidget(d->networkEdit, 2, 1, 1, 2); gLayout2->setContentsMargins(spacing, spacing, spacing, spacing); gLayout2->setSpacing(spacing); // -------------------------------------------------------------- QGroupBox* const umsMountBox = new QGroupBox(i18n("Camera Mount Path"), page); QVBoxLayout* const gLayout3 = new QVBoxLayout(umsMountBox); QLabel* const umsMountLabel = new QLabel(umsMountBox); umsMountLabel->setText(i18n("Note: only for USB/IEEE mass storage cameras.")); d->umsMountURL = new DFileSelector(umsMountBox); d->umsMountURL->setFileDlgPath(QLatin1String("/mnt/camera")); d->umsMountURL->setFileDlgMode(QFileDialog::Directory); d->umsMountURL->setWhatsThis(i18n("

Set here the mount path to use on your computer. This " "option is only required if you use a USB Mass Storage " "camera.

")); gLayout3->addWidget(umsMountLabel); gLayout3->addWidget(d->umsMountURL); gLayout3->setContentsMargins(spacing, spacing, spacing, spacing); gLayout3->setSpacing(spacing); // -------------------------------------------------------------- QWidget* const box2 = new QWidget(page); QGridLayout* const gLayout4 = new QGridLayout(box2); QLabel* const logo = new QLabel(box2); logo->setPixmap(QIcon::fromTheme(QLatin1String("digikam")).pixmap(QSize(48,48))); QLabel* const link = new QLabel(box2); link->setText(i18n("

To set a USB Mass Storage camera
" "(which looks like a removable drive when mounted
" "on your desktop), please use
" "%1 from the camera list.

", d->UMSCameraNameShown)); QLabel* const link2 = new QLabel(box2); link2->setText(i18n("

To set a Generic PTP USB Device
" "(which uses Picture Transfer Protocol), please
" "use %1 from the camera list.

", d->PTPCameraNameShown)); QLabel* const link3 = new QLabel(box2); link3->setText(i18n("

To set a Generic PTP/IP Network Device
" "(which uses Picture Transfer Protocol), please
" "use %1 from the camera list.

", d->PTPIPCameraNameShown)); QLabel* const explanation = new QLabel(box2); explanation->setOpenExternalLinks(true); explanation->setText(i18n("

A complete list of camera settings to use is
" "available at " "this URL.

")); gLayout4->setContentsMargins(spacing, spacing, spacing, spacing); gLayout4->setSpacing(spacing); gLayout4->addWidget(logo, 0, 0, 1, 1); gLayout4->addWidget(link, 0, 1, 2, 1); gLayout4->addWidget(link2, 2, 1, 2, 1); gLayout4->addWidget(link3, 4, 1, 2, 1); gLayout4->addWidget(explanation, 6, 1, 2, 1); // -------------------------------------------------------------- mainBoxLayout->addWidget(d->listView, 0, 0, 6, 1); mainBoxLayout->addWidget(d->searchBar, 7, 0, 1, 1); mainBoxLayout->addWidget(titleBox, 0, 1, 1, 1); mainBoxLayout->addWidget(portPathBox, 1, 1, 1, 1); mainBoxLayout->addWidget(umsMountBox, 2, 1, 1, 1); mainBoxLayout->addWidget(box2, 3, 1, 2, 1); mainBoxLayout->setColumnStretch(0, 10); mainBoxLayout->setRowStretch(6, 10); mainBoxLayout->setContentsMargins(QMargins()); mainBoxLayout->setSpacing(spacing); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(page); vbx->addWidget(d->buttons); setLayout(vbx); // Connections -------------------------------------------------- connect(link, SIGNAL(linkActivated(QString)), this, SLOT(slotUMSCameraLinkUsed())); connect(link2, SIGNAL(linkActivated(QString)), this, SLOT(slotPTPCameraLinkUsed())); connect(link3, SIGNAL(linkActivated(QString)), this, SLOT(slotPTPIPCameraLinkUsed())); connect(d->networkEdit, SIGNAL(textChanged(QString)), this, SLOT(slotNetworkEditChanged(QString))); connect(d->listView, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotSelectionChanged(QTreeWidgetItem*,int))); connect(d->portButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotPortChanged())); connect(d->searchBar, SIGNAL(signalSearchTextSettings(SearchTextSettings)), this, SLOT(slotSearchTextChanged(SearchTextSettings))); connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(slotOkClicked())); connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); connect(d->buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotHelp())); // Initialize -------------------------------------------------- #ifndef HAVE_GPHOTO2 + // If digiKam is compiled without Gphoto2 support, we hide widgets relevant. + d->listView->hide(); d->searchBar->hide(); box2->hide(); slotUMSCameraLinkUsed(); + #else + getCameraList(); getSerialPortList(); -#endif /* HAVE_GPHOTO2 */ + +#endif // HAVE_GPHOTO2 qApp->restoreOverrideCursor(); } CameraSelection::~CameraSelection() { delete d; } void CameraSelection::slotUMSCameraLinkUsed() { QList list = d->listView->findItems(d->UMSCameraNameShown, Qt::MatchExactly, 0); if (!list.isEmpty()) { QTreeWidgetItem* const item = list.first(); if (item) { d->listView->setCurrentItem(item); d->listView->scrollToItem(item); } } } void CameraSelection::slotPTPCameraLinkUsed() { QList list = d->listView->findItems(d->PTPCameraNameShown, Qt::MatchExactly, 0); if (!list.isEmpty()) { QTreeWidgetItem* const item = list.first(); if (item) { d->listView->setCurrentItem(item); d->listView->scrollToItem(item); } } } void CameraSelection::slotPTPIPCameraLinkUsed() { QList list = d->listView->findItems(d->PTPIPCameraNameShown, Qt::MatchExactly, 0); if (!list.isEmpty()) { QTreeWidgetItem* const item = list.first(); if (item) { d->listView->setCurrentItem(item); d->listView->scrollToItem(item); } } } void CameraSelection::slotNetworkEditChanged(const QString& text) { int cursorPosition = d->networkEdit->cursorPosition(); QStringList ipRanges = text.split(QLatin1Char('.')); - for (int i = 0; i < ipRanges.count(); ++i) + for (int i = 0 ; i < ipRanges.count() ; ++i) { bool ok; - for (int a = ipRanges.at(i).count(); a < 3; ++a) + for (int a = ipRanges.at(i).count() ; a < 3 ; ++a) { ipRanges[i].append(QLatin1Char('0')); } if (ipRanges.at(i).toInt(&ok) > 255) { ipRanges[i] = QLatin1String("255"); } if (!ok) { ipRanges[i] = QLatin1String("000"); } } d->networkEdit->setText(ipRanges.join(QLatin1Char('.'))); d->networkEdit->setCursorPosition(cursorPosition); } void CameraSelection::setCamera(const QString& title, const QString& model, const QString& port, const QString& path) { QString camModel(model); if (camModel == d->UMSCameraNameActual) { camModel = d->UMSCameraNameShown; } QList list = d->listView->findItems(camModel, Qt::MatchExactly, 0); if (!list.isEmpty()) { QTreeWidgetItem* const item = list.first(); if (!item) { return; } d->listView->setCurrentItem(item); d->listView->scrollToItem(item); d->titleEdit->setText(title); - if (port.contains(QLatin1String("usb"))) + if (port.contains(QLatin1String("usb"))) { d->usbButton->setChecked(true); slotPortChanged(); } else if (port.contains(QLatin1String("serial"))) { d->serialButton->setChecked(true); for (int i = 0 ; i < d->portPathComboBox->count() ; ++i) { if (port == d->portPathComboBox->itemText(i)) { d->portPathComboBox->setCurrentIndex(i); break; } } slotPortChanged(); } else if (port.contains(QLatin1String("ptpip"))) { d->networkButton->setChecked(true); d->networkEdit->setText(port); slotPortChanged(); } d->umsMountURL->setFileDlgPath(path); } } void CameraSelection::getCameraList() { int count = 0; QStringList clist; QString cname; GPCamera::getSupportedCameras(count, clist); for (int i = 0 ; i < count ; ++i) { cname = clist.at(i); if (cname == d->UMSCameraNameActual) { new QTreeWidgetItem(d->listView, QStringList() << d->UMSCameraNameShown); } else { new QTreeWidgetItem(d->listView, QStringList() << cname); } } } void CameraSelection::getSerialPortList() { QStringList plist; GPCamera::getSupportedPorts(plist); d->serialPortList.clear(); for (int i = 0; i < plist.count() ; ++i) { if ((plist.at(i)).startsWith(QLatin1String("serial:"))) { d->serialPortList.append(plist.at(i)); } } } void CameraSelection::slotSelectionChanged(QTreeWidgetItem* item, int) { if (!item) { return; } QString model(item->text(0)); if (model == d->UMSCameraNameShown) { model = d->UMSCameraNameActual; d->titleEdit->setText(model); d->usbButton->setEnabled(true); d->usbButton->setChecked(false); d->usbButton->setEnabled(false); d->serialButton->setEnabled(true); d->serialButton->setChecked(false); d->serialButton->setEnabled(false); d->networkButton->setEnabled(true); d->networkButton->setChecked(false); d->networkButton->setEnabled(false); d->portPathComboBox->setEnabled(true); d->portPathComboBox->clear(); d->portPathComboBox->insertItem(0, QLatin1String("NONE")); d->portPathComboBox->setEnabled(false); d->networkEdit->setEnabled(true); d->networkEdit->setText(QLatin1String("192.168.001.001")); d->networkEdit->setEnabled(false); d->umsMountURL->setEnabled(true); d->umsMountURL->setFileDlgPath(QLatin1String("/mnt/camera")); + return; } else { d->umsMountURL->setEnabled(true); d->umsMountURL->setFileDlgPath(QLatin1String("/")); d->umsMountURL->setEnabled(false); } d->titleEdit->setText(model); QStringList plist; GPCamera::getCameraSupportedPorts(model, plist); if (plist.contains(QLatin1String("serial"))) { d->serialButton->setEnabled(true); d->serialButton->setChecked(true); } else { d->serialButton->setEnabled(true); d->serialButton->setChecked(false); d->serialButton->setEnabled(false); } if (plist.contains(QLatin1String("ptpip"))) { d->networkButton->setEnabled(true); d->networkButton->setChecked(true); } else { d->networkButton->setEnabled(true); d->networkButton->setChecked(false); d->networkButton->setEnabled(false); } if (plist.contains(QLatin1String("usb"))) { d->usbButton->setEnabled(true); d->usbButton->setChecked(true); } else { d->usbButton->setEnabled(true); d->usbButton->setChecked(false); d->usbButton->setEnabled(false); } slotPortChanged(); } void CameraSelection::slotPortChanged() { if (d->usbButton->isChecked()) { d->portPathComboBox->setEnabled(true); d->portPathComboBox->clear(); d->portPathComboBox->insertItem(0, QLatin1String("usb:")); d->portPathComboBox->setEnabled(false); d->networkEdit->setEnabled(false); + return; } if (d->networkButton->isChecked()) { d->portPathComboBox->setEnabled(true); d->portPathComboBox->clear(); d->portPathComboBox->insertItem(0, QLatin1String("ptpip:")); d->portPathComboBox->setEnabled(false); d->networkEdit->setEnabled(true); + return; } if (d->serialButton->isChecked()) { d->portPathComboBox->setEnabled(true); d->portPathComboBox->clear(); d->portPathComboBox->insertItems(0, d->serialPortList); d->networkEdit->setEnabled(false); } } QString CameraSelection::currentTitle() const { return d->titleEdit->text(); } QString CameraSelection::currentModel() const { QTreeWidgetItem* const item = d->listView->currentItem(); if (!item) { return QString(); } QString model(item->text(0)); if (model == d->UMSCameraNameShown) { model = d->UMSCameraNameActual; } return model; } QString CameraSelection::currentPortPath() const { if (d->networkButton->isChecked()) { return (d->portPathComboBox->currentText() + d->networkEdit->text()); } else { return d->portPathComboBox->currentText(); } } QString CameraSelection::currentCameraPath() const { return d->umsMountURL->fileDlgPath(); } void CameraSelection::slotOkClicked() { emit signalOkClicked(currentTitle(), currentModel(), currentPortPath(), currentCameraPath()); accept(); } void CameraSelection::slotSearchTextChanged(const SearchTextSettings& settings) { bool query = false; QString search = settings.text; QTreeWidgetItemIterator it(d->listView); while (*it) { - QTreeWidgetItem* const item = *it; + QTreeWidgetItem* const item = *it; if (item->text(0).contains(search, settings.caseSensitive)) { query = true; item->setHidden(false); } else { item->setHidden(true); } ++it; } d->searchBar->slotSearchResult(query); } void CameraSelection::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/core/utilities/setup/camera/importfilterdlg.cpp b/core/utilities/setup/camera/importfilterdlg.cpp index 85580e37fa..d118649fd4 100644 --- a/core/utilities/setup/camera/importfilterdlg.cpp +++ b/core/utilities/setup/camera/importfilterdlg.cpp @@ -1,254 +1,255 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2010-12-16 * Description : Import filters configuration dialog * * Copyright (C) 2010-2011 by Petri Damstén * Copyright (C) 2012-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "importfilterdlg.h" // Qt includes #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include // Local includes #include "digikam_debug.h" #include "importfiltercombobox.h" #include "dexpanderbox.h" namespace Digikam { class Q_DECL_HIDDEN ImportFilterDlg::Private { public: explicit Private() + : buttons(nullptr), + filterName(nullptr), + mimeCheckBox(nullptr), + mimeLabel(nullptr), + mimeButton(nullptr), + fileNameCheckBox(nullptr), + fileNameEdit(nullptr), + pathCheckBox(nullptr), + pathEdit(nullptr), + newFilesCheckBox(nullptr) { - buttons = nullptr; - filterName = nullptr; - mimeCheckBox = nullptr; - mimeLabel = nullptr; - mimeButton = nullptr; - fileNameCheckBox = nullptr; - fileNameEdit = nullptr; - pathCheckBox = nullptr; - pathEdit = nullptr; - newFilesCheckBox = nullptr; } QDialogButtonBox* buttons; QLineEdit* filterName; QCheckBox* mimeCheckBox; DAdjustableLabel* mimeLabel; QToolButton* mimeButton; QCheckBox* fileNameCheckBox; QLineEdit* fileNameEdit; QCheckBox* pathCheckBox; QLineEdit* pathEdit; QCheckBox* newFilesCheckBox; }; // ---------------------------------------------------------------------------------------- ImportFilterDlg::ImportFilterDlg(QWidget* const parent) : QDialog(parent), d(new Private) { setWindowTitle(i18n("Edit Import Filters")); d->buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); QWidget* const page = new QWidget(this); QVBoxLayout* const verticalLayout = new QVBoxLayout(page); QLabel* label = nullptr; QHBoxLayout* horizontalLayout = nullptr; QSpacerItem* spacer = nullptr; + // To prevent cppcheck warnings. (void)label; (void)horizontalLayout; (void)spacer; label = new QLabel(page); label->setText(i18n("Name:")); verticalLayout->addWidget(label); d->filterName = new QLineEdit(page); verticalLayout->addWidget(d->filterName); d->mimeCheckBox = new QCheckBox(page); d->mimeCheckBox->setText(i18n("Mime filter:")); verticalLayout->addWidget(d->mimeCheckBox); horizontalLayout = new QHBoxLayout(); spacer = new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Minimum); horizontalLayout->addItem(spacer); d->mimeLabel = new DAdjustableLabel(page); horizontalLayout->addWidget(d->mimeLabel); d->mimeButton = new QToolButton(page); d->mimeButton->setText(i18n("Select Type Mime...")); horizontalLayout->addWidget(d->mimeButton); verticalLayout->addLayout(horizontalLayout); d->fileNameCheckBox = new QCheckBox(page); d->fileNameCheckBox->setText(i18n("File name filter:")); verticalLayout->addWidget(d->fileNameCheckBox); horizontalLayout = new QHBoxLayout(); spacer = new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Minimum); horizontalLayout->addItem(spacer); d->fileNameEdit = new QLineEdit(page); horizontalLayout->addWidget(d->fileNameEdit); verticalLayout->addLayout(horizontalLayout); d->pathCheckBox = new QCheckBox(page); d->pathCheckBox->setText(i18n("Path filter:")); verticalLayout->addWidget(d->pathCheckBox); horizontalLayout = new QHBoxLayout(); spacer = new QSpacerItem(20, 20, QSizePolicy::Fixed, QSizePolicy::Minimum); horizontalLayout->addItem(spacer); d->pathEdit = new QLineEdit(page); horizontalLayout->addWidget(d->pathEdit); verticalLayout->addLayout(horizontalLayout); d->newFilesCheckBox = new QCheckBox(page); d->newFilesCheckBox->setText(i18n("Show only new files")); verticalLayout->addWidget(d->newFilesCheckBox); spacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding); verticalLayout->addItem(spacer); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(page); vbx->addWidget(d->buttons); setLayout(vbx); connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); connect(d->mimeCheckBox, SIGNAL(clicked(bool)), d->mimeButton, SLOT(setEnabled(bool))); connect(d->mimeButton, SIGNAL(clicked(bool)), this, SLOT(mimeButtonClicked())); connect(d->fileNameCheckBox, SIGNAL(clicked(bool)), d->fileNameEdit, SLOT(setEnabled(bool))); connect(d->pathCheckBox, SIGNAL(clicked(bool)), d->pathEdit, SLOT(setEnabled(bool))); connect(d->mimeCheckBox, SIGNAL(clicked(bool)), this, SLOT(mimeCheckBoxClicked())); connect(d->fileNameCheckBox, SIGNAL(clicked()), this, SLOT(fileNameCheckBoxClicked())); connect(d->pathCheckBox, SIGNAL(clicked()), this, SLOT(pathCheckBoxClicked())); adjustSize(); } ImportFilterDlg::~ImportFilterDlg() { delete d; } void ImportFilterDlg::fileNameCheckBoxClicked() { if (!d->fileNameCheckBox->isChecked()) { d->fileNameEdit->clear(); } } void ImportFilterDlg::pathCheckBoxClicked() { if (!d->pathCheckBox->isChecked()) { d->pathEdit->clear(); } } void ImportFilterDlg::mimeCheckBoxClicked() { if (!d->mimeCheckBox->isChecked()) { d->mimeLabel->setAdjustedText(); } } void ImportFilterDlg::mimeButtonClicked() { QString text = i18n("Select the MimeTypes you want for this filter."); QStringList list = d->mimeLabel->adjustedText().split(QLatin1Char(';'), QString::SkipEmptyParts); QPointer dlg = new KMimeTypeChooserDialog(i18n("Select Mime Types"), text, list, QLatin1String("image"), this); if (dlg->exec() == QDialog::Accepted) { d->mimeLabel->setAdjustedText(dlg->chooser()->mimeTypes().join(QLatin1Char(';'))); } delete dlg; } void ImportFilterDlg::setData(const Filter& filter) { d->filterName->setText(filter.name); d->mimeCheckBox->setChecked(!filter.mimeFilter.isEmpty()); d->mimeLabel->setAdjustedText(filter.mimeFilter); d->mimeButton->setEnabled(!filter.mimeFilter.isEmpty()); d->fileNameCheckBox->setChecked(!filter.fileFilter.isEmpty()); d->fileNameEdit->setText(filter.fileFilter.join(QLatin1Char(';'))); d->fileNameEdit->setEnabled(!filter.fileFilter.isEmpty()); d->pathCheckBox->setChecked(!filter.pathFilter.isEmpty()); d->pathEdit->setText(filter.pathFilter.join(QLatin1Char(';'))); d->pathEdit->setEnabled(!filter.pathFilter.isEmpty()); d->newFilesCheckBox->setChecked(filter.onlyNew); } void ImportFilterDlg::getData(Filter* const filter) { filter->name = d->filterName->text(); filter->mimeFilter = d->mimeLabel->adjustedText(); filter->fileFilter = d->fileNameEdit->text().split(QLatin1Char(';'), QString::SkipEmptyParts); filter->pathFilter = d->pathEdit->text().split(QLatin1Char(';'), QString::SkipEmptyParts); filter->onlyNew = d->newFilesCheckBox->isChecked(); } } // namespace Digikam diff --git a/core/utilities/setup/camera/setupcamera.cpp b/core/utilities/setup/camera/setupcamera.cpp index 688418d1d1..e683b57781 100644 --- a/core/utilities/setup/camera/setupcamera.cpp +++ b/core/utilities/setup/camera/setupcamera.cpp @@ -1,1023 +1,1037 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-10 * Description : camera setup tab. * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupcamera.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "albumselectwidget.h" #include "cameralist.h" #include "cameraselection.h" #include "cameratype.h" #include "digikam_config.h" #include "gpcamera.h" #include "importfiltercombobox.h" #include "importfilterdlg.h" #include "dfontselect.h" #include "importsettings.h" #include "fullscreensettings.h" #include "dxmlguiwindow.h" #include "dactivelabel.h" namespace Digikam { class Q_DECL_HIDDEN SetupCameraItem : public QTreeWidgetItem { public: explicit SetupCameraItem(QTreeWidget* const parent, CameraType* const ctype) - : QTreeWidgetItem(parent), m_ctype(nullptr) + : QTreeWidgetItem(parent), + m_ctype(nullptr) { setCameraType(ctype); }; ~SetupCameraItem() { delete m_ctype; }; void setCameraType(CameraType* const ctype) { delete m_ctype; m_ctype = new CameraType(*ctype); if (m_ctype) { setText(0, m_ctype->title()); setText(1, m_ctype->model()); setText(2, m_ctype->port()); setText(3, m_ctype->path()); } }; CameraType* cameraType() const { return m_ctype; }; private: CameraType* m_ctype; }; // ------------------------------------------------------------------- class Q_DECL_HIDDEN CameraAutoDetectThread::Private { public: explicit Private() + : result(0) { - result = 0; } int result; QString model; QString port; }; CameraAutoDetectThread::CameraAutoDetectThread(QObject* const parent) : DBusyThread(parent), d(new Private) { d->result = -1; } CameraAutoDetectThread::~CameraAutoDetectThread() { delete d; } void CameraAutoDetectThread::run() { d->result = GPCamera::autoDetect(d->model, d->port); + emit signalComplete(); } int CameraAutoDetectThread::result() const { return(d->result); } QString CameraAutoDetectThread::model() const { return(d->model); } QString CameraAutoDetectThread::port() const { return(d->port); } // ------------------------------------------------------------------- class Q_DECL_HIDDEN SetupCamera::Private { public: explicit Private() : addButton(nullptr), removeButton(nullptr), editButton(nullptr), autoDetectButton(nullptr), importAddButton(nullptr), importRemoveButton(nullptr), importEditButton(nullptr), storeDiffButton(nullptr), overwriteButton(nullptr), skipFileButton(nullptr), conflictButtonGroup(nullptr), useFileMetadata(nullptr), turnHighQualityThumbs(nullptr), useDefaultTargetAlbum(nullptr), iconShowNameBox(nullptr), iconShowSizeBox(nullptr), iconShowDateBox(nullptr), iconShowResolutionBox(nullptr), iconShowTagsBox(nullptr), iconShowOverlaysBox(nullptr), iconShowRatingBox(nullptr), iconShowFormatBox(nullptr), iconShowCoordinatesBox(nullptr), previewLoadFullImageSize(nullptr), previewItemsWhileDownload(nullptr), previewShowIcons(nullptr), leftClickActionComboBox(nullptr), iconViewFontSelect(nullptr), target1AlbumSelector(nullptr), listView(nullptr), importListView(nullptr), tab(nullptr), ignoreNamesEdit(nullptr), ignoreExtensionsEdit(nullptr), fullScreenSettings(nullptr) { } static const QString configGroupName; static const QString configUseFileMetadata; static const QString configTrunHighQualityThumbs; static const QString configUseDefaultTargetAlbum; static const QString configDefaultTargetAlbumId; static const QString configFileSaveConflictRule; static const QString importFiltersConfigGroupName; QPushButton* addButton; QPushButton* removeButton; QPushButton* editButton; QPushButton* autoDetectButton; QPushButton* importAddButton; QPushButton* importRemoveButton; QPushButton* importEditButton; QRadioButton* storeDiffButton; QRadioButton* overwriteButton; QRadioButton* skipFileButton; QButtonGroup* conflictButtonGroup; QCheckBox* useFileMetadata; QCheckBox* turnHighQualityThumbs; QCheckBox* useDefaultTargetAlbum; QCheckBox* iconShowNameBox; QCheckBox* iconShowSizeBox; QCheckBox* iconShowDateBox; QCheckBox* iconShowResolutionBox; QCheckBox* iconShowTagsBox; QCheckBox* iconShowOverlaysBox; QCheckBox* iconShowRatingBox; QCheckBox* iconShowFormatBox; QCheckBox* iconShowCoordinatesBox; QCheckBox* previewLoadFullImageSize; QCheckBox* previewItemsWhileDownload; QCheckBox* previewShowIcons; QComboBox* leftClickActionComboBox; DFontSelect* iconViewFontSelect; AlbumSelectWidget* target1AlbumSelector; QTreeWidget* listView; QListWidget* importListView; QTabWidget* tab; QLineEdit* ignoreNamesEdit; QLineEdit* ignoreExtensionsEdit; FilterList filters; FullScreenSettings* fullScreenSettings; }; const QString SetupCamera::Private::configGroupName(QLatin1String("Camera Settings")); const QString SetupCamera::Private::configUseFileMetadata(QLatin1String("UseFileMetadata")); const QString SetupCamera::Private::configTrunHighQualityThumbs(QLatin1String("TurnHighQualityThumbs")); const QString SetupCamera::Private::configUseDefaultTargetAlbum(QLatin1String("UseDefaultTargetAlbum")); const QString SetupCamera::Private::configDefaultTargetAlbumId(QLatin1String("DefaultTargetAlbumId")); const QString SetupCamera::Private::configFileSaveConflictRule(QLatin1String("FileSaveConflictRule")); const QString SetupCamera::Private::importFiltersConfigGroupName(QLatin1String("Import Filters")); SetupCamera::SetupCamera(QWidget* const parent) : QScrollArea(parent), d(new Private) { d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); - const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); + const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QWidget* const panel = new QWidget(d->tab); QGridLayout* const grid = new QGridLayout(panel); d->listView = new QTreeWidget(panel); d->listView->sortItems(0, Qt::AscendingOrder); d->listView->setColumnCount(4); d->listView->setRootIsDecorated(false); d->listView->setSelectionMode(QAbstractItemView::SingleSelection); d->listView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); d->listView->setAllColumnsShowFocus(true); d->listView->setWhatsThis(i18n("Here you can see the digital camera list used by digiKam " "via the Gphoto interface.")); QStringList labels; labels.append(i18n("Title")); labels.append(i18n("Model")); labels.append(i18n("Port")); labels.append(i18n("Path")); d->listView->setHeaderLabels(labels); d->listView->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); d->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch); d->listView->header()->setSectionResizeMode(2, QHeaderView::Stretch); d->listView->header()->setSectionResizeMode(3, QHeaderView::Stretch); // ------------------------------------------------------------- d->addButton = new QPushButton(panel); d->removeButton = new QPushButton(panel); d->editButton = new QPushButton(panel); d->autoDetectButton = new QPushButton(panel); d->addButton->setText(i18n("&Add...")); d->addButton->setIcon(QIcon::fromTheme(QLatin1String("list-add"))); d->removeButton->setText(i18n("&Remove")); d->removeButton->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->editButton->setText(i18n("&Edit...")); d->editButton->setIcon(QIcon::fromTheme(QLatin1String("configure"))); d->autoDetectButton->setText(i18n("Auto-&Detect")); d->autoDetectButton->setIcon(QIcon::fromTheme(QLatin1String("edit-find"))); d->removeButton->setEnabled(false); d->editButton->setEnabled(false); // ------------------------------------------------------------- QSpacerItem* const spacer = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); DActiveLabel* const gphotoLogoLabel = new DActiveLabel(QUrl(QLatin1String("http://www.gphoto.org")), QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/logo-gphoto.png")), panel); gphotoLogoLabel->setToolTip(i18n("Visit Gphoto project website")); #ifndef HAVE_GPHOTO2 // If digiKam is compiled without Gphoto2 support, we hide widgets relevant. d->autoDetectButton->hide(); gphotoLogoLabel->hide(); #endif // HAVE_GPHOTO2 // ------------------------------------------------------------- grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); grid->setAlignment(Qt::AlignTop); grid->addWidget(d->listView, 0, 0, 6, 1); grid->addWidget(d->addButton, 0, 1, 1, 1); grid->addWidget(d->removeButton, 1, 1, 1, 1); grid->addWidget(d->editButton, 2, 1, 1, 1); grid->addWidget(d->autoDetectButton, 3, 1, 1, 1); grid->addItem(spacer, 4, 1, 1, 1); grid->addWidget(gphotoLogoLabel, 5, 1, 1, 1); d->tab->insertTab(0, panel, i18n("Devices")); // ------------------------------------------------------------- QWidget* const panel2 = new QWidget(d->tab); QVBoxLayout* const layout = new QVBoxLayout(panel2); d->useFileMetadata = new QCheckBox(i18n("Use file metadata (makes connection slower)"), panel2); d->turnHighQualityThumbs = new QCheckBox(i18n("Turn on high quality thumbnail loading (slower loading)"), panel2); d->useDefaultTargetAlbum = new QCheckBox(i18n("Use a default target album to download from camera"), panel2); d->target1AlbumSelector = new AlbumSelectWidget(panel2); QGroupBox* const conflictBox = new QGroupBox(panel2); QLabel* const conflictIcon = new QLabel(conflictBox); conflictIcon->setPixmap(QIcon::fromTheme(QLatin1String("document-save-as")).pixmap(32)); QLabel* const conflictLabel = new QLabel(i18n("If target file exists when downloaded from camera"), conflictBox); QGridLayout* const boxLayout = new QGridLayout(conflictBox); d->conflictButtonGroup = new QButtonGroup(conflictBox); d->storeDiffButton = new QRadioButton(i18n("Store as a different name"), conflictBox); d->overwriteButton = new QRadioButton(i18n("Overwrite automatically"), conflictBox); d->skipFileButton = new QRadioButton(i18n("Skip automatically"), conflictBox); d->conflictButtonGroup->addButton(d->overwriteButton, OVERWRITE); d->conflictButtonGroup->addButton(d->storeDiffButton, DIFFNAME); d->conflictButtonGroup->addButton(d->skipFileButton, SKIPFILE); d->conflictButtonGroup->setExclusive(true); d->storeDiffButton->setChecked(true); boxLayout->setContentsMargins(spacing, spacing, spacing, spacing); boxLayout->setSpacing(spacing); boxLayout->addWidget(conflictIcon, 0, 0); boxLayout->addWidget(conflictLabel, 0, 1); boxLayout->addWidget(d->storeDiffButton, 1, 0, 1, 3); boxLayout->addWidget(d->overwriteButton, 2, 0, 1, 3); boxLayout->addWidget(d->skipFileButton, 3, 0, 1, 3); boxLayout->setColumnStretch(2, 1); conflictBox->setLayout(boxLayout); d->tab->insertTab(1, panel2, i18n("Behavior")); layout->setContentsMargins(spacing, spacing, spacing, spacing); layout->setSpacing(spacing); layout->addWidget(d->useFileMetadata); layout->addWidget(d->turnHighQualityThumbs); layout->addWidget(d->useDefaultTargetAlbum); layout->addWidget(d->target1AlbumSelector); layout->addWidget(conflictBox); layout->addStretch(); // ------------------------------------------------------------- QWidget* const panel3 = new QWidget(d->tab); QGridLayout* const importGrid = new QGridLayout(panel3); d->importListView = new QListWidget(panel3); d->importListView->setSelectionMode(QAbstractItemView::SingleSelection); d->importListView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); d->importListView->setWhatsThis(i18n("Here you can see filters that can be used to filter " "files in import dialog.")); d->importAddButton = new QPushButton(panel3); d->importRemoveButton = new QPushButton(panel3); d->importEditButton = new QPushButton(panel3); QSpacerItem* const spacer2 = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding); QGroupBox* const groupBox = new QGroupBox(panel3); QVBoxLayout* const verticalLayout = new QVBoxLayout(groupBox); QLabel* const label = new QLabel(groupBox); verticalLayout->addWidget(label); d->ignoreNamesEdit = new QLineEdit(groupBox); verticalLayout->addWidget(d->ignoreNamesEdit); QLabel* const label2 = new QLabel(groupBox); verticalLayout->addWidget(label2); d->ignoreExtensionsEdit = new QLineEdit(groupBox); verticalLayout->addWidget(d->ignoreExtensionsEdit); groupBox->setTitle(i18n("Always ignore")); label->setText(i18n("Ignored file names:")); label2->setText(i18n("Ignored file extensions:")); d->importAddButton->setText(i18n("&Add...")); d->importAddButton->setIcon(QIcon::fromTheme(QLatin1String("list-add"))); d->importRemoveButton->setText(i18n("&Remove")); d->importRemoveButton->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->importEditButton->setText(i18n("&Edit...")); d->importEditButton->setIcon(QIcon::fromTheme(QLatin1String("configure"))); d->importRemoveButton->setEnabled(false); d->importEditButton->setEnabled(false); importGrid->setContentsMargins(spacing, spacing, spacing, spacing); importGrid->setSpacing(spacing); importGrid->setAlignment(Qt::AlignTop); importGrid->addWidget(d->importListView, 0, 0, 4, 1); importGrid->addWidget(groupBox, 5, 0, 1, 1); importGrid->addWidget(d->importAddButton, 0, 1, 1, 1); importGrid->addWidget(d->importRemoveButton, 1, 1, 1, 1); importGrid->addWidget(d->importEditButton, 2, 1, 1, 1); importGrid->addItem(spacer2, 3, 1, 1, 1); d->tab->insertTab(2, panel3, i18n("Import Filters")); // -- Import Icon View ---------------------------------------------------------- QWidget* const panel4 = new QWidget(d->tab); QVBoxLayout* const layout2 = new QVBoxLayout(panel4); QGroupBox* const iconViewGroup = new QGroupBox(i18n("Icon-View Options"), panel4); QGridLayout* const grid2 = new QGridLayout(iconViewGroup); d->iconShowNameBox = new QCheckBox(i18n("Show file&name"), iconViewGroup); d->iconShowNameBox->setWhatsThis(i18n("Set this option to show the filename below the image thumbnail.")); d->iconShowSizeBox = new QCheckBox(i18n("Show file si&ze"), iconViewGroup); d->iconShowSizeBox->setWhatsThis(i18n("Set this option to show the file size below the image thumbnail.")); d->iconShowDateBox = new QCheckBox(i18n("Show camera creation &date"), iconViewGroup); d->iconShowDateBox->setWhatsThis(i18n("Set this option to show the camera creation date " "below the image thumbnail.")); /* d->iconShowResolutionBox = new QCheckBox(i18n("Show ima&ge dimensions"), iconViewGroup); d->iconShowResolutionBox->setWhatsThis(i18n("Set this option to show the image size in pixels " "below the image thumbnail.")); */ d->iconShowFormatBox = new QCheckBox(i18n("Show image Format"), iconViewGroup); d->iconShowFormatBox->setWhatsThis(i18n("Set this option to show image format over image thumbnail.")); d->iconShowCoordinatesBox = new QCheckBox(i18n("Show Geolocation Indicator"), iconViewGroup); d->iconShowCoordinatesBox->setWhatsThis(i18n("Set this option to indicate if image has geolocation information.")); d->iconShowTagsBox = new QCheckBox(i18n("Show digiKam &tags"), iconViewGroup); d->iconShowTagsBox->setWhatsThis(i18n("Set this option to show the digiKam tags " "below the image thumbnail.")); d->iconShowRatingBox = new QCheckBox(i18n("Show item &rating"), iconViewGroup); d->iconShowRatingBox->setWhatsThis(i18n("Set this option to show the item rating " "below the image thumbnail.")); d->iconShowOverlaysBox = new QCheckBox(i18n("Show rotation overlay buttons"), iconViewGroup); d->iconShowOverlaysBox->setWhatsThis(i18n("Set this option to show overlay buttons on " "the image thumbnail for image rotation.")); QLabel* const leftClickLabel = new QLabel(i18n("Thumbnail click action:"), iconViewGroup); d->leftClickActionComboBox = new QComboBox(iconViewGroup); d->leftClickActionComboBox->addItem(i18n("Show embedded preview"), ImportSettings::ShowPreview); d->leftClickActionComboBox->addItem(i18n("Start image editor"), ImportSettings::StartEditor); d->leftClickActionComboBox->setToolTip(i18n("Choose what should happen when you click on a thumbnail.")); d->iconViewFontSelect = new DFontSelect(i18n("Icon View font:"), panel); d->iconViewFontSelect->setToolTip(i18n("Select here the font used to display text in Icon Views.")); grid2->addWidget(d->iconShowNameBox, 0, 0, 1, 1); grid2->addWidget(d->iconShowSizeBox, 1, 0, 1, 1); grid2->addWidget(d->iconShowDateBox, 2, 0, 1, 1); grid2->addWidget(d->iconShowFormatBox, 3, 0, 1, 1); -// grid2->addWidget(d->iconShowResolutionBox, 4, 0, 1, 1); TODO - +/* + TODO + grid2->addWidget(d->iconShowResolutionBox, 4, 0, 1, 1); +*/ grid2->addWidget(d->iconShowTagsBox, 0, 1, 1, 1); grid2->addWidget(d->iconShowRatingBox, 1, 1, 1, 1); grid2->addWidget(d->iconShowOverlaysBox, 2, 1, 1, 1); grid2->addWidget(d->iconShowCoordinatesBox, 3, 1, 1, 1); grid2->addWidget(leftClickLabel, 5, 0, 1, 1); grid2->addWidget(d->leftClickActionComboBox, 5, 1, 1, 1); grid2->addWidget(d->iconViewFontSelect, 6, 0, 1, 2); grid2->setContentsMargins(spacing, spacing, spacing, spacing); grid2->setSpacing(spacing); // -------------------------------------------------------- QGroupBox* const interfaceOptionsGroup = new QGroupBox(i18n("Preview Options"), panel4); QGridLayout* const grid3 = new QGridLayout(interfaceOptionsGroup); d->previewLoadFullImageSize = new QCheckBox(i18n("Embedded preview loads full-sized images"), interfaceOptionsGroup); d->previewLoadFullImageSize->setWhatsThis(i18n("

Set this option to load images at their full size " "for preview, rather than at a reduced size. As this option " "will make it take longer to load images, only use it if you have " "a fast computer.

" "

Note: for Raw images, a half size version of the Raw data " "is used instead of the embedded JPEG preview.

")); d->previewItemsWhileDownload = new QCheckBox(i18n("Preview each item while downloading it"), interfaceOptionsGroup); d->previewItemsWhileDownload->setWhatsThis(i18n("

Set this option to preview each item while downloading.

")); d->previewShowIcons = new QCheckBox(i18n("Show icons and text over preview"), interfaceOptionsGroup); d->previewShowIcons->setWhatsThis(i18n("Uncheck this if you do not want to see icons and text in the image preview.")); grid3->setContentsMargins(spacing, spacing, spacing, spacing); grid3->setSpacing(spacing); grid3->addWidget(d->previewLoadFullImageSize, 0, 0, 1, 2); grid3->addWidget(d->previewItemsWhileDownload, 1, 0, 1, 2); grid3->addWidget(d->previewShowIcons, 2, 0, 1, 2); // -------------------------------------------------------- d->fullScreenSettings = new FullScreenSettings(FS_IMPORTUI, panel4); layout2->setContentsMargins(QMargins()); layout2->setSpacing(spacing); layout2->addWidget(iconViewGroup); layout2->addWidget(interfaceOptionsGroup); layout2->addWidget(d->fullScreenSettings); layout2->addStretch(); d->tab->insertTab(3, panel4, i18n("Import Window")); // ------------------------------------------------------------- adjustSize(); // ------------------------------------------------------------- connect(d->listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged())); connect(d->addButton, SIGNAL(clicked()), this, SLOT(slotAddCamera())); connect(d->removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveCamera())); connect(d->editButton, SIGNAL(clicked()), this, SLOT(slotEditCamera())); connect(d->autoDetectButton, SIGNAL(clicked()), this, SLOT(slotAutoDetectCamera())); connect(d->useDefaultTargetAlbum, SIGNAL(toggled(bool)), d->target1AlbumSelector, SLOT(setEnabled(bool))); connect(d->previewItemsWhileDownload, SIGNAL(clicked()), this, SLOT(slotPreviewItemsClicked())); connect(d->previewLoadFullImageSize, SIGNAL(clicked()), this, SLOT(slotPreviewFullImageSizeClicked())); // ------------------------------------------------------------- connect(d->importListView, SIGNAL(itemSelectionChanged()), this, SLOT(slotImportSelectionChanged())); connect(d->importAddButton, SIGNAL(clicked()), this, SLOT(slotAddFilter())); connect(d->importRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveFilter())); connect(d->importEditButton, SIGNAL(clicked()), this, SLOT(slotEditFilter())); // ------------------------------------------------------------- connect(d->useFileMetadata, SIGNAL(toggled(bool)), this, SIGNAL(signalUseFileMetadataChanged(bool))); // ------------------------------------------------------------- readSettings(); } SetupCamera::~SetupCamera() { delete d; } bool SetupCamera::useFileMetadata() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); return (group.readEntry(d->configUseFileMetadata, false)); } void SetupCamera::readSettings() { // Populate cameras -------------------------------------- CameraList* const clist = CameraList::defaultList(); if (clist) { QList* const cl = clist->cameraList(); foreach (CameraType* const ctype, *cl) { new SetupCameraItem(d->listView, ctype); } } // ------------------------------------------------------- KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); d->useFileMetadata->setChecked(useFileMetadata()); d->turnHighQualityThumbs->setChecked(group.readEntry(d->configTrunHighQualityThumbs, false)); d->useDefaultTargetAlbum->setChecked(group.readEntry(d->configUseDefaultTargetAlbum, false)); PAlbum* const album = AlbumManager::instance()->findPAlbum(group.readEntry(d->configDefaultTargetAlbumId, 0)); d->target1AlbumSelector->setCurrentAlbum(album); d->target1AlbumSelector->setEnabled(d->useDefaultTargetAlbum->isChecked()); d->conflictButtonGroup->button(group.readEntry(d->configFileSaveConflictRule, (int)DIFFNAME))->setChecked(true); d->fullScreenSettings->readSettings(group); // ------------------------------------------------------- KConfigGroup importGroup = config->group(d->importFiltersConfigGroupName); - for (int i = 0; true; ++i) + for (int i = 0 ; true ; ++i) { QString filter = importGroup.readEntry(QString::fromUtf8("Filter%1").arg(i), QString()); if (filter.isEmpty()) { break; } Filter* const f = new Filter; f->fromString(filter); d->filters.append(f); } ImportFilterComboBox::defaultFilters(&d->filters); foreach (Filter* const f, d->filters) { new QListWidgetItem(f->name, d->importListView); } d->importListView->sortItems(); d->ignoreNamesEdit->setText(importGroup.readEntry(QLatin1String("IgnoreNames"), ImportFilterComboBox::defaultIgnoreNames)); d->ignoreExtensionsEdit->setText(importGroup.readEntry(QLatin1String("IgnoreExtensions"), ImportFilterComboBox::defaultIgnoreExtensions)); ImportSettings* const settings = ImportSettings::instance(); if (!settings) { return; } d->iconShowNameBox->setChecked(settings->getIconShowName()); d->iconShowTagsBox->setChecked(settings->getIconShowTags()); d->iconShowSizeBox->setChecked(settings->getIconShowSize()); d->iconShowDateBox->setChecked(settings->getIconShowDate()); - //TODO: d->iconShowResolutionBox->setChecked(settings->getIconShowResolution()); +/* + TODO + d->iconShowResolutionBox->setChecked(settings->getIconShowResolution()); +*/ d->iconShowOverlaysBox->setChecked(settings->getIconShowOverlays()); d->iconShowRatingBox->setChecked(settings->getIconShowRating()); d->iconShowFormatBox->setChecked(settings->getIconShowImageFormat()); d->iconShowCoordinatesBox->setChecked(settings->getIconShowCoordinates()); d->iconViewFontSelect->setFont(settings->getIconViewFont()); d->leftClickActionComboBox->setCurrentIndex((int)settings->getItemLeftClickAction()); d->previewLoadFullImageSize->setChecked(settings->getPreviewLoadFullImageSize()); d->previewItemsWhileDownload->setChecked(settings->getPreviewItemsWhileDownload()); d->previewShowIcons->setChecked(settings->getPreviewShowIcons()); } void SetupCamera::applySettings() { // Save camera devices ----------------------------------- CameraList* const clist = CameraList::defaultList(); if (clist) { clist->clear(); QTreeWidgetItemIterator it(d->listView); while (*it) { SetupCameraItem* const item = dynamic_cast(*it); if (item) { CameraType* const ctype = item->cameraType(); if (ctype) { clist->insert(new CameraType(*ctype)); } } ++it; } clist->save(); } // ------------------------------------------------------- KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); group.writeEntry(d->configUseFileMetadata, d->useFileMetadata->isChecked()); group.writeEntry(d->configTrunHighQualityThumbs, d->turnHighQualityThumbs->isChecked()); group.writeEntry(d->configUseDefaultTargetAlbum, d->useDefaultTargetAlbum->isChecked()); PAlbum* const album = d->target1AlbumSelector->currentAlbum(); group.writeEntry(d->configDefaultTargetAlbumId, album ? album->id() : 0); group.writeEntry(d->configFileSaveConflictRule, d->conflictButtonGroup->checkedId()); d->fullScreenSettings->saveSettings(group); group.sync(); // ------------------------------------------------------- KConfigGroup importGroup = config->group(d->importFiltersConfigGroupName); importGroup.deleteGroup(); - for (int i = 0; i < d->filters.count(); ++i) + for (int i = 0 ; i < d->filters.count() ; ++i) { importGroup.writeEntry(QString::fromUtf8("Filter%1").arg(i), d->filters[i]->toString()); } importGroup.writeEntry(QLatin1String("IgnoreNames"), d->ignoreNamesEdit->text()); importGroup.writeEntry(QLatin1String("IgnoreExtensions"), d->ignoreExtensionsEdit->text()); importGroup.sync(); ImportSettings* const settings = ImportSettings::instance(); if (!settings) { return; } settings->setIconShowName(d->iconShowNameBox->isChecked()); settings->setIconShowTags(d->iconShowTagsBox->isChecked()); settings->setIconShowSize(d->iconShowSizeBox->isChecked()); settings->setIconShowDate(d->iconShowDateBox->isChecked()); - //TODO: settings->setIconShowResolution(d->iconShowResolutionBox->isChecked()); +/* + TODO + settings->setIconShowResolution(d->iconShowResolutionBox->isChecked()); +*/ settings->setIconShowOverlays(d->iconShowOverlaysBox->isChecked()); settings->setIconShowRating(d->iconShowRatingBox->isChecked()); settings->setIconShowImageFormat(d->iconShowFormatBox->isChecked()); settings->setIconShowCoordinates(d->iconShowCoordinatesBox->isChecked()); settings->setIconViewFont(d->iconViewFontSelect->font()); settings->setItemLeftClickAction((ImportSettings::ItemLeftClickAction) d->leftClickActionComboBox->currentIndex()); settings->setPreviewLoadFullImageSize(d->previewLoadFullImageSize->isChecked()); settings->setPreviewItemsWhileDownload(d->previewItemsWhileDownload->isChecked()); settings->setPreviewShowIcons(d->previewShowIcons->isChecked()); settings->saveSettings(); } bool SetupCamera::checkSettings() { if (d->useDefaultTargetAlbum->isChecked() && !d->target1AlbumSelector->currentAlbum()) { d->tab->setCurrentIndex(1); QMessageBox::information(this, qApp->applicationName(), i18n("No default target album have been selected to process download " "from camera device. Please select one.")); return false; } return true; } void SetupCamera::slotSelectionChanged() { QTreeWidgetItem* const item = d->listView->currentItem(); if (!item) { d->removeButton->setEnabled(false); d->editButton->setEnabled(false); return; } d->removeButton->setEnabled(true); d->editButton->setEnabled(true); } void SetupCamera::slotAddCamera() { CameraSelection* const select = new CameraSelection; connect(select, SIGNAL(signalOkClicked(QString,QString,QString,QString)), this, SLOT(slotAddedCamera(QString,QString,QString,QString))); select->show(); } void SetupCamera::slotAddedCamera(const QString& title, const QString& model, const QString& port, const QString& path) { CameraType ctype(title, model, port, path, 1); new SetupCameraItem(d->listView, &ctype); } void SetupCamera::slotRemoveCamera() { SetupCameraItem* const item = dynamic_cast(d->listView->currentItem()); delete item; } void SetupCamera::slotEditCamera() { SetupCameraItem* const item = dynamic_cast(d->listView->currentItem()); if (!item) { return; } CameraType* const ctype = item->cameraType(); if (!ctype) { return; } CameraSelection* const select = new CameraSelection; select->setCamera(ctype->title(), ctype->model(), ctype->port(), ctype->path()); connect(select, SIGNAL(signalOkClicked(QString,QString,QString,QString)), this, SLOT(slotEditedCamera(QString,QString,QString,QString))); select->show(); } void SetupCamera::slotEditedCamera(const QString& title, const QString& model, const QString& port, const QString& path) { SetupCameraItem* const item = dynamic_cast(d->listView->currentItem()); if (!item) { return; } CameraType ctype(title, model, port, path, 1); item->setCameraType(&ctype); } void SetupCamera::slotAutoDetectCamera() { DBusyDlg* const dlg = new DBusyDlg(i18n("Device detection under progress, please wait..."), this); CameraAutoDetectThread* const thread = new CameraAutoDetectThread(this); dlg->setBusyThread(thread); dlg->exec(); QString model = thread->model(); QString port = thread->port(); int ret = thread->result(); if (ret != 0) { QMessageBox::critical(this, qApp->applicationName(), i18n("Failed to auto-detect camera.\n" "Please check if your camera is turned on " "and retry or try setting it manually.")); return; } // NOTE: See note in digikam/digikam/cameralist.cpp + if (port.startsWith(QLatin1String("usb:"))) { port = QLatin1String("usb:"); } if (!d->listView->findItems(model, Qt::MatchExactly, 1).isEmpty()) { QMessageBox::information(this, qApp->applicationName(), i18n("Camera '%1' (%2) is already in list.", model, port)); } else { QMessageBox::information(this, qApp->applicationName(), i18n("Found camera '%1' (%2) and added it to the list.", model, port)); slotAddedCamera(model, model, port, QLatin1String("/")); } } void SetupCamera::slotImportSelectionChanged() { QListWidgetItem* const item = d->importListView->currentItem(); d->importRemoveButton->setEnabled(item); d->importEditButton->setEnabled(item); } void SetupCamera::slotAddFilter() { Filter filter; filter.name = i18n("Untitled"); QPointer dlg = new ImportFilterDlg(this); dlg->setData(filter); if (dlg->exec() == QDialog::Accepted) { Filter* const f = new Filter; dlg->getData(f); d->filters.append(f); new QListWidgetItem(f->name, d->importListView); } delete dlg; slotImportSelectionChanged(); } void SetupCamera::slotRemoveFilter() { QListWidgetItem* const item = d->importListView->currentItem(); int current = d->importListView->currentRow(); for (int i = 0 ; i < d->filters.count() ; ++i) { if (d->filters.at(i)->name == item->text()) { delete d->filters.takeAt(i); delete d->importListView->takeItem(current); slotImportSelectionChanged(); break; } } } void SetupCamera::slotEditFilter() { QListWidgetItem* const item = d->importListView->currentItem(); for (int i = 0 ; i < d->filters.count() ; ++i) { if (d->filters.at(i)->name == item->text()) { Filter filter = *d->filters.at(i); QPointer dlg = new ImportFilterDlg(this); dlg->setData(filter); if (dlg->exec() == QDialog::Accepted) { Filter* const f = d->filters.at(i); dlg->getData(f); item->setText(f->name); } delete dlg; break; } } } void SetupCamera::slotPreviewItemsClicked() { if (d->previewItemsWhileDownload->isChecked() && d->previewLoadFullImageSize->isChecked()) { - QMessageBox::information(this, qApp->applicationName(), i18n("In order to enable this feature, the full-sized preview will be disabled.")); + QMessageBox::information(this, qApp->applicationName(), + i18n("In order to enable this feature, the full-sized preview will be disabled.")); d->previewLoadFullImageSize->setChecked(false); } } void SetupCamera::slotPreviewFullImageSizeClicked() { if (d->previewItemsWhileDownload->isChecked() && d->previewLoadFullImageSize) { - QMessageBox::information(this, qApp->applicationName(), i18n("If the full-sized preview is enabled it will affect the speed of previewing each item while download.")); + QMessageBox::information(this, qApp->applicationName(), + i18n("If the full-sized preview is enabled it will affect the speed of previewing each item while download.")); + d->previewItemsWhileDownload->setChecked(false); } } } // namespace Digikam diff --git a/core/utilities/setup/collections/dwitemdelegate.cpp b/core/utilities/setup/collections/dwitemdelegate.cpp index c9f252f927..6143fc12e9 100644 --- a/core/utilities/setup/collections/dwitemdelegate.cpp +++ b/core/utilities/setup/collections/dwitemdelegate.cpp @@ -1,110 +1,110 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-15 * Description : widget item delegate for setup collection view * - * Copyright (C) 2015 by Gilles Caulier + * Copyright (C) 2015-2020 by Gilles Caulier * Copyright (C) 2007-2008 by Rafael Fernández López * Copyright (C) 2008 by Kevin Ottens * * 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 "dwitemdelegate.h" #include "dwitemdelegate_p.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include // Local includes #include "dwitemdelegatepool.h" namespace Digikam { DWItemDelegate::DWItemDelegate(QAbstractItemView* const itemView, QObject* const parent) : QAbstractItemDelegate(parent), d(new DWItemDelegatePrivate(this)) { Q_ASSERT(itemView); itemView->setMouseTracking(true); itemView->viewport()->setAttribute(Qt::WA_Hover); d->itemView = itemView; itemView->viewport()->installEventFilter(d); // mouse events itemView->installEventFilter(d); // keyboard events if (qobject_cast(itemView)) { connect(itemView, SIGNAL(collapsed(QModelIndex)), d, SLOT(initializeModel())); connect(itemView, SIGNAL(expanded(QModelIndex)), d, SLOT(initializeModel())); } } DWItemDelegate::~DWItemDelegate() { delete d; } QAbstractItemView* DWItemDelegate::itemView() const { return d->itemView; } QPersistentModelIndex DWItemDelegate::focusedIndex() const { const QPersistentModelIndex idx = d->widgetPool->d->widgetInIndex.value(QApplication::focusWidget()); if (idx.isValid()) { return idx; } // Use the mouse position, if the widget refused to take keyboard focus. + const QPoint pos = d->itemView->viewport()->mapFromGlobal(QCursor::pos()); return d->itemView->indexAt(pos); } void DWItemDelegate::setBlockedEventTypes(QWidget* const widget, QList types) const { widget->setProperty("DigiKam:blockedEventTypes", qVariantFromValue(types)); } QList DWItemDelegate::blockedEventTypes(QWidget* const widget) const { return widget->property("Digikam:blockedEventTypes").value >(); } } // namespace Digikam diff --git a/core/utilities/setup/collections/dwitemdelegate.h b/core/utilities/setup/collections/dwitemdelegate.h index 86ca5744cd..4ecf673d7f 100644 --- a/core/utilities/setup/collections/dwitemdelegate.h +++ b/core/utilities/setup/collections/dwitemdelegate.h @@ -1,167 +1,168 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-15 * Description : widget item delegate for setup collection view * - * Copyright (C) 2015 by Gilles Caulier + * Copyright (C) 2015-2020 by Gilles Caulier * Copyright (C) 2007-2008 by Rafael Fernández López * Copyright (C) 2008 by Kevin Ottens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DW_ITEM_DELEGATE_H #define DIGIKAM_DW_ITEM_DELEGATE_H // Qt includes #include #include #include #include // Local includes #include "dwitemdelegate_p.h" #include "digikam_export.h" class QObject; class QPainter; class QStyleOption; class QStyleOptionViewItem; class QAbstractItemView; class QItemSelection; namespace Digikam { class DWItemDelegatePool; class DWItemDelegatePrivate; /** * This class allows to create item delegates embedding simple widgets to interact * with items. For instance you can add push buttons, line edits, etc. to your delegate * and use them to modify the state of your model. */ class DIGIKAM_EXPORT DWItemDelegate : public QAbstractItemDelegate { Q_OBJECT public: + /** * Creates a new ItemDelegate to be used with a given itemview. * * @param itemView the item view the new delegate will monitor * @param parent the parent of this delegate */ explicit DWItemDelegate(QAbstractItemView* const itemView, QObject* const parent = nullptr); virtual ~DWItemDelegate(); /** * Retrieves the item view this delegate is monitoring. * * @return the item view this delegate is monitoring */ QAbstractItemView* itemView() const; /** * Retrieves the currently focused index. An invalid index if none is focused. * * @return the current focused index, or QPersistentModelIndex() if none is focused. */ QPersistentModelIndex focusedIndex() const; protected: /** * Creates the list of widgets needed for an item. * * @note No initialization of the widgets is supposed to happen here. * The widgets will be initialized based on needs for a given item. * * @note If you want to connect some widget signals to any slot, you should * do it here. * * @arg index the index to create widgets for. * * @note If you want to know the index for which you are creating widgets, it is * available as a QModelIndex Q_PROPERTY called "goya:creatingWidgetsForIndex". * Ensure to add Q_DECLARE_METATYPE(QModelIndex) before your method definition * to tell QVariant about QModelIndex. * * @return the list of newly created widgets which will be used to interact with an item. * @see updateItemWidgets() */ virtual QList createItemWidgets(const QModelIndex& index) const = 0; /** * Updates a list of widgets for its use inside of the delegate (painting or * event handling). * * @note All the positioning and sizing should be done in item coordinates. * * @warning Do not make widget connections in here, since this method will * be called very regularly. * * @param widgets the widgets to update * @param option the current set of style options for the view. * @param index the model index of the item currently manipulated. */ virtual void updateItemWidgets(const QList widgets, const QStyleOptionViewItem& option, const QPersistentModelIndex& index) const = 0; /** * Sets the list of event @p types that a @p widget will block. * * Blocked events are not passed to the view. This way you can prevent an item * from being selected when a button is clicked for instance. * * @param widget the widget which must block events * @param types the list of event types the widget must block */ void setBlockedEventTypes(QWidget* const widget, QList types) const; /** * Retrieves the list of blocked event types for the given widget. * * @param widget the specified widget. * * @return the list of blocked event types, can be empty if no events are blocked. */ QList blockedEventTypes(QWidget* const widget) const; private: friend class DWItemDelegatePool; friend class DWItemDelegateEventListener; DWItemDelegatePrivate* const d; Q_PRIVATE_SLOT(d, void slotDWRowsInserted(const QModelIndex&,int,int)) Q_PRIVATE_SLOT(d, void slotDWRowsAboutToBeRemoved(const QModelIndex&,int,int)) Q_PRIVATE_SLOT(d, void slotDWRowsRemoved(const QModelIndex&,int,int)) Q_PRIVATE_SLOT(d, void slotDWDataChanged(const QModelIndex&,const QModelIndex&)) Q_PRIVATE_SLOT(d, void slotDWLayoutChanged()) Q_PRIVATE_SLOT(d, void slotDWModelReset()) Q_PRIVATE_SLOT(d, void slotDWSelectionChanged(const QItemSelection&,const QItemSelection&)) }; } // namespace Digikam Q_DECLARE_METATYPE(QList) #endif // DIGIKAM_DW_ITEM_DELEGATE_H diff --git a/core/utilities/setup/collections/dwitemdelegate_p.cpp b/core/utilities/setup/collections/dwitemdelegate_p.cpp index a6bb7b3e80..d2286a3888 100644 --- a/core/utilities/setup/collections/dwitemdelegate_p.cpp +++ b/core/utilities/setup/collections/dwitemdelegate_p.cpp @@ -1,316 +1,329 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-15 * Description : widget item delegate for setup collection view * - * Copyright (C) 2015 by Gilles Caulier + * Copyright (C) 2015-2020 by Gilles Caulier * Copyright (C) 2007-2008 by Rafael Fernández López * Copyright (C) 2008 by Kevin Ottens * * 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 "dwitemdelegate_p.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Local includes #include "dwitemdelegatepool.h" namespace Digikam { DWItemDelegatePrivate::DWItemDelegatePrivate(DWItemDelegate* const q, QObject* const parent) : QObject(parent), itemView(nullptr), widgetPool(new DWItemDelegatePool(q)), model(nullptr), selectionModel(nullptr), viewDestroyed(false), q(q) { } DWItemDelegatePrivate::~DWItemDelegatePrivate() { if (!viewDestroyed) { widgetPool->fullClear(); } delete widgetPool; } void DWItemDelegatePrivate::slotDWRowsInserted(const QModelIndex& parent, int start, int end) { Q_UNUSED(end); + // We need to update the rows behind the inserted row as well because the widgets need to be // moved to their new position + updateRowRange(parent, start, model->rowCount(parent), false); } void DWItemDelegatePrivate::slotDWRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) { updateRowRange(parent, start, end, true); } void DWItemDelegatePrivate::slotDWRowsRemoved(const QModelIndex& parent, int start, int end) { Q_UNUSED(end); + // We need to update the rows that come behind the deleted rows because the widgets need to be // moved to the new position + updateRowRange(parent, start, model->rowCount(parent), false); } void DWItemDelegatePrivate::slotDWDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { - for (int i = topLeft.row(); i <= bottomRight.row(); ++i) + for (int i = topLeft.row() ; i <= bottomRight.row() ; ++i) { - for (int j = topLeft.column(); j <= bottomRight.column(); ++j) + for (int j = topLeft.column() ; j <= bottomRight.column() ; ++j) { const QModelIndex index = model->index(i, j, topLeft.parent()); widgetPool->findWidgets(index, optionView(index)); } } } void DWItemDelegatePrivate::slotDWLayoutChanged() { foreach (QWidget* const widget, widgetPool->invalidIndexesWidgets()) { widget->setVisible(false); } QTimer::singleShot(0, this, SLOT(initializeModel())); } void DWItemDelegatePrivate::slotDWModelReset() { widgetPool->fullClear(); QTimer::singleShot(0, this, SLOT(initializeModel())); } void DWItemDelegatePrivate::slotDWSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { foreach (const QModelIndex& index, selected.indexes()) { widgetPool->findWidgets(index, optionView(index)); } foreach (const QModelIndex& index, deselected.indexes()) { widgetPool->findWidgets(index, optionView(index)); } } void DWItemDelegatePrivate::updateRowRange(const QModelIndex& parent, int start, int end, bool isRemoving) { int i = start; while (i <= end) { - for (int j = 0; j < model->columnCount(parent); ++j) + for (int j = 0 ; j < model->columnCount(parent) ; ++j) { const QModelIndex index = model->index(i, j, parent); QList widgetList = widgetPool->findWidgets(index, optionView(index), isRemoving ? DWItemDelegatePool::NotUpdateWidgets : DWItemDelegatePool::UpdateWidgets); if (isRemoving) { widgetPool->d->allocatedWidgets.removeAll(widgetList); foreach (QWidget* const widget, widgetList) { const QModelIndex idx = widgetPool->d->widgetInIndex[widget]; widgetPool->d->usedWidgets.remove(idx); widgetPool->d->widgetInIndex.remove(widget); delete widget; } } } i++; } } inline QStyleOptionViewItem DWItemDelegatePrivate::optionView(const QModelIndex& index) { QStyleOptionViewItem optionView; optionView.initFrom(itemView->viewport()); optionView.rect = itemView->visualRect(index); optionView.decorationSize = itemView->iconSize(); + return optionView; } void DWItemDelegatePrivate::initializeModel(const QModelIndex& parent) { if (!model) { return; } - for (int i = 0; i < model->rowCount(parent); ++i) + for (int i = 0 ; i < model->rowCount(parent) ; ++i) { - for (int j = 0; j < model->columnCount(parent); ++j) + for (int j = 0 ; j < model->columnCount(parent) ; ++j) { const QModelIndex index = model->index(i, j, parent); if (index.isValid()) { widgetPool->findWidgets(index, optionView(index)); } } + // Check if we need to go recursively through the children of parent (if any) to initialize // all possible indexes that are shown. + const QModelIndex index = model->index(i, 0, parent); if (index.isValid() && model->hasChildren(index)) { initializeModel(index); } } } bool DWItemDelegatePrivate::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Destroy) { // we care for the view since it deletes the widgets (parentage). // if the view hasn't been deleted, it might be that just the // delegate is removed from it, in which case we need to remove the widgets // manually, otherwise they still get drawn. + if (watched == itemView) { viewDestroyed = true; } return false; } Q_ASSERT(itemView); if (model != itemView->model()) { if (model) { disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(slotDWRowsInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), q, SLOT(slotDWRowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), q, SLOT(slotDWRowsRemoved(QModelIndex,int,int))); disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(slotDWDataChanged(QModelIndex,QModelIndex))); disconnect(model, SIGNAL(layoutChanged()), q, SLOT(slotDWLayoutChanged())); disconnect(model, SIGNAL(modelReset()), q, SLOT(slotDWModelReset())); } model = itemView->model(); connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), q, SLOT(slotDWRowsInserted(QModelIndex,int,int))); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), q, SLOT(slotDWRowsAboutToBeRemoved(QModelIndex,int,int))); connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), q, SLOT(slotDWRowsRemoved(QModelIndex,int,int))); connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), q, SLOT(slotDWDataChanged(QModelIndex,QModelIndex))); connect(model, SIGNAL(layoutChanged()), q, SLOT(slotDWLayoutChanged())); connect(model, SIGNAL(modelReset()), q, SLOT(slotDWModelReset())); QTimer::singleShot(0, this, SLOT(initializeModel())); } if (selectionModel != itemView->selectionModel()) { if (selectionModel) { disconnect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotDWSelectionChanged(QItemSelection,QItemSelection))); } selectionModel = itemView->selectionModel(); connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), q, SLOT(slotDWSelectionChanged(QItemSelection,QItemSelection))); QTimer::singleShot(0, this, SLOT(initializeModel())); } switch (event->type()) { case QEvent::Polish: case QEvent::Resize: + if (!qobject_cast(watched)) { QTimer::singleShot(0, this, SLOT(initializeModel())); } + break; + case QEvent::FocusIn: case QEvent::FocusOut: + if (qobject_cast(watched)) { foreach (const QModelIndex& index, selectionModel->selectedIndexes()) { if (index.isValid()) { widgetPool->findWidgets(index, optionView(index)); } } } + default: break; } return QObject::eventFilter(watched, event); } } // namespace Digikam diff --git a/core/utilities/setup/collections/dwitemdelegate_p.h b/core/utilities/setup/collections/dwitemdelegate_p.h index 932dec603d..35897ce59f 100644 --- a/core/utilities/setup/collections/dwitemdelegate_p.h +++ b/core/utilities/setup/collections/dwitemdelegate_p.h @@ -1,84 +1,82 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-15 * Description : widget item delegate for setup collection view * - * Copyright (C) 2015 by Gilles Caulier + * Copyright (C) 2015-2020 by Gilles Caulier * Copyright (C) 2007-2008 by Rafael Fernández López * Copyright (C) 2008 by Kevin Ottens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DW_ITEM_DELEGATE_PRIVATE_H #define DIGIKAM_DW_ITEM_DELEGATE_PRIVATE_H +#include "dwitemdelegate.h" + // Qt includes #include #include -// Local includes - -#include "dwitemdelegate.h" - namespace Digikam { class DWItemDelegate; class DWItemDelegatePool; class Q_DECL_HIDDEN DWItemDelegatePrivate : public QObject { Q_OBJECT public: explicit DWItemDelegatePrivate(DWItemDelegate* const q, QObject* const parent = nullptr); ~DWItemDelegatePrivate(); void updateRowRange(const QModelIndex& parent, int start, int end, bool isRemoving); QStyleOptionViewItem optionView(const QModelIndex& index); public Q_SLOTS: void initializeModel(const QModelIndex& parent = QModelIndex()); void slotDWRowsInserted(const QModelIndex& parent, int start, int end); void slotDWRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end); void slotDWRowsRemoved(const QModelIndex& parent, int start, int end); void slotDWDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); void slotDWLayoutChanged(); void slotDWModelReset(); void slotDWSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); protected: virtual bool eventFilter(QObject* watched, QEvent* event); public: QAbstractItemView* itemView; DWItemDelegatePool* widgetPool; QAbstractItemModel* model; QItemSelectionModel* selectionModel; bool viewDestroyed; DWItemDelegate* q; }; } // namespace Digikam #endif // DIGIKAM_DW_ITEM_DELEGATE_PRIVATE_H diff --git a/core/utilities/setup/collections/dwitemdelegatepool.cpp b/core/utilities/setup/collections/dwitemdelegatepool.cpp index c397924ec8..1dbd33f5b2 100644 --- a/core/utilities/setup/collections/dwitemdelegatepool.cpp +++ b/core/utilities/setup/collections/dwitemdelegatepool.cpp @@ -1,261 +1,262 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-15 * Description : widget item delegate for setup collection view * - * Copyright (C) 2015 by Gilles Caulier + * Copyright (C) 2015-2020 by Gilles Caulier * Copyright (C) 2007-2008 by Rafael Fernández López * Copyright (C) 2008 by Kevin Ottens * * 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 "dwitemdelegatepool.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // Local includes #include "digikam_debug.h" #include "dwitemdelegate.h" #include "dwitemdelegate_p.h" namespace Digikam { class Q_DECL_HIDDEN DWItemDelegateEventListener : public QObject { public: DWItemDelegateEventListener(DWItemDelegatePoolPrivate* const poolPrivate, QObject* const parent = nullptr) : QObject(parent), poolPrivate(poolPrivate) { } virtual bool eventFilter(QObject* watched, QEvent* event); private: DWItemDelegatePoolPrivate* poolPrivate; }; // ------------------------------------------------------------------------------------------- DWItemDelegatePoolPrivate::DWItemDelegatePoolPrivate(DWItemDelegate* const d) : delegate(d), eventListener(new DWItemDelegateEventListener(this)), clearing(false) { } // ------------------------------------------------------------------------------------------- DWItemDelegatePool::DWItemDelegatePool(DWItemDelegate* const delegate) : d(new DWItemDelegatePoolPrivate(delegate)) { } DWItemDelegatePool::~DWItemDelegatePool() { delete d->eventListener; delete d; } QList DWItemDelegatePool::findWidgets(const QPersistentModelIndex& idx, const QStyleOptionViewItem& option, UpdateWidgetsEnum updateWidgets) const { QList result; if (!idx.isValid()) { return result; } QModelIndex index; if (const QAbstractProxyModel* proxyModel = qobject_cast(idx.model())) { index = proxyModel->mapToSource(idx); } else { index = idx; } if (!index.isValid()) { return result; } if (d->usedWidgets.contains(index)) { result = d->usedWidgets[index]; } else { result = d->delegate->createItemWidgets(index); d->allocatedWidgets << result; d->usedWidgets[index] = result; foreach (QWidget* const widget, result) { d->widgetInIndex[widget] = index; widget->setParent(d->delegate->d->itemView); widget->installEventFilter(d->eventListener); widget->setVisible(true); } } if (updateWidgets == UpdateWidgets) { foreach (QWidget* const widget, result) { widget->setVisible(true); } d->delegate->updateItemWidgets(result, option, idx); foreach (QWidget* const widget, result) { widget->move(widget->x() + option.rect.left(), widget->y() + option.rect.top()); } } return result; } QList DWItemDelegatePool::invalidIndexesWidgets() const { QList result; foreach (QWidget* const widget, d->widgetInIndex.keys()) { const QAbstractProxyModel* const proxyModel = qobject_cast(d->delegate->d->model); QModelIndex index; if (proxyModel) { index = proxyModel->mapFromSource(d->widgetInIndex[widget]); } else { index = d->widgetInIndex[widget]; } if (!index.isValid()) { result << widget; } } return result; } void DWItemDelegatePool::fullClear() { d->clearing = true; qDeleteAll(d->widgetInIndex.keys()); d->clearing = false; d->allocatedWidgets.clear(); d->usedWidgets.clear(); d->widgetInIndex.clear(); } bool DWItemDelegateEventListener::eventFilter(QObject* watched, QEvent* event) { QWidget* const widget = static_cast(watched); if (event->type() == QEvent::Destroy && !poolPrivate->clearing) { qCWarning(DIGIKAM_GENERAL_LOG) << "User of DWItemDelegate should not delete widgets created by createItemWidgets!"; // assume the application has kept a list of widgets and tries to delete them manually // they have been reparented to the view in any case, so no leaking occurs + poolPrivate->widgetInIndex.remove(widget); QWidget* const viewport = poolPrivate->delegate->d->itemView->viewport(); QApplication::sendEvent(viewport, event); } if (dynamic_cast(event) && !poolPrivate->delegate->blockedEventTypes(widget).contains(event->type())) { QWidget* const viewport = poolPrivate->delegate->d->itemView->viewport(); switch (event->type()) { case QEvent::MouseMove: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: { QMouseEvent* const mouseEvent = static_cast(event); QMouseEvent evt(event->type(), viewport->mapFromGlobal(mouseEvent->globalPos()), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); QApplication::sendEvent(viewport, &evt); break; } case QEvent::Wheel: { QWheelEvent* const wheelEvent = static_cast(event); QWheelEvent evt(viewport->mapFromGlobal(wheelEvent->globalPos()), wheelEvent->delta(), wheelEvent->buttons(), wheelEvent->modifiers(), wheelEvent->orientation()); QApplication::sendEvent(viewport, &evt); break; } case QEvent::TabletMove: case QEvent::TabletPress: case QEvent::TabletRelease: case QEvent::TabletEnterProximity: case QEvent::TabletLeaveProximity: { QTabletEvent* const tabletEvent = static_cast(event); QTabletEvent evt(event->type(), QPointF(viewport->mapFromGlobal(tabletEvent->globalPos())), tabletEvent->globalPosF(), tabletEvent->device(), tabletEvent->pointerType(), tabletEvent->pressure(), tabletEvent->xTilt(), tabletEvent->yTilt(), tabletEvent->tangentialPressure(), tabletEvent->rotation(), tabletEvent->z(), tabletEvent->modifiers(), tabletEvent->uniqueId()); QApplication::sendEvent(viewport, &evt); break; } default: QApplication::sendEvent(viewport, event); break; } } return QObject::eventFilter(watched, event); } } // namespace Digikam diff --git a/core/utilities/setup/collections/dwitemdelegatepool.h b/core/utilities/setup/collections/dwitemdelegatepool.h index b0b96c2793..407c792d88 100644 --- a/core/utilities/setup/collections/dwitemdelegatepool.h +++ b/core/utilities/setup/collections/dwitemdelegatepool.h @@ -1,123 +1,123 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-15 * Description : widget item delegate for setup collection view * - * Copyright (C) 2015 by Gilles Caulier + * Copyright (C) 2015-2020 by Gilles Caulier * Copyright (C) 2007-2008 by Rafael Fernández López * Copyright (C) 2008 by Kevin Ottens * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_DW_ITEM_DELEGATE_POOL_H #define DIGIKAM_DW_ITEM_DELEGATE_POOL_H // Qt includes #include #include #include // Local includes #include "digikam_export.h" class QWidget; class QStyleOptionViewItem; namespace Digikam { class DWItemDelegate; class DWItemDelegatePoolPrivate; class DIGIKAM_EXPORT DWItemDelegatePool { public: enum UpdateWidgetsEnum { UpdateWidgets = 0, NotUpdateWidgets }; public: /** - * Creates a new ItemDelegatePool. - * - * @param delegate the ItemDelegate for this pool. - */ + * Creates a new ItemDelegatePool. + * + * @param delegate the ItemDelegate for this pool. + */ explicit DWItemDelegatePool(DWItemDelegate* const delegate); ~DWItemDelegatePool(); /** - * @brief Returns the widget associated to @p index and @p widget - * @param index The index to search into. - * @param option a QStyleOptionViewItem. - * @return A QList of the pointers to the widgets found. - * @internal - */ + * @brief Returns the widget associated to @p index and @p widget + * @param index The index to search into. + * @param option a QStyleOptionViewItem. + * @return A QList of the pointers to the widgets found. + * @internal + */ QList findWidgets(const QPersistentModelIndex& index, const QStyleOptionViewItem& option, UpdateWidgetsEnum updateWidgets = UpdateWidgets) const; QList invalidIndexesWidgets() const; void fullClear(); private: // Hidden copy constructor and assignment operator. DWItemDelegatePool(const DWItemDelegatePool&); DWItemDelegatePool& operator=(const DWItemDelegatePool&); friend class DWItemDelegate; friend class DWItemDelegatePrivate; DWItemDelegatePoolPrivate* const d; }; // ----------------------------------------------------------------------------------------------------------- class DWItemDelegateEventListener; class DWItemDelegatePoolPrivate { public: explicit DWItemDelegatePoolPrivate(DWItemDelegate* const d); public: DWItemDelegate* delegate; DWItemDelegateEventListener* eventListener; QList > allocatedWidgets; QHash > usedWidgets; QHash widgetInIndex; bool clearing; private: // Hidden copy constructor and assignment operator. DWItemDelegatePoolPrivate(const DWItemDelegatePoolPrivate&); DWItemDelegatePoolPrivate& operator=(const DWItemDelegatePoolPrivate&); }; } // namespace Digikam #endif // DIGIKAM_DW_ITEM_DELEGATE_POOL_H diff --git a/core/utilities/setup/collections/setupcollections.cpp b/core/utilities/setup/collections/setupcollections.cpp index 2ba0238deb..281046d6ec 100644 --- a/core/utilities/setup/collections/setupcollections.cpp +++ b/core/utilities/setup/collections/setupcollections.cpp @@ -1,148 +1,153 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-02-01 * Description : collections setup tab * * Copyright (C) 2005-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupcollections.h" // Qt includes #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "applicationsettings.h" #include "setupcollectionview.h" namespace Digikam { class Q_DECL_HIDDEN SetupCollections::Private { public: explicit Private() : rootsPathChanged(false), collectionView(nullptr), collectionModel(nullptr), monitoringBox(nullptr) { } bool rootsPathChanged; SetupCollectionTreeView* collectionView; SetupCollectionModel* collectionModel; QCheckBox* monitoringBox; }; SetupCollections::SetupCollections(QWidget* const parent) : QScrollArea(parent), d(new Private) { const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); QWidget* const panel = new QWidget; QVBoxLayout* const layout = new QVBoxLayout(panel); // -------------------------------------------------------- QGroupBox* const albumPathBox = new QGroupBox(i18n("Root Album Folders"), panel); #ifndef Q_OS_WIN + QLabel* const albumPathLabel = new QLabel(i18n("

Below are the locations of your root albums used to store " "your images. Write access is necessary to be able " "to edit images in these albums.

" "

Note: Removable media (such as USB drives or DVDs) and remote file systems " "(such as NFS, or Samba mounted with cifs/smbfs) are supported.

" "

Important: You need to mount the share natively on your system before to setup a remote collection.

" "

"), albumPathBox); + #else + QLabel* const albumPathLabel = new QLabel(i18n("

Below are the locations of your root albums used to store " "your images. Write access is necessary to be able " "to edit images in these albums.

" "

"), albumPathBox); + #endif + albumPathLabel->setWordWrap(true); d->collectionView = new SetupCollectionTreeView(albumPathBox); d->collectionModel = new SetupCollectionModel(panel); d->collectionView->setModel(d->collectionModel); d->monitoringBox = new QCheckBox(i18n("Monitor the albums for external changes (requires restart)"), panel); QVBoxLayout* const albumPathBoxLayout = new QVBoxLayout; albumPathBoxLayout->addWidget(albumPathLabel); albumPathBoxLayout->addWidget(d->collectionView); albumPathBoxLayout->addWidget(d->monitoringBox); albumPathBox->setLayout(albumPathBoxLayout); albumPathBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing); albumPathBoxLayout->setSpacing(0); // -------------------------------------------------------- layout->addWidget(albumPathBox); setWidget(panel); setWidgetResizable(true); // -------------------------------------------------------- readSettings(); adjustSize(); } SetupCollections::~SetupCollections() { delete d; } void SetupCollections::applySettings() { d->collectionModel->apply(); ApplicationSettings* const settings = ApplicationSettings::instance(); settings->setAlbumMonitoring(d->monitoringBox->isChecked()); } void SetupCollections::readSettings() { d->collectionModel->loadCollections(); ApplicationSettings* const settings = ApplicationSettings::instance(); d->monitoringBox->setChecked(settings->getAlbumMonitoring()); } } // namespace Digikam diff --git a/core/utilities/setup/collections/setupcollectionview.cpp b/core/utilities/setup/collections/setupcollectionview.cpp index 7223dff4f7..afd1602311 100644 --- a/core/utilities/setup/collections/setupcollectionview.cpp +++ b/core/utilities/setup/collections/setupcollectionview.cpp @@ -1,1320 +1,1384 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2008-11-15 * Description : collections setup tab model/view * * Copyright (C) 2008-2012 by Marcel Wiesweg * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2012 by Andi Clemens * * 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. * * ============================================================ */ #define INTERNALID 65535 #include "setupcollectionview.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dmessagebox.h" #include "dfiledialog.h" #include "applicationsettings.h" #include "collectionlocation.h" #include "collectionmanager.h" #include "newitemsfinder.h" namespace Digikam { SetupCollectionDelegate::SetupCollectionDelegate(QAbstractItemView* const view, QObject* const parent) : DWItemDelegate(view, parent), m_categoryMaxStyledWidth(0) { // We keep a standard delegate that does all the normal drawing work for us // DWItemDelegate handles the widgets, for the rest of the work we act as a proxy to m_styledDelegate + m_styledDelegate = new QStyledItemDelegate(parent); // forward all signals + connect(m_styledDelegate, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), this, SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint))); connect(m_styledDelegate, SIGNAL(commitData(QWidget*)), this, SIGNAL(commitData(QWidget*))); connect(m_styledDelegate, SIGNAL(sizeHintChanged(QModelIndex)), this, SIGNAL(sizeHintChanged(QModelIndex))); // For size hint. To get a valid size hint, the widgets seem to need a parent widget + m_samplePushButton = new QPushButton(view); m_samplePushButton->hide(); m_sampleUpdateButton = new QToolButton(view); m_sampleUpdateButton->hide(); m_sampleDeleteButton = new QToolButton(view); m_sampleDeleteButton->hide(); } SetupCollectionDelegate::~SetupCollectionDelegate() { } QList SetupCollectionDelegate::createItemWidgets(const QModelIndex& /*index*/) const { // We only need a push button for certain indexes and two tool button for others, // but we have no index here, but need to provide the widgets for each index QList list; QPushButton* const pushButton = new QPushButton(); list << pushButton; connect(pushButton, &QPushButton::clicked, this, [this, pushButton]() { emit categoryButtonPressed(pushButton->property("id").toInt()); }); QToolButton* const updateButton = new QToolButton(); updateButton->setAutoRaise(true); list << updateButton; connect(updateButton, &QToolButton::clicked, this, [this, updateButton]() { emit updatePressed(updateButton->property("id").toInt()); }); QToolButton* const deleteButton = new QToolButton(); deleteButton->setAutoRaise(true); list << deleteButton; connect(deleteButton, &QToolButton::clicked, this, [this, deleteButton]() { emit deletePressed(deleteButton->property("id").toInt()); }); return list; } QSize SetupCollectionDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { // get default size hint + QSize hint = m_styledDelegate->sizeHint(option, index); // We need to handle those two cases where we display widgets - if (index.data(SetupCollectionModel::IsCategoryRole).toBool()) + + if (index.data(SetupCollectionModel::IsCategoryRole).toBool()) { // get the largest size hint for the icon/text of all category entries + int maxStyledWidth = 0; foreach (const QModelIndex& catIndex, static_cast(index.model())->categoryIndexes()) { maxStyledWidth = qMax(maxStyledWidth, m_styledDelegate->sizeHint(option, catIndex).width()); } const_cast(this)->m_categoryMaxStyledWidth = maxStyledWidth; // set real text on sample button to compute correct size hint + m_samplePushButton->setText(index.data(SetupCollectionModel::CategoryButtonDisplayRole).toString()); QSize widgetHint = m_samplePushButton->sizeHint(); // add largest of the icon/text sizes (so that all buttons are aligned) and our button size hint + hint.setWidth(m_categoryMaxStyledWidth + widgetHint.width()); hint.setHeight(qMax(hint.height(), widgetHint.height())); } else if (index.data(SetupCollectionModel::IsUpdateRole).toBool()) { // set real pixmap on sample button to compute correct size hint + QIcon pix = index.data(SetupCollectionModel::UpdateDecorationRole).value(); m_sampleUpdateButton->setIcon(index.data(SetupCollectionModel::UpdateDecorationRole).value()); QSize widgetHint = m_sampleUpdateButton->sizeHint(); // combine hints + hint.setWidth(hint.width() + widgetHint.width()); hint.setHeight(qMax(hint.height(), widgetHint.height())); } else if (index.data(SetupCollectionModel::IsDeleteRole).toBool()) { // set real pixmap on sample button to compute correct size hint + QIcon pix = index.data(SetupCollectionModel::DeleteDecorationRole).value(); m_sampleDeleteButton->setIcon(index.data(SetupCollectionModel::DeleteDecorationRole).value()); QSize widgetHint = m_sampleDeleteButton->sizeHint(); // combine hints + hint.setWidth(hint.width() + widgetHint.width()); hint.setHeight(qMax(hint.height(), widgetHint.height())); } return hint; } void SetupCollectionDelegate::updateItemWidgets(const QList widgets, - const QStyleOptionViewItem& option, const QPersistentModelIndex& index) const + const QStyleOptionViewItem& option, + const QPersistentModelIndex& index) const { QPushButton* const pushButton = static_cast(widgets.at(0)); QToolButton* const updateButton = static_cast(widgets.at(1)); QToolButton* const deleteButton = static_cast(widgets.at(2)); - if (index.data(SetupCollectionModel::IsCategoryRole).toBool()) + if (index.data(SetupCollectionModel::IsCategoryRole).toBool()) { // set text from model + pushButton->setText(index.data(SetupCollectionModel::CategoryButtonDisplayRole).toString()); + // resize according to size hint + pushButton->resize(pushButton->sizeHint()); + // move to position in line. We have cached the icon/text size hint from sizeHint() + pushButton->move(m_categoryMaxStyledWidth, (option.rect.height() - pushButton->height()) / 2); pushButton->show(); updateButton->hide(); deleteButton->hide(); pushButton->setEnabled(itemView()->isEnabled()); pushButton->setProperty("id", index.data(SetupCollectionModel::CategoryButtonMapId)); } else if (index.data(SetupCollectionModel::IsUpdateRole).toBool()) { updateButton->setIcon(index.data(SetupCollectionModel::UpdateDecorationRole).value()); updateButton->resize(updateButton->sizeHint()); updateButton->move(0, (option.rect.height() - updateButton->height()) / 2); updateButton->show(); pushButton->hide(); updateButton->setEnabled(itemView()->isEnabled()); updateButton->setProperty("id", index.data(SetupCollectionModel::UpdateMapId)); } else if (index.data(SetupCollectionModel::IsDeleteRole).toBool()) { deleteButton->setIcon(index.data(SetupCollectionModel::DeleteDecorationRole).value()); deleteButton->resize(deleteButton->sizeHint()); deleteButton->move(0, (option.rect.height() - deleteButton->height()) / 2); deleteButton->show(); pushButton->hide(); deleteButton->setEnabled(itemView()->isEnabled()); deleteButton->setProperty("id", index.data(SetupCollectionModel::DeleteMapId)); } else { pushButton->hide(); updateButton->hide(); deleteButton->hide(); } } QWidget* SetupCollectionDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const { return m_styledDelegate->createEditor(parent, option, index); } bool SetupCollectionDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) { return static_cast(m_styledDelegate)->editorEvent(event, model, option, index); } void SetupCollectionDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { m_styledDelegate->paint(painter, option, index); } void SetupCollectionDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { m_styledDelegate->setEditorData(editor, index); } void SetupCollectionDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const { m_styledDelegate->setModelData(editor, model, index); } void SetupCollectionDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const { m_styledDelegate->updateEditorGeometry(editor, option, index); } // ------------- View ----------------- // SetupCollectionTreeView::SetupCollectionTreeView(QWidget* const parent) : QTreeView(parent) { setRootIsDecorated(false); setExpandsOnDoubleClick(false); setHeaderHidden(true); // Set custom delegate + setItemDelegate(new SetupCollectionDelegate(this, this)); } void SetupCollectionTreeView::setModel(SetupCollectionModel* collectionModel) { if (model()) { disconnect(model(), nullptr, this, nullptr); } // we need to do some things after the model has loaded its data + connect(collectionModel, SIGNAL(collectionsLoaded()), this, SLOT(modelLoadedCollections())); // connect button click signals from the delegate to the model + connect(static_cast(itemDelegate()), SIGNAL(categoryButtonPressed(int)), collectionModel, SLOT(slotCategoryButtonPressed(int))); connect(static_cast(itemDelegate()), SIGNAL(updatePressed(int)), collectionModel, SLOT(slotUpdatePressed(int))); connect(static_cast(itemDelegate()), SIGNAL(deletePressed(int)), collectionModel, SLOT(slotDeletePressed(int))); // give model a widget to use as parent for message boxes + collectionModel->setParentWidgetForDialogs(this); QTreeView::setModel(collectionModel); } void SetupCollectionTreeView::modelLoadedCollections() { // make category entries span the whole line + for (int i = 0 ; i < model()->rowCount(QModelIndex()) ; ++i) { setFirstColumnSpanned(i, QModelIndex(), true); } // show all entries + expandAll(); // Resize name and path column + header()->setSectionResizeMode(SetupCollectionModel::ColumnName, QHeaderView::Stretch); header()->setSectionResizeMode(SetupCollectionModel::ColumnPath, QHeaderView::Stretch); // Resize last column, so that delete button is always rightbound + header()->setStretchLastSection(false); // defaults to true header()->setSectionResizeMode(SetupCollectionModel::ColumnUpdateButton, QHeaderView::Fixed); resizeColumnToContents(SetupCollectionModel::ColumnUpdateButton); header()->setSectionResizeMode(SetupCollectionModel::ColumnDeleteButton, QHeaderView::Fixed); resizeColumnToContents(SetupCollectionModel::ColumnDeleteButton); // Resize first column // This is more difficult because we need to ignore the width of the category entries, // which are formally location in the first column (although spanning the whole line). // resizeColumnToContents fails therefore. + SetupCollectionModel* const collectionModel = static_cast(model()); QModelIndex categoryIndex = collectionModel->indexForCategory(SetupCollectionModel::CategoryLocal); QModelIndex firstChildOfFirstCategory = collectionModel->index(0, SetupCollectionModel::ColumnStatus, categoryIndex); QSize hint = sizeHintForIndex(firstChildOfFirstCategory); setColumnWidth(SetupCollectionModel::ColumnStatus, hint.width() + indentation()); } // ------------- Model ----------------- // SetupCollectionModel::Item::Item() : parentId(INTERNALID), updated(false), deleted(false) { } SetupCollectionModel::Item::Item(const CollectionLocation& location) : location(location), updated(false), deleted(false) { parentId = SetupCollectionModel::typeToCategory(location.type()); } SetupCollectionModel::Item::Item(const QString& path, const QString& label, SetupCollectionModel::Category category) : label(label), path(path), parentId(category), updated(false), deleted(false) { } -/* - Internal data structure: - - The category entries get a model index with INTERNALID and are identified by their row(). - The item entries get the index in m_collections as INTERNALID. - No item is ever removed from m_collections, deleted entries are only marked as such. - - Items have a location, a parentId, and a name and label field. - parentId always contains the category, needed to implement parent(). - The location is the location if it exists, or is null if the item was added. - Name and label are null if unchanged, then the values from location are used. - They are valid if edited (label) or the location was added (both valid, location null). -*/ +/** + * Internal data structure: + * + * The category entries get a model index with INTERNALID and are identified by their row(). + * The item entries get the index in m_collections as INTERNALID. + * No item is ever removed from m_collections, deleted entries are only marked as such. + * + * Items have a location, a parentId, and a name and label field. + * parentId always contains the category, needed to implement parent(). + * The location is the location if it exists, or is null if the item was added. + * Name and label are null if unchanged, then the values from location are used. + * They are valid if edited (label) or the location was added (both valid, location null). + */ SetupCollectionModel::SetupCollectionModel(QObject* const parent) : QAbstractItemModel(parent), m_dialogParentWidget(nullptr) { } SetupCollectionModel::~SetupCollectionModel() { } void SetupCollectionModel::loadCollections() { beginResetModel(); m_collections.clear(); QList locations = CollectionManager::instance()->allLocations(); foreach (const CollectionLocation& location, locations) { m_collections << Item(location); } endResetModel(); emit collectionsLoaded(); } void SetupCollectionModel::apply() { QList newItems, deletedItems, updatedItems, renamedItems; for (int i = 0 ; i < m_collections.count() ; ++i) { const Item& item = m_collections.at(i); - if (item.deleted && !item.location.isNull()) - // if item was deleted and had a valid location, i.e. exists in DB + if (item.deleted && !item.location.isNull()) { + // if item was deleted and had a valid location, i.e. exists in DB + deletedItems << i; } else if (!item.deleted && item.location.isNull()) - // if item has no valid location, i.e. does not yet exist in db { + // if item has no valid location, i.e. does not yet exist in db + newItems << i; } else if (!item.deleted && !item.location.isNull()) { // if item has a valid location, is updated or has changed its label + if (item.updated) { updatedItems << i; } else if (!item.label.isNull() && item.label != item.location.label()) { renamedItems << i; } } } // Delete deleted items + foreach (int i, deletedItems) { Item& item = m_collections[i]; CollectionManager::instance()->removeLocation(item.location); item.location = CollectionLocation(); } // Add added items + QList failedItems; foreach (int i, newItems) { Item& item = m_collections[i]; CollectionLocation location; if (item.parentId == CategoryRemote) { location = CollectionManager::instance()->addNetworkLocation(QUrl::fromLocalFile(item.path), item.label); } else { location = CollectionManager::instance()->addLocation(QUrl::fromLocalFile(item.path), item.label); } if (location.isNull()) { failedItems << item; } else { item.location = location; item.path.clear(); item.label.clear(); } } // Update collections + foreach (int i, updatedItems) { Item& item = m_collections[i]; CollectionLocation location; int newType = CollectionLocation::TypeVolumeHardWired; - if (item.parentId == CategoryRemovable) + if (item.parentId == CategoryRemovable) { newType = CollectionLocation::TypeVolumeRemovable; } else if (item.parentId == CategoryRemote) { newType = CollectionLocation::TypeNetwork; } location = CollectionManager::instance()->refreshLocation(item.location, newType, QUrl::fromLocalFile(item.path), item.label); if (location.isNull()) { failedItems << item; } else { item.location = location; item.path.clear(); item.label.clear(); } } // Rename collections + foreach (int i, renamedItems) { Item& item = m_collections[i]; CollectionManager::instance()->setLabel(item.location, item.label); item.label.clear(); } // Handle any errors + if (!failedItems.isEmpty()) { QStringList failedPaths; foreach (const Item& item, failedItems) { failedPaths << QDir::toNativeSeparators(item.path); } DMessageBox::showInformationList(QMessageBox::Critical, m_dialogParentWidget, qApp->applicationName(), i18n("It was not possible to add a collection for the following paths:"), failedPaths); } // Trigger collection scan + if (!newItems.isEmpty() || !updatedItems.isEmpty() || !deletedItems.isEmpty()) { NewItemsFinder* const tool = new NewItemsFinder(); tool->start(); } } void SetupCollectionModel::setParentWidgetForDialogs(QWidget* widget) { m_dialogParentWidget = widget; } void SetupCollectionModel::slotCategoryButtonPressed(int mappedId) { addCollection(mappedId); } void SetupCollectionModel::slotUpdatePressed(int mappedId) { updateCollection(mappedId); } void SetupCollectionModel::slotDeletePressed(int mappedId) { deleteCollection(mappedId); } void SetupCollectionModel::addCollection(int category) { - if (category < 0 || category >= NumberOfCategories) + if ((category < 0) || (category >= NumberOfCategories)) { return; } QString path; QString label; if (askForNewCollectionPath(category, &path, &label)) { // Add new item to model. Adding to CollectionManager is done in apply()! + QModelIndex parent = indexForCategory((Category)category); int row = rowCount(parent); beginInsertRows(parent, row, row); m_collections << Item(path, label, (Category)category); endInsertRows(); // only workaround for bug 182753 + emit layoutChanged(); } } /* //This code works, but is currently not used. Was intended as a workaround for 219876. void SetupCollectionModel::emitDataChangedForChildren(const QModelIndex& parent) { int rows = rowCount(parent); int columns = columnCount(parent); emit dataChanged(index(0, 0, parent), index(rows, columns, parent)); - for (int r = 0; r < rows; ++r) + for (int r = 0 ; r < rows ; ++r) { - for (int c = 0; c < columns; ++c) + for (int c = 0 ; c < columns ; ++c) { QModelIndex i = index(r, c, parent); if (i.isValid()) + { emitDataChangedForChildren(i); + } } } } */ void SetupCollectionModel::updateCollection(int internalId) { QModelIndex index = indexForId(internalId, (int)ColumnStatus); - if (!index.isValid() || internalId >= m_collections.count()) + if (!index.isValid() || (internalId >= m_collections.count())) { return; } Item& item = m_collections[index.internalId()]; int parentId = item.parentId; if (askForNewCollectionCategory(&parentId)) { QString path = item.path; QString label; if (!item.location.isNull()) { path = item.location.albumRootPath(); } // Mark item as deleted so that // the path can be used again. + item.deleted = true; if (askForNewCollectionPath(parentId, &path, &label)) { item.parentId = parentId; item.label = label; item.path = path; item.updated = true; // only workaround for bug 182753 + emit layoutChanged(); } item.deleted = false; } } void SetupCollectionModel::deleteCollection(int internalId) { QModelIndex index = indexForId(internalId, (int)ColumnStatus); QModelIndex parentIndex = parent(index); - if (!index.isValid() || internalId >= m_collections.count()) + if (!index.isValid() || (internalId >= m_collections.count())) { return; } Item& item = m_collections[index.internalId()]; // Ask for confirmation + QString label = data(indexForId(internalId, (int)ColumnName), Qt::DisplayRole).toString(); int result = QMessageBox::warning(m_dialogParentWidget, i18n("Remove Collection?"), i18n("Do you want to remove the collection \"%1\" from your list of collections?", label), QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::Yes) { // Remove from model. Removing from CollectionManager is done in apply()! + beginRemoveRows(parentIndex, index.row(), index.row()); item.deleted = true; endRemoveRows(); // only workaround for bug 182753 + emit layoutChanged(); } } QVariant SetupCollectionModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.internalId() == INTERNALID) { if (index.column() == 0) { switch (role) { case Qt::DisplayRole: switch (index.row()) { case CategoryLocal: return i18n("Local Collections"); case CategoryRemovable: return i18n("Collections on Removable Media"); case CategoryRemote: return i18n("Collections on Network Shares"); } break; case Qt::DecorationRole: switch (index.row()) { case CategoryLocal: return QIcon::fromTheme(QLatin1String("drive-harddisk")); case CategoryRemovable: return QIcon::fromTheme(QLatin1String("drive-removable-media")); case CategoryRemote: return QIcon::fromTheme(QLatin1String("network-wired-activated")); } break; case IsCategoryRole: return true; case CategoryButtonDisplayRole: return i18n("Add Collection"); case CategoryButtonMapId: return categoryButtonMapId(index); default: break; } } } else { const Item& item = m_collections.at(index.internalId()); switch (index.column()) { case ColumnName: - if (role == Qt::DisplayRole || role == Qt::EditRole) + if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) { if (!item.label.isNull()) { return item.label; } if (!item.location.label().isNull()) { return item.location.label(); } return i18n("Col. %1", index.row()); } break; case ColumnPath: - if (role == Qt::DisplayRole || role == Qt::ToolTipRole) + if ((role == Qt::DisplayRole) || (role == Qt::ToolTipRole)) { if (!item.path.isNull()) { return QDir::toNativeSeparators(item.path); } - //TODO: Path can be empty for items not available, + // TODO: Path can be empty for items not available, // query more info from CollectionManager + return QDir::toNativeSeparators(item.location.albumRootPath()); } break; case ColumnStatus: if (role == Qt::DecorationRole) { if (item.updated) { return QIcon::fromTheme(QLatin1String("view-refresh")); } if (item.deleted) { return QIcon::fromTheme(QLatin1String("edit-delete")); } if (item.location.isNull()) { return QIcon::fromTheme(QLatin1String("folder-new")); } switch (item.location.status()) { case CollectionLocation::LocationAvailable: return QIcon::fromTheme(QLatin1String("dialog-ok-apply")); case CollectionLocation::LocationHidden: return QIcon::fromTheme(QLatin1String("object-locked")); case CollectionLocation::LocationUnavailable: switch (item.parentId) { case CategoryLocal: return QIcon::fromTheme(QLatin1String("drive-harddisk")).pixmap(16, QIcon::Disabled); case CategoryRemovable: return QIcon::fromTheme(QLatin1String("drive-removable-media-usb")).pixmap(16, QIcon::Disabled); case CategoryRemote: return QIcon::fromTheme(QLatin1String("network-wired-activated")).pixmap(16, QIcon::Disabled); } break; case CollectionLocation::LocationNull: case CollectionLocation::LocationDeleted: return QIcon::fromTheme(QLatin1String("edit-delete")); } } else if (role == Qt::ToolTipRole) { switch (item.location.status()) { case CollectionLocation::LocationUnavailable: return i18n("This collection is currently not available."); case CollectionLocation::LocationAvailable: return i18n("No problems found, enjoy this collection."); case CollectionLocation::LocationHidden: return i18n("This collection is hidden."); default: break; } } break; case ColumnUpdateButton: switch (role) { case Qt::ToolTipRole: return i18n("Update collection"); case IsUpdateRole: return true; case UpdateDecorationRole: return QIcon::fromTheme(QLatin1String("view-refresh")); case UpdateMapId: return buttonMapId(index); } break; case ColumnDeleteButton: switch (role) { case Qt::ToolTipRole: return i18n("Remove collection"); case IsDeleteRole: return true; case DeleteDecorationRole: return QIcon::fromTheme(QLatin1String("edit-delete")); case DeleteMapId: return buttonMapId(index); } break; } } return QVariant(); } QVariant SetupCollectionModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::DisplayRole && orientation == Qt::Horizontal && section < NumberOfColumns) + if ((role == Qt::DisplayRole) && (orientation == Qt::Horizontal) && (section < NumberOfColumns)) { switch (section) { case ColumnName: return i18n("Name"); case ColumnPath: return i18n("Path"); case ColumnStatus: return i18n("Status"); case ColumnUpdateButton: break; case ColumnDeleteButton: break; } } return QVariant(); } int SetupCollectionModel::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return NumberOfCategories; // Level 0: the three top level items } if (parent.column() != 0) { return 0; } if (parent.internalId() != INTERNALID) { - return 0; // Level 2: no children + return 0; // Level 2: no children } // Level 1: item children count + int parentId = parent.row(); int rowCount = 0; foreach (const Item& item, m_collections) { if (!item.deleted && item.parentId == parentId) { ++rowCount; } } return rowCount; } int SetupCollectionModel::columnCount(const QModelIndex& /*parent*/) const { return 5; } Qt::ItemFlags SetupCollectionModel::flags(const QModelIndex& index) const { if (!index.isValid()) { return Qt::NoItemFlags; } if (index.internalId() == INTERNALID) { return Qt::ItemIsEnabled; } else { switch (index.column()) { case ColumnName: - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + return (Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); default: - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + return (Qt::ItemIsEnabled | Qt::ItemIsSelectable); } } } bool SetupCollectionModel::setData(const QModelIndex& index, const QVariant& value, int role) { // only editable in one case - if (index.isValid() && index.internalId() != INTERNALID && index.column() == ColumnName && role == Qt::EditRole) + + if (index.isValid() && (index.internalId() != INTERNALID) && (index.column() == ColumnName) && (role == Qt::EditRole)) { Item& item = m_collections[index.internalId()]; item.label = value.toString(); emit dataChanged(index, index); } return false; } QModelIndex SetupCollectionModel::index(int row, int column, const QModelIndex& parent) const { - if (!parent.isValid()) + if (!parent.isValid()) { - if (row < NumberOfCategories && row >= 0 && column == 0) + if ((row < NumberOfCategories) && (row >= 0) && (column == 0)) { return createIndex(row, 0, INTERNALID); } } - else if (row >= 0 && column < 5) + else if ((row >= 0) && (column < 5)) { // m_collections is a flat list with all entries, of all categories and also deleted entries. // The model indices contain as internal id the index to this list. int parentId = parent.row(); int rowCount = 0; for (int i = 0 ; i < m_collections.count() ; ++i) { const Item& item = m_collections.at(i); if (!item.deleted && item.parentId == parentId) { if (rowCount == row) { return createIndex(row, column, i); } ++rowCount; } } } return QModelIndex(); } QModelIndex SetupCollectionModel::parent(const QModelIndex& index) const { if (!index.isValid()) { return QModelIndex(); } if (index.internalId() == INTERNALID) { return QModelIndex(); // one of the three toplevel items } const Item& item = m_collections.at(index.internalId()); return createIndex(item.parentId, 0, INTERNALID); } QModelIndex SetupCollectionModel::indexForCategory(Category category) const { return index(category, 0, QModelIndex()); } QList SetupCollectionModel::categoryIndexes() const { QList list; for (int cat = 0 ; cat < NumberOfCategories ; ++cat) { list << index(cat, 0, QModelIndex()); } return list; } QModelIndex SetupCollectionModel::indexForId(int id, int column) const { int row = 0; const Item& indexItem = m_collections.at(id); for (int i = 0 ; i < m_collections.count() ; ++i) { const Item& item = m_collections.at(i); - if (!item.deleted && item.parentId == indexItem.parentId) + if (!item.deleted && (item.parentId == indexItem.parentId)) { if (i == id) { return createIndex(row, column, i); } ++row; } } return QModelIndex(); } SetupCollectionModel::Category SetupCollectionModel::typeToCategory(CollectionLocation::Type type) { switch (type) { default: case CollectionLocation::TypeVolumeHardWired: return CategoryLocal; case CollectionLocation::TypeVolumeRemovable: return CategoryRemovable; case CollectionLocation::TypeNetwork: return CategoryRemote; } } bool SetupCollectionModel::askForNewCollectionPath(int category, QString* const newPath, QString* const newLabel) { QString picPath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); if (newPath && !(*newPath).isEmpty() && QFileInfo::exists(*newPath)) { picPath = *newPath; } QUrl curl = DFileDialog::getExistingDirectoryUrl(m_dialogParentWidget, i18n("Choose the folder containing your collection"), QUrl::fromLocalFile(picPath)); if (curl.isEmpty()) { return false; } // Check path: First check with manager + QString messageFromManager, deviceIcon; QList assumeDeleted; foreach (const Item& item, m_collections) { if (item.deleted && !item.location.isNull()) { assumeDeleted << item.location; } } CollectionManager::LocationCheckResult result; if (category == CategoryRemote) + { result = CollectionManager::instance()->checkNetworkLocation(curl, assumeDeleted, &messageFromManager, &deviceIcon); + } else + { result = CollectionManager::instance()->checkLocation(curl, assumeDeleted, &messageFromManager, &deviceIcon); + } QString path = QDir::fromNativeSeparators(curl.toDisplayString(QUrl::PreferLocalFile )); // If there are other added collections then CollectionManager does not know about them. Check here. + foreach (const Item& item, m_collections) { if (!item.deleted && item.location.isNull()) { if (!item.path.isEmpty() && path.startsWith(item.path)) { - if (path == item.path || path.startsWith(item.path + QLatin1Char('/'))) + if ((path == item.path) || path.startsWith(item.path + QLatin1Char('/'))) { messageFromManager = i18n("You have previously added a collection " "that contains the path \"%1\".", QDir::toNativeSeparators(path)); result = CollectionManager::LocationNotAllowed; break; } } } } // If check failed, display sorry message + QString iconName; switch (result) { case CollectionManager::LocationAllRight: iconName = QLatin1String("dialog-ok-apply"); break; case CollectionManager::LocationHasProblems: iconName = QLatin1String("dialog-information"); break; case CollectionManager::LocationNotAllowed: case CollectionManager::LocationInvalidCheck: QMessageBox::warning(m_dialogParentWidget, i18n("Problem Adding Collection"), messageFromManager); // fail return false; } // Create a dialog that displays volume information and allows to change the name of the collection - QDialog* const dialog = new QDialog(m_dialogParentWidget); + + QDialog* const dialog = new QDialog(m_dialogParentWidget); dialog->setWindowTitle(i18n("Adding Collection")); QWidget* const mainWidget = new QWidget(dialog); QLabel* const nameLabel = new QLabel; nameLabel->setText(i18n("Your new collection will be created with this name:")); nameLabel->setWordWrap(true); // lineedit for collection name + QLineEdit* const nameEdit = new QLineEdit; nameEdit->setClearButtonEnabled(true); nameLabel->setBuddy(nameEdit); // label for the icon showing the type of storage (hard disk, CD, USB drive) + QLabel* const deviceIconLabel = new QLabel; deviceIconLabel->setPixmap(QIcon::fromTheme(deviceIcon).pixmap(64)); QGroupBox* const infoBox = new QGroupBox; - //infoBox->setTitle(i18n("More Information")); - +/* + infoBox->setTitle(i18n("More Information")); +*/ // label either signalling everything is all right, or raising awareness to some problems // (like handling of CD identified by a label) + QLabel* const iconLabel = new QLabel; iconLabel->setPixmap(QIcon::fromTheme(iconName).pixmap(48)); QLabel* const infoLabel = new QLabel; infoLabel->setText(messageFromManager); infoLabel->setWordWrap(true); QHBoxLayout* const hbox1 = new QHBoxLayout; hbox1->addWidget(iconLabel); hbox1->addWidget(infoLabel); infoBox->setLayout(hbox1); QGridLayout* const grid1 = new QGridLayout; grid1->addWidget(deviceIconLabel, 0, 0, 3, 1); grid1->addWidget(nameLabel, 0, 1); grid1->addWidget(nameEdit, 1, 1); grid1->addWidget(infoBox, 2, 1); mainWidget->setLayout(grid1); QVBoxLayout* const vbx = new QVBoxLayout(dialog); QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog); vbx->addWidget(mainWidget); vbx->addWidget(buttons); dialog->setLayout(vbx); connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), dialog, SLOT(accept())); connect(buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), dialog, SLOT(reject())); // default to directory name as collection name + QDir dir(path); nameEdit->setText(dir.dirName()); if (dialog->exec() == QDialog::Accepted) { if (newPath && newLabel) { *newLabel = nameEdit->text(); *newPath = path; return true; } } return false; } bool SetupCollectionModel::askForNewCollectionCategory(int* const category) { // Create a dialog that displays the category and allows to change the category of the collection - QDialog* const dialog = new QDialog(m_dialogParentWidget); + + QDialog* const dialog = new QDialog(m_dialogParentWidget); dialog->setWindowTitle(i18n("Select Category")); QWidget* const mainWidget = new QWidget(dialog); QLabel* const nameLabel = new QLabel; nameLabel->setText(i18n("Your collection will use this category:")); nameLabel->setWordWrap(true); // combobox for collection category + QComboBox* const categoryBox = new QComboBox; categoryBox->addItem(i18n("Local Collections"), CategoryLocal); categoryBox->addItem(i18n("Collections on Removable Media"), CategoryRemovable); categoryBox->addItem(i18n("Collections on Network Shares"), CategoryRemote); // label for the icon showing the refresh icon + QLabel* const questionIconLabel = new QLabel; questionIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("view-sort")).pixmap(64)); QGridLayout* const grid1 = new QGridLayout; grid1->addWidget(questionIconLabel, 0, 0, 3, 1); grid1->addWidget(nameLabel, 0, 1); grid1->addWidget(categoryBox, 1, 1); mainWidget->setLayout(grid1); QVBoxLayout* const vbx = new QVBoxLayout(dialog); QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog); vbx->addWidget(mainWidget); vbx->addWidget(buttons); dialog->setLayout(vbx); connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), dialog, SLOT(accept())); connect(buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), dialog, SLOT(reject())); // default to current category if (category) { categoryBox->setCurrentIndex(categoryBox->findData(*category)); } if (dialog->exec() == QDialog::Accepted) { if (category) { *category = categoryBox->currentData().toInt(); } return true; } return false; } int SetupCollectionModel::categoryButtonMapId(const QModelIndex& index) const { if (!index.isValid() || index.parent().isValid()) { return INTERNALID; } return index.row(); } int SetupCollectionModel::buttonMapId(const QModelIndex& index) const { - if (!index.isValid() || index.internalId() == INTERNALID) + if (!index.isValid() || (index.internalId() == INTERNALID)) { return INTERNALID; } return index.internalId(); } } // namespace Digikam diff --git a/core/utilities/setup/collections/setupcollectionview.h b/core/utilities/setup/collections/setupcollectionview.h index 2bc1fe1e02..f805617ef4 100644 --- a/core/utilities/setup/collections/setupcollectionview.h +++ b/core/utilities/setup/collections/setupcollectionview.h @@ -1,277 +1,287 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2008-11-15 * Description : collections setup tab model/view * * Copyright (C) 2008-2012 by Marcel Wiesweg * Copyright (C) 2005-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_SETUP_COLLECTION_VIEW_H #define DIGIKAM_SETUP_COLLECTION_VIEW_H // Qt includes #include #include #include #include #include #include #include // Local includes #include "collectionlocation.h" #include "dwitemdelegate.h" #include "digikam_export.h" namespace Digikam { class DIGIKAM_EXPORT SetupCollectionModel : public QAbstractItemModel { Q_OBJECT public: - /** SetupCollectionModel is a model specialized for use in - * SetupCollectionTreeView. It provides a reads the current collections - * from CollectionManager, displays them in three categories, - * and supports adding and removing collections + /** + * SetupCollectionModel is a model specialized for use in + * SetupCollectionTreeView. It provides a reads the current collections + * from CollectionManager, displays them in three categories, + * and supports adding and removing collections */ enum SetupCollectionDataRole { /// Returns true if the model index is the index of a category IsCategoryRole = Qt::UserRole, + /// The text for the category button CategoryButtonDisplayRole = Qt::UserRole + 1, CategoryButtonMapId = Qt::UserRole + 2, + /// Returns true if the model index is the index of a button IsUpdateRole = Qt::UserRole + 3, + /// The pixmap of the button UpdateDecorationRole = Qt::UserRole + 4, UpdateMapId = Qt::UserRole + 5, + /// Returns true if the model index is the index of a button IsDeleteRole = Qt::UserRole + 6, + /// The pixmap of the button DeleteDecorationRole = Qt::UserRole + 7, DeleteMapId = Qt::UserRole + 8 }; enum Columns { ColumnStatus = 0, ColumnName = 1, ColumnPath = 2, ColumnUpdateButton = 3, ColumnDeleteButton = 4, NumberOfColumns }; enum Category { CategoryLocal = 0, CategoryRemovable = 1, CategoryRemote = 2, NumberOfCategories }; public: explicit SetupCollectionModel(QObject* const parent = nullptr); ~SetupCollectionModel(); /// Read collections from CollectionManager void loadCollections(); /// Set a widget used as parent for dialogs and message boxes void setParentWidgetForDialogs(QWidget* const widget); /// Apply the changed settings to CollectionManager void apply(); QModelIndex indexForCategory(Category category) const; QList categoryIndexes() const; - // QAbstractItemModel implementation + /// QAbstractItemModel implementation virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; virtual Qt::ItemFlags flags(const QModelIndex& index) const; virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex& index) const; /* virtual Qt::DropActions supportedDropActions() const; virtual QStringList mimeTypes() const; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex& parent); virtual QMimeData * mimeData(const QModelIndexList& indexes) const; */ Q_SIGNALS: /// Emitted when all collections were loaded and the model reset in loadCollections void collectionsLoaded(); public Q_SLOTS: - /** Forward category button clicked signals to this slot. - * mappedId is retrieved with the CategoryButtonMapId role - * for the model index of the button + /** + * Forward category button clicked signals to this slot. + * mappedId is retrieved with the CategoryButtonMapId role + * for the model index of the button */ void slotCategoryButtonPressed(int mappedId); - /** Forward button clicked signals to this slot. - * mappedId is retrieved with the ButtonMapId role - * for the model index of the button + /** + * Forward button clicked signals to this slot. + * mappedId is retrieved with the ButtonMapId role + * for the model index of the button */ void slotUpdatePressed(int mappedId); void slotDeletePressed(int mappedId); protected Q_SLOTS: void addCollection(int category); void updateCollection(int internalId); void deleteCollection(int internalId); protected: QModelIndex indexForId(int id, int column) const; bool askForNewCollectionPath(int category, QString* const newPath, QString* const newLabel); bool askForNewCollectionCategory(int* const category); int categoryButtonMapId(const QModelIndex& index) const; int buttonMapId(const QModelIndex& index) const; static Category typeToCategory(CollectionLocation::Type type); protected: class Item { public: Item(); explicit Item(const CollectionLocation& location); Item(const QString& path, const QString& label, SetupCollectionModel::Category category); + public: + CollectionLocation location; QString label; QString path; int parentId; bool updated; bool deleted; }; protected: QList m_collections; QWidget* m_dialogParentWidget; }; // ----------------------------------------------------------------------- class SetupCollectionTreeView : public QTreeView { Q_OBJECT public: explicit SetupCollectionTreeView(QWidget* const parent = nullptr); void setModel(SetupCollectionModel* model); protected Q_SLOTS: void modelLoadedCollections(); private: void setModel(QAbstractItemModel* model) { setModel(static_cast(model)); } }; // ----------------------------------------------------------------------- class SetupCollectionDelegate : public DWItemDelegate { Q_OBJECT public: explicit SetupCollectionDelegate(QAbstractItemView* const view, QObject* const parent = nullptr); ~SetupCollectionDelegate(); virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override; virtual bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override; virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; virtual void setEditorData(QWidget* editor, const QModelIndex& index) const override; virtual void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override; virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; virtual void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override; virtual QList createItemWidgets(const QModelIndex& index) const override; virtual void updateItemWidgets(const QList widgets, const QStyleOptionViewItem& option, const QPersistentModelIndex& index) const override; Q_SIGNALS: void categoryButtonPressed(int mappedId) const; void updatePressed(int mappedId) const; void deletePressed(int mappedId) const; protected: QStyledItemDelegate* m_styledDelegate; QPushButton* m_samplePushButton; QToolButton* m_sampleUpdateButton; QToolButton* m_sampleDeleteButton; int m_categoryMaxStyledWidth; }; } // namespace Digikam #endif // DIGIKAM_SETUP_COLLECTION_VIEW_H diff --git a/core/utilities/setup/editor/setupiofiles.cpp b/core/utilities/setup/editor/setupiofiles.cpp index 5cbecb4894..39992bca96 100644 --- a/core/utilities/setup/editor/setupiofiles.cpp +++ b/core/utilities/setup/editor/setupiofiles.cpp @@ -1,223 +1,269 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-01-23 * Description : setup image editor output files settings. * * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupiofiles.h" // Qt includes #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_config.h" #include "jpegsettings.h" #include "pgfsettings.h" #include "pngsettings.h" #include "tiffsettings.h" #ifdef HAVE_JASPER # include "jp2ksettings.h" #endif // HAVE_JASPER #ifdef HAVE_X265 # include "heifsettings.h" #endif // HAVE_X265 namespace Digikam { class Q_DECL_HIDDEN SetupIOFiles::Private { public: explicit Private() : JPEGOptions(nullptr), PNGOptions(nullptr), TIFFOptions(nullptr), + #ifdef HAVE_JASPER + JPEG2000Options(nullptr), + #endif // HAVE_JASPER + PGFOptions(nullptr), + #ifdef HAVE_X265 + HEIFOptions(nullptr), + #endif // HAVE_X265 + showImageSettingsDialog(nullptr) { } QWidget* createGroupBox(QWidget* const w) const { QGroupBox* const box = new QGroupBox; QVBoxLayout* const layout = new QVBoxLayout; layout->addWidget(w); box->setLayout(layout); + return box; } public: static const QString configGroupName; static const QString configJPEGCompressionEntry; static const QString configJPEGSubSamplingEntry; static const QString configPNGCompressionEntry; static const QString configTIFFCompressionEntry; static const QString configJPEG2000CompressionEntry; static const QString configJPEG2000LossLessEntry; static const QString configPGFCompressionEntry; static const QString configPGFLossLessEntry; static const QString configHEIFCompressionEntry; static const QString configHEIFLossLessEntry; static const QString configShowImageSettingsDialog; JPEGSettings* JPEGOptions; PNGSettings* PNGOptions; TIFFSettings* TIFFOptions; + #ifdef HAVE_JASPER + JP2KSettings* JPEG2000Options; + #endif // HAVE_JASPER + PGFSettings* PGFOptions; + #ifdef HAVE_X265 + HEIFSettings* HEIFOptions; + #endif // HAVE_X265 QCheckBox* showImageSettingsDialog; }; const QString SetupIOFiles::Private::configGroupName(QLatin1String("ImageViewer Settings")); const QString SetupIOFiles::Private::configJPEGCompressionEntry(QLatin1String("JPEGCompression")); const QString SetupIOFiles::Private::configJPEGSubSamplingEntry(QLatin1String("JPEGSubSampling")); const QString SetupIOFiles::Private::configPNGCompressionEntry(QLatin1String("PNGCompression")); const QString SetupIOFiles::Private::configTIFFCompressionEntry(QLatin1String("TIFFCompression")); const QString SetupIOFiles::Private::configJPEG2000CompressionEntry(QLatin1String("JPEG2000Compression")); const QString SetupIOFiles::Private::configJPEG2000LossLessEntry(QLatin1String("JPEG2000LossLess")); const QString SetupIOFiles::Private::configPGFCompressionEntry(QLatin1String("PGFCompression")); const QString SetupIOFiles::Private::configPGFLossLessEntry(QLatin1String("PGFLossLess")); const QString SetupIOFiles::Private::configHEIFCompressionEntry(QLatin1String("HEIFCompression")); const QString SetupIOFiles::Private::configHEIFLossLessEntry(QLatin1String("HEIFLossLess")); const QString SetupIOFiles::Private::configShowImageSettingsDialog(QLatin1String("ShowImageSettingsDialog")); // -------------------------------------------------------- SetupIOFiles::SetupIOFiles(QWidget* const parent) : QScrollArea(parent), d(new Private) { QWidget* const panel = new QWidget; QVBoxLayout* const vbox = new QVBoxLayout; d->JPEGOptions = new JPEGSettings; d->PNGOptions = new PNGSettings; d->TIFFOptions = new TIFFSettings; + #ifdef HAVE_JASPER + d->JPEG2000Options = new JP2KSettings; + #endif // HAVE_JASPER + d->PGFOptions = new PGFSettings; + #ifdef HAVE_X265 + d->HEIFOptions = new HEIFSettings; + #endif // HAVE_X265 // Show Settings Dialog Option d->showImageSettingsDialog = new QCheckBox(panel); d->showImageSettingsDialog->setText(i18n("Show Settings Dialog when Saving Image Files")); d->showImageSettingsDialog->setWhatsThis(i18n("
  • Checked: A dialog where settings can be changed when saving image files
  • " "
  • Unchecked: Default settings are used when saving image files
")); vbox->addWidget(d->createGroupBox(d->JPEGOptions)); vbox->addWidget(d->createGroupBox(d->PNGOptions)); vbox->addWidget(d->createGroupBox(d->TIFFOptions)); + #ifdef HAVE_JASPER + vbox->addWidget(d->createGroupBox(d->JPEG2000Options)); + #endif // HAVE_JASPER + vbox->addWidget(d->createGroupBox(d->PGFOptions)); + #ifdef HAVE_X265 + vbox->addWidget(d->createGroupBox(d->HEIFOptions)); + #endif // HAVE_265 + vbox->addWidget(d->createGroupBox(d->showImageSettingsDialog)); vbox->addStretch(); panel->setLayout(vbox); setWidget(panel); setWidgetResizable(true); // -------------------------------------------------------- readSettings(); } SetupIOFiles::~SetupIOFiles() { delete d; } void SetupIOFiles::applySettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); group.writeEntry(d->configJPEGCompressionEntry, d->JPEGOptions->getCompressionValue()); group.writeEntry(d->configJPEGSubSamplingEntry, d->JPEGOptions->getSubSamplingValue()); group.writeEntry(d->configPNGCompressionEntry, d->PNGOptions->getCompressionValue()); group.writeEntry(d->configTIFFCompressionEntry, d->TIFFOptions->getCompression()); + #ifdef HAVE_JASPER group.writeEntry(d->configJPEG2000CompressionEntry, d->JPEG2000Options->getCompressionValue()); group.writeEntry(d->configJPEG2000LossLessEntry, d->JPEG2000Options->getLossLessCompression()); + #endif // HAVE_JASPER + group.writeEntry(d->configPGFCompressionEntry, d->PGFOptions->getCompressionValue()); group.writeEntry(d->configPGFLossLessEntry, d->PGFOptions->getLossLessCompression()); + #ifdef HAVE_X265 + group.writeEntry(d->configHEIFCompressionEntry, d->HEIFOptions->getCompressionValue()); group.writeEntry(d->configHEIFLossLessEntry, d->HEIFOptions->getLossLessCompression()); + #endif // HAVE_X265 + group.writeEntry(d->configShowImageSettingsDialog, d->showImageSettingsDialog->isChecked()); config->sync(); } void SetupIOFiles::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); d->JPEGOptions->setCompressionValue(group.readEntry(d->configJPEGCompressionEntry, 75)); d->JPEGOptions->setSubSamplingValue(group.readEntry(d->configJPEGSubSamplingEntry, 1)); // Medium sub-sampling d->PNGOptions->setCompressionValue(group.readEntry(d->configPNGCompressionEntry, 9)); d->TIFFOptions->setCompression(group.readEntry(d->configTIFFCompressionEntry, false)); + #ifdef HAVE_JASPER + d->JPEG2000Options->setCompressionValue(group.readEntry(d->configJPEG2000CompressionEntry, 75)); d->JPEG2000Options->setLossLessCompression(group.readEntry(d->configJPEG2000LossLessEntry, true)); + #endif // HAVE_JASPER + d->PGFOptions->setCompressionValue(group.readEntry(d->configPGFCompressionEntry, 3)); d->PGFOptions->setLossLessCompression(group.readEntry(d->configPGFLossLessEntry, true)); + #ifdef HAVE_X265 + d->HEIFOptions->setCompressionValue(group.readEntry(d->configHEIFCompressionEntry, 75)); d->HEIFOptions->setLossLessCompression(group.readEntry(d->configHEIFLossLessEntry, true)); + #endif // HAVE_X265 + d->showImageSettingsDialog->setChecked(group.readEntry(d->configShowImageSettingsDialog, true)); } } // namespace Digikam diff --git a/core/utilities/setup/editor/setupraw.cpp b/core/utilities/setup/editor/setupraw.cpp index 837fcbc478..f7aa2c21ed 100644 --- a/core/utilities/setup/editor/setupraw.cpp +++ b/core/utilities/setup/editor/setupraw.cpp @@ -1,299 +1,300 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-02-06 * Description : setup RAW decoding settings. * * Copyright (C) 2007-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupraw.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "drawdecoding.h" #include "drawdecoderwidget.h" #include "dpluginloader.h" #include "dpluginrawimport.h" #include "dpluginaboutdlg.h" namespace Digikam { class Q_DECL_HIDDEN SetupRaw::Private { public: explicit Private() : tab(nullptr), behaviorPanel(nullptr), settingsPanel(nullptr), openSimple(nullptr), openDefault(nullptr), openTool(nullptr), rawImportTool(nullptr), toolAbout(nullptr), rawSettings(nullptr) { } static const QString configGroupName; static const QString configUseRawImportToolEntry; static const QString configRawImportToolIidEntry; static const QString nativeRawImportToolIid; QTabWidget* tab; QWidget* behaviorPanel; QWidget* settingsPanel; QRadioButton* openSimple; QRadioButton* openDefault; QRadioButton* openTool; QComboBox* rawImportTool; QPushButton* toolAbout; DRawDecoderWidget* rawSettings; }; const QString SetupRaw::Private::configGroupName(QLatin1String("ImageViewer Settings")); const QString SetupRaw::Private::configUseRawImportToolEntry(QLatin1String("UseRawImportTool")); const QString SetupRaw::Private::configRawImportToolIidEntry(QLatin1String("RawImportToolIid")); const QString SetupRaw::Private::nativeRawImportToolIid(QLatin1String("org.kde.digikam.plugin.rawimport.Native")); SetupRaw::SetupRaw(QTabWidget* const tab) : QObject(tab), d(new Private) { d->tab = tab; // -------------------------------------------------------- d->behaviorPanel = new QWidget; QVBoxLayout* const behaviorLayout = new QVBoxLayout; QLabel* const rawExplanation = new QLabel; rawExplanation->setText(i18nc("@info", "

A raw image file contains minimally processed data " "from the image sensor of a digital camera.

" "

Opening a raw file requires extensive data interpretation and processing.

")); rawExplanation->setWordWrap(true); QLabel* const rawIcon = new QLabel; rawIcon->setPixmap(QIcon::fromTheme(QLatin1String("camera-photo")).pixmap(48)); QHBoxLayout* const header = new QHBoxLayout; header->addWidget(rawIcon); header->addWidget(rawExplanation); header->setStretchFactor(rawExplanation, 10); header->addStretch(1); QGroupBox* const behaviorBox = new QGroupBox; QGridLayout* const boxLayout = new QGridLayout; QLabel* const openIcon = new QLabel; openIcon->setPixmap(QIcon::fromTheme(QLatin1String("document-open")).pixmap(32)); QLabel* const openIntro = new QLabel(i18nc("@label", "Open raw files in the image editor")); d->openSimple = new QRadioButton(i18nc("@option:radio Open raw files...", "Fast and simple, as 8 bit image")); d->openDefault = new QRadioButton(i18nc("@option:radio Open raw files...", "Using the default settings, in 16 bit")); d->openTool = new QRadioButton(i18nc("@option:radio Open raw files...", "Always open the Raw Import Tool to customize settings")); d->rawImportTool = new QComboBox; foreach (DPlugin* const p, DPluginLoader::instance()->allPlugins()) { DPluginRawImport* const raw = dynamic_cast(p); if (raw) { QString iid = raw->iid(); QString name = raw->name(); if (iid == d->nativeRawImportToolIid) { name += i18n(" (default)"); } d->rawImportTool->addItem(name, iid); } } d->toolAbout = new QPushButton; d->toolAbout->setIcon(QIcon::fromTheme(QLatin1String("help-about"))); d->toolAbout->setToolTip(i18n("About this Raw Import tool...")); // ---------------------------------------------- boxLayout->addWidget(openIcon, 0, 0); boxLayout->addWidget(openIntro, 0, 1); boxLayout->addWidget(d->openSimple, 1, 0, 1, 4); boxLayout->addWidget(d->openDefault, 2, 0, 1, 4); boxLayout->addWidget(d->openTool, 3, 0, 1, 2); boxLayout->addWidget(d->rawImportTool, 3, 2, 1, 1); boxLayout->addWidget(d->toolAbout, 3, 3, 1, 1); boxLayout->setColumnStretch(2, 1); behaviorBox->setLayout(boxLayout); behaviorLayout->addLayout(header); behaviorLayout->addWidget(behaviorBox); behaviorLayout->addStretch(); d->behaviorPanel->setLayout(behaviorLayout); // -------------------------------------------------------- d->settingsPanel = new QWidget; QVBoxLayout* const settingsLayout = new QVBoxLayout; d->rawSettings = new DRawDecoderWidget(nullptr, 0 /* no advanced settings shown */); d->rawSettings->setItemIcon(0, QIcon::fromTheme(QLatin1String("image-x-adobe-dng"))); d->rawSettings->setItemIcon(1, QIcon::fromTheme(QLatin1String("bordertool"))); d->rawSettings->setItemIcon(2, QIcon::fromTheme(QLatin1String("lensdistortion"))); settingsLayout->addWidget(d->rawSettings); d->settingsPanel->setLayout(settingsLayout); // -------------------------------------------------------- d->tab->addTab(d->behaviorPanel, i18nc("@title:tab", "RAW Behavior")); d->tab->addTab(d->settingsPanel, i18nc("@title:tab", "RAW Default Settings")); // -------------------------------------------------------- connect(d->openSimple, SIGNAL(toggled(bool)), this, SLOT(slotBehaviorChanged())); connect(d->openDefault, SIGNAL(toggled(bool)), this, SLOT(slotBehaviorChanged())); connect(d->openTool, SIGNAL(toggled(bool)), this, SLOT(slotBehaviorChanged())); connect(d->rawSettings, SIGNAL(signalSixteenBitsImageToggled(bool)), this, SLOT(slotSixteenBitsImageToggled(bool))); connect(d->toolAbout, SIGNAL(clicked()), this, SLOT(slotAboutRawImportPlugin())); // -------------------------------------------------------- readSettings(); } SetupRaw::~SetupRaw() { delete d; } void SetupRaw::slotSixteenBitsImageToggled(bool) { // Libraw provide a way to set brightness of image in 16 bits color depth. // We always set on this option. We drive brightness adjustment in digiKam Raw image loader. + d->rawSettings->setEnabledBrightnessSettings(true); } void SetupRaw::slotBehaviorChanged() { d->rawImportTool->setEnabled(d->openTool->isChecked()); DRawDecoderSettings settings = d->rawSettings->settings(); settings.sixteenBitsImage = !d->openSimple->isChecked(); d->rawSettings->setSettings(settings); } void SetupRaw::applySettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); group.writeEntry(d->configUseRawImportToolEntry, d->openTool->isChecked()); group.writeEntry(d->configRawImportToolIidEntry, d->rawImportTool->itemData(d->rawImportTool->currentIndex())); d->rawSettings->writeSettings(group); config->sync(); } void SetupRaw::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); d->rawSettings->readSettings(group); bool useTool = group.readEntry(d->configUseRawImportToolEntry, false); if (useTool) { d->openTool->setChecked(true); } else { if (d->rawSettings->settings().sixteenBitsImage) { d->openDefault->setChecked(true); } else { d->openSimple->setChecked(true); } } QString iid = group.readEntry(d->configRawImportToolIidEntry, d->nativeRawImportToolIid); d->rawImportTool->setCurrentIndex(d->rawImportTool->findData(iid)); } void SetupRaw::slotAboutRawImportPlugin() { QString iid = d->rawImportTool->itemData(d->rawImportTool->currentIndex()).toString(); foreach (DPlugin* const p, DPluginLoader::instance()->allPlugins()) { DPluginRawImport* const raw = dynamic_cast(p); if (raw) { if (raw->iid() == iid) { QPointer dlg = new DPluginAboutDlg(dynamic_cast(raw)); dlg->exec(); delete dlg; } } } } } // namespace Digikam diff --git a/core/utilities/setup/editor/setupversioning.cpp b/core/utilities/setup/editor/setupversioning.cpp index d7525d6fd9..26928df768 100644 --- a/core/utilities/setup/editor/setupversioning.cpp +++ b/core/utilities/setup/editor/setupversioning.cpp @@ -1,473 +1,480 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2010-08-06 * Description : setup tab for image versioning * * Copyright (C) 2010 by Martin Klapetek * Copyright (C) 2012-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupversioning.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "applicationsettings.h" #include "versionmanager.h" namespace Digikam { class Q_DECL_HIDDEN SetupVersioning::Private { public: explicit Private() : tab(nullptr), nonDestructivePanel(nullptr), workspaceGB(nullptr), closingGB(nullptr), snapshotGB(nullptr), viewGB(nullptr), enableNonDestructive(nullptr), snapshotAfterRaw(nullptr), snapshotSession(nullptr), snapshotComplex(nullptr), viewShowOriginal(nullptr), viewShowSnapshots(nullptr), formatBox(nullptr), askToSave(nullptr), autoSave(nullptr), infoNonDestructive(nullptr), infoFormat(nullptr), infoSnapshot(nullptr), infoView(nullptr) { } QTabWidget* tab; QWidget* nonDestructivePanel; QGroupBox* workspaceGB; QGroupBox* closingGB; QGroupBox* snapshotGB; QGroupBox* viewGB; QCheckBox* enableNonDestructive; QCheckBox* snapshotAfterRaw; QCheckBox* snapshotSession; QCheckBox* snapshotComplex; QCheckBox* viewShowOriginal; QCheckBox* viewShowSnapshots; QComboBox* formatBox; QRadioButton* askToSave; QRadioButton* autoSave; QPushButton* infoNonDestructive; QPushButton* infoFormat; QPushButton* infoSnapshot; QPushButton* infoView; }; SetupVersioning::SetupVersioning(QWidget* const parent) : QScrollArea(parent), d(new Private) { d->nonDestructivePanel = new QWidget; QVBoxLayout* const nonDestructiveLayout = new QVBoxLayout; // --- QGridLayout* const gridHeader = new QGridLayout; d->enableNonDestructive = new QCheckBox; d->enableNonDestructive->setText(i18n("Enable Non-Destructive Editing and Versioning")); d->enableNonDestructive->setToolTip(i18nc("@info:tooltip", "Enable support for non-destructive editing and image versioning")); d->enableNonDestructive->setWhatsThis(xi18nc("@info:whatsthis", "Non-Destructive Editing and Versioning " "allows different versions of an image to be created, " "whilst always preserving the original image. " " All steps of the editing history are recorded and can be accessed later.")); QLabel* const iconLabel = new QLabel; iconLabel->setPixmap(QIcon::fromTheme(QLatin1String("view-catalog")).pixmap(32)); d->infoNonDestructive = new QPushButton; d->infoNonDestructive->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoNonDestructive->setToolTip(i18nc("@info:tooltip", "Get information on non-destructive editing and file versioning")); gridHeader->addWidget(iconLabel, 0, 0); gridHeader->addWidget(d->enableNonDestructive, 0, 1); gridHeader->addWidget(d->infoNonDestructive, 0, 3); gridHeader->setColumnStretch(2, 1); // -------------------------------------------------------- d->workspaceGB = new QGroupBox(i18nc("@title:group", "Workspace File Format")); QGridLayout* const wsLayout = new QGridLayout; QLabel* const workIcon = new QLabel; workIcon->setPixmap(QIcon::fromTheme(QLatin1String("document-save-as")).pixmap(32)); QLabel* const formatLabel = new QLabel(i18nc("@label", "Save files as")); // keep in sync with VersionManager::workspaceFileFormats() + d->formatBox = new QComboBox; d->formatBox->addItem(i18nc("@label:listbox", "JPEG"), QLatin1String("JPG")); d->formatBox->addItem(i18nc("@label:listbox", "TIFF"), QLatin1String("TIFF")); d->formatBox->addItem(i18nc("@label:listbox", "PNG"), QLatin1String("PNG")); d->formatBox->addItem(i18nc("@label:listbox", "PGF"), QLatin1String("PGF")); d->formatBox->addItem(i18nc("@label:listbox", "JPEG 2000"), QLatin1String("JP2")); d->formatBox->insertSeparator(1); d->formatBox->insertSeparator(4); d->formatBox->setWhatsThis(xi18nc("@info:whatsthis", "Default File Format for Saving" "Select the file format in which edited images are saved automatically. " "Format-specific options, like compression settings, " "can be configured on the Format Options tab." "" + // Lossy: JPEG + "" "JPEG: " "JPEG is the most commonly used file format, but it employs lossy compression, " "which means that with each saving operation some image information will be irreversibly lost. " "JPEG offers a good compression rate, resulting in smaller files. " "" + // Traditional lossless: PNG, TIFF + "" "PNG: " "A widely used format employing lossless compression. " "The files, though, will be larger because PNG does not achieve very good compression rates." "" "" "TIFF: " "A commonly used format, usually uncompressed or with modest lossless compression. " "Resulting files will be large, but without quality loss due to compression. " "" + // Modern lossless: PGF, JPEG 2000 + "" "PGF: " "This is a technically superior file format offering good compression rates " "with either lossy or lossless compression. " "But it is not yet widely used and supported, so your friends may not directly be able to open these files, " "and you may not be able to directly publish them on the web. " "" "" "JPEG 2000: " "JPEG 2000 is similar to PGF. Loading or saving is slower, the compression rate is better, " "and the format more widely supported, though still not comparable " "to the tradition formats JPEG, PNG or TIFF. " "" "")); d->infoFormat = new QPushButton; d->infoFormat->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoFormat->setToolTip(i18nc("@info:tooltip", "Get information on available image file formats")); wsLayout->addWidget(workIcon, 0, 0); wsLayout->addWidget(formatLabel, 0, 1); wsLayout->addWidget(d->formatBox, 0, 2); wsLayout->addWidget(d->infoFormat, 0, 4); wsLayout->setColumnStretch(1, 1); wsLayout->setColumnStretch(2, 2); wsLayout->setColumnStretch(3, 3); d->workspaceGB->setLayout(wsLayout); // --- d->closingGB = new QGroupBox;//(i18nc("@title:group", "Automatic Saving")); QGridLayout* const closingLayout = new QGridLayout; QLabel* const closingExplanation = new QLabel(i18nc("@label", "When closing the editor")); QLabel* const closingIcon = new QLabel; closingIcon->setPixmap(QIcon::fromTheme(QLatin1String("dialog-ok-apply")).pixmap(32)); d->askToSave = new QRadioButton(i18nc("@option:radio", "Always ask to save changes")); d->autoSave = new QRadioButton(i18nc("@option:radio", "Save changes automatically")); closingLayout->addWidget(closingIcon, 0, 0); closingLayout->addWidget(closingExplanation, 0, 1); closingLayout->addWidget(d->askToSave, 1, 0, 1, 3); closingLayout->addWidget(d->autoSave, 2, 0, 1, 3); closingLayout->setColumnStretch(3, 1); d->closingGB->setLayout(closingLayout); // --- // -------------------------------------------------------- /* QGridLayout* const snapshotHeader = new QGridLayout; QLabel* const snapshotExplanation = new QLabel; snapshotExplanation->setText(i18nc("@label", "For an edited image, there is at least one file representing the current version." "digiKam can take and keep additional, intermediate snapshots during editing.")); snapshotExplanation->setWordWrap(true); snapshotHeader->addWidget(snapshotIconLabel, 0, 0); snapshotHeader->addWidget(snapshotExplanation, 0, 1); */ d->snapshotGB = new QGroupBox;//(i18nc("@title:group", "Intermediate Version Snapshots")); QGridLayout* const snapshotLayout = new QGridLayout; QString snapshotWhatsThis = xi18nc("@info:whatsthis", "First and foremost, the original image will never be overwritten. " "Instead, when an image is edited, a new file is created: " "The current version. " "You can also create multiple versions " "deriving from the same original image. " "In addition to these files representing a current version, " "digiKam can take and keep additional, intermediate snapshots " "during the editing process. " "This can be useful if you want to preserve the intermediate steps for later " "access, for example if some editing steps cannot be automatically reproduced."); d->snapshotGB->setWhatsThis(snapshotWhatsThis); QLabel* const snapshotIconLabel = new QLabel; snapshotIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("insert-image")).pixmap(32)); QLabel* const snapshotLabel = new QLabel(i18nc("@label", "Keep a snapshot of an edited image")); d->infoSnapshot = new QPushButton; d->infoSnapshot->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoSnapshot->setToolTip(i18nc("@info:tooltip", "Get an explanation for these options")); d->snapshotAfterRaw = new QCheckBox(i18nc("@option:check", "After converting from a RAW image")); d->snapshotSession = new QCheckBox(i18nc("@option:check", "After each editing session")); d->snapshotComplex = new QCheckBox(i18nc("@option:check", "After each step that is not completely reproducible")); snapshotLayout->addWidget(snapshotIconLabel, 0, 0); snapshotLayout->addWidget(snapshotLabel, 0, 1); snapshotLayout->addWidget(d->infoSnapshot, 0, 3); snapshotLayout->addWidget(d->snapshotAfterRaw, 1, 0, 1, 4); snapshotLayout->addWidget(d->snapshotSession, 2, 0, 1, 4); snapshotLayout->addWidget(d->snapshotComplex, 3, 0, 1, 4); snapshotLayout->setColumnStretch(2, 1); d->snapshotGB->setLayout(snapshotLayout); /* / --- snapshotLayout->addLayout(snapshotHeader); snapshotLayout->addWidget(d->snapshotGB); snapshotLayout->addStretch(); d->snapshotPanel->setLayout(snapshotLayout); */ // -------------------------------------------------------- d->viewGB = new QGroupBox; QGridLayout* const viewGBLayout = new QGridLayout; QString viewWhatsThis = xi18nc("@info:whatsthis", "If an image has been edited, only the current versions " "will be shown in the main thumbnail view. " "From the right sidebar, you always have access to all hidden files. " "With the options here, you can choose to show certain files permanently. " "If you activate non-destructive editing and image versioning for the first time, " "it will only be work for newly saved images."); d->viewGB->setWhatsThis(viewWhatsThis); QLabel* const viewLabel = new QLabel(i18nc("@label", "In main view")); QLabel* const viewIconLabel = new QLabel; viewIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("view-list-icons")).pixmap(32)); d->infoView = new QPushButton; d->infoView->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoView->setToolTip(i18nc("@info:tooltip", "Get an explanation for these options")); d->viewShowOriginal = new QCheckBox(i18nc("@option:check", "Always show original images")); d->viewShowSnapshots = new QCheckBox(i18nc("@option:check", "Always show intermediate snapshots")); viewGBLayout->addWidget(viewIconLabel, 0, 0); viewGBLayout->addWidget(viewLabel, 0, 1); viewGBLayout->addWidget(d->infoView, 0, 3); viewGBLayout->addWidget(d->viewShowOriginal, 1, 0, 1, 4); viewGBLayout->addWidget(d->viewShowSnapshots, 2, 0, 1, 4); viewGBLayout->setColumnStretch(2, 1); d->viewGB->setLayout(viewGBLayout); // -------------------------------------------------------- connect(d->enableNonDestructive, SIGNAL(toggled(bool)), this, SLOT(enableToggled(bool))); connect(d->infoNonDestructive, SIGNAL(clicked()), this, SLOT(showNonDestructiveInformation())); connect(d->infoFormat, SIGNAL(clicked()), this, SLOT(showFormatInformation())); connect(d->infoSnapshot, SIGNAL(clicked()), this, SLOT(showSnapshotInformation())); connect(d->infoView, SIGNAL(clicked()), this, SLOT(showViewInformation())); // -------------------------------------------------------- nonDestructiveLayout->addLayout(gridHeader); nonDestructiveLayout->addWidget(d->workspaceGB); nonDestructiveLayout->addWidget(d->closingGB); nonDestructiveLayout->addWidget(d->snapshotGB); nonDestructiveLayout->addWidget(d->viewGB); nonDestructiveLayout->addStretch(); d->nonDestructivePanel->setLayout(nonDestructiveLayout); setWidget(d->nonDestructivePanel); setWidgetResizable(true); // -------------------------------------------------------- readSettings(); enableToggled(d->enableNonDestructive->isChecked()); } SetupVersioning::~SetupVersioning() { delete d; } void SetupVersioning::applySettings() { VersionManagerSettings settings; settings.enabled = d->enableNonDestructive->isChecked(); if (d->snapshotSession->isChecked()) { settings.saveIntermediateVersions |= VersionManagerSettings::AfterEachSession; } if (d->snapshotAfterRaw->isChecked()) { settings.saveIntermediateVersions |= VersionManagerSettings::AfterRawConversion; } if (d->snapshotComplex->isChecked()) { settings.saveIntermediateVersions |= VersionManagerSettings::WhenNotReproducible; } if (d->viewShowOriginal->isChecked()) { settings.showInViewFlags |= VersionManagerSettings::ShowOriginal; } else { settings.showInViewFlags &= ~VersionManagerSettings::ShowOriginal; } if (d->viewShowSnapshots->isChecked()) { settings.showInViewFlags |= VersionManagerSettings::ShowIntermediates; } if (d->autoSave->isChecked()) { settings.editorClosingMode = VersionManagerSettings::AutoSave; } else // d->askToSave->isChecked() { settings.editorClosingMode = VersionManagerSettings::AlwaysAsk; } settings.format = d->formatBox->itemData(d->formatBox->currentIndex()).toString(); ApplicationSettings::instance()->setVersionManagerSettings(settings); ApplicationSettings::instance()->saveSettings(); } void SetupVersioning::readSettings() { VersionManagerSettings settings = ApplicationSettings::instance()->getVersionManagerSettings(); d->enableNonDestructive->setChecked(settings.enabled); d->snapshotSession->setChecked(settings.saveIntermediateVersions & VersionManagerSettings::AfterEachSession); d->snapshotAfterRaw->setChecked(settings.saveIntermediateVersions & VersionManagerSettings::AfterRawConversion); d->snapshotComplex->setChecked(settings.saveIntermediateVersions & VersionManagerSettings::WhenNotReproducible); d->viewShowOriginal->setChecked(settings.showInViewFlags & VersionManagerSettings::ShowOriginal); d->viewShowSnapshots->setChecked(settings.showInViewFlags & VersionManagerSettings::ShowIntermediates); d->askToSave->setChecked(settings.editorClosingMode == VersionManagerSettings::AlwaysAsk); d->autoSave->setChecked(settings.editorClosingMode == VersionManagerSettings::AutoSave); d->formatBox->setCurrentIndex(d->formatBox->findData(settings.format)); } void SetupVersioning::showNonDestructiveInformation() { qApp->postEvent(d->enableNonDestructive, new QHelpEvent(QEvent::WhatsThis, QPoint(0, 0), d->enableNonDestructive->mapToGlobal(QPoint(0, 0)))); } void SetupVersioning::showFormatInformation() { qApp->postEvent(d->formatBox, new QHelpEvent(QEvent::WhatsThis, QPoint(0, 0), d->formatBox->mapToGlobal(QPoint(0, 0)))); } void SetupVersioning::showSnapshotInformation() { QPoint p(0, 0); qApp->postEvent(d->snapshotGB, new QHelpEvent(QEvent::WhatsThis, p, d->snapshotGB->mapToGlobal(p))); } void SetupVersioning::showViewInformation() { QPoint p(0, 0); qApp->postEvent(d->viewGB, new QHelpEvent(QEvent::WhatsThis, p, d->viewGB->mapToGlobal(p))); } void SetupVersioning::enableToggled(bool on) { d->workspaceGB->setEnabled(on); d->closingGB->setEnabled(on); d->snapshotGB->setEnabled(on); d->viewGB->setEnabled(on); } } // namespace Digikam diff --git a/core/utilities/setup/metadata/advancedmetadatatab.cpp b/core/utilities/setup/metadata/advancedmetadatatab.cpp index 49f1c3b039..0134834291 100644 --- a/core/utilities/setup/metadata/advancedmetadatatab.cpp +++ b/core/utilities/setup/metadata/advancedmetadatatab.cpp @@ -1,538 +1,543 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2015-06-16 * Description : Advanced Configuration tab for metadata. * * Copyright (C) 2015 by Veaceslav Munteanu * * 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 "advancedmetadatatab.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dmetadatasettings.h" #include "namespacelistview.h" #include "namespaceeditdlg.h" #include "dmessagebox.h" #include "digikam_debug.h" namespace Digikam { class Q_DECL_HIDDEN AdvancedMetadataTab::Private { public: explicit Private() + : metadataType(nullptr), + operationType(nullptr), + addButton(nullptr), + editButton(nullptr), + deleteButton(nullptr), + moveUpButton(nullptr), + moveDownButton(nullptr), + revertChanges(nullptr), + resetButton(nullptr), + unifyReadWrite(nullptr), + namespaceView(nullptr), + metadataTypeSize(0), + changed(false) { - metadataType = nullptr; - operationType = nullptr; - addButton = nullptr; - editButton = nullptr; - deleteButton = nullptr; - moveUpButton = nullptr; - moveDownButton = nullptr; - revertChanges = nullptr; - resetButton = nullptr; - unifyReadWrite = nullptr; - namespaceView = nullptr; - metadataTypeSize = 0; - changed = false; } QComboBox* metadataType; QComboBox* operationType; QPushButton* addButton; QPushButton* editButton; QPushButton* deleteButton; QPushButton* moveUpButton; QPushButton* moveDownButton; QPushButton* revertChanges; QPushButton* resetButton; QCheckBox* unifyReadWrite; QList models; NamespaceListView* namespaceView; DMetadataSettingsContainer container; int metadataTypeSize; bool changed; }; AdvancedMetadataTab::AdvancedMetadataTab(QWidget* const parent) : QWidget(parent), d(new Private()) { // ---------- Advanced Configuration Panel ----------------------------- d->container = DMetadataSettings::instance()->settings(); setUi(); setModels(); connectButtons(); d->unifyReadWrite->setChecked(d->container.unifyReadWrite()); connect(d->unifyReadWrite, SIGNAL(toggled(bool)), this, SLOT(slotUnifyChecked(bool))); connect(d->metadataType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged())); connect(d->operationType, SIGNAL(currentIndexChanged(int)), this, SLOT(slotIndexChanged())); /** * Connect all actions to slotRevertAvailable, which will enable revert to original * if an add, edit, delete, or reorder was made */ connect(d->namespaceView, SIGNAL(signalItemsChanged()), this, SLOT(slotRevertChangesAvailable())); if (d->unifyReadWrite->isChecked()) { d->operationType->setEnabled(false); } } AdvancedMetadataTab::~AdvancedMetadataTab() { delete d; } void AdvancedMetadataTab::slotResetToDefault() { const int result = DMessageBox::showContinueCancel(QMessageBox::Warning, this, i18n("Warning"), i18n("This option will reset configuration to default\n" "All your changes will be lost.\n " "Do you want to continue?")); if (result != QMessageBox::Yes) { return; } d->container.defaultValues(); d->models.at(getModelIndex())->clear(); setModelData(d->models.at(getModelIndex()), getCurrentContainer()); d->namespaceView->setModel(d->models.at(getModelIndex())); } void AdvancedMetadataTab::slotRevertChanges() { d->models.at(getModelIndex())->clear(); setModelData(d->models.at(getModelIndex()), getCurrentContainer()); d->namespaceView->setModel(d->models.at(getModelIndex())); d->changed = false; d->revertChanges->setEnabled(false); } void AdvancedMetadataTab::slotAddNewNamespace() { NamespaceEntry entry; // Setting some default parameters; - if (d->metadataType->currentData().toString() == NamespaceEntry::DM_TAG_CONTAINER()) + if (d->metadataType->currentData().toString() == NamespaceEntry::DM_TAG_CONTAINER()) { entry.nsType = NamespaceEntry::TAGS; } else if (d->metadataType->currentData().toString() == NamespaceEntry::DM_RATING_CONTAINER()) { entry.nsType = NamespaceEntry::RATING; } else if (d->metadataType->currentData().toString() == NamespaceEntry::DM_COMMENT_CONTAINER()) { entry.nsType = NamespaceEntry::COMMENT; } entry.isDefault = false; entry.subspace = NamespaceEntry::XMP; if (!NamespaceEditDlg::create(qApp->activeWindow(), entry)) { return; } QStandardItem* const root = d->models.at(getModelIndex())->invisibleRootItem(); QStandardItem* const item = new QStandardItem(entry.namespaceName); setDataToItem(item, entry); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); root->appendRow(item); slotRevertChangesAvailable(); } void AdvancedMetadataTab::slotEditNamespace() { if (!d->namespaceView->currentIndex().isValid()) { return; } NamespaceEntry entry = getCurrentContainer().at(d->namespaceView->currentIndex().row()); - if (!NamespaceEditDlg::edit(qApp->activeWindow(), entry)) { return; } QStandardItem* const root = d->models.at(getModelIndex())->invisibleRootItem(); QStandardItem* const item = root->child(d->namespaceView->currentIndex().row()); setDataToItem(item, entry); slotRevertChangesAvailable(); } void AdvancedMetadataTab::applySettings() { updateContainer(); DMetadataSettings::instance()->setSettings(d->container); } void AdvancedMetadataTab::slotUnifyChecked(bool value) { d->operationType->setDisabled(value); d->container.setUnifyReadWrite(value); d->operationType->setCurrentIndex(0); slotIndexChanged(); } void AdvancedMetadataTab::slotIndexChanged() { d->namespaceView->setModel(d->models.at(getModelIndex())); } void AdvancedMetadataTab::slotRevertChangesAvailable() { if (!d->changed) { d->revertChanges->setEnabled(true); d->changed = true; } updateContainer(); } void AdvancedMetadataTab::connectButtons() { connect(d->addButton, SIGNAL(clicked()), this, SLOT(slotAddNewNamespace())); connect(d->editButton, SIGNAL(clicked()), this, SLOT(slotEditNamespace())); connect(d->deleteButton, SIGNAL(clicked()), d->namespaceView, SLOT(slotDeleteSelected())); connect(d->resetButton, SIGNAL(clicked()), this, SLOT(slotResetToDefault())); connect(d->revertChanges, SIGNAL(clicked()), this, SLOT(slotRevertChanges())); connect(d->moveUpButton, SIGNAL(clicked()), d->namespaceView, SLOT(slotMoveItemUp())); connect(d->moveDownButton, SIGNAL(clicked()), d->namespaceView, SLOT(slotMoveItemDown())); } void AdvancedMetadataTab::setModelData(QStandardItemModel* model, const QList& container) { QStandardItem* const root = model->invisibleRootItem(); for (NamespaceEntry e : container) { QStandardItem* const item = new QStandardItem(e.namespaceName); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); setDataToItem(item, e); root->appendRow(item); } connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotRevertChangesAvailable())); } void AdvancedMetadataTab::setUi() { QVBoxLayout* const advancedConfLayout = new QVBoxLayout(this); QHBoxLayout* const topLayout = new QHBoxLayout(); QHBoxLayout* const bottomLayout = new QHBoxLayout(); QLabel* const tipLabel = new QLabel(this); tipLabel->setTextFormat(Qt::RichText); tipLabel->setWordWrap(true); tipLabel->setText(i18n("Advanced configuration menu allow you to manage metadata namespaces" " used by digiKam to store and retrieve tags, rating and comments.
" "Note: Order is important when reading metadata" )); //--- Top layout ---------------- d->metadataType = new QComboBox(this); d->operationType = new QComboBox(this); d->operationType->insertItems(0, QStringList() << i18n("Read Options") << i18n("Write Options")); d->unifyReadWrite = new QCheckBox(i18n("Unify read and write")); topLayout->addWidget(d->metadataType); topLayout->addWidget(d->operationType); topLayout->addWidget(d->unifyReadWrite); //------------ Bottom Layout------------- // View + d->namespaceView = new NamespaceListView(this); // Buttons + QVBoxLayout* const buttonsLayout = new QVBoxLayout(); buttonsLayout->setAlignment(Qt::AlignTop); d->addButton = new QPushButton(QIcon::fromTheme(QLatin1String("list-add")), i18n("Add")); d->editButton = new QPushButton(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Edit")); d->deleteButton = new QPushButton(QIcon::fromTheme(QLatin1String("window-close")), i18n("Delete")); d->moveUpButton = new QPushButton(QIcon::fromTheme(QLatin1String("go-up")), i18n("Move Up")); d->moveDownButton = new QPushButton(QIcon::fromTheme(QLatin1String("go-down")), i18n("Move Down")); d->revertChanges = new QPushButton(QIcon::fromTheme(QLatin1String("edit-undo")), i18n("Revert Changes")); // Revert changes is disabled, until a change is made + d->revertChanges->setEnabled(false); d->resetButton = new QPushButton(QIcon::fromTheme(QLatin1String("view-refresh")), i18n("Reset to Default")); buttonsLayout->addWidget(d->addButton); buttonsLayout->addWidget(d->editButton); buttonsLayout->addWidget(d->deleteButton); buttonsLayout->addWidget(d->moveUpButton); buttonsLayout->addWidget(d->moveDownButton); buttonsLayout->addWidget(d->revertChanges); buttonsLayout->addWidget(d->resetButton); QVBoxLayout* const vbox = new QVBoxLayout(); vbox->addWidget(d->namespaceView); bottomLayout->addLayout(vbox); bottomLayout->addLayout(buttonsLayout); advancedConfLayout->addWidget(tipLabel); advancedConfLayout->addLayout(topLayout); advancedConfLayout->addLayout(bottomLayout); } void AdvancedMetadataTab::setDataToItem(QStandardItem* item, NamespaceEntry& entry) { item->setData(entry.namespaceName, Qt::DisplayRole); item->setData(entry.namespaceName, NAME_ROLE); item->setData((int)entry.tagPaths, ISTAG_ROLE); item->setData(entry.separator, SEPARATOR_ROLE); item->setData((int)entry.nsType, NSTYPE_ROLE); if (entry.nsType == NamespaceEntry::RATING) { item->setData(entry.convertRatio.at(0), ZEROSTAR_ROLE); item->setData(entry.convertRatio.at(1), ONESTAR_ROLE); item->setData(entry.convertRatio.at(2), TWOSTAR_ROLE); item->setData(entry.convertRatio.at(3), THREESTAR_ROLE); item->setData(entry.convertRatio.at(4), FOURSTAR_ROLE); item->setData(entry.convertRatio.at(5), FIVESTAR_ROLE); } item->setData((int)entry.specialOpts, SPECIALOPTS_ROLE); item->setData(entry.alternativeName, ALTNAME_ROLE); item->setData((int)entry.subspace, SUBSPACE_ROLE); item->setData((int)entry.secondNameOpts, ALTNAMEOPTS_ROLE); item->setData(entry.isDefault, ISDEFAULT_ROLE); item->setCheckable(true); if (!entry.isDisabled) { item->setCheckState(Qt::Checked); } } int AdvancedMetadataTab::getModelIndex() { if (d->unifyReadWrite->isChecked()) { return d->metadataType->currentIndex(); } else { // for 3 metadata types: // read operation = 3*0 + (0, 1, 2) // write operation = 3*1 + (0, 1, 2) = (3, 4 ,5) - return (d->metadataTypeSize * d->operationType->currentIndex()) - + d->metadataType->currentIndex(); + + return ( + (d->metadataTypeSize * d->operationType->currentIndex()) + + d->metadataType->currentIndex() + ); } } QList& AdvancedMetadataTab::getCurrentContainer() { int currentIndex = getModelIndex(); if (currentIndex >= d->metadataTypeSize) { return d->container.getWriteMapping(QString::fromUtf8(d->metadataType->currentData().toByteArray())); } else { return d->container.getReadMapping(QString::fromUtf8(d->metadataType->currentData().toByteArray())); } } void AdvancedMetadataTab::setModels() { QList keys = d->container.mappingKeys(); foreach (const QString& str, keys) { d->metadataType->addItem(str, str); } d->metadataTypeSize = keys.size(); for (int i = 0 ; i < keys.size() * 2 ; ++i) { d->models.append(new QStandardItemModel(this)); } int index = 0; foreach (const QString& str, keys) { setModelData(d->models.at(index++), d->container.getReadMapping(str)); } foreach (const QString& str, keys) { setModelData(d->models.at(index++), d->container.getWriteMapping(str)); } slotIndexChanged(); } void AdvancedMetadataTab::updateContainer() { QList keys = d->container.mappingKeys(); int index = 0; foreach (const QString& str, keys) { d->container.getReadMapping(str).clear(); saveModelData(d->models.at(index++), d->container.getReadMapping(str)); } foreach (const QString& str, keys) { d->container.getWriteMapping(str).clear(); saveModelData(d->models.at(index++), d->container.getWriteMapping(str)); } } void AdvancedMetadataTab::saveModelData(QStandardItemModel* model, QList& container) { QStandardItem* const root = model->invisibleRootItem(); if (!root->hasChildren()) { return; } for (int i = 0 ; i < root->rowCount() ; ++i) { NamespaceEntry ns; QStandardItem* const current = root->child(i); ns.namespaceName = current->data(NAME_ROLE).toString(); ns.tagPaths = (NamespaceEntry::TagType)current->data(ISTAG_ROLE).toInt(); ns.separator = current->data(SEPARATOR_ROLE).toString(); ns.nsType = (NamespaceEntry::NamespaceType)current->data(NSTYPE_ROLE).toInt(); if (ns.nsType == NamespaceEntry::RATING) { ns.convertRatio.append(current->data(ZEROSTAR_ROLE).toInt()); ns.convertRatio.append(current->data(ONESTAR_ROLE).toInt()); ns.convertRatio.append(current->data(TWOSTAR_ROLE).toInt()); ns.convertRatio.append(current->data(THREESTAR_ROLE).toInt()); ns.convertRatio.append(current->data(FOURSTAR_ROLE).toInt()); ns.convertRatio.append(current->data(FIVESTAR_ROLE).toInt()); } ns.specialOpts = (NamespaceEntry::SpecialOptions)current->data(SPECIALOPTS_ROLE).toInt(); ns.alternativeName = current->data(ALTNAME_ROLE).toString(); ns.subspace = (NamespaceEntry::NsSubspace)current->data(SUBSPACE_ROLE).toInt(); ns.secondNameOpts = (NamespaceEntry::SpecialOptions)current->data(ALTNAMEOPTS_ROLE).toInt(); ns.index = i; ns.isDefault = current->data(ISDEFAULT_ROLE).toBool(); if (current->checkState() == Qt::Checked) { ns.isDisabled = false; } else { ns.isDisabled = true; } container.append(ns); } } } // namespace Digikam diff --git a/core/utilities/setup/metadata/advancedmetadatatab.h b/core/utilities/setup/metadata/advancedmetadatatab.h index 83bef4dd3c..e8da56e788 100644 --- a/core/utilities/setup/metadata/advancedmetadatatab.h +++ b/core/utilities/setup/metadata/advancedmetadatatab.h @@ -1,141 +1,142 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2015-06-16 * Description : Advanced Configuration tab for metadata. * * Copyright (C) 2015 by Veaceslav Munteanu * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_ADVANCED_METADATA_TAB_H #define DIGIKAM_ADVANCED_METADATA_TAB_H // Qt includes #include // Local includes #include "dmetadatasettingscontainer.h" class QStandardItemModel; class QStandardItem; namespace Digikam { class AdvancedMetadataTab : public QWidget { Q_OBJECT public: explicit AdvancedMetadataTab(QWidget* const parent = nullptr); virtual ~AdvancedMetadataTab(); void applySettings(); public Q_SLOTS: void slotResetToDefault(); void slotRevertChanges(); void slotAddNewNamespace(); void slotEditNamespace(); private Q_SLOTS: void slotUnifyChecked(bool value); void slotIndexChanged(); void slotRevertChangesAvailable(); private: /** * @brief The NsRoles enum will encode data from NamespaceEntry in * model items, so we could retrieve and save it later */ enum NsRoles { NAME_ROLE = Qt::UserRole+1, ISTAG_ROLE = Qt::UserRole+2, SEPARATOR_ROLE = Qt::UserRole+3, NSTYPE_ROLE = Qt::UserRole+5, ZEROSTAR_ROLE = Qt::UserRole+6, ONESTAR_ROLE = Qt::UserRole+7, TWOSTAR_ROLE = Qt::UserRole+8, THREESTAR_ROLE = Qt::UserRole+9, FOURSTAR_ROLE = Qt::UserRole+10, FIVESTAR_ROLE = Qt::UserRole+11, SPECIALOPTS_ROLE = Qt::UserRole+12, ALTNAME_ROLE = Qt::UserRole+13, SUBSPACE_ROLE = Qt::UserRole+14, ALTNAMEOPTS_ROLE = Qt::UserRole+15, ISDEFAULT_ROLE = Qt::UserRole+16, }; enum ModelNumbers { READ_TAGS = 0, READ_RATINGS = 1, READ_COMMENTS = 2, WRITE_TAGS = 3, WRITE_RATINGS = 4, WRITE_COMMENTS = 5 }; private: void connectButtons(); + /** * @brief setModelData for one model * @param model - model to be populated * @param container - namespace container to get data */ void setModelData(QStandardItemModel* model, const QList& container); void setUi(); void setDataToItem(QStandardItem* item, NamespaceEntry& entry); /** * @brief getModelIndex - the view can have up to 6 models * based on tags, comments, rating selection * and read/ write operation selected * @return - return index of correct model in d->models */ int getModelIndex(); QList& getCurrentContainer(); void setModels(); void updateContainer(); void saveModelData(QStandardItemModel* model, QList& container); private: class Private; Private* d; }; } // namespace Digikam #endif // DIGIKAM_ADVANCED_METADATA_TAB_H diff --git a/core/utilities/setup/metadata/namespaceeditdlg.cpp b/core/utilities/setup/metadata/namespaceeditdlg.cpp index dcef6cb84a..1694b99dca 100644 --- a/core/utilities/setup/metadata/namespaceeditdlg.cpp +++ b/core/utilities/setup/metadata/namespaceeditdlg.cpp @@ -1,688 +1,683 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2015-07-03 * Description : dialog to edit and create digiKam xmp namespaces * * Copyright (C) 2015 by Veaceslav Munteanu * * 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 "namespaceeditdlg.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dxmlguiwindow.h" #include "digikam_debug.h" namespace Digikam { class Q_DECL_HIDDEN NamespaceEditDlg::Private { public: explicit Private() + : buttons(nullptr), + create(0), + topLabel(nullptr), + logo(nullptr), + gridLayout(nullptr), + page(nullptr), + subspaceCombo(nullptr), // NamespaceEntry variables + specialOptsCombo(nullptr), + altSpecialOptsCombo(nullptr), + namespaceName(nullptr), + alternativeName(nullptr), + nameSpaceSeparator(nullptr), + isPath(nullptr), + ratingMappings(nullptr), + zeroStars(nullptr), + oneStar(nullptr), + twoStars(nullptr), + threeStars(nullptr), + fourStars(nullptr), + fiveStars(nullptr), + tagTipLabel(nullptr), // Labels + ratingTipLabel(nullptr), + commentTipLabel(nullptr), + subspaceLabel(nullptr), + titleLabel(nullptr), + specialOptsLabel(nullptr), + alternativeNameLabel(nullptr), + altspecialOptsLabel(nullptr), + isTagLabel(nullptr), + separatorLabel(nullptr), + tipLabel2(nullptr), + nsType(NamespaceEntry::TAGS) { - buttons = nullptr; - create = 0; - topLabel = nullptr; - logo = nullptr; - gridLayout = nullptr; - page = nullptr; - - // NamespaceEntry variables - subspaceCombo = nullptr; - specialOptsCombo = nullptr; - altSpecialOptsCombo = nullptr; - namespaceName = nullptr; - alternativeName = nullptr; - nameSpaceSeparator = nullptr; - isPath = nullptr; - ratingMappings = nullptr; - - zeroStars = nullptr; - oneStar = nullptr; - twoStars = nullptr; - threeStars = nullptr; - fourStars = nullptr; - fiveStars = nullptr; - - // Labels - tagTipLabel = nullptr; - ratingTipLabel = nullptr; - commentTipLabel = nullptr; - subspaceLabel = nullptr; - titleLabel = nullptr; - specialOptsLabel = nullptr; - alternativeNameLabel = nullptr; - altspecialOptsLabel = nullptr; - isTagLabel = nullptr; - separatorLabel = nullptr; - - tipLabel2 = nullptr; - - nsType = NamespaceEntry::TAGS; } QDialogButtonBox* buttons; bool create; QLabel* topLabel; QLabel* logo; QGridLayout* gridLayout; QWidget* page; // NamespaceEntry variables QComboBox* subspaceCombo; QComboBox* specialOptsCombo; QComboBox* altSpecialOptsCombo; QLineEdit* namespaceName; QLineEdit* alternativeName; QLineEdit* nameSpaceSeparator; QCheckBox* isPath; QGroupBox* ratingMappings; QSpinBox* zeroStars; QSpinBox* oneStar; QSpinBox* twoStars; QSpinBox* threeStars; QSpinBox* fourStars; QSpinBox* fiveStars; // Labels QLabel* tagTipLabel; QLabel* ratingTipLabel; QLabel* commentTipLabel; QLabel* subspaceLabel; QLabel* titleLabel; QLabel* specialOptsLabel; QLabel* alternativeNameLabel; QLabel* altspecialOptsLabel; QLabel* isTagLabel; QLabel* separatorLabel; QLabel* tipLabel2; NamespaceEntry::NamespaceType nsType; }; NamespaceEditDlg::NamespaceEditDlg(bool create, NamespaceEntry& entry, QWidget* const parent) : QDialog(parent), d(new Private()) { setModal(true); d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); if (create) { setWindowTitle(i18n("New Xmp Namespace")); } else { setWindowTitle(i18n("Edit Xmp Namespace")); } d->create = create; d->nsType = entry.nsType; setupTagGui(entry); // --- NOTE: use dynamic binding as slots below are virtual method which can be re-implemented in derived classes. connect(d->buttons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &NamespaceEditDlg::accept); connect(d->buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &NamespaceEditDlg::reject); connect(d->buttons->button(QDialogButtonBox::Help), &QPushButton::clicked, this, &NamespaceEditDlg::slotHelp); // -------------------------------------------------------- if (!d->create) { populateFields(entry); } setType(entry.nsType); if (entry.isDefault) { makeReadOnly(); } qCDebug(DIGIKAM_GENERAL_LOG) << "Entry type" << entry.nsType << "subspace" << entry.subspace << entry.isDefault; adjustSize(); } NamespaceEditDlg::~NamespaceEditDlg() { delete d; } bool NamespaceEditDlg::create(QWidget* const parent, NamespaceEntry& entry) { QPointer dlg = new NamespaceEditDlg(true,entry,parent); qCDebug(DIGIKAM_GENERAL_LOG) << "Name before save: " << entry.namespaceName; bool valRet = dlg->exec(); if (valRet == QDialog::Accepted) { dlg->saveData(entry); } qCDebug(DIGIKAM_GENERAL_LOG) << "Name after save: " << entry.namespaceName; delete dlg; return valRet; } bool NamespaceEditDlg::edit(QWidget* const parent, NamespaceEntry& entry) { QPointer dlg = new NamespaceEditDlg(false, entry, parent); qCDebug(DIGIKAM_GENERAL_LOG) << "Name before save: " << entry.namespaceName; bool valRet = dlg->exec(); if (valRet == QDialog::Accepted && !entry.isDefault) { dlg->saveData(entry); } qCDebug(DIGIKAM_GENERAL_LOG) << "Name before save: " << entry.namespaceName; delete dlg; return valRet; } void NamespaceEditDlg::setupTagGui(NamespaceEntry& entry) { - d->page = new QWidget(this); - d->gridLayout = new QGridLayout(d->page); - d->logo = new QLabel(d->page); + d->page = new QWidget(this); + d->gridLayout = new QGridLayout(d->page); + d->logo = new QLabel(d->page); d->logo->setPixmap(QIcon::fromTheme(QLatin1String("digikam")).pixmap(QSize(48,48))); - d->topLabel = new QLabel(d->page); + d->topLabel = new QLabel(d->page); d->topLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); d->topLabel->setWordWrap(false); d->topLabel->setText(i18n("Add metadata namespace")); d->subspaceCombo = new QComboBox(this); d->subspaceLabel = new QLabel(d->page); d->subspaceLabel->setText(i18n("Metadata Subspace")); d->subspaceCombo->addItem(QLatin1String("EXIF"), (int)NamespaceEntry::EXIF); d->subspaceCombo->addItem(QLatin1String("IPTC"), (int)NamespaceEntry::IPTC); d->subspaceCombo->addItem(QLatin1String("XMP"), (int)NamespaceEntry::XMP); d->subspaceCombo->setCurrentIndex((int)entry.subspace); qCDebug(DIGIKAM_GENERAL_LOG) << "Entry subspace" << (int)entry.subspace; // -------------------Tag Elements--------------------------------- d->titleLabel = new QLabel(d->page); d->titleLabel->setText(i18n("Name:")); d->namespaceName = new QLineEdit(this); //----------------- Tip Labels -------------------------------------- d->tagTipLabel = new QLabel(d->page); d->tagTipLabel->setTextFormat(Qt::RichText); d->tagTipLabel->setWordWrap(true); d->tagTipLabel->setText(i18n("

To create new namespaces, you need to specify parameters:

" "

  • Namespace name with dots.
    " "Ex.: \"Xmp.digiKam.TagsList\"
  • " "
  • Separator parameter, used by tag paths
    " "Ex.: \"City/Paris\" or \"City|Paris\"
  • " "
  • Specify if only keyword or the whole path must be written.

" )); d->ratingTipLabel = new QLabel(d->page); d->ratingTipLabel->setTextFormat(Qt::RichText); d->ratingTipLabel->setWordWrap(true); d->ratingTipLabel->setText(i18n("

To create new rating namespaces, you need to specify parameters:

" "

  • Namespace name with dots.
    " "Ex.: \"Xmp.xmp.Rating\"
  • " "
  • Rating mappings, if namespace need other values than 0-5
    " "Ex.: Microsoft uses 0 1 25 50 75 99
  • " "
  • Select the correct namespace option from list.

" )); d->commentTipLabel = new QLabel(d->page); d->commentTipLabel->setTextFormat(Qt::RichText); d->commentTipLabel->setWordWrap(true); d->commentTipLabel->setText(i18n("

To create new comment namespaces, you need to specify parameters:

" "

  • Namespace name with dots.
    " "Ex.: \"Xmp.xmp.Rating\"
  • " "
  • Select the correct namespace option from list.

" )); // ------------------------------------------------------- d->specialOptsLabel = new QLabel(d->page); d->specialOptsLabel->setText(i18n("Special Options")); d->specialOptsCombo = new QComboBox(d->page); d->specialOptsCombo->addItem(QLatin1String("NO_OPTS"), (int)NamespaceEntry::NO_OPTS); if (entry.nsType == NamespaceEntry::COMMENT) { d->specialOptsCombo->addItem(QLatin1String("COMMENT_ALTLANG"), NamespaceEntry::COMMENT_ALTLANG); d->specialOptsCombo->addItem(QLatin1String("COMMENT_ALTLANGLIST"), NamespaceEntry::COMMENT_ATLLANGLIST); d->specialOptsCombo->addItem(QLatin1String("COMMENT_XMP"), NamespaceEntry::COMMENT_XMP); d->specialOptsCombo->addItem(QLatin1String("COMMENT_JPEG"), NamespaceEntry::COMMENT_JPEG); } if (entry.nsType == NamespaceEntry::TAGS) { d->specialOptsCombo->addItem(QLatin1String("TAG_XMPBAG"), NamespaceEntry::TAG_XMPBAG); d->specialOptsCombo->addItem(QLatin1String("TAG_XMPSEQ"), NamespaceEntry::TAG_XMPSEQ); d->specialOptsCombo->addItem(QLatin1String("TAG_ACDSEE"), NamespaceEntry::TAG_ACDSEE); } d->alternativeNameLabel = new QLabel(d->page); d->alternativeNameLabel->setText(i18n("Alternative name")); d->alternativeName = new QLineEdit(d->page); d->altspecialOptsLabel = new QLabel(d->page); d->altspecialOptsLabel->setText(i18n("Alternative special options")); d->altSpecialOptsCombo = new QComboBox(d->page); d->altSpecialOptsCombo->addItem(QLatin1String("NO_OPTS"), (int)NamespaceEntry::NO_OPTS); if (entry.nsType == NamespaceEntry::COMMENT) { d->altSpecialOptsCombo->addItem(QLatin1String("COMMENT_ALTLANG"), NamespaceEntry::COMMENT_ALTLANG); d->altSpecialOptsCombo->addItem(QLatin1String("COMMENT_ALTLANGLIST"), NamespaceEntry::COMMENT_ATLLANGLIST); d->altSpecialOptsCombo->addItem(QLatin1String("COMMENT_XMP"), NamespaceEntry::COMMENT_XMP); d->altSpecialOptsCombo->addItem(QLatin1String("COMMENT_JPEG"), NamespaceEntry::COMMENT_JPEG); } if (entry.nsType == NamespaceEntry::TAGS) { d->altSpecialOptsCombo->addItem(QLatin1String("TAG_XMPBAG"), NamespaceEntry::TAG_XMPBAG); d->altSpecialOptsCombo->addItem(QLatin1String("TAG_XMPSEQ"), NamespaceEntry::TAG_XMPSEQ); d->altSpecialOptsCombo->addItem(QLatin1String("TAG_ACDSEE"), NamespaceEntry::TAG_ACDSEE); } // -------------------------------------------------------- d->separatorLabel = new QLabel(d->page); d->separatorLabel->setText(i18n("Separator:")); d->nameSpaceSeparator = new QLineEdit(this); // -------------------------------------------------------- d->isTagLabel = new QLabel(d->page); d->isTagLabel->setText(i18n("Set Tags Path:")); d->isPath = new QCheckBox(this); d->tipLabel2 = new QLabel(d->page); d->tipLabel2->setTextFormat(Qt::RichText); d->tipLabel2->setWordWrap(true); QPalette sample_palette; sample_palette.setColor(QPalette::Window, QColor(255, 51, 51, 150)); sample_palette.setColor(QPalette::WindowText, Qt::black); d->tipLabel2->setAutoFillBackground(true); d->tipLabel2->setPalette(sample_palette); d->tipLabel2->hide(); // ----------------------Rating Elements---------------------------------- d->ratingMappings = new QGroupBox(this); d->ratingMappings->setFlat(true); QGridLayout* const ratingMappingsLayout = new QGridLayout(d->ratingMappings); QLabel* const ratingLabel = new QLabel(d->page); ratingLabel->setText(i18n("Rating Mapping:")); d->zeroStars = new QSpinBox(this); d->zeroStars->setValue(0); d->oneStar = new QSpinBox(this); d->oneStar->setValue(1); d->twoStars = new QSpinBox(this); d->twoStars->setValue(2); d->threeStars = new QSpinBox(this); d->threeStars->setValue(3); d->fourStars = new QSpinBox(this); d->fourStars->setValue(4); d->fiveStars = new QSpinBox(this); d->fiveStars->setValue(5); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); const int cmargin = QApplication::style()->pixelMetric(QStyle::PM_DefaultChildMargin); ratingMappingsLayout->addWidget(ratingLabel, 0, 0, 1, 2); ratingMappingsLayout->addWidget(d->zeroStars, 1, 0, 1, 1); ratingMappingsLayout->addWidget(d->oneStar, 1, 1, 1, 1); ratingMappingsLayout->addWidget(d->twoStars, 1, 2, 1, 1); ratingMappingsLayout->addWidget(d->threeStars, 1, 3, 1, 1); ratingMappingsLayout->addWidget(d->fourStars, 1, 4, 1, 1); ratingMappingsLayout->addWidget(d->fiveStars, 1, 5, 1, 1); d->gridLayout->addWidget(d->logo, 0, 0, 1, 2); d->gridLayout->addWidget(d->topLabel, 0, 1, 1, 4); d->gridLayout->addWidget(d->tagTipLabel, 1, 0, 1, 6); d->gridLayout->addWidget(d->ratingTipLabel, 2, 0, 1, 6); d->gridLayout->addWidget(d->commentTipLabel, 3, 0, 1, 6); d->gridLayout->addWidget(d->subspaceLabel, 5, 0, 1, 2); d->gridLayout->addWidget(d->subspaceCombo, 5, 2, 1, 4); d->gridLayout->addWidget(d->titleLabel, 6, 0, 1, 2); d->gridLayout->addWidget(d->namespaceName, 6, 2, 1, 4); d->gridLayout->addWidget(d->specialOptsLabel, 7, 0, 1, 2); d->gridLayout->addWidget(d->specialOptsCombo, 7, 2, 1, 4); d->gridLayout->addWidget(d->alternativeNameLabel, 8, 0, 1, 2); d->gridLayout->addWidget(d->alternativeName, 8, 2, 1, 4); d->gridLayout->addWidget(d->altspecialOptsLabel, 9, 0, 1, 2); d->gridLayout->addWidget(d->altSpecialOptsCombo, 9, 2, 1, 4); d->gridLayout->addWidget(d->separatorLabel, 10, 0, 1, 2); d->gridLayout->addWidget(d->nameSpaceSeparator, 10, 2, 1, 4); d->gridLayout->addWidget(d->isTagLabel, 11, 0, 1, 2); d->gridLayout->addWidget(d->isPath, 11, 2, 1, 3); d->gridLayout->addWidget(d->ratingMappings, 12, 0, 2, 6); d->gridLayout->addWidget(d->tipLabel2, 14, 0, 1, 6); d->gridLayout->setContentsMargins(cmargin, cmargin, cmargin, cmargin); d->gridLayout->setSpacing(spacing); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(d->page); vbx->addWidget(d->buttons); } void NamespaceEditDlg::populateFields(NamespaceEntry& entry) { d->namespaceName->setText(entry.namespaceName); d->nameSpaceSeparator->setText(entry.separator); if (entry.tagPaths == NamespaceEntry::TAGPATH) { d->isPath->setChecked(true); } else { d->isPath->setChecked(false); } d->alternativeName->setText(entry.alternativeName); d->specialOptsCombo->setCurrentIndex(d->specialOptsCombo->findData(entry.specialOpts)); d->altSpecialOptsCombo->setCurrentIndex(d->altSpecialOptsCombo->findData(entry.secondNameOpts)); if (entry.convertRatio.size() == 6) { d->zeroStars->setValue(entry.convertRatio.at(0)); d->oneStar->setValue(entry.convertRatio.at(1)); d->twoStars->setValue(entry.convertRatio.at(2)); d->threeStars->setValue(entry.convertRatio.at(3)); d->fourStars->setValue(entry.convertRatio.at(4)); d->fiveStars->setValue(entry.convertRatio.at(5)); } } void NamespaceEditDlg::setType(NamespaceEntry::NamespaceType type) { - switch(type) + switch (type) { case NamespaceEntry::TAGS: qCDebug(DIGIKAM_GENERAL_LOG) << "Setting up tags"; d->ratingTipLabel->hide(); d->commentTipLabel->hide(); d->ratingMappings->hide(); + // disable IPTC and EXIV for tags + d->subspaceCombo->setItemData(0, 0, Qt::UserRole -1); d->subspaceCombo->setItemData(1, 0, Qt::UserRole -1); break; case NamespaceEntry::RATING: d->tagTipLabel->hide(); d->commentTipLabel->hide(); d->isPath->hide(); d->isTagLabel->hide(); d->separatorLabel->hide(); d->nameSpaceSeparator->hide(); break; case NamespaceEntry::COMMENT: d->tagTipLabel->hide(); d->ratingTipLabel->hide(); d->isPath->hide(); d->isTagLabel->hide(); d->separatorLabel->hide(); d->nameSpaceSeparator->hide(); d->ratingMappings->hide(); break; default: break; } } void NamespaceEditDlg::makeReadOnly() { QString txt = i18n("This is a default namespace. Default namespaces can only be disabled"); d->tipLabel2->setText(txt); d->tipLabel2->show(); d->subspaceCombo->setDisabled(true); d->specialOptsCombo->setDisabled(true); d->altSpecialOptsCombo->setDisabled(true); d->namespaceName->setDisabled(true); d->alternativeName->setDisabled(true); d->nameSpaceSeparator->setDisabled(true); d->isPath->setDisabled(true); d->ratingMappings->setDisabled(true); d->zeroStars->setDisabled(true); d->oneStar->setDisabled(true); d->twoStars->setDisabled(true); d->threeStars->setDisabled(true); d->fourStars->setDisabled(true); d->fiveStars->setDisabled(true); } bool NamespaceEditDlg::validifyCheck(QString& errMsg) { // bool result = true; NOT USED if (d->namespaceName->text().isEmpty()) { errMsg = i18n("The namespace name is required"); return false; } switch (d->subspaceCombo->currentData().toInt()) { case NamespaceEntry::EXIF: if (d->namespaceName->text().split(QLatin1Char('.')).first() != QLatin1String("Exif")) { errMsg = i18n("EXIF namespace name must start with \"Exif\"."); return false; } if (!d->alternativeName->text().isEmpty() && d->alternativeName->text().split(QLatin1Char('.')).first() != QLatin1String("Exif")) { errMsg = i18n("EXIF alternative namespace name must start with \"Exif\"."); return false; } break; case NamespaceEntry::IPTC: if (d->namespaceName->text().split(QLatin1Char('.')).first() != QLatin1String("Iptc")) { errMsg = i18n("IPTC namespace name must start with \"Iptc\"."); return false; } if (!d->alternativeName->text().isEmpty() && d->alternativeName->text().split(QLatin1Char('.')).first() != QLatin1String("Iptc")) { errMsg = i18n("IPTC alternative namespace name must start with \"Iptc\"."); return false; } break; case NamespaceEntry::XMP: if (d->namespaceName->text().split(QLatin1Char('.')).first() != QLatin1String("Xmp")) { errMsg = i18n("XMP namespace name must start with \"Xmp\"."); return false; } if (!d->alternativeName->text().isEmpty() && d->alternativeName->text().split(QLatin1Char('.')).first() != QLatin1String("Xmp")) { errMsg = i18n("XMP alternative namespace name must start with \"Xmp\"."); return false; } break; default: break; } switch (d->nsType) { case NamespaceEntry::TAGS: if (d->nameSpaceSeparator->text().isEmpty()) { errMsg = i18n("Tag Path separator is required"); return false; } if (d->nameSpaceSeparator->text().size() > 1) { errMsg = i18n("Only one character is now supported as tag path separator"); return false; } break; case NamespaceEntry::RATING: break; case NamespaceEntry::COMMENT: break; default: break; } return true; } void NamespaceEditDlg::saveData(NamespaceEntry& entry) { entry.namespaceName = d->namespaceName->text(); entry.separator = d->nameSpaceSeparator->text(); if (d->isPath->isChecked()) { entry.tagPaths = NamespaceEntry::TAGPATH; } else { entry.tagPaths = NamespaceEntry::TAG; } entry.alternativeName = d->alternativeName->text(); entry.specialOpts = (NamespaceEntry::SpecialOptions)d->specialOptsCombo->currentData().toInt(); entry.secondNameOpts = (NamespaceEntry::SpecialOptions)d->altSpecialOptsCombo->currentData().toInt(); entry.subspace = (NamespaceEntry::NsSubspace)d->subspaceCombo->currentData().toInt(); entry.convertRatio.clear(); entry.convertRatio.append(d->zeroStars->value()); entry.convertRatio.append(d->oneStar->value()); entry.convertRatio.append(d->twoStars->value()); entry.convertRatio.append(d->threeStars->value()); entry.convertRatio.append(d->fourStars->value()); entry.convertRatio.append(d->fiveStars->value()); } void NamespaceEditDlg::accept() { QString errMsg; if (validifyCheck(errMsg)) { QDialog::accept(); } else { d->tipLabel2->setText(errMsg); d->tipLabel2->show(); } } void NamespaceEditDlg::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/core/utilities/setup/metadata/namespacelistview.cpp b/core/utilities/setup/metadata/namespacelistview.cpp index f52ba262df..5bd0322f7b 100644 --- a/core/utilities/setup/metadata/namespacelistview.cpp +++ b/core/utilities/setup/metadata/namespacelistview.cpp @@ -1,179 +1,180 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-08-22 * Description : Reimplemented QListView for metadata setup, with support for * drag-n-drop * * Copyright (C) 2013-2015 by Veaceslav Munteanu * * 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 "namespacelistview.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" namespace Digikam { NamespaceListView::NamespaceListView(QWidget* const parent) : QListView(parent) { setAlternatingRowColors(true); setAcceptDrops(true); setDragEnabled(true); setDragDropMode(QAbstractItemView::InternalMove); setSelectionMode(QAbstractItemView::SingleSelection); } void NamespaceListView::startDrag(Qt::DropActions supportedActions) { QListView::startDrag(supportedActions); } QModelIndexList NamespaceListView::mySelectedIndexes() { return selectedIndexes(); } void NamespaceListView::dropEvent(QDropEvent* e) { QListView::dropEvent(e); + emit signalItemsChanged(); } QModelIndex NamespaceListView::indexVisuallyAt(const QPoint& p) { if (viewport()->rect().contains(p)) { QModelIndex index = indexAt(p); if (index.isValid() && visualRect(index).contains(p)) { return index; } } return QModelIndex(); } void NamespaceListView::slotDeleteSelected() { QModelIndexList sel = selectionModel()->selectedIndexes(); if (sel.isEmpty()) { return; } QStandardItemModel* const model = dynamic_cast(this->model()); if (!model) { qCDebug(DIGIKAM_GENERAL_LOG) << "Error! no model available!"; return; } foreach (const QModelIndex& index, sel) { QStandardItem* const root = model->invisibleRootItem(); root->removeRow(index.row()); } emit signalItemsChanged(); } void NamespaceListView::slotMoveItemDown() { QModelIndexList sel = selectionModel()->selectedIndexes(); if (sel.isEmpty()) { return; } QStandardItemModel* const model = dynamic_cast(this->model()); if (!model) { qCDebug(DIGIKAM_GENERAL_LOG) << "Error! no model available!"; return; } QModelIndex index = sel.first(); QStandardItem* const root = model->invisibleRootItem(); if (index.row() == root->rowCount() - 1) { return; } root->insertRow(index.row() + 1, root->takeRow(index.row())); setCurrentIndex(model->index(index.row() + 1, index.column(), index.parent())); emit signalItemsChanged(); } void NamespaceListView::slotMoveItemUp() { QModelIndexList sel = selectionModel()->selectedIndexes(); if (sel.isEmpty()) { return; } QStandardItemModel* const model = dynamic_cast(this->model()); if (!model) { qCDebug(DIGIKAM_GENERAL_LOG) << "Error! no model available!"; return; } QModelIndex index = sel.first(); QStandardItem* const root = model->invisibleRootItem(); if (index.row() == 0) { return; } root->insertRow(index.row() - 1, root->takeRow(index.row())); setCurrentIndex(model->index(index.row() - 1, index.column(), index.parent())); emit signalItemsChanged(); } } // namespace Digikam diff --git a/core/utilities/setup/metadata/namespacelistview.h b/core/utilities/setup/metadata/namespacelistview.h index 9fd2d99b0b..770165b603 100644 --- a/core/utilities/setup/metadata/namespacelistview.h +++ b/core/utilities/setup/metadata/namespacelistview.h @@ -1,80 +1,82 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2013-08-22 * Description : Reimplemented QListView for metadata setup, with support for * drag-n-drop * * Copyright (C) 2013-2015 by Veaceslav Munteanu * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_NAMESPACE_LISTVIEW_H #define DIGIKAM_NAMESPACE_LISTVIEW_H // Qt includes #include class QPoint; namespace Digikam { class NamespaceListView : public QListView { Q_OBJECT public: explicit NamespaceListView(QWidget* const parent = nullptr); QModelIndexList mySelectedIndexes(); protected: /** * Reimplemented methods to enable custom drag-n-drop in QListView */ void startDrag(Qt::DropActions supportedActions) override; void dropEvent(QDropEvent* e) override; QModelIndex indexVisuallyAt(const QPoint& p); -// /** -// * @brief contextMenuEvent - reimplemented method from QListView -// * to handle custom context menu -// */ -// void contextMenuEvent(QContextMenuEvent* event); + /** + * @brief contextMenuEvent - reimplemented method from QListView + * to handle custom context menu + */ +/* + void contextMenuEvent(QContextMenuEvent* event); +*/ Q_SIGNALS: void signalItemsChanged(); public Q_SLOTS: /** * @brief slotDeleteSelected - delete selected item from Quick Access List */ void slotDeleteSelected(); void slotMoveItemDown(); void slotMoveItemUp(); }; } // namespace Digikam #endif // DIGIKAM_NAMESPACE_LISTVIEW_H diff --git a/core/utilities/setup/metadata/setupmetadata.cpp b/core/utilities/setup/metadata/setupmetadata.cpp index d53e445109..f65da440b3 100644 --- a/core/utilities/setup/metadata/setupmetadata.cpp +++ b/core/utilities/setup/metadata/setupmetadata.cpp @@ -1,914 +1,919 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-08-03 * Description : setup Metadata tab. * * Copyright (C) 2003-2004 by Ralf Holzer * Copyright (C) 2003-2020 by Gilles Caulier * Copyright (C) 2009-2012 by Marcel Wiesweg * Copyright (C) 2017 by Simon Frei * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupmetadata.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "advancedmetadatatab.h" #include "applicationsettings.h" #include "dactivelabel.h" #include "digikam_config.h" #include "digikam_debug.h" #include "metaengine.h" #include "metadatapanel.h" #include "metaenginesettings.h" #include "setuputils.h" namespace Digikam { class Q_DECL_HIDDEN SetupMetadata::Private { public: explicit Private() : exifAutoRotateOriginal(false), exifAutoRotateShowedInfo(false), clearMetadataShowedInfo(false), fieldsGroup(nullptr), readWriteGroup(nullptr), rotationGroup(nullptr), rotationAdvGroup(nullptr), saveTagsBox(nullptr), saveCommentsBox(nullptr), saveRatingBox(nullptr), savePickLabelBox(nullptr), saveColorLabelBox(nullptr), saveDateTimeBox(nullptr), saveTemplateBox(nullptr), saveFaceTags(nullptr), useLazySync(nullptr), writeRawFilesBox(nullptr), writeXMPSidecarBox(nullptr), readXMPSidecarBox(nullptr), sidecarFileNameBox(nullptr), updateFileTimeStampBox(nullptr), rescanImageIfModifiedBox(nullptr), clearMetadataIfRescanBox(nullptr), writingModeCombo(nullptr), rotateByFlag(nullptr), rotateByContents(nullptr), allowRotateByMetadata(nullptr), allowLossyRotate(nullptr), exifRotateBox(nullptr), exifSetOrientationBox(nullptr), saveToBalooBox(nullptr), readFromBalooBox(nullptr), tab(nullptr), displaySubTab(nullptr), tagsCfgPanel(nullptr), advTab(nullptr), extensionsEdit(nullptr) { } bool exifAutoRotateOriginal; bool exifAutoRotateShowedInfo; bool clearMetadataShowedInfo; QGroupBox* fieldsGroup; QGroupBox* readWriteGroup; QGroupBox* rotationGroup; QGroupBox* rotationAdvGroup; QCheckBox* saveTagsBox; QCheckBox* saveCommentsBox; QCheckBox* saveRatingBox; QCheckBox* savePickLabelBox; QCheckBox* saveColorLabelBox; QCheckBox* saveDateTimeBox; QCheckBox* saveTemplateBox; QCheckBox* saveFaceTags; QCheckBox* useLazySync; QCheckBox* writeRawFilesBox; QCheckBox* writeXMPSidecarBox; QCheckBox* readXMPSidecarBox; QCheckBox* sidecarFileNameBox; QCheckBox* updateFileTimeStampBox; QCheckBox* rescanImageIfModifiedBox; QCheckBox* clearMetadataIfRescanBox; QComboBox* writingModeCombo; QRadioButton* rotateByFlag; QRadioButton* rotateByContents; QCheckBox* allowRotateByMetadata; QCheckBox* allowLossyRotate; QCheckBox* exifRotateBox; QCheckBox* exifSetOrientationBox; QCheckBox* saveToBalooBox; QCheckBox* readFromBalooBox; QTabWidget* tab; QTabWidget* displaySubTab; MetadataPanel* tagsCfgPanel; AdvancedMetadataTab* advTab; QLineEdit* extensionsEdit; }; SetupMetadata::SetupMetadata(QWidget* const parent) : QScrollArea(parent), d(new Private) { - d->tab = new QTabWidget(viewport()); + d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); - QWidget* const panel = new QWidget; - QVBoxLayout* const mainLayout = new QVBoxLayout; + QWidget* const panel = new QWidget; + QVBoxLayout* const mainLayout = new QVBoxLayout; // -------------------------------------------------------- d->fieldsGroup = new QGroupBox; QGridLayout* const fieldsLayout = new QGridLayout; d->fieldsGroup->setWhatsThis(xi18nc("@info:whatsthis", "In addition to the pixel content, image files usually " "contain a variety of metadata. A lot of the parameters you can use " "in digiKam to manage files, such as rating or comment, can be written " "to the files' metadata. " "Storing in metadata allows one to preserve this information " "when moving or sending the files to different systems.")); QLabel* const fieldsIconLabel = new QLabel; fieldsIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("format-list-unordered")).pixmap(32)); QLabel* const fieldsLabel = new QLabel(i18nc("@label", "Write This Information to the Metadata")); d->saveTagsBox = new QCheckBox; d->saveTagsBox->setText(i18nc("@option:check", "Image tags")); d->saveTagsBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item tags " "in the XMP and IPTC tags.")); d->saveCommentsBox = new QCheckBox; d->saveCommentsBox->setText(i18nc("@option:check", "Captions and title")); d->saveCommentsBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store item caption and title " "in the JFIF Comment section, the EXIF tag, the XMP tag, " "and the IPTC tag.")); d->saveRatingBox = new QCheckBox; d->saveRatingBox->setText(i18nc("@option:check", "Rating")); d->saveRatingBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item rating " "in the EXIF tag and the XMP tags.")); d->savePickLabelBox = new QCheckBox; d->savePickLabelBox->setText(i18nc("@option:check", "Pick label")); d->savePickLabelBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item pick label " "in the XMP tags.")); d->saveColorLabelBox = new QCheckBox; d->saveColorLabelBox->setText(i18nc("@option:check", "Color label")); d->saveColorLabelBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item color label " "in the XMP tags.")); d->saveDateTimeBox = new QCheckBox; d->saveDateTimeBox->setText(i18nc("@option:check", "Timestamps")); d->saveDateTimeBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the item date and time " "in the EXIF, XMP, and IPTC tags.")); d->saveTemplateBox = new QCheckBox; d->saveTemplateBox->setText(i18nc("@option:check", "Metadata templates (Copyright etc.)")); d->saveTemplateBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store the metadata " "template in the XMP and the IPTC tags. " "You can set template values to Template setup page.")); d->saveFaceTags = new QCheckBox; d->saveFaceTags->setText(i18nc("@option:check", "Face Tags (including face areas)")); d->saveFaceTags->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to store face tags " "with face rectangles in the XMP tags.")); fieldsLayout->addWidget(fieldsIconLabel, 0, 0, 2, 3); fieldsLayout->addWidget(fieldsLabel, 0, 1, 2, 3); fieldsLayout->addWidget(d->saveTagsBox, 2, 0, 1, 3); fieldsLayout->addWidget(d->saveCommentsBox, 3, 0, 1, 3); fieldsLayout->addWidget(d->saveRatingBox, 4, 0, 1, 3); fieldsLayout->addWidget(d->savePickLabelBox, 5, 0, 1, 3); fieldsLayout->addWidget(d->saveColorLabelBox, 6, 0, 1, 3); fieldsLayout->addWidget(d->saveDateTimeBox, 7, 0, 1, 3); fieldsLayout->addWidget(d->saveTemplateBox, 8, 0, 1, 3); fieldsLayout->addWidget(d->saveFaceTags, 9 ,0, 1, 3); fieldsLayout->setColumnStretch(3, 10); d->fieldsGroup->setLayout(fieldsLayout); // -------------------------------------------------------- d->readWriteGroup = new QGroupBox; QGridLayout* const readWriteLayout = new QGridLayout; QLabel* const readWriteIconLabel = new QLabel; readWriteIconLabel->setPixmap(QIcon::fromTheme(QLatin1String("document-open")).pixmap(32)); QLabel* const readWriteLabel = new QLabel(i18nc("@label", "Reading and Writing Metadata")); d->useLazySync = new QCheckBox; d->useLazySync->setText(i18nc("@option:check", "Use lazy synchronization")); d->useLazySync->setWhatsThis(i18nc("@info:whatsthis", "Instead of synchronizing metadata, just schedule it for synchronization." "Synchronization can be done later by triggering the apply pending, or at digikam exit")); d->writeRawFilesBox = new QCheckBox; d->writeRawFilesBox->setText(i18nc("@option:check", "If possible write Metadata to RAW files (experimental)")); d->writeRawFilesBox->setWhatsThis(i18nc("@info:whatsthis", "Turn on this option to write metadata into RAW TIFF/EP files. " "This feature requires the Exiv2 shared library, version >= 0.18.0. It is still " "experimental, and is disabled by default.")); d->writeRawFilesBox->setEnabled(MetaEngine::supportMetadataWritting(QLatin1String("image/x-raw"))); d->updateFileTimeStampBox = new QCheckBox; d->updateFileTimeStampBox->setText(i18nc("@option:check", "&Update file modification timestamp when files are modified")); d->updateFileTimeStampBox->setWhatsThis(i18nc("@info:whatsthis", "Turn off this option to not update file timestamps when files are changed as " "when you update metadata or image data. Note: disabling this option can " "introduce some dysfunctions with applications which use file timestamps " "properties to detect file modifications automatically.")); d->rescanImageIfModifiedBox = new QCheckBox; d->rescanImageIfModifiedBox->setText(i18nc("@option:check", "&Rescan file when files are modified")); d->rescanImageIfModifiedBox->setWhatsThis(i18nc("@info:whatsthis", "Turning this option on, will force digiKam to rescan files that has been " "modified outside digiKam. If a file has changed it is file size or if " "the last modified timestamp has changed, a rescan of that " "file will be performed when digiKam starts.")); d->clearMetadataIfRescanBox = new QCheckBox; d->clearMetadataIfRescanBox->setText(i18nc("@option:check", "&Clean up the metadata from the database when rescan files")); d->clearMetadataIfRescanBox->setWhatsThis(i18nc("@info:whatsthis", "Turning this option on, will force digiKam to delete the file metadata " "contained in the database before the file is rescanned. WARNING: " "if your metadata has been written to the database only and not " "to the file or sidecar, you will be able to lose inserted " "metadata such as tags, keywords, or geographic coordinates.")); readWriteLayout->addWidget(readWriteIconLabel, 0, 0, 2, 3); readWriteLayout->addWidget(readWriteLabel, 0, 1, 2, 3); readWriteLayout->addWidget(d->useLazySync, 2, 0, 1, 3); readWriteLayout->addWidget(d->writeRawFilesBox, 3, 0, 1, 3); readWriteLayout->addWidget(d->updateFileTimeStampBox, 4, 0, 1, 3); readWriteLayout->addWidget(d->rescanImageIfModifiedBox, 5, 0, 1, 3); readWriteLayout->addWidget(d->clearMetadataIfRescanBox, 6, 0, 1, 3); readWriteLayout->setColumnStretch(3, 10); d->readWriteGroup->setLayout(readWriteLayout); // -------------------------------------------------------- QFrame* const infoBox = new QFrame; QGridLayout* const infoBoxGrid = new QGridLayout; infoBox->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); DActiveLabel* const exiv2LogoLabel = new DActiveLabel(QUrl(QLatin1String("https://www.exiv2.org")), QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/logo-exiv2.png")), infoBox); exiv2LogoLabel->setWhatsThis(i18n("Visit Exiv2 project website")); QLabel* const explanation = new QLabel(infoBox); explanation->setOpenExternalLinks(true); explanation->setWordWrap(true); QString txt; txt.append(i18n("

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

")); txt.append(i18n("

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

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

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

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

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

" "

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

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

Add file types to be recognised as sidecars.

" "

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

" "

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

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

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

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

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

" "

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

" "

We strongly recommend not to enable this option.

"), QMessageBox::Yes | QMessageBox::No, this); msgBox->button(QMessageBox::Yes)->setText(i18n("Yes I understand")); msgBox->setDefaultButton(QMessageBox::No); int result = msgBox->exec(); delete msgBox; if (result == QMessageBox::Yes) { QPointer msgBox = new QMessageBox(QMessageBox::Warning, qApp->applicationName(), i18n("You would rather disable writing metadata to RAW files?"), QMessageBox::Yes | QMessageBox::No, this); int result = msgBox->exec(); delete msgBox; if (result == QMessageBox::No) { return; } } d->writeRawFilesBox->setChecked(false); } } } // namespace Digikam diff --git a/core/utilities/setup/setup.cpp b/core/utilities/setup/setup.cpp index 640ddd476f..1cba75a075 100644 --- a/core/utilities/setup/setup.cpp +++ b/core/utilities/setup/setup.cpp @@ -1,585 +1,602 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-03 * Description : digiKam setup dialog. * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2003-2020 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 #include #include // Local includes #include "digikam_debug.h" #include "loadingcacheinterface.h" #include "applicationsettings.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 "setupplugins.h" #include "importsettings.h" #include "dxmlguiwindow.h" namespace Digikam { class Q_DECL_HIDDEN Setup::Private { public: explicit Private() : page_database(nullptr), page_collections(nullptr), page_albumView(nullptr), page_tooltip(nullptr), page_metadata(nullptr), page_template(nullptr), page_lighttable(nullptr), page_editor(nullptr), page_slideshow(nullptr), page_imagequalitysorter(nullptr), page_icc(nullptr), page_camera(nullptr), page_plugins(nullptr), page_misc(nullptr), databasePage(nullptr), collectionsPage(nullptr), albumViewPage(nullptr), tooltipPage(nullptr), metadataPage(nullptr), templatePage(nullptr), lighttablePage(nullptr), editorPage(nullptr), slideshowPage(nullptr), imageQualitySorterPage(nullptr), iccPage(nullptr), cameraPage(nullptr), pluginsPage(nullptr), miscPage(nullptr) { } 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_plugins; 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; SetupPlugins* pluginsPage; 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); 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))); d->pluginsPage = new SetupPlugins(); d->page_plugins = addPage(d->pluginsPage, i18n("Plugins")); d->page_plugins->setHeader(i18n("Plug-in Settings
" "Set which plugins will be accessible from application
")); d->page_plugins->setIcon(QIcon::fromTheme(QLatin1String("preferences-plugin"))); 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); } } connect(buttonBox(), SIGNAL(helpRequested()), this, SLOT(slotHelp())); connect(buttonBox()->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &Setup::slotOkClicked); 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 == PluginsPage || - page == MiscellaneousPage) + + if ( + (page == CollectionsPage) || + (page == AlbumViewPage) || + (page == TemplatePage) || + (page == LightTablePage) || + (page == EditorPage) || + (page == PluginsPage) || + (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(nullptr, 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(nullptr, 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; + + if (!cur) + { + return false; + } SetupMetadata* const widget = dynamic_cast(cur->widget()); - if (!widget) return false; + + 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->pluginsPage->applySettings(); d->miscPage->applySettings(); ApplicationSettings::instance()->emitSetupChanged(); ImportSettings::instance()->emitSetupChanged(); qApp->restoreOverrideCursor(); if (d->metadataPage->exifAutoRotateHasChanged()) { LoadingCacheInterface::cleanThumbnailCache(); } accept(); } void Setup::showPage(Setup::Page page) { DConfigDlgWdgItem* item = nullptr; 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_plugins) { return PluginsPage; } 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::PluginsPage: return page_plugins; case Setup::MiscellaneousPage: return page_misc; default: return nullptr; } } } // namespace Digikam diff --git a/core/utilities/setup/setup.h b/core/utilities/setup/setup.h index 3900d63860..5b10216365 100644 --- a/core/utilities/setup/setup.h +++ b/core/utilities/setup/setup.h @@ -1,109 +1,110 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-02-03 * Description : digiKam setup dialog. * * Copyright (C) 2003-2005 by Renchi Raju * Copyright (C) 2003-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_SETUP_H #define DIGIKAM_SETUP_H // Local includes #include "digikam_config.h" #include "setuptemplate.h" #include "template.h" #include "searchtextbar.h" #include "dconfigdlg.h" namespace Digikam { class Setup : public DConfigDlg { Q_OBJECT public: enum Page { LastPageUsed = -1, DatabasePage = 0, CollectionsPage, AlbumViewPage, ToolTipPage, MetadataPage, TemplatePage, EditorPage, ICCPage, LightTablePage, SlideshowPage, ImageQualityPage, CameraPage, PluginsPage, MiscellaneousPage, + SetupPageEnumLast }; public: - /* + /** * Show a setup dialog. The specified page will be selected. * True is returned if the dialog was closed with Ok. */ static bool execDialog(Page page = LastPageUsed); static bool execDialog(QWidget* const parent, Page page = LastPageUsed); - /* + /** * Show a setup dialog. Only the specified page will be available. */ static bool execSinglePage(Page page); static bool execSinglePage(QWidget* const parent, Page page); static bool execTemplateEditor(QWidget* const parent, const Template& t); void setTemplate(const Template& t); static bool execMetadataFilters(QWidget* const parent, int tab); QSize sizeHint() const override; private Q_SLOTS: void slotHelp(); void slotOkClicked(); private: explicit Setup(QWidget* const parent = nullptr); ~Setup(); Setup::Page activePageIndex() const; void showPage(Setup::Page page); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_SETUP_H diff --git a/core/utilities/setup/setupdatabase.cpp b/core/utilities/setup/setupdatabase.cpp index ceb6931e26..ed21c77ff3 100644 --- a/core/utilities/setup/setupdatabase.cpp +++ b/core/utilities/setup/setupdatabase.cpp @@ -1,323 +1,325 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2009-11-14 * Description : database setup tab * * Copyright (C) 2009-2010 by Holger Foerster * Copyright (C) 2012-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupdatabase.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 // KDE includes #include // Local includes #include "albummanager.h" #include "applicationsettings.h" #include "coredbschemaupdater.h" #include "databaseserverstarter.h" #include "dbengineparameters.h" #include "dbsettingswidget.h" #include "digikam_debug.h" #include "scancontroller.h" #include "setuputils.h" namespace Digikam { class Q_DECL_HIDDEN SetupDatabase::Private { public: explicit Private() : databaseWidget(nullptr), updateBox(nullptr), hashesButton(nullptr), ignoreEdit(nullptr), ignoreLabel(nullptr) { } DatabaseSettingsWidget* databaseWidget; QGroupBox* updateBox; QPushButton* hashesButton; QLineEdit* ignoreEdit; QLabel* ignoreLabel; }; SetupDatabase::SetupDatabase(QWidget* const parent) : QScrollArea(parent), d(new Private) { QTabWidget* tab = new QTabWidget(viewport()); setWidget(tab); setWidgetResizable(true); // -------------------------------------------------------- QWidget* const settingsPanel = new QWidget(tab); QVBoxLayout* settingsLayout = new QVBoxLayout(settingsPanel); - d->databaseWidget = new DatabaseSettingsWidget; + d->databaseWidget = new DatabaseSettingsWidget; settingsLayout->addWidget(d->databaseWidget); if (!CoreDbSchemaUpdater::isUniqueHashUpToDate()) { createUpdateBox(); settingsLayout->addStretch(10); settingsLayout->addWidget(d->updateBox); } tab->insertTab(DbSettings, settingsPanel, i18nc("@title:tab", "Database Settings")); // -------------------------------------------------------- - QWidget* const ignorePanel = new QWidget(tab); + QWidget* const ignorePanel = new QWidget(tab); QGridLayout* ignoreLayout = new QGridLayout(ignorePanel); QLabel* const ignoreInfoLabel = new QLabel( i18n("

Set the names of directories that you want to ignore " "from your photo collections. The names are case sensitive " "and should be separated by a semicolon.

" "

This is for example useful when you store your photos " "on a Synology NAS (Network Attached Storage). In every " "directory the system creates a subdirectory @eaDir to " "store thumbnails. To avoid digiKam inserting the original " "photo and its corresponding thumbnail twice, @eaDir is " "ignored by default.

" "

To re-include directories that are ignored by default " "prefix it with a minus, e.g. -@eaDir.

"), ignorePanel); ignoreInfoLabel->setWordWrap(true); QLabel* const logoLabel1 = new QLabel(ignorePanel); logoLabel1->setPixmap(QIcon::fromTheme(QLatin1String("folder")).pixmap(48)); d->ignoreLabel = new QLabel(ignorePanel); d->ignoreLabel->setText(i18n("Additional directories to ignore " "(Currently ignored directories):")); d->ignoreEdit = new QLineEdit(ignorePanel); d->ignoreEdit->setClearButtonEnabled(true); d->ignoreEdit->setPlaceholderText(i18n("Enter directories that you want to " "ignore from adding to your collections.")); ignoreInfoLabel->setBuddy(d->ignoreEdit); int row = 0; ignoreLayout->addWidget(ignoreInfoLabel, row, 0, 1, 2); row++; ignoreLayout->addWidget(logoLabel1, row, 0, 2, 1); ignoreLayout->addWidget(d->ignoreLabel, row, 1, 1, 1); row++; ignoreLayout->addWidget(d->ignoreEdit, row, 1, 1, 1); row++; ignoreLayout->setColumnStretch(1, 10); ignoreLayout->setRowStretch(row, 10); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); ignoreLayout->setContentsMargins(spacing, spacing, spacing, spacing); ignoreLayout->setSpacing(spacing); connect(d->ignoreLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotShowCurrentIgnoredDirectoriesSettings())); tab->insertTab(IgnoreDirs, ignorePanel, i18nc("@title:tab", "Ignored Directories")); // -------------------------------------------------------- readSettings(); adjustSize(); } SetupDatabase::~SetupDatabase() { delete d; } void SetupDatabase::applySettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } QString ignoreDirectory; CoreDbAccess().db()->getUserIgnoreDirectoryFilterSettings(&ignoreDirectory); if (d->ignoreEdit->text() != ignoreDirectory) { CoreDbAccess().db()->setUserIgnoreDirectoryFilterSettings( cleanUserFilterString(d->ignoreEdit->text(), true, true)); ScanController::instance()->completeCollectionScanInBackground(false); } if (d->databaseWidget->getDbEngineParameters() == d->databaseWidget->orgDatabasePrm()) { qCDebug(DIGIKAM_GENERAL_LOG) << "No DB settings changes. Do nothing..."; return; } if (!d->databaseWidget->checkDatabaseSettings()) { qCDebug(DIGIKAM_GENERAL_LOG) << "DB settings check invalid. Do nothing..."; return; } switch (d->databaseWidget->databaseType()) { case DatabaseSettingsWidget::SQlite: { qCDebug(DIGIKAM_GENERAL_LOG) << "Switch to SQlite DB config..."; DbEngineParameters params = d->databaseWidget->getDbEngineParameters(); settings->setDbEngineParameters(params); settings->saveSettings(); AlbumManager::instance()->changeDatabase(params); break; } + case DatabaseSettingsWidget::MysqlInternal: { qCDebug(DIGIKAM_GENERAL_LOG) << "Switch to Mysql Internal DB config..."; DbEngineParameters params = d->databaseWidget->getDbEngineParameters(); settings->setDbEngineParameters(params); settings->saveSettings(); AlbumManager::instance()->changeDatabase(params); break; } + default: // DatabaseSettingsWidget::MysqlServer { qCDebug(DIGIKAM_GENERAL_LOG) << "Switch to Mysql server DB config..."; DbEngineParameters params = d->databaseWidget->getDbEngineParameters(); settings->setDbEngineParameters(params); settings->saveSettings(); AlbumManager::instance()->changeDatabase(params); break; } } } void SetupDatabase::readSettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } QString ignoreDirectory; CoreDbAccess().db()->getUserIgnoreDirectoryFilterSettings(&ignoreDirectory); d->ignoreEdit->setText(ignoreDirectory); d->databaseWidget->setParametersFromSettings(settings); } void SetupDatabase::upgradeUniqueHashes() { int result = QMessageBox::warning(this, qApp->applicationName(), i18nc("@info", "

The process of updating the file hashes takes a few minutes.

" "

Please ensure that any important collections on removable media are connected. " "After the upgrade you cannot use your database with a digiKam version " "prior to 2.0.

" "

Do you want to begin the update?

"), QMessageBox::Yes | QMessageBox::No); if (result == QMessageBox::Yes) { ScanController::instance()->updateUniqueHash(); } } void SetupDatabase::createUpdateBox() { d->updateBox = new QGroupBox(i18nc("@title:group", "Updates")); QGridLayout* const updateLayout = new QGridLayout; d->hashesButton = new QPushButton(i18nc("@action:button", "Update File Hashes")); d->hashesButton->setWhatsThis(i18nc("@info:tooltip", "File hashes are used to identify identical files and to display thumbnails. " "A new, improved algorithm to create the hash is now used. " "The old algorithm, though, still works quite well, so it is recommended to " "carry out this upgrade, but not required.
" "After the upgrade you cannot use your database with a digiKam version " "prior to 2.0.
")); QPushButton* const infoHash = new QPushButton; infoHash->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); infoHash->setToolTip(i18nc("@info:tooltip", "Get information about Update File Hashes")); updateLayout->addWidget(d->hashesButton, 0, 0); updateLayout->addWidget(infoHash, 0, 1); updateLayout->setColumnStretch(2, 1); d->updateBox->setLayout(updateLayout); connect(d->hashesButton, SIGNAL(clicked()), this, SLOT(upgradeUniqueHashes())); connect(infoHash, SIGNAL(clicked()), this, SLOT(showHashInformation())); } void SetupDatabase::showHashInformation() { qApp->postEvent(d->hashesButton, new QHelpEvent(QEvent::WhatsThis, QPoint(0, 0), QCursor::pos())); } void SetupDatabase::slotShowCurrentIgnoredDirectoriesSettings() const { QStringList ignoreDirectoryList; CoreDbAccess().db()->getIgnoreDirectoryFilterSettings(&ignoreDirectoryList); QString text = i18n("

Directories starting with a dot are ignored by " "default.
%1

", ignoreDirectoryList.join(QLatin1Char(';'))); QWhatsThis::showText(d->ignoreLabel->mapToGlobal(QPoint(0, 0)), text, d->ignoreLabel); } } // namespace Digikam diff --git a/core/utilities/setup/setupicc.cpp b/core/utilities/setup/setupicc.cpp index 690a481ad6..09b706ac27 100644 --- a/core/utilities/setup/setupicc.cpp +++ b/core/utilities/setup/setupicc.cpp @@ -1,968 +1,987 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-11-24 * Description : Color management setup tab. * * Copyright (C) 2005-2007 by F.J. Cruz * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2009-2012 by Marcel Wiesweg * * 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 "setupicc.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "dlayoutbox.h" #include "squeezedcombobox.h" #include "digikam_debug.h" #include "applicationsettings.h" #include "iccprofileinfodlg.h" #include "iccprofilescombobox.h" #include "iccsettings.h" #include "iccsettingscontainer.h" #include "dactivelabel.h" #include "dfileselector.h" namespace Digikam { class Q_DECL_HIDDEN SetupICC::Private { public: explicit Private() : iccFolderLabel(nullptr), enableColorManagement(nullptr), defaultSRGBConvert(nullptr), bpcAlgorithm(nullptr), managedView(nullptr), managedPreviews(nullptr), defaultAskMismatch(nullptr), defaultConvertMismatch(nullptr), defaultAskMissing(nullptr), defaultSRGBMissing(nullptr), defaultWSMissing(nullptr), defaultInputMissing(nullptr), defaultAskRaw(nullptr), defaultInputRaw(nullptr), defaultGuessRaw(nullptr), infoWorkProfiles(nullptr), infoMonitorProfiles(nullptr), infoInProfiles(nullptr), infoProofProfiles(nullptr), workspaceGB(nullptr), mismatchGB(nullptr), missingGB(nullptr), rawGB(nullptr), inputGB(nullptr), viewGB(nullptr), proofGB(nullptr), iccFolderGB(nullptr), advancedSettingsGB(nullptr), defaultPathKU(nullptr), renderingIntentKC(nullptr), behaviorPanel(nullptr), profilesPanel(nullptr), advancedPanel(nullptr), tab(nullptr), dlgBtnBox(nullptr), inProfilesKC(nullptr), workProfilesKC(nullptr), proofProfilesKC(nullptr), monitorProfilesKC(nullptr) { } QLabel* iccFolderLabel; QCheckBox* enableColorManagement; QCheckBox* defaultSRGBConvert; QCheckBox* bpcAlgorithm; QCheckBox* managedView; QCheckBox* managedPreviews; QRadioButton* defaultAskMismatch; QRadioButton* defaultConvertMismatch; QRadioButton* defaultAskMissing; QRadioButton* defaultSRGBMissing; QRadioButton* defaultWSMissing; QRadioButton* defaultInputMissing; QRadioButton* defaultAskRaw; QRadioButton* defaultInputRaw; QRadioButton* defaultGuessRaw; QPushButton* infoWorkProfiles; QPushButton* infoMonitorProfiles; QPushButton* infoInProfiles; QPushButton* infoProofProfiles; QGroupBox* workspaceGB; QGroupBox* mismatchGB; QGroupBox* missingGB; QGroupBox* rawGB; QGroupBox* inputGB; QGroupBox* viewGB; QGroupBox* proofGB; QGroupBox* iccFolderGB; QGroupBox* advancedSettingsGB; DFileSelector* defaultPathKU; IccRenderingIntentComboBox* renderingIntentKC; QWidget* behaviorPanel; QWidget* profilesPanel; QWidget* advancedPanel; QTabWidget* tab; QDialogButtonBox* dlgBtnBox; IccProfilesComboBox* inProfilesKC; IccProfilesComboBox* workProfilesKC; IccProfilesComboBox* proofProfilesKC; IccProfilesComboBox* monitorProfilesKC; }; SetupICC::SetupICC(QDialogButtonBox* const dlgBtnBox, QWidget* const parent) : QScrollArea(parent), d(new Private) { const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); d->dlgBtnBox = dlgBtnBox; d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); d->behaviorPanel = new QWidget; QVBoxLayout* const mainLayout = new QVBoxLayout(d->behaviorPanel); // -------------------------------------------------------- QWidget* const colorPolicy = new QWidget; QGridLayout* const gridHeader = new QGridLayout(colorPolicy); d->enableColorManagement = new QCheckBox(colorPolicy); d->enableColorManagement->setText(i18n("Enable Color Management")); d->enableColorManagement->setWhatsThis(i18n("
  • Checked: Color Management is enabled
  • " "
  • Unchecked: Color Management is " "disabled
")); DActiveLabel* const lcmsLogoLabel = new DActiveLabel(QUrl(QLatin1String("http://www.littlecms.com")), QStandardPaths::locate(QStandardPaths::GenericDataLocation, QLatin1String("digikam/data/logo-lcms.png")), colorPolicy); lcmsLogoLabel->setToolTip(i18n("Visit Little CMS project website")); gridHeader->addWidget(d->enableColorManagement, 0, 0, 1, 1); gridHeader->addWidget(lcmsLogoLabel, 0, 2, 1, 1); gridHeader->setColumnStretch(1, 10); gridHeader->setContentsMargins(spacing, spacing, spacing, spacing); gridHeader->setSpacing(0); // -------------------------------------------------------- d->workspaceGB = new QGroupBox(i18n("Working Color Space")); QHBoxLayout* const hboxWS = new QHBoxLayout(d->workspaceGB); QLabel* const workIcon = new QLabel; workIcon->setPixmap(QIcon::fromTheme(QLatin1String("input-tablet")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize))); d->workProfilesKC = new IccProfilesComboBox; d->workProfilesKC->setWhatsThis(i18n("

This is the color space all the images will be converted to when opened " "(if you choose to convert) and the profile that will be embedded when saving. " "Good and safe choices are Adobe RGB (1998) and sRGB IEC61966-2.1

")); d->infoWorkProfiles = new QPushButton; d->infoWorkProfiles->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoWorkProfiles->setWhatsThis(i18n("

You can use this button to get more detailed " "information about the selected workspace profile.

")); hboxWS->addWidget(workIcon); hboxWS->addWidget(d->workProfilesKC, 10); hboxWS->addWidget(d->infoWorkProfiles); // -------------------------------------------------------- - d->mismatchGB = new QGroupBox;//(i18n("Behavior on Profile Mismatch"); + d->mismatchGB = new QGroupBox; // NOTE: Behavior on Profile Mismatch QVBoxLayout* const vlayMismatch = new QVBoxLayout(d->mismatchGB); QLabel* const behaviorIcon = new QLabel; behaviorIcon->setPixmap(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(32)); QLabel* const behaviorLabel = new QLabel(i18n("When the profile of an image does not match the working color space")); behaviorLabel->setWordWrap(true); QHBoxLayout* const hboxBL = new QHBoxLayout; hboxBL->addWidget(behaviorIcon); hboxBL->addWidget(behaviorLabel, 10); d->defaultAskMismatch = new QRadioButton(d->mismatchGB); d->defaultAskMismatch->setText(i18n("Ask when opening the image")); d->defaultAskMismatch->setWhatsThis(i18n("

If an image has an embedded color profile not matching the working " "space profile, digiKam will ask if you want to convert to the working space, " "keep the embedded profile or discard the embedded profile and assign " "a different one.

")); d->defaultConvertMismatch = new QRadioButton(d->mismatchGB); d->defaultConvertMismatch->setText(i18n("Convert the image to the working color space")); d->defaultConvertMismatch->setWhatsThis(i18n("

If an image has an embedded color profile not matching the working " "space profile, digiKam will convert the image's color information to " "the working color space. This changes the pixel data, but not the " "appearance of the image.

")); vlayMismatch->addLayout(hboxBL); vlayMismatch->addWidget(d->defaultAskMismatch); vlayMismatch->addWidget(d->defaultConvertMismatch); // -------------------------------------------------------- d->missingGB = new QGroupBox;//(i18n("Missing Profile Behavior")); QVBoxLayout* const vlayMissing = new QVBoxLayout(d->missingGB); QLabel* const missingIcon = new QLabel; missingIcon->setPixmap(QIcon::fromTheme(QLatin1String("paint-unknown")).pixmap(32)); QLabel* const missingLabel = new QLabel(i18n("When an image has no color profile information")); missingLabel->setWordWrap(true); - QHBoxLayout* const hboxMP = new QHBoxLayout; + QHBoxLayout* const hboxMP = new QHBoxLayout; hboxMP->addWidget(missingIcon); hboxMP->addWidget(missingLabel, 10); - d->defaultAskMissing = new QRadioButton(i18n("Ask when opening the image")); + d->defaultAskMissing = new QRadioButton(i18n("Ask when opening the image")); d->defaultAskMissing->setWhatsThis(i18n("

If an image has no embedded color profile, " "digiKam will ask which color space shall be used to interpret the image " "and to which color space it shall be transformed for editing.

")); d->defaultSRGBMissing = new QRadioButton(i18n("Assume it is using the sRGB color space (Internet standard)")); + /** * @todo d->defaultSRGBMissing->setWhatsThis( i18n("

")); */ d->defaultSRGBConvert = new QCheckBox(i18n("and convert it to the working color space")); + /** * @todo d->defaultSRGBConvert->setWhatsThis( i18n("

")); */ d->defaultSRGBConvert->setChecked(true); QGridLayout* const gridRgb = new QGridLayout; gridRgb->addWidget(d->defaultSRGBMissing, 0, 0, 1, 2); gridRgb->addWidget(d->defaultSRGBConvert, 1, 1); gridRgb->setColumnMinimumWidth(0, 10); d->defaultWSMissing = new QRadioButton(i18n("Assume it is using the working color space")); + /** * @todo d->defaultWSMissing->setWhatsThis( i18n("

")); */ d->defaultInputMissing = new QRadioButton(i18n("Convert it from default input color space to working space")); + /** * @todo d->defaultWSMissing->setWhatsThis( i18n("

")); */ vlayMissing->addLayout(hboxMP); vlayMissing->addWidget(d->defaultAskMissing); vlayMissing->addLayout(gridRgb); vlayMissing->addWidget(d->defaultWSMissing); vlayMissing->addWidget(d->defaultInputMissing); // -------------------------------------------------------- d->rawGB = new QGroupBox;//(i18n("Raw File Behavior")); QVBoxLayout* const vlayRaw = new QVBoxLayout(d->rawGB); QLabel* const rawBehaviorIcon = new QLabel; rawBehaviorIcon->setPixmap(QIcon::fromTheme(QLatin1String("image-x-adobe-dng")).pixmap(32)); QLabel* const rawBehaviorLabel = new QLabel(i18n("When loading a RAW file with uncalibrated colors")); rawBehaviorLabel->setWordWrap(true); QHBoxLayout* const hboxRF = new QHBoxLayout; hboxRF->addWidget(rawBehaviorIcon); hboxRF->addWidget(rawBehaviorLabel, 10); d->defaultAskRaw = new QRadioButton(i18n("Ask for the input profile")); + /** - * @todo d->defaultAskRaw->setWhatsThis( i18n("

")); - */ + * @todo d->defaultAskRaw->setWhatsThis( i18n("

")); + */ d->defaultGuessRaw = new QRadioButton(i18n("Automatic color correction")); + /** - * @todo d->defaultGuessRaw->setWhatsThis( i18n("

")); - */ + * @todo d->defaultGuessRaw->setWhatsThis( i18n("

")); + */ d->defaultInputRaw = new QRadioButton(i18n("Convert it from the default input profile")); + /** - * @todo d->defaultSRGBMissing->setWhatsThis( i18n("

")); - */ + * @todo d->defaultSRGBMissing->setWhatsThis( i18n("

")); + */ d->defaultGuessRaw->setChecked(true); vlayRaw->addLayout(hboxRF); vlayRaw->addWidget(d->defaultAskRaw); vlayRaw->addWidget(d->defaultGuessRaw); vlayRaw->addWidget(d->defaultInputRaw); mainLayout->addWidget(colorPolicy); mainLayout->addWidget(d->workspaceGB); mainLayout->addWidget(d->mismatchGB); mainLayout->addWidget(d->missingGB); mainLayout->addWidget(d->rawGB); mainLayout->addStretch(); // -------------------------------------------------------- d->profilesPanel = new QWidget; QVBoxLayout* const vboxDisplay = new QVBoxLayout(d->profilesPanel); d->viewGB = new QGroupBox(i18n("Color Managed View")); QGridLayout* const gridView = new QGridLayout(d->viewGB); QLabel* const monitorIcon = new QLabel; monitorIcon->setPixmap(QIcon::fromTheme(QLatin1String("video-display")).pixmap(32)); QLabel* const monitorProfiles = new QLabel(i18n("Monitor profile:")); d->monitorProfilesKC = new IccProfilesComboBox; monitorProfiles->setBuddy(d->monitorProfilesKC); d->monitorProfilesKC->setWhatsThis(i18n("

Select the color profile for your monitor here.

")); d->infoMonitorProfiles = new QPushButton; d->infoMonitorProfiles->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoMonitorProfiles->setWhatsThis(i18n("

You can use this button to get more detailed " "information about the selected monitor profile.

")); d->managedView = new QCheckBox; d->managedView->setText(i18n("Use color managed view in editor")); d->managedView->setWhatsThis(i18n("

Turn on this option if " "you want to use your Monitor Color Profile to show your pictures in " "the Image Editor window with a color correction adapted to your monitor. " "You can at any time toggle this option from the Editor window. " "Warning: This can slow down rendering of the image, depending on the speed of your computer.

")); d->managedPreviews = new QCheckBox; d->managedPreviews->setText(i18n("Use color managed view for previews and thumbnails")); + /** - * @todo d->managedPreview->setWhatsThis( i18n("") ); - */ + * @todo d->managedPreview->setWhatsThis( i18n("") ); + */ gridView->addWidget(monitorIcon, 0, 0); gridView->addWidget(monitorProfiles, 0, 1, 1, 2); gridView->addWidget(d->monitorProfilesKC, 1, 0, 1, 2); gridView->addWidget(d->infoMonitorProfiles, 1, 2); gridView->addWidget(d->managedView, 2, 0, 1, 3); gridView->addWidget(d->managedPreviews, 3, 0, 1, 3); gridView->setColumnStretch(1, 10); // -------------------------------------------------------- d->inputGB = new QGroupBox(i18n("Camera and Scanner")); QGridLayout* const gridIP = new QGridLayout(d->inputGB); QLabel* const inputIcon = new QLabel; inputIcon->setPixmap(QIcon::fromTheme(QLatin1String("input-tablet")).pixmap(32)); QLabel* const inputLabel = new QLabel(i18n("Default input color profile:")); d->inProfilesKC = new IccProfilesComboBox; d->inProfilesKC->setWhatsThis(i18n("

This is the default color profile for your input device " "(that is your camera - or your scanner). A camera input profile " "is recommended for correct conversion of RAW images in 16bit. " "Some of the options about loading behavior above refer to this profile.

")); d->infoInProfiles = new QPushButton; d->infoInProfiles->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoInProfiles->setWhatsThis(i18n("

You can use this button to get more detailed " "information about the selected input profile.

")); gridIP->addWidget(inputIcon, 0, 0); gridIP->addWidget(inputLabel, 0, 1, 1, 2); gridIP->addWidget(d->inProfilesKC, 1, 0, 1, 2); gridIP->addWidget(d->infoInProfiles, 1, 2); gridIP->setColumnStretch(1, 10); // -------------------------------------------------------- d->proofGB = new QGroupBox(i18n("Printing and Proofing")); QGridLayout* const gridProof = new QGridLayout(d->proofGB); QLabel* const proofIcon = new QLabel; proofIcon->setPixmap(QIcon::fromTheme(QLatin1String("printer")).pixmap(32)); QLabel* const proofLabel = new QLabel(i18n("Output device profile:")); d->proofProfilesKC = new IccProfilesComboBox; proofLabel->setBuddy(d->proofProfilesKC); d->proofProfilesKC->setWhatsThis(i18n("

Select the profile for your output device " "(usually, your printer). This profile will be used to do a soft proof, so you will " "be able to preview how an image will be rendered via an output device.

")); d->infoProofProfiles = new QPushButton; d->infoProofProfiles->setIcon(QIcon::fromTheme(QLatin1String("dialog-information"))); d->infoProofProfiles->setWhatsThis(i18n("

You can use this button to get more detailed " "information about the selected proofing profile.

")); gridProof->addWidget(proofIcon, 0, 0); gridProof->addWidget(proofLabel, 0, 1, 1, 2); gridProof->addWidget(d->proofProfilesKC, 1, 0, 1, 2); gridProof->addWidget(d->infoProofProfiles, 1, 2); gridProof->setColumnStretch(1, 10); // -------------------------------------------------------- d->iccFolderGB = new QGroupBox(i18n("Color Profiles Repository")); QGridLayout* const gridIccFolder = new QGridLayout(d->iccFolderGB); QLabel* const iccFolderIcon = new QLabel; iccFolderIcon->setPixmap(QIcon::fromTheme(QLatin1String("folder-downloads")).pixmap(32)); d->iccFolderLabel = new QLabel(i18n("digiKam looks for ICC profiles in a number of default locations. " "You can specify an additional folder:")); d->iccFolderLabel->setWordWrap(true); d->defaultPathKU = new DFileSelector; d->iccFolderLabel->setBuddy(d->defaultPathKU); d->defaultPathKU->lineEdit()->setReadOnly(true); d->defaultPathKU->setFileDlgMode(QFileDialog::Directory); d->defaultPathKU->setWhatsThis(i18n("

digiKam searches ICC profiles in default system folders " "and ships itself a few selected profiles. " "Store all your additional color profiles in the directory set here.

")); gridIccFolder->addWidget(iccFolderIcon, 0, 0); gridIccFolder->addWidget(d->iccFolderLabel, 0, 1); gridIccFolder->addWidget(d->defaultPathKU, 1, 0, 1, 2); gridIccFolder->setColumnStretch(1, 10); vboxDisplay->addWidget(d->viewGB); vboxDisplay->addWidget(d->inputGB); vboxDisplay->addWidget(d->proofGB); vboxDisplay->addWidget(d->iccFolderGB); vboxDisplay->addStretch(1); // -------------------------------------------------------- d->advancedPanel = new QWidget; QVBoxLayout* const vboxAdvanced = new QVBoxLayout(d->advancedPanel); d->advancedSettingsGB = new QGroupBox(i18n("Advanced Settings")); QGridLayout* const gridAdvanced = new QGridLayout(d->advancedSettingsGB); d->bpcAlgorithm = new QCheckBox(d->advancedSettingsGB); d->bpcAlgorithm->setText(i18n("Use black point compensation")); d->bpcAlgorithm->setWhatsThis(i18n("

Black Point Compensation is a way to make " "adjustments between the maximum " "black levels of digital files and the black capabilities of various " "digital devices.

")); QLabel* const lablel = new QLabel(d->advancedSettingsGB); lablel->setText(i18n("Rendering Intents:")); d->renderingIntentKC = new IccRenderingIntentComboBox(d->advancedSettingsGB); gridAdvanced->addWidget(d->bpcAlgorithm, 0, 0, 1, 2); gridAdvanced->addWidget(lablel, 1, 0, 1, 1); gridAdvanced->addWidget(d->renderingIntentKC, 1, 1, 1, 1); gridAdvanced->setContentsMargins(spacing, spacing, spacing, spacing); gridAdvanced->setSpacing(0); vboxAdvanced->addWidget(d->advancedSettingsGB); vboxAdvanced->addStretch(1); // -------------------------------------------------------- d->tab->addTab(d->behaviorPanel, i18n("Behavior")); d->tab->addTab(d->profilesPanel, i18n("Profiles")); d->tab->addTab(d->advancedPanel, i18n("Advanced")); // -------------------------------------------------------- connect(d->enableColorManagement, SIGNAL(toggled(bool)), this, SLOT(slotToggledEnabled())); connect(d->infoProofProfiles, SIGNAL(clicked()), this, SLOT(slotClickedProof())); connect(d->infoInProfiles, SIGNAL(clicked()), this, SLOT(slotClickedIn())); connect(d->infoMonitorProfiles, SIGNAL(clicked()), this, SLOT(slotClickedMonitor())); connect(d->infoWorkProfiles, SIGNAL(clicked()), this, SLOT(slotClickedWork())); connect(d->defaultPathKU, SIGNAL(signalUrlSelected(QUrl)), this, SLOT(slotUrlChanged())); connect(d->defaultPathKU->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(slotUrlTextChanged())); connect(d->iccFolderLabel, SIGNAL(linkActivated(QString)), this, SLOT(slotShowDefaultSearchPaths())); connect(d->defaultAskMissing, SIGNAL(toggled(bool)), this, SLOT(slotMissingToggled(bool))); connect(d->defaultSRGBMissing, SIGNAL(toggled(bool)), this, SLOT(slotMissingToggled(bool))); connect(d->defaultWSMissing, SIGNAL(toggled(bool)), this, SLOT(slotMissingToggled(bool))); connect(d->defaultInputMissing, SIGNAL(toggled(bool)), this, SLOT(slotMissingToggled(bool))); // -------------------------------------------------------- adjustSize(); readSettings(); slotToggledEnabled(); // -------------------------------------------------------- } SetupICC::~SetupICC() { delete d; } void SetupICC::applySettings() { ICCSettingsContainer settings; settings.enableCM = d->enableColorManagement->isChecked(); - if (d->defaultAskMismatch->isChecked()) + if (d->defaultAskMismatch->isChecked()) { settings.defaultMismatchBehavior = ICCSettingsContainer::AskUser; } else if (d->defaultConvertMismatch->isChecked()) { settings.defaultMismatchBehavior = ICCSettingsContainer::EmbeddedToWorkspace; } - if (d->defaultAskMissing->isChecked()) + if (d->defaultAskMissing->isChecked()) { settings.defaultMissingProfileBehavior = ICCSettingsContainer::AskUser; } else if (d->defaultSRGBMissing->isChecked()) { settings.defaultMissingProfileBehavior = ICCSettingsContainer::UseSRGB; if (d->defaultSRGBConvert->isChecked()) { settings.defaultMissingProfileBehavior |= ICCSettingsContainer::ConvertToWorkspace; } else { settings.defaultMissingProfileBehavior |= ICCSettingsContainer::KeepProfile; } } else if (d->defaultWSMissing->isChecked()) { settings.defaultMissingProfileBehavior = ICCSettingsContainer::UseWorkspace | ICCSettingsContainer::KeepProfile; } else if (d->defaultInputMissing->isChecked()) { settings.defaultMissingProfileBehavior = ICCSettingsContainer::InputToWorkspace; } - if (d->defaultAskRaw->isChecked()) + if (d->defaultAskRaw->isChecked()) { settings.defaultUncalibratedBehavior = ICCSettingsContainer::AskUser; } else if (d->defaultInputRaw->isChecked()) { settings.defaultUncalibratedBehavior = ICCSettingsContainer::InputToWorkspace; } else if (d->defaultGuessRaw->isChecked()) { settings.defaultUncalibratedBehavior = ICCSettingsContainer::AutomaticColors | ICCSettingsContainer::ConvertToWorkspace; } settings.iccFolder = d->defaultPathKU->fileDlgPath(); settings.useBPC = d->bpcAlgorithm->isChecked(); settings.renderingIntent = d->renderingIntentKC->intent(); settings.useManagedView = d->managedView->isChecked(); settings.useManagedPreviews = d->managedPreviews->isChecked(); settings.defaultInputProfile = d->inProfilesKC->currentProfile().filePath(); settings.workspaceProfile = d->workProfilesKC->currentProfile().filePath(); settings.defaultProofProfile = d->proofProfilesKC->currentProfile().filePath(); if (!IccSettings::instance()->monitorProfileFromSystem()) { settings.monitorProfile = d->monitorProfilesKC->currentProfile().filePath(); } IccSettings::instance()->setSettings(settings); } void SetupICC::readSettings(bool restore) { ICCSettingsContainer settings = IccSettings::instance()->settings(); if (!restore) { d->enableColorManagement->setChecked(settings.enableCM); } d->bpcAlgorithm->setChecked(settings.useBPC); d->renderingIntentKC->setIntent(settings.renderingIntent); d->managedView->setChecked(settings.useManagedView); d->managedPreviews->setChecked(settings.useManagedPreviews); - if (settings.defaultMismatchBehavior & ICCSettingsContainer::AskUser) + if (settings.defaultMismatchBehavior & ICCSettingsContainer::AskUser) { d->defaultAskMismatch->setChecked(true); } else if (settings.defaultMismatchBehavior & ICCSettingsContainer::ConvertToWorkspace) { d->defaultConvertMismatch->setChecked(true); } if (settings.defaultMissingProfileBehavior & ICCSettingsContainer::AskUser) { d->defaultAskMissing->setChecked(true); } else { - if (settings.defaultMissingProfileBehavior & ICCSettingsContainer::UseSRGB) + if (settings.defaultMissingProfileBehavior & ICCSettingsContainer::UseSRGB) { d->defaultSRGBMissing->setChecked(true); d->defaultSRGBConvert->setChecked(settings.defaultMissingProfileBehavior & ICCSettingsContainer::ConvertToWorkspace); } else if (settings.defaultMissingProfileBehavior & ICCSettingsContainer::UseWorkspace) { d->defaultWSMissing->setChecked(true); } else if (settings.defaultMissingProfileBehavior & ICCSettingsContainer::UseDefaultInputProfile) { d->defaultInputMissing->setChecked(true); } } - if (settings.defaultUncalibratedBehavior & ICCSettingsContainer::AskUser) + if (settings.defaultUncalibratedBehavior & ICCSettingsContainer::AskUser) { d->defaultAskRaw->setChecked(true); } else if (settings.defaultUncalibratedBehavior & ICCSettingsContainer::UseDefaultInputProfile) { d->defaultInputRaw->setChecked(true); } else if (settings.defaultUncalibratedBehavior & ICCSettingsContainer::AutomaticColors) { d->defaultGuessRaw->setChecked(true); } d->defaultPathKU->setFileDlgPath(settings.iccFolder); fillCombos(false); d->workProfilesKC->setCurrentProfile(IccProfile(settings.workspaceProfile)); d->inProfilesKC->setCurrentProfile(IccProfile(settings.defaultInputProfile)); d->proofProfilesKC->setCurrentProfile(IccProfile(settings.defaultProofProfile)); if (IccSettings::instance()->monitorProfileFromSystem()) { d->monitorProfilesKC->clear(); d->monitorProfilesKC->setNoProfileIfEmpty(i18n("Monitor Profile From System Settings")); } else { d->monitorProfilesKC->setCurrentProfile(IccProfile(settings.monitorProfile)); } } void SetupICC::slotUrlChanged() { IccSettings::instance()->setIccPath(d->defaultPathKU->fileDlgPath()); fillCombos(true); } void SetupICC::slotUrlTextChanged() { d->defaultPathKU->setFileDlgPath(d->defaultPathKU->fileDlgPath()); } void SetupICC::fillCombos(bool report) { if (!d->enableColorManagement->isChecked()) { return; } QList profiles = IccSettings::instance()->allProfiles(); if (profiles.isEmpty()) { if (report) { QString message = i18n("No ICC profiles files found."); QMessageBox::information(this, qApp->applicationName(), message); } qCDebug(DIGIKAM_GENERAL_LOG) << "No ICC profile files found!!!"; d->dlgBtnBox->button(QDialogButtonBox::Ok)->setEnabled(false); + return; } d->workProfilesKC->replaceProfilesSqueezed(IccSettings::instance()->workspaceProfiles()); d->monitorProfilesKC->replaceProfilesSqueezed(IccSettings::instance()->displayProfiles()); d->inProfilesKC->replaceProfilesSqueezed(IccSettings::instance()->inputProfiles()); d->proofProfilesKC->replaceProfilesSqueezed(IccSettings::instance()->outputProfiles()); d->workProfilesKC->setNoProfileIfEmpty(i18n("No Profile Available")); d->monitorProfilesKC->setNoProfileIfEmpty(i18n("No Display Profile Available")); d->inProfilesKC->setNoProfileIfEmpty(i18n("No Input Profile Available")); d->proofProfilesKC->setNoProfileIfEmpty(i18n("No Output Profile Available")); if (d->monitorProfilesKC->count() == 0) { d->managedView->setEnabled(false); d->managedPreviews->setEnabled(false); } else { d->dlgBtnBox->button(QDialogButtonBox::Ok)->setEnabled(true); d->managedPreviews->setEnabled(true); } if (d->workProfilesKC->count() == 0) { // If there is no workspace ICC profiles available, // the CM is broken and cannot be used. + d->dlgBtnBox->button(QDialogButtonBox::Ok)->setEnabled(false); + return; } d->dlgBtnBox->button(QDialogButtonBox::Ok)->setEnabled(true); } void SetupICC::setWidgetsEnabled(bool enabled) { d->workspaceGB->setEnabled(enabled); d->mismatchGB->setEnabled(enabled); d->missingGB->setEnabled(enabled); d->rawGB->setEnabled(enabled); d->tab->setTabEnabled(1, enabled); d->tab->setTabEnabled(2, enabled); - //d->profilesPanel->setEnabled(enabled); - //d->advancedPanel->setEnabled(enabled); +/* + d->profilesPanel->setEnabled(enabled); + d->advancedPanel->setEnabled(enabled); +*/ } void SetupICC::slotToggledEnabled() { bool enabled = d->enableColorManagement->isChecked(); setWidgetsEnabled(enabled); if (enabled) { readSettings(true); } else { d->dlgBtnBox->button(QDialogButtonBox::Ok)->setEnabled(true); } } void SetupICC::slotClickedWork() { IccProfile profile = d->workProfilesKC->currentProfile(); if (!profile.isNull()) { profileInfo(profile); } } void SetupICC::slotClickedIn() { IccProfile profile = d->inProfilesKC->currentProfile(); if (!profile.isNull()) { profileInfo(profile); } } void SetupICC::slotClickedMonitor() { IccProfile profile; if (IccSettings::instance()->monitorProfileFromSystem()) { profile = IccSettings::instance()->monitorProfile(); } else { profile = d->monitorProfilesKC->currentProfile(); } if (!profile.isNull()) { profileInfo(profile); } } void SetupICC::slotClickedProof() { IccProfile profile = d->proofProfilesKC->currentProfile(); if (!profile.isNull()) { profileInfo(profile); } } void SetupICC::profileInfo(const IccProfile& profile) { if (profile.isNull()) { QMessageBox::critical(this, i18n("Profile Error"), i18n("No profile is selected.")); return; } ICCProfileInfoDlg infoDlg(this, profile.filePath(), profile); infoDlg.exec(); } void SetupICC::slotMissingToggled(bool on) { if (!on) { return; } d->defaultSRGBConvert->setEnabled(d->defaultSRGBMissing->isChecked()); } void SetupICC::slotShowDefaultSearchPaths() { QStringList defaultSearchPaths = IccProfile::defaultSearchPaths(); QString existingPaths; if (defaultSearchPaths.isEmpty()) { existingPaths = i18nc("none of the paths", "none"); } else { existingPaths = defaultSearchPaths.join(QLatin1String("
  • ")); } #ifdef Q_OS_WIN QString text = i18n("On Windows, the default search paths include " "
      " "
    • %1/Windows/Spool/Drivers/Color/
    • " // For Win2K and WinXP "
    • %2/Windows/Color/
    • " // For Win98 and WinMe "
    " "On your system, currently these paths exist and are scanned:" "
      " "
    • %3
    • " "
    ", QDir::rootPath(), QDir::rootPath(), existingPaths); #elif defined (Q_OS_OSX) + QString text = i18n("On Mac OS X, the default search paths include " "
      " "
    • /System/Library/ColorSync/Profiles
    • " "
    • /Library/ColorSync/Profiles
    • " "
    • ~/Library/ColorSync/Profiles
    • " "
    • /opt/local/share/color/icc
    • " "
    • /opt/digikam/share/color/icc
    • " "
    • ~/.local/share/color/icc/
    • " "
    • ~/.local/share/icc/
    • " "
    • ~/.color/icc/
    • " "
    " "On your system, currently these paths exist and are scanned:" "
      " "
    • %1
    • " "
    ", existingPaths); #else // Linux + QString text = i18n("On Linux, the default search paths include " "
      " "
    • /usr/share/color/icc
    • " "
    • /usr/local/share/color/icc
    • " "
    • ~/.local/share/color/icc/
    • " "
    • ~/.local/share/icc/
    • " "
    • ~/.color/icc/
    • " "
    " "On your system, currently these paths exist and are scanned:" "
      " "
    • %1
    • " "
    ", existingPaths); + #endif QWhatsThis::showText(d->iccFolderLabel->mapToGlobal(QPoint(0, 0)), text, d->iccFolderLabel); } bool SetupICC::iccRepositoryIsValid() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Color Management")); // If color management is disable, no need to check anymore. + if (!group.readEntry(QLatin1String("EnableCM"), false)) { return true; } // Can at least RawEngine profiles be opened? + if (IccProfile::sRGB().open()) { return true; } // To be valid, the ICC profiles repository must exist and be readable. + QString extraPath = group.readEntry(QLatin1String("DefaultPath"), QString()); QFileInfo info(extraPath); if (info.isDir() && info.exists() && info.isReadable()) { return true; } QStringList paths = IccProfile::defaultSearchPaths(); - return !paths.isEmpty(); + return (!paths.isEmpty()); } } // namespace Digikam diff --git a/core/utilities/setup/setuplighttable.cpp b/core/utilities/setup/setuplighttable.cpp index 1c872902bf..aa827a1974 100644 --- a/core/utilities/setup/setuplighttable.cpp +++ b/core/utilities/setup/setuplighttable.cpp @@ -1,169 +1,167 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-05-11 * Description : setup Light Table tab. * * Copyright (C) 2007-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setuplighttable.h" // Qt includes #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "fullscreensettings.h" #include "dxmlguiwindow.h" namespace Digikam { class Q_DECL_HIDDEN SetupLightTable::Private { public: explicit Private() : autoSyncPreview(nullptr), autoLoadOnRightPanel(nullptr), clearOnClose(nullptr), fullScreenSettings(nullptr) { } static const QString configGroupName; static const QString configAutoSyncPreviewEntry; static const QString configAutoLoadRightPanelEntry; static const QString configLoadFullImagesizeEntry; static const QString configClearOnCloseEntry; QCheckBox* autoSyncPreview; QCheckBox* autoLoadOnRightPanel; QCheckBox* clearOnClose; FullScreenSettings* fullScreenSettings; }; const QString SetupLightTable::Private::configGroupName(QLatin1String("LightTable Settings")); const QString SetupLightTable::Private::configAutoSyncPreviewEntry(QLatin1String("Auto Sync Preview")); const QString SetupLightTable::Private::configAutoLoadRightPanelEntry(QLatin1String("Auto Load Right Panel")); const QString SetupLightTable::Private::configClearOnCloseEntry(QLatin1String("Clear On Close")); // -------------------------------------------------------- SetupLightTable::SetupLightTable(QWidget* const parent) : QScrollArea(parent), d(new Private) { - const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); + const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); - QWidget* const panel = new QWidget(viewport()); + QWidget* const panel = new QWidget(viewport()); setWidget(panel); setWidgetResizable(true); QVBoxLayout* const layout = new QVBoxLayout(panel); // -------------------------------------------------------- QGroupBox* const interfaceOptionsGroup = new QGroupBox(i18n("Interface Options"), panel); QVBoxLayout* const gLayout = new QVBoxLayout(interfaceOptionsGroup); - d->autoSyncPreview = new QCheckBox(i18n("Synchronize panels automatically"), interfaceOptionsGroup); + d->autoSyncPreview = new QCheckBox(i18n("Synchronize panels automatically"), interfaceOptionsGroup); d->autoSyncPreview->setWhatsThis(i18n("Set this option to automatically synchronize " "zooming and panning between left and right panels if the " "images have the same size.")); d->autoLoadOnRightPanel = new QCheckBox(i18n("Selecting a thumbbar item loads the image to the right panel"), interfaceOptionsGroup); d->autoLoadOnRightPanel->setWhatsThis(i18n("Set this option to automatically load an image " "into the right panel when the corresponding item is selected on the thumbbar.")); d->clearOnClose = new QCheckBox(i18n("Clear the light table on close")); d->clearOnClose->setWhatsThis(i18n("Set this option to remove all images " "from the light table when you close it, " "or unset it to preserve the images " "currently on the light table.")); gLayout->addWidget(d->autoSyncPreview); gLayout->addWidget(d->autoLoadOnRightPanel); gLayout->addWidget(d->clearOnClose); gLayout->setContentsMargins(spacing, spacing, spacing, spacing); gLayout->setSpacing(0); // -------------------------------------------------------- d->fullScreenSettings = new FullScreenSettings(FS_LIGHTTABLE, panel); // -------------------------------------------------------- layout->addWidget(interfaceOptionsGroup); layout->addWidget(d->fullScreenSettings); layout->setContentsMargins(QMargins()); layout->setSpacing(spacing); layout->addStretch(); // -------------------------------------------------------- readSettings(); - - // -------------------------------------------------------- } SetupLightTable::~SetupLightTable() { delete d; } void SetupLightTable::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); QColor Black(Qt::black); QColor White(Qt::white); d->fullScreenSettings->readSettings(group); d->autoSyncPreview->setChecked(group.readEntry(d->configAutoSyncPreviewEntry, true)); d->autoLoadOnRightPanel->setChecked(group.readEntry(d->configAutoLoadRightPanelEntry, true)); d->clearOnClose->setChecked(group.readEntry(d->configClearOnCloseEntry, false)); } void SetupLightTable::applySettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(d->configGroupName); d->fullScreenSettings->saveSettings(group); group.writeEntry(d->configAutoSyncPreviewEntry, d->autoSyncPreview->isChecked()); group.writeEntry(d->configAutoLoadRightPanelEntry, d->autoLoadOnRightPanel->isChecked()); group.writeEntry(d->configClearOnCloseEntry, d->clearOnClose->isChecked()); config->sync(); } } // namespace Digikam diff --git a/core/utilities/setup/setupmisc.cpp b/core/utilities/setup/setupmisc.cpp index 17cf3db2aa..034684b46b 100644 --- a/core/utilities/setup/setupmisc.cpp +++ b/core/utilities/setup/setupmisc.cpp @@ -1,445 +1,451 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-08-23 * Description : mics configuration setup tab * * Copyright (C) 2004 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2017 by Simon Frei * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupmisc.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_config.h" #include "dlayoutbox.h" #include "dfontselect.h" #include "applicationsettings.h" namespace Digikam { class Q_DECL_HIDDEN SetupMisc::Private { public: explicit Private() : tab(nullptr), sidebarTypeLabel(nullptr), stringComparisonTypeLabel(nullptr), applicationStyleLabel(nullptr), applicationIconLabel(nullptr), minSimilarityBoundLabel(nullptr), showSplashCheck(nullptr), showTrashDeleteDialogCheck(nullptr), showPermanentDeleteDialogCheck(nullptr), sidebarApplyDirectlyCheck(nullptr), useNativeFileDialogCheck(nullptr), drawFramesToGroupedCheck(nullptr), scrollItemToCenterCheck(nullptr), showOnlyPersonTagsInPeopleSidebarCheck(nullptr), scanAtStart(nullptr), cleanAtStart(nullptr), sidebarType(nullptr), stringComparisonType(nullptr), applicationStyle(nullptr), applicationIcon(nullptr), applicationFont(nullptr), minimumSimilarityBound(nullptr), groupingButtons(QHash()) { } QTabWidget* tab; QLabel* sidebarTypeLabel; QLabel* stringComparisonTypeLabel; QLabel* applicationStyleLabel; QLabel* applicationIconLabel; QLabel* minSimilarityBoundLabel; QCheckBox* showSplashCheck; QCheckBox* showTrashDeleteDialogCheck; QCheckBox* showPermanentDeleteDialogCheck; QCheckBox* sidebarApplyDirectlyCheck; QCheckBox* useNativeFileDialogCheck; QCheckBox* drawFramesToGroupedCheck; QCheckBox* scrollItemToCenterCheck; QCheckBox* showOnlyPersonTagsInPeopleSidebarCheck; QCheckBox* scanAtStart; QCheckBox* cleanAtStart; QComboBox* sidebarType; QComboBox* stringComparisonType; QComboBox* applicationStyle; QComboBox* applicationIcon; DFontSelect* applicationFont; QSpinBox* minimumSimilarityBound; QHash groupingButtons; }; SetupMisc::SetupMisc(QWidget* const parent) : QScrollArea(parent), d(new Private) { - d->tab = new QTabWidget(viewport()); + d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); // -- Application Behavior Options -------------------------------------------------------- QWidget* const behaviourPanel = new QWidget(d->tab); QVBoxLayout* const layout = new QVBoxLayout(behaviourPanel); DHBox* const stringComparisonHbox = new DHBox(behaviourPanel); d->stringComparisonTypeLabel = new QLabel(i18n("String comparison type:"), stringComparisonHbox); d->stringComparisonType = new QComboBox(stringComparisonHbox); d->stringComparisonType->addItem(i18nc("method to compare strings", "Natural"), ApplicationSettings::Natural); d->stringComparisonType->addItem(i18nc("method to compare strings", "Normal"), ApplicationSettings::Normal); d->stringComparisonType->setToolTip(i18n("Sets the way in which strings are compared inside digiKam. " "This eg. influences the sorting of the tree views.
    " "Natural tries to compare strings in a way that regards some normal conventions " "and will eg. result in sorting numbers naturally even if they have a different number of digits.
    " "Normal uses a more technical approach. " "Use this style if you eg. want to entitle albums with ISO dates (201006 or 20090523) " "and the albums should be sorted according to these dates.
    ")); // -------------------------------------------------------- d->showTrashDeleteDialogCheck = new QCheckBox(i18n("Confirm when moving items to the &trash"), behaviourPanel); d->showPermanentDeleteDialogCheck = new QCheckBox(i18n("Confirm when permanently deleting items"), behaviourPanel); d->sidebarApplyDirectlyCheck = new QCheckBox(i18n("Do not confirm when applying changes in the &right sidebar"), behaviourPanel); d->scanAtStart = new QCheckBox(i18n("&Scan for new items at startup (makes startup slower)"), behaviourPanel); d->scanAtStart->setToolTip(i18n("Set this option to force digiKam to scan all collections for new items to\n" "register new elements in database. The scan is performed in the background through\n" "the progress manager available in the statusbar\n when digiKam main interface\n" "is loaded. If your computer is fast enough, this will have no effect on usability\n" "of digiKam while scanning. If your collections are huge or if you use a remote database,\n" "this can introduce low latency, and it is recommended to disable this option and to plan\n" "a manual scan through the maintenance tool at the right moment.")); d->cleanAtStart = new QCheckBox(i18n("Remove obsolete core database objects (makes startup slower)"), behaviourPanel); d->cleanAtStart->setToolTip(i18n("Set this option to force digiKam to clean up the core database from obsolete item entries.\n" "Entries are only deleted if the connected image/video/audio file was already removed, i.e.\n" "the database object wastes space.\n" "This option does not clean up other databases as the thumbnails or recognition db.\n" "For clean up routines for other databases, please use the maintenance.")); d->scrollItemToCenterCheck = new QCheckBox(i18n("Scroll current item to center of thumbbar"), behaviourPanel); d->showOnlyPersonTagsInPeopleSidebarCheck = new QCheckBox(i18n("Show only face tags for assigning names in people sidebar"), behaviourPanel); // --------------------------------------------------------- DHBox* const minSimilarityBoundHbox = new DHBox(behaviourPanel); d->minSimilarityBoundLabel = new QLabel(i18n("Lower bound for minimum similarity:"), minSimilarityBoundHbox); d->minimumSimilarityBound = new QSpinBox(minSimilarityBoundHbox); d->minimumSimilarityBound->setSuffix(QLatin1String("%")); d->minimumSimilarityBound->setRange(1, 100); d->minimumSimilarityBound->setSingleStep(1); d->minimumSimilarityBound->setValue(40); d->minimumSimilarityBound->setToolTip(i18n("Select here the lower bound of " "the minimum similarity threshold " "for fuzzy and duplicates searches. " "The default value is 40. Selecting " "a lower value than 40 can make the search really slow.")); d->minSimilarityBoundLabel->setBuddy(d->minimumSimilarityBound); // --------------------------------------------------------- layout->setContentsMargins(spacing, spacing, spacing, spacing); layout->setSpacing(spacing); layout->addWidget(stringComparisonHbox); layout->addWidget(d->scanAtStart); layout->addWidget(d->cleanAtStart); layout->addWidget(d->showTrashDeleteDialogCheck); layout->addWidget(d->showPermanentDeleteDialogCheck); layout->addWidget(d->sidebarApplyDirectlyCheck); layout->addWidget(d->scrollItemToCenterCheck); layout->addWidget(d->showOnlyPersonTagsInPeopleSidebarCheck); layout->addWidget(minSimilarityBoundHbox); layout->addStretch(); d->tab->insertTab(Behaviour, behaviourPanel, i18nc("@title:tab", "Behaviour")); // -- Application Appearance Options -------------------------------------------------------- QWidget* const appearancePanel = new QWidget(d->tab); QVBoxLayout* const layout2 = new QVBoxLayout(appearancePanel); d->showSplashCheck = new QCheckBox(i18n("&Show splash screen at startup"), appearancePanel); d->useNativeFileDialogCheck = new QCheckBox(i18n("Use native file dialogs from system"), appearancePanel); d->drawFramesToGroupedCheck = new QCheckBox(i18n("Draw frames around grouped items"), appearancePanel); DHBox* const tabStyleHbox = new DHBox(appearancePanel); d->sidebarTypeLabel = new QLabel(i18n("Sidebar tab title:"), tabStyleHbox); d->sidebarType = new QComboBox(tabStyleHbox); d->sidebarType->addItem(i18n("Only For Active Tab"), 0); d->sidebarType->addItem(i18n("For All Tabs"), 1); d->sidebarType->setToolTip(i18n("Set this option to configure how sidebar tab titles are visible. " "Use \"Only For Active Tab\" option if you use a small screen resolution as with a laptop computer.")); DHBox* const appStyleHbox = new DHBox(appearancePanel); d->applicationStyleLabel = new QLabel(i18n("Widget style:"), appStyleHbox); d->applicationStyle = new QComboBox(appStyleHbox); d->applicationStyle->setToolTip(i18n("Set this option to choose the default window decoration and looks.")); QStringList styleList = QStyleFactory::keys(); for (int i = 0 ; i < styleList.count() ; ++i) { if (styleList.at(i).compare(QLatin1String("windowsvista"), Qt::CaseInsensitive) != 0) { d->applicationStyle->addItem(styleList.at(i), styleList.at(i).toLower()); } } #ifndef HAVE_APPSTYLE_SUPPORT + // See Bug #365262 appStyleHbox->setVisible(false); + #endif DHBox* const iconThemeHbox = new DHBox(appearancePanel); d->applicationIconLabel = new QLabel(i18n("Icon theme (changes after restart):"), iconThemeHbox); d->applicationIcon = new QComboBox(iconThemeHbox); d->applicationIcon->setToolTip(i18n("Set this option to choose the default icon theme.")); QMap iconThemes; QMap themeWhiteList; themeWhiteList.insert(QLatin1String("adwaita"), i18nc("icon theme", "Adwaita")); themeWhiteList.insert(QLatin1String("breeze"), i18nc("icon theme", "Breeze")); themeWhiteList.insert(QLatin1String("breeze-dark"), i18nc("icon theme", "Breeze Dark")); themeWhiteList.insert(QLatin1String("faenza"), i18nc("icon theme", "Faenza")); themeWhiteList.insert(QLatin1String("faenza-ambiance"), i18nc("icon theme", "Ambiance")); themeWhiteList.insert(QLatin1String("humanity"), i18nc("icon theme", "Humanity")); themeWhiteList.insert(QLatin1String("oxygen"), i18nc("icon theme", "Oxygen")); foreach (const QString& path, QIcon::themeSearchPaths()) { QDirIterator it(path, QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); while (it.hasNext()) { if (QFile::exists(it.next() + QLatin1String("/index.theme"))) { QString iconKey = it.fileInfo().fileName().toLower(); if (themeWhiteList.contains(iconKey)) { iconThemes[themeWhiteList.value(iconKey)] = it.fileInfo().fileName(); } } } } QMap::const_iterator it = iconThemes.constBegin(); d->applicationIcon->addItem(i18n("Use Icon Theme From System"), QString()); for ( ; it != iconThemes.constEnd() ; ++it) { d->applicationIcon->addItem(it.key(), it.value()); } d->applicationFont = new DFontSelect(i18n("Application font:"), appearancePanel); d->applicationFont->setToolTip(i18n("Select here the font used to display text in whole application.")); // -------------------------------------------------------- layout2->setContentsMargins(spacing, spacing, spacing, spacing); layout2->setSpacing(spacing); layout2->addWidget(d->showSplashCheck); layout2->addWidget(d->useNativeFileDialogCheck); layout2->addWidget(d->drawFramesToGroupedCheck); layout2->addWidget(tabStyleHbox); layout2->addWidget(appStyleHbox); layout2->addWidget(iconThemeHbox); layout2->addWidget(d->applicationFont); layout2->addStretch(); d->tab->insertTab(Appearance, appearancePanel, i18nc("@title:tab", "Appearance")); // -------------------------------------------------------- QWidget* const groupingPanel = new QWidget(d->tab); QGridLayout* const grid = new QGridLayout(groupingPanel); // -------------------------------------------------------- QLabel* const description = new QLabel(i18n("Perform the following operations on all group members:"), groupingPanel); description->setToolTip(i18n("When images are grouped the following operations
    " "are performed only on the displayed item (No)
    " "or on all the hidden items in the group as well (Yes).
    " "If Ask is selected, there will be a prompt every
    " "time this operation is executed.")); QLabel* const noLabel = new QLabel(i18n("No"), groupingPanel); QLabel* const yesLabel = new QLabel(i18n("Yes"), groupingPanel); QLabel* const askLabel = new QLabel(i18n("Ask"), groupingPanel); QHash labels; for (int i = 0 ; i != ApplicationSettings::Unspecified ; ++i) { labels.insert(i, new QLabel(ApplicationSettings::operationTypeTitle( (ApplicationSettings::OperationType)i), groupingPanel)); QString explanation = ApplicationSettings::operationTypeExplanation( (ApplicationSettings::OperationType)i); if (!explanation.isEmpty()) { labels.value(i)->setToolTip(explanation); } d->groupingButtons.insert(i, new QButtonGroup(groupingPanel)); d->groupingButtons.value(i)->addButton(new QRadioButton(groupingPanel), 0); d->groupingButtons.value(i)->addButton(new QRadioButton(groupingPanel), 1); d->groupingButtons.value(i)->addButton(new QRadioButton(groupingPanel), 2); } // -------------------------------------------------------- grid->addWidget(description, 0, 0, 1, 4); grid->addWidget(noLabel, 1, 1, 1, 1); grid->addWidget(yesLabel, 1, 2, 1, 1); grid->addWidget(askLabel, 1, 3, 1, 1); for (int i = 0 ; i != ApplicationSettings::Unspecified ; ++i) { grid->addWidget(labels.value(i), i+2, 0, 1, 1); grid->addWidget(d->groupingButtons.value(i)->button(0), i+2, 1, 1, 1); grid->addWidget(d->groupingButtons.value(i)->button(1), i+2, 2, 1, 1); grid->addWidget(d->groupingButtons.value(i)->button(2), i+2, 3, 1, 1); } grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); grid->setColumnStretch(0, 10); grid->setColumnMinimumWidth(1, 30); grid->setColumnMinimumWidth(2, 30); grid->setColumnMinimumWidth(3, 30); grid->setRowStretch(20, 10); d->tab->insertTab(Grouping, groupingPanel, i18nc("@title:tab", "Grouping")); // -------------------------------------------------------- readSettings(); adjustSize(); } SetupMisc::~SetupMisc() { delete d; } void SetupMisc::applySettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); settings->setShowSplashScreen(d->showSplashCheck->isChecked()); settings->setShowTrashDeleteDialog(d->showTrashDeleteDialogCheck->isChecked()); settings->setShowPermanentDeleteDialog(d->showPermanentDeleteDialogCheck->isChecked()); settings->setMinimumSimilarityBound(d->minimumSimilarityBound->value()); settings->setApplySidebarChangesDirectly(d->sidebarApplyDirectlyCheck->isChecked()); settings->setScanAtStart(d->scanAtStart->isChecked()); settings->setCleanAtStart(d->cleanAtStart->isChecked()); settings->setUseNativeFileDialog(d->useNativeFileDialogCheck->isChecked()); settings->setDrawFramesToGrouped(d->drawFramesToGroupedCheck->isChecked()); settings->setScrollItemToCenter(d->scrollItemToCenterCheck->isChecked()); settings->setShowOnlyPersonTagsInPeopleSidebar(d->showOnlyPersonTagsInPeopleSidebarCheck->isChecked()); settings->setSidebarTitleStyle(d->sidebarType->currentIndex() == 0 ? DMultiTabBar::ActiveIconText : DMultiTabBar::AllIconsText); settings->setStringComparisonType((ApplicationSettings::StringComparisonType) d->stringComparisonType->itemData(d->stringComparisonType->currentIndex()).toInt()); for (int i = 0 ; i != ApplicationSettings::Unspecified ; ++i) { settings->setGroupingOperateOnAll((ApplicationSettings::OperationType)i, (ApplicationSettings::ApplyToEntireGroup)d->groupingButtons.value(i)->checkedId()); } #ifdef HAVE_APPSTYLE_SUPPORT + settings->setApplicationStyle(d->applicationStyle->currentText()); + #endif settings->setIconTheme(d->applicationIcon->currentData().toString()); settings->setApplicationFont(d->applicationFont->font()); settings->saveSettings(); } void SetupMisc::readSettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); d->showSplashCheck->setChecked(settings->getShowSplashScreen()); d->showTrashDeleteDialogCheck->setChecked(settings->getShowTrashDeleteDialog()); d->showPermanentDeleteDialogCheck->setChecked(settings->getShowPermanentDeleteDialog()); d->minimumSimilarityBound->setValue(settings->getMinimumSimilarityBound()); d->sidebarApplyDirectlyCheck->setChecked(settings->getApplySidebarChangesDirectly()); d->sidebarApplyDirectlyCheck->setChecked(settings->getApplySidebarChangesDirectly()); d->scanAtStart->setChecked(settings->getScanAtStart()); d->cleanAtStart->setChecked(settings->getCleanAtStart()); d->useNativeFileDialogCheck->setChecked(settings->getUseNativeFileDialog()); d->drawFramesToGroupedCheck->setChecked(settings->getDrawFramesToGrouped()); d->scrollItemToCenterCheck->setChecked(settings->getScrollItemToCenter()); d->showOnlyPersonTagsInPeopleSidebarCheck->setChecked(settings->showOnlyPersonTagsInPeopleSidebar()); d->sidebarType->setCurrentIndex(settings->getSidebarTitleStyle() == DMultiTabBar::ActiveIconText ? 0 : 1); d->stringComparisonType->setCurrentIndex(settings->getStringComparisonType()); for (int i = 0 ; i != ApplicationSettings::Unspecified ; ++i) { d->groupingButtons.value(i)->button((int)settings->getGroupingOperateOnAll((ApplicationSettings::OperationType)i))->setChecked(true); } #ifdef HAVE_APPSTYLE_SUPPORT + d->applicationStyle->setCurrentIndex(d->applicationStyle->findData(settings->getApplicationStyle().toLower())); + #endif d->applicationIcon->setCurrentIndex(d->applicationIcon->findData(settings->getIconTheme())); d->applicationFont->setFont(settings->getApplicationFont()); } } // namespace Digikam diff --git a/core/utilities/setup/setupmisc.h b/core/utilities/setup/setupmisc.h index e6a0c7f70c..ff79a3785e 100644 --- a/core/utilities/setup/setupmisc.h +++ b/core/utilities/setup/setupmisc.h @@ -1,65 +1,67 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-08-23 * Description : mics configuration setup tab * * Copyright (C) 2004 by Renchi Raju * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2017 by Simon Frei * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #ifndef DIGIKAM_SETUP_MISC_H #define DIGIKAM_SETUP_MISC_H // Qt includes #include namespace Digikam { class SetupMisc : public QScrollArea { public: enum MiscTab { Behaviour = 0, Appearance, Grouping }; +public: + explicit SetupMisc(QWidget* const parent = nullptr); ~SetupMisc(); void applySettings(); private: void readSettings(); private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_SETUP_MISC_H diff --git a/core/utilities/setup/setupplugins.cpp b/core/utilities/setup/setupplugins.cpp index 77d5ab8b14..3029c2d403 100644 --- a/core/utilities/setup/setupplugins.cpp +++ b/core/utilities/setup/setupplugins.cpp @@ -1,116 +1,116 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-02-06 * Description : Setup view panel for dplugins. * * Copyright (C) 2018-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setupplugins.h" // Qt includes #include #include #include #include // KDE includes #include // Local includes #include "dpluginsetup.h" #include "dpluginaction.h" #include "dpluginconfviewgeneric.h" #include "dpluginconfvieweditor.h" #include "dpluginconfviewbqm.h" #include "dpluginconfviewdimg.h" namespace Digikam { class Q_DECL_HIDDEN SetupPlugins::Private { public: explicit Private() : tab(nullptr), setupGeneric(nullptr), setupEditor(nullptr), setupBqm(nullptr), setupDImg(nullptr) { } QTabWidget* tab; DPluginSetup* setupGeneric; DPluginSetup* setupEditor; DPluginSetup* setupBqm; DPluginSetup* setupDImg; }; SetupPlugins::SetupPlugins(QWidget* const parent) : QScrollArea(parent), d(new Private) { - d->tab = new QTabWidget(viewport()); + d->tab = new QTabWidget(viewport()); setWidget(d->tab); setWidgetResizable(true); // -------------------- d->setupGeneric = new DPluginSetup(d->tab); d->setupGeneric->setPluginConfView(new DPluginConfViewGeneric(d->setupGeneric)); d->tab->insertTab(Generic, d->setupGeneric, i18nc("@title:tab", "Generic")); // -------------------- - d->setupEditor = new DPluginSetup(d->tab); + d->setupEditor = new DPluginSetup(d->tab); d->setupEditor->setPluginConfView(new DPluginConfViewEditor(d->setupEditor)); d->tab->insertTab(Editor, d->setupEditor, i18nc("@title:tab", "Image Editor")); // -------------------- - d->setupBqm = new DPluginSetup(d->tab); + d->setupBqm = new DPluginSetup(d->tab); d->setupBqm->setPluginConfView(new DPluginConfViewBqm(d->setupBqm)); d->tab->insertTab(Bqm, d->setupBqm, i18nc("@title:tab", "Batch Queue Manager")); // -------------------- - d->setupDImg = new DPluginSetup(d->tab); + d->setupDImg = new DPluginSetup(d->tab); d->setupDImg->setPluginConfView(new DPluginConfViewDImg(d->setupDImg)); d->tab->insertTab(Loaders, d->setupDImg, i18nc("@title:tab", "Image Loaders")); } SetupPlugins::~SetupPlugins() { delete d; } void SetupPlugins::applySettings() { d->setupGeneric->applySettings(); d->setupEditor->applySettings(); d->setupBqm->applySettings(); d->setupDImg->applySettings(); } } // namespace Digikam diff --git a/core/utilities/setup/setupslideshow.cpp b/core/utilities/setup/setupslideshow.cpp index 9da90127c9..5a2ca88344 100644 --- a/core/utilities/setup/setupslideshow.cpp +++ b/core/utilities/setup/setupslideshow.cpp @@ -1,304 +1,304 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2005-05-21 * Description : setup tab for slideshow options. * * Copyright (C) 2005-2020 by Gilles Caulier * Copyright (C) 2019 by Minh Nghia Duong * * 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 "setupslideshow.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "dnuminput.h" #include "dfontselect.h" #include "digikam_debug.h" #include "slideshowsettings.h" namespace Digikam { class Q_DECL_HIDDEN SetupSlideShow::Private { public: explicit Private() : startWithCurrent(nullptr), loopMode(nullptr), suffleMode(nullptr), showName(nullptr), showDate(nullptr), showApertureFocal(nullptr), showExpoSensitivity(nullptr), showMakeModel(nullptr), showLabels(nullptr), showRating(nullptr), showComment(nullptr), showTitle(nullptr), showTags(nullptr), showCapIfNoTitle(nullptr), showProgress(nullptr), screenPlacement(nullptr), captionFont(nullptr), delayInput(nullptr) { } QCheckBox* startWithCurrent; QCheckBox* loopMode; QCheckBox* suffleMode; QCheckBox* showName; QCheckBox* showDate; QCheckBox* showApertureFocal; QCheckBox* showExpoSensitivity; QCheckBox* showMakeModel; QCheckBox* showLabels; QCheckBox* showRating; QCheckBox* showComment; QCheckBox* showTitle; QCheckBox* showTags; QCheckBox* showCapIfNoTitle; QCheckBox* showProgress; QComboBox* screenPlacement; DFontSelect* captionFont; DIntNumInput* delayInput; }; // -------------------------------------------------------- SetupSlideShow::SetupSlideShow(QWidget* const parent) : QScrollArea(parent), d(new Private) { QWidget* const panel = new QWidget(viewport()); setWidget(panel); setWidgetResizable(true); const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); DHBox* const hbox1 = new DHBox(panel); new QLabel(i18n("Delay between images:"), hbox1); d->delayInput = new DIntNumInput(hbox1); d->delayInput->setDefaultValue(5); d->delayInput->setRange(1, 3600, 1); d->delayInput->setWhatsThis(i18n("The delay, in seconds, between images.")); d->startWithCurrent = new QCheckBox(i18n("Start with current image"), panel); d->startWithCurrent->setWhatsThis(i18n("If this option is enabled, the Slideshow will be started " "with the current image selected in the images list.")); d->loopMode = new QCheckBox(i18n("Slideshow runs in a loop"), panel); d->loopMode->setWhatsThis(i18n("Run the slideshow in a loop.")); d->suffleMode = new QCheckBox(i18n("Shuffle images"), panel); d->suffleMode->setWhatsThis(i18n("If this option is enabled, the Slideshow will run in random order")); d->showProgress = new QCheckBox(i18n("Show progress indicator"), panel); d->showProgress->setWhatsThis(i18n("Show a progress indicator with pending items to show and time progression.")); d->showName = new QCheckBox(i18n("Show image file name"), panel); d->showName->setWhatsThis(i18n("Show the image file name at the bottom of the screen.")); d->showDate = new QCheckBox(i18n("Show image creation date"), panel); d->showDate->setWhatsThis(i18n("Show the image creation time/date at the bottom of the screen.")); d->showApertureFocal = new QCheckBox(i18n("Show camera aperture and focal length"), panel); d->showApertureFocal->setWhatsThis(i18n("Show the camera aperture and focal length at the bottom of the screen.")); d->showExpoSensitivity = new QCheckBox(i18n("Show camera exposure and sensitivity"), panel); d->showExpoSensitivity->setWhatsThis(i18n("Show the camera exposure and sensitivity at the bottom of the screen.")); d->showMakeModel = new QCheckBox(i18n("Show camera make and model"), panel); d->showMakeModel->setWhatsThis(i18n("Show the camera make and model at the bottom of the screen.")); d->showComment = new QCheckBox(i18n("Show image caption"), panel); d->showComment->setWhatsThis(i18n("Show the image caption at the bottom of the screen.")); d->showTitle = new QCheckBox(i18n("Show image title"), panel); d->showTitle->setWhatsThis(i18n("Show the image title at the bottom of the screen.")); d->showCapIfNoTitle = new QCheckBox(i18n("Show image caption if it has not title"), panel); d->showCapIfNoTitle->setWhatsThis(i18n("Show the image caption at the bottom of the screen if no titles existed.")); d->showTags = new QCheckBox(i18n("Show image tags"), panel); d->showTags->setWhatsThis(i18n("Show the digiKam image tag names at the bottom of the screen.")); d->showLabels = new QCheckBox(i18n("Show image labels"), panel); d->showLabels->setWhatsThis(i18n("Show the digiKam image color label and pick label at the bottom of the screen.")); d->showRating = new QCheckBox(i18n("Show image rating"), panel); d->showRating->setWhatsThis(i18n("Show the digiKam image rating at the bottom of the screen.")); d->captionFont = new DFontSelect(i18n("Caption font:"), panel); d->captionFont->setToolTip(i18n("Select here the font used to display text in the slideshow.")); DHBox* const screenSelectBox = new DHBox(panel); new QLabel(i18n("Screen placement:"), screenSelectBox); d->screenPlacement = new QComboBox(screenSelectBox); d->screenPlacement->setToolTip(i18n("In case of multi-screen computer, select here the monitor to slide contents.")); QStringList choices; choices.append(i18nc("@label:listbox The current screen, for the presentation mode", "Current Screen")); choices.append(i18nc("@label:listbox The default screen for the presentation mode", "Default Screen")); for (int i = 0 ; i < qApp->screens().count() ; ++i) { QString model = qApp->screens().at(i)->model(); choices.append(i18nc("@label:listbox %1 is the screen number (0, 1, ...)", "Screen %1", i) + QString::fromUtf8(" (%1)").arg(model.left(model.length() - 1))); } d->screenPlacement->addItems(choices); // Disable and uncheck the "Show captions if no title" checkbox if the "Show comment" checkbox enabled connect(d->showComment, SIGNAL(stateChanged(int)), this, SLOT(slotSetUnchecked(int))); connect(d->showComment, SIGNAL(toggled(bool)), d->showCapIfNoTitle, SLOT(setDisabled(bool))); // Only digiKam support this feature, showFoto do not support digiKam database information. if (qApp->applicationName() == QLatin1String("showfoto")) { d->showCapIfNoTitle->hide(); d->showLabels->hide(); d->showRating->hide(); d->showTitle->hide(); d->showTags->hide(); } QGridLayout* const grid = new QGridLayout(panel); grid->addWidget(hbox1, 0, 0, 1, 2); grid->addWidget(d->startWithCurrent, 1, 0, 1, 1); grid->addWidget(d->loopMode, 1, 1, 1, 1); grid->addWidget(d->suffleMode, 2, 0, 1, 1); grid->addWidget(d->showProgress, 2, 1, 1, 1); grid->addWidget(d->showName, 3, 0, 1, 1); grid->addWidget(d->showDate, 3, 1, 1, 1); grid->addWidget(d->showApertureFocal, 4, 0, 1, 1); grid->addWidget(d->showExpoSensitivity, 4, 1, 1, 1); grid->addWidget(d->showMakeModel, 5, 0, 1, 1); grid->addWidget(d->showComment, 5, 1, 1, 1); grid->addWidget(d->showTitle, 6, 0, 1, 1); grid->addWidget(d->showCapIfNoTitle, 6, 1, 1, 1); grid->addWidget(d->showTags, 7, 0, 1, 1); grid->addWidget(d->showLabels, 7, 1, 1, 1); grid->addWidget(d->showRating, 8, 0, 1, 1); grid->addWidget(d->captionFont, 9, 0, 1, 2); grid->addWidget(screenSelectBox, 10, 0, 1, 2); grid->setRowStretch(11, 10); grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); readSettings(); } SetupSlideShow::~SetupSlideShow() { delete d; } void SetupSlideShow::slotSetUnchecked(int) { d->showCapIfNoTitle->setCheckState(Qt::Unchecked); } void SetupSlideShow::applySettings() { SlideShowSettings settings; settings.delay = d->delayInput->value(); settings.startWithCurrent = d->startWithCurrent->isChecked(); settings.loop = d->loopMode->isChecked(); settings.suffle = d->suffleMode->isChecked(); settings.printName = d->showName->isChecked(); settings.printDate = d->showDate->isChecked(); settings.printApertureFocal = d->showApertureFocal->isChecked(); settings.printExpoSensitivity = d->showExpoSensitivity->isChecked(); settings.printMakeModel = d->showMakeModel->isChecked(); settings.printComment = d->showComment->isChecked(); settings.printTitle = d->showTitle->isChecked(); settings.printCapIfNoTitle = d->showCapIfNoTitle->isChecked(); settings.printTags = d->showTags->isChecked(); settings.printLabels = d->showLabels->isChecked(); settings.printRating = d->showRating->isChecked(); settings.showProgressIndicator = d->showProgress->isChecked(); settings.captionFont = d->captionFont->font(); settings.slideScreen = d->screenPlacement->currentIndex() - 2; settings.writeToConfig(); } void SetupSlideShow::readSettings() { SlideShowSettings settings; settings.readFromConfig(); d->delayInput->setValue(settings.delay); d->startWithCurrent->setChecked(settings.startWithCurrent); d->loopMode->setChecked(settings.loop); d->suffleMode->setChecked(settings.suffle); d->showName->setChecked(settings.printName); d->showDate->setChecked(settings.printDate); d->showApertureFocal->setChecked(settings.printApertureFocal); d->showExpoSensitivity->setChecked(settings.printExpoSensitivity); d->showMakeModel->setChecked(settings.printMakeModel); d->showComment->setChecked(settings.printComment); d->showTitle->setChecked(settings.printTitle); d->showCapIfNoTitle->setChecked(settings.printCapIfNoTitle); d->showTags->setChecked(settings.printTags); d->showLabels->setChecked(settings.printLabels); d->showRating->setChecked(settings.printRating); d->showProgress->setChecked(settings.showProgressIndicator); d->captionFont->setFont(settings.captionFont); const int screen = settings.slideScreen; - if (screen >= -2 && screen < qApp->screens().count()) + if ((screen >= -2) && (screen < qApp->screens().count())) { d->screenPlacement->setCurrentIndex(screen + 2); } else { d->screenPlacement->setCurrentIndex(0); settings.slideScreen = -2; settings.writeToConfig(); } } } // namespace Digikam diff --git a/core/utilities/setup/setuptemplate.cpp b/core/utilities/setup/setuptemplate.cpp index eb5d29a730..2d23fc4663 100644 --- a/core/utilities/setup/setuptemplate.cpp +++ b/core/utilities/setup/setuptemplate.cpp @@ -1,291 +1,297 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-07-04 * Description : metadata template setup page. * * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setuptemplate.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "templatelist.h" #include "templatepanel.h" #include "altlangstredit.h" namespace Digikam { class Q_DECL_HIDDEN SetupTemplate::Private { public: - explicit Private() : - addButton(nullptr), + explicit Private() + : addButton(nullptr), delButton(nullptr), repButton(nullptr), titleEdit(nullptr), listView(nullptr), tview(nullptr) { } QPushButton* addButton; QPushButton* delButton; QPushButton* repButton; QLineEdit* titleEdit; TemplateList* listView; TemplatePanel* tview; }; SetupTemplate::SetupTemplate(QWidget* const parent) - : QScrollArea(parent), d(new Private) + : QScrollArea(parent), + d(new Private) { QWidget* const panel = new QWidget(viewport()); setWidget(panel); setWidgetResizable(true); - const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); + const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); - d->listView = new TemplateList(panel); + d->listView = new TemplateList(panel); d->listView->setFixedHeight(100); // -------------------------------------------------------- QLabel* const label0 = new QLabel(i18n("Template Title:"), panel); d->titleEdit = new QLineEdit(panel); d->titleEdit->setClearButtonEnabled(true); d->titleEdit->setPlaceholderText(i18n("Enter the metadata template title here.")); d->titleEdit->setWhatsThis(i18n("

    Enter the metadata template title here. This title will be " "used to identify a template in your collection.

    ")); label0->setBuddy(d->titleEdit); // -------------------------------------------------------- - d->tview = new TemplatePanel(panel); + d->tview = new TemplatePanel(panel); // -------------------------------------------------------- QLabel* const note = new QLabel(i18n("Note: These information are used to set " "XMP " "and IPTC tag contents. " "There is no limitation with XMP, but note that IPTC text tags " "only support the printable ASCII " "character set, and tag sizes are limited. " "Use contextual help for details."), panel); note->setOpenExternalLinks(true); note->setWordWrap(true); note->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); // ------------------------------------------------------------- d->addButton = new QPushButton(panel); d->delButton = new QPushButton(panel); d->repButton = new QPushButton(panel); d->addButton->setText(i18n("&Add...")); d->addButton->setIcon(QIcon::fromTheme(QLatin1String("list-add"))); d->delButton->setText(i18n("&Remove")); d->delButton->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); d->repButton->setText(i18n("&Replace...")); d->repButton->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); d->delButton->setEnabled(false); d->repButton->setEnabled(false); // ------------------------------------------------------------- QGridLayout* const grid = new QGridLayout; grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); grid->setAlignment(Qt::AlignTop); grid->setColumnStretch(1, 10); grid->setRowStretch(4, 10); grid->addWidget(d->listView, 0, 0, 4, 2); grid->addWidget(d->addButton, 0, 2, 1, 1); grid->addWidget(d->delButton, 1, 2, 1, 1); grid->addWidget(d->repButton, 2, 2, 1, 1); grid->addWidget(label0, 4, 0, 1, 1); grid->addWidget(d->titleEdit, 4, 1, 1, 1); grid->addWidget(d->tview, 5, 0, 1, 3); grid->addWidget(note, 6, 0, 1, 3); panel->setLayout(grid); panel->setTabOrder(d->listView, d->addButton); panel->setTabOrder(d->addButton, d->delButton); panel->setTabOrder(d->delButton, d->repButton); panel->setTabOrder(d->repButton, d->titleEdit); panel->setTabOrder(d->titleEdit, d->tview); // -------------------------------------------------------- connect(d->listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotSelectionChanged())); connect(d->addButton, SIGNAL(clicked()), this, SLOT(slotAddTemplate())); connect(d->delButton, SIGNAL(clicked()), this, SLOT(slotDelTemplate())); connect(d->repButton, SIGNAL(clicked()), this, SLOT(slotRepTemplate())); // -------------------------------------------------------- readSettings(); d->titleEdit->setFocus(); d->listView->sortItems(0, Qt::AscendingOrder); d->listView->setSortingEnabled(true); } SetupTemplate::~SetupTemplate() { delete d; } void SetupTemplate::applySettings() { d->listView->applySettings(); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Setup Dialog")); group.writeEntry(QLatin1String("Template Tab"), (int)(d->tview->currentIndex())); config->sync(); } void SetupTemplate::readSettings() { d->listView->readSettings(); KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(QLatin1String("Setup Dialog")); d->tview->setCurrentIndex((TemplatePanel::TemplateTab)group.readEntry(QLatin1String("Template Tab"), (int)TemplatePanel::RIGHTS)); } void SetupTemplate::setTemplate(const Template& t) { if (!t.isNull()) { TemplateListItem* const item = d->listView->find(t.templateTitle()); d->listView->setCurrentItem(item); + return; } populateTemplate(t); } void SetupTemplate::slotSelectionChanged() { TemplateListItem* const item = dynamic_cast(d->listView->currentItem()); if (!item) { d->delButton->setEnabled(false); d->repButton->setEnabled(false); + return; } d->delButton->setEnabled(true); d->repButton->setEnabled(true); populateTemplate(item->getTemplate()); } void SetupTemplate::populateTemplate(const Template& t) { d->tview->setTemplate(t); d->titleEdit->setText(t.templateTitle()); d->titleEdit->setFocus(); } void SetupTemplate::slotAddTemplate() { QString title = d->titleEdit->text(); if (title.isEmpty()) { QMessageBox::critical(this, qApp->applicationName(), i18n("Cannot register new metadata template without title.")); + return; } if (d->listView->find(title)) { QMessageBox::critical(this, qApp->applicationName(), i18n("A metadata template named '%1' already exists.", title)); + return; } d->tview->apply(); Template t = d->tview->getTemplate(); t.setTemplateTitle(d->titleEdit->text()); new TemplateListItem(d->listView, t); } void SetupTemplate::slotDelTemplate() { TemplateListItem* const item = dynamic_cast(d->listView->currentItem()); delete item; } void SetupTemplate::slotRepTemplate() { QString title = d->titleEdit->text(); if (title.isEmpty()) { QMessageBox::critical(this, qApp->applicationName(), i18n("Cannot register new metadata template without title.")); + return; } TemplateListItem* const item = dynamic_cast(d->listView->currentItem()); if (!item) { return; } d->tview->apply(); Template t = d->tview->getTemplate(); t.setTemplateTitle(title); item->setTemplate(t); } } // namespace Digikam diff --git a/core/utilities/setup/setuptooltip.cpp b/core/utilities/setup/setuptooltip.cpp index 00ae64f870..ea2fc30e54 100644 --- a/core/utilities/setup/setuptooltip.cpp +++ b/core/utilities/setup/setuptooltip.cpp @@ -1,693 +1,693 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-07-09 * Description : item tool tip configuration setup tab * * Copyright (C) 2006-2020 by Gilles Caulier * * This program is free software; you can redistribute it * and/or modify it under the terms of the GNU General * Public License as published by the Free Software Foundation; * either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * ============================================================ */ #include "setuptooltip.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dlayoutbox.h" #include "applicationsettings.h" #include "importsettings.h" #include "setupcamera.h" #include "dfontselect.h" #include "dexpanderbox.h" namespace Digikam { class Q_DECL_HIDDEN SetupToolTip::Private { public: explicit Private() : cameraUseFileMetadata(false), showToolTipsBox(nullptr), showFileNameBox(nullptr), showFileDateBox(nullptr), showFileSizeBox(nullptr), showImageTypeBox(nullptr), showImageDimBox(nullptr), showImageARBox(nullptr), showPhotoMakeBox(nullptr), showPhotoLensBox(nullptr), showPhotoDateBox(nullptr), showPhotoFocalBox(nullptr), showPhotoExpoBox(nullptr), showPhotoModeBox(nullptr), showPhotoFlashBox(nullptr), showPhotoWbBox(nullptr), showVideoAspectRatio(nullptr), showVideoAudioBitRate(nullptr), showVideoAudioChannelType(nullptr), showVideoAudioCodec(nullptr), showVideoDuration(nullptr), showVideoFrameRate(nullptr), showVideoVideoCodec(nullptr), showAlbumNameBox(nullptr), showTitlesBox(nullptr), showCommentsBox(nullptr), showTagsBox(nullptr), showLabelsBox(nullptr), showAlbumToolTipsBox(nullptr), showAlbumTitleBox(nullptr), showAlbumDateBox(nullptr), showAlbumCollectionBox(nullptr), showAlbumCategoryBox(nullptr), showAlbumCaptionBox(nullptr), showAlbumPreviewBox(nullptr), showImportToolTipsBox(nullptr), showItemTitleBox(nullptr), showItemDateBox(nullptr), showItemSizeBox(nullptr), showItemTypeBox(nullptr), showItemDimensionsBox(nullptr), showItemPhotoMakeBox(nullptr), showItemPhotoLensBox(nullptr), showItemPhotoFocalBox(nullptr), showItemPhotoExpoBox(nullptr), showItemPhotoFlashBox(nullptr), showItemPhotoWBBox(nullptr), fileSettingBox(nullptr), photoSettingBox(nullptr), videoSettingBox(nullptr), digikamSettingBox(nullptr), albumSettingBox(nullptr), importSettingBox(nullptr), tab(nullptr), fontSelect(nullptr) { } bool cameraUseFileMetadata; QCheckBox* showToolTipsBox; QCheckBox* showFileNameBox; QCheckBox* showFileDateBox; QCheckBox* showFileSizeBox; QCheckBox* showImageTypeBox; QCheckBox* showImageDimBox; QCheckBox* showImageARBox; QCheckBox* showPhotoMakeBox; QCheckBox* showPhotoLensBox; QCheckBox* showPhotoDateBox; QCheckBox* showPhotoFocalBox; QCheckBox* showPhotoExpoBox; QCheckBox* showPhotoModeBox; QCheckBox* showPhotoFlashBox; QCheckBox* showPhotoWbBox; QCheckBox* showVideoAspectRatio; QCheckBox* showVideoAudioBitRate; QCheckBox* showVideoAudioChannelType; QCheckBox* showVideoAudioCodec; QCheckBox* showVideoDuration; QCheckBox* showVideoFrameRate; QCheckBox* showVideoVideoCodec; QCheckBox* showAlbumNameBox; QCheckBox* showTitlesBox; QCheckBox* showCommentsBox; QCheckBox* showTagsBox; QCheckBox* showLabelsBox; QCheckBox* showAlbumToolTipsBox; QCheckBox* showAlbumTitleBox; QCheckBox* showAlbumDateBox; QCheckBox* showAlbumCollectionBox; QCheckBox* showAlbumCategoryBox; QCheckBox* showAlbumCaptionBox; QCheckBox* showAlbumPreviewBox; QCheckBox* showImportToolTipsBox; QCheckBox* showItemTitleBox; QCheckBox* showItemDateBox; QCheckBox* showItemSizeBox; QCheckBox* showItemTypeBox; QCheckBox* showItemDimensionsBox; QCheckBox* showItemPhotoMakeBox; QCheckBox* showItemPhotoLensBox; QCheckBox* showItemPhotoFocalBox; QCheckBox* showItemPhotoExpoBox; QCheckBox* showItemPhotoFlashBox; QCheckBox* showItemPhotoWBBox; QGroupBox* fileSettingBox; QGroupBox* photoSettingBox; QGroupBox* videoSettingBox; QGroupBox* digikamSettingBox; QGroupBox* albumSettingBox; QGroupBox* importSettingBox; QTabWidget* tab; DFontSelect* fontSelect; }; SetupToolTip::SetupToolTip(QWidget* const parent) : QScrollArea(parent), d(new Private) { - QWidget* const panel = new QWidget(viewport()); + QWidget* const panel = new QWidget(viewport()); setWidget(panel); setWidgetResizable(true); - const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); + const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); - QVBoxLayout* const vlay = new QVBoxLayout(panel); + QVBoxLayout* const vlay = new QVBoxLayout(panel); - d->fontSelect = new DFontSelect(i18n("Tool-Tips Font:"), panel); + d->fontSelect = new DFontSelect(i18n("Tool-Tips Font:"), panel); d->fontSelect->setToolTip(i18n("Select here the font used to display text in tool-tips.")); - d->tab = new QTabWidget(panel); + d->tab = new QTabWidget(panel); // -------------------------------------------------------- DVBox* const vbox = new DVBox(panel); d->showToolTipsBox = new QCheckBox(i18n("Show icon-view and thumb-bar items' tool-tips"), vbox); d->showToolTipsBox->setWhatsThis(i18n("Set this option to display image information when " "the mouse hovers over an icon-view or thumb-bar item.")); d->fileSettingBox = new QGroupBox(i18n("File/Item Information"), vbox); QGridLayout* const grid2 = new QGridLayout(d->fileSettingBox); d->showFileNameBox = new QCheckBox(i18n("File name"), d->fileSettingBox); d->showFileNameBox->setWhatsThis(i18n("Set this option to display the image file name.")); d->showFileDateBox = new QCheckBox(i18n("File date"), d->fileSettingBox); d->showFileDateBox->setWhatsThis(i18n("Set this option to display the image file date.")); d->showFileSizeBox = new QCheckBox(i18n("File size"), d->fileSettingBox); d->showFileSizeBox->setWhatsThis(i18n("Set this option to display the image file size.")); d->showImageTypeBox = new QCheckBox(i18n("Image type"), d->fileSettingBox); d->showImageTypeBox->setWhatsThis(i18n("Set this option to display the image type.")); d->showImageDimBox = new QCheckBox(i18n("Image dimensions"), d->fileSettingBox); d->showImageDimBox->setWhatsThis(i18n("Set this option to display the image dimensions in pixels.")); d->showImageARBox = new QCheckBox(i18n("Image aspect ratio"), d->fileSettingBox); d->showImageARBox->setWhatsThis(i18n("Set this option to display the image aspect ratio.")); grid2->addWidget(d->showFileNameBox, 0, 0, 1, 1); grid2->addWidget(d->showFileDateBox, 1, 0, 1, 1); grid2->addWidget(d->showFileSizeBox, 2, 0, 1, 1); grid2->addWidget(d->showImageTypeBox, 0, 1, 1, 1); grid2->addWidget(d->showImageDimBox, 1, 1, 1, 1); grid2->addWidget(d->showImageARBox, 2, 1, 1, 1); grid2->setContentsMargins(spacing, spacing, spacing, spacing); grid2->setSpacing(0); // -------------------------------------------------------- d->photoSettingBox = new QGroupBox(i18n("Photograph Information"), vbox); QGridLayout* const grid3 = new QGridLayout(d->photoSettingBox); d->showPhotoMakeBox = new QCheckBox(i18n("Camera make and model"), d->photoSettingBox); d->showPhotoMakeBox->setWhatsThis(i18n("Set this option to display the make and model of the " "camera with which the image has been taken.")); d->showPhotoLensBox = new QCheckBox(i18n("Camera lens model"), d->photoSettingBox); d->showPhotoLensBox->setWhatsThis(i18n("Set this option to display the lens model with " "which the image was taken.")); d->showPhotoDateBox = new QCheckBox(i18n("Camera date"), d->photoSettingBox); d->showPhotoDateBox->setWhatsThis(i18n("Set this option to display the date when the image was taken.")); d->showPhotoFocalBox = new QCheckBox(i18n("Camera aperture and focal length"), d->photoSettingBox); d->showPhotoFocalBox->setWhatsThis(i18n("Set this option to display the camera aperture and focal settings " "used to take the image.")); d->showPhotoExpoBox = new QCheckBox(i18n("Camera exposure and sensitivity"), d->photoSettingBox); d->showPhotoExpoBox->setWhatsThis(i18n("Set this option to display the camera exposure and sensitivity " "used to take the image.")); d->showPhotoModeBox = new QCheckBox(i18n("Camera mode and program"), d->photoSettingBox); d->showPhotoModeBox->setWhatsThis(i18n("Set this option to display the camera mode and program " "used to take the image.")); d->showPhotoFlashBox = new QCheckBox(i18n("Camera flash settings"), d->photoSettingBox); d->showPhotoFlashBox->setWhatsThis(i18n("Set this option to display the camera flash settings " "used to take the image.")); d->showPhotoWbBox = new QCheckBox(i18n("Camera white balance settings"), d->photoSettingBox); d->showPhotoWbBox->setWhatsThis(i18n("Set this option to display the camera white balance settings " "used to take the image.")); grid3->addWidget(d->showPhotoMakeBox, 0, 0, 1, 1); grid3->addWidget(d->showPhotoLensBox, 1, 0, 1, 1); grid3->addWidget(d->showPhotoDateBox, 2, 0, 1, 1); grid3->addWidget(d->showPhotoFocalBox, 3, 0, 1, 1); grid3->addWidget(d->showPhotoExpoBox, 0, 1, 1, 1); grid3->addWidget(d->showPhotoModeBox, 1, 1, 1, 1); grid3->addWidget(d->showPhotoFlashBox, 2, 1, 1, 1); grid3->addWidget(d->showPhotoWbBox, 3, 1, 1, 1); grid3->setContentsMargins(spacing, spacing, spacing, spacing); grid3->setSpacing(0); // -------------------------------------------------------- d->digikamSettingBox = new QGroupBox(i18n("digiKam Information"), vbox); QGridLayout* const grid4 = new QGridLayout(d->digikamSettingBox); d->showAlbumNameBox = new QCheckBox(i18n("Album name"), d->digikamSettingBox); d->showAlbumNameBox->setWhatsThis(i18n("Set this option to display the album name.")); d->showTitlesBox = new QCheckBox(i18n("Image title"), d->digikamSettingBox); d->showTitlesBox->setWhatsThis(i18n("Set this option to display the image title.")); d->showCommentsBox = new QCheckBox(i18n("Image caption"), d->digikamSettingBox); d->showCommentsBox->setWhatsThis(i18n("Set this option to display the image captions.")); d->showTagsBox = new QCheckBox(i18n("Image tags"), d->digikamSettingBox); d->showTagsBox->setWhatsThis(i18n("Set this option to display the image tags.")); d->showLabelsBox = new QCheckBox(i18n("Image labels"), d->digikamSettingBox); d->showLabelsBox->setWhatsThis(i18n("Set this option to display the image pick, color, rating labels.")); grid4->addWidget(d->showAlbumNameBox, 0, 0, 1, 1); grid4->addWidget(d->showTitlesBox, 1, 0, 1, 1); grid4->addWidget(d->showCommentsBox, 2, 0, 1, 1); grid4->addWidget(d->showTagsBox, 0, 1, 1, 1); grid4->addWidget(d->showLabelsBox, 1, 1, 1, 1); grid4->setContentsMargins(spacing, spacing, spacing, spacing); grid4->setSpacing(0); // -------------------------------------------------------- d->videoSettingBox = new QGroupBox(i18n("Audio/Video Information"), vbox); QGridLayout* const grid5 = new QGridLayout(d->videoSettingBox); d->showVideoAspectRatio = new QCheckBox(i18n("Video Aspect Ratio"), d->videoSettingBox); d->showVideoAspectRatio->setWhatsThis(i18n("Set this option to display the Aspect Ratio of the Video.")); d->showVideoAudioBitRate = new QCheckBox(i18n("Audio Bit Rate"), d->videoSettingBox); d->showVideoAudioBitRate->setWhatsThis(i18n("Set this option to display the Audio Bit Rate of the Video.")); d->showVideoAudioChannelType = new QCheckBox(i18n("Audio Channel Type"), d->videoSettingBox); d->showVideoAudioChannelType->setWhatsThis(i18n("Set this option to display the Audio Channel Type of the Video.")); d->showVideoAudioCodec = new QCheckBox(i18n("Audio Codec"), d->videoSettingBox); d->showVideoAudioCodec->setWhatsThis(i18n("Set this option to display the Audio Codec of the Video.")); d->showVideoDuration = new QCheckBox(i18n("Video Duration"), d->videoSettingBox); d->showVideoDuration->setWhatsThis(i18n("Set this option to display the Duration of the Video.")); d->showVideoFrameRate = new QCheckBox(i18n("Video Frame Rate"), d->videoSettingBox); d->showVideoFrameRate->setWhatsThis(i18n("Set this option to display the Aspect Ratio of the Video.")); d->showVideoVideoCodec = new QCheckBox(i18n("Video Codec"), d->videoSettingBox); d->showVideoVideoCodec->setWhatsThis(i18n("Set this option to display the Codec of the Video.")); grid5->addWidget(d->showVideoAspectRatio, 0, 0, 1, 1); grid5->addWidget(d->showVideoAudioBitRate, 1, 0, 1, 1); grid5->addWidget(d->showVideoAudioChannelType, 2, 0, 1, 1); - grid5->addWidget(d->showVideoAudioCodec, 3, 0, 1, 1); + grid5->addWidget(d->showVideoAudioCodec, 3, 0, 1, 1); grid5->addWidget(d->showVideoDuration, 0, 1, 1, 1); grid5->addWidget(d->showVideoFrameRate, 1, 1, 1, 1); grid5->addWidget(d->showVideoVideoCodec, 2, 1, 1, 1); grid5->setContentsMargins(spacing, spacing, spacing, spacing); grid5->setSpacing(0); QWidget* const space = new QWidget(vbox); vbox->setStretchFactor(space, 10); vbox->setContentsMargins(spacing, spacing, spacing, spacing); vbox->setSpacing(spacing); // -------------------------------------------------------- DVBox* const vbox2 = new DVBox(panel); d->showAlbumToolTipsBox = new QCheckBox(i18n("Show album items' tool-tips"), vbox2); d->albumSettingBox = new QGroupBox(i18n("Album Information"), vbox2); d->showAlbumToolTipsBox->setWhatsThis(i18n("Set this option to display album information when " "the mouse hovers over a folder-view item.")); d->showAlbumTitleBox = new QCheckBox(i18n("Album name")); d->showAlbumTitleBox->setWhatsThis(i18n("Set this option to display the album name.")); d->showAlbumDateBox = new QCheckBox(i18n("Album date")); d->showAlbumDateBox->setWhatsThis(i18n("Set this option to display the album date.")); d->showAlbumCollectionBox = new QCheckBox(i18n("Album collection")); d->showAlbumCollectionBox->setWhatsThis(i18n("Set this option to display the album collection.")); d->showAlbumCategoryBox = new QCheckBox(i18n("Album category")); d->showAlbumCategoryBox->setWhatsThis(i18n("Set this option to display the album category.")); d->showAlbumCaptionBox = new QCheckBox(i18n("Album caption")); d->showAlbumCaptionBox->setWhatsThis(i18n("Set this option to display the album caption.")); d->showAlbumPreviewBox = new QCheckBox(i18n("Album preview")); d->showAlbumPreviewBox->setWhatsThis(i18n("Set this option to display the album preview.")); QGridLayout* const albumSettingBoxLayout = new QGridLayout; albumSettingBoxLayout->addWidget(d->showAlbumTitleBox, 0, 0, 1, 1); albumSettingBoxLayout->addWidget(d->showAlbumDateBox, 1, 0, 1, 1); albumSettingBoxLayout->addWidget(d->showAlbumCollectionBox, 2, 0, 1, 1); albumSettingBoxLayout->addWidget(d->showAlbumCategoryBox, 0, 1, 1, 1); albumSettingBoxLayout->addWidget(d->showAlbumCaptionBox, 1, 1, 1, 1); albumSettingBoxLayout->addWidget(d->showAlbumPreviewBox, 2, 1, 1, 1); d->albumSettingBox->setLayout(albumSettingBoxLayout); QWidget* const space2 = new QWidget(vbox2); vbox2->setStretchFactor(space2, 10); vbox2->setContentsMargins(spacing, spacing, spacing, spacing); vbox2->setSpacing(spacing); // -------------------------------------------------------- DVBox* const vbox3 = new DVBox(panel); d->showImportToolTipsBox = new QCheckBox(i18n("Show import items' tool-tips"), vbox3); d->importSettingBox = new QGroupBox(i18n("Import Information"), vbox3); d->showAlbumToolTipsBox->setWhatsThis(i18n("Set this option to display album information when " "the mouse hovers over a folder-view item.")); d->showItemTitleBox = new QCheckBox(i18n("Item name")); d->showItemTitleBox->setWhatsThis(i18n("Set this option to display the item name.")); d->showItemDateBox = new QCheckBox(i18n("Item date")); d->showItemDateBox->setWhatsThis(i18n("Set this option to display the item date.")); d->showItemSizeBox = new QCheckBox(i18n("Item size")); d->showItemSizeBox->setWhatsThis(i18n("Set this option to display the item size.")); d->showItemTypeBox = new QCheckBox(i18n("Item type")); d->showItemTypeBox->setWhatsThis(i18n("Set this option to display the item type.")); d->showItemDimensionsBox = new QCheckBox(i18n("Item dimensions")); d->showItemDimensionsBox->setWhatsThis(i18n("Set this option to display the item dimensions.")); DLineWidget* const line = new DLineWidget(Qt::Horizontal, d->photoSettingBox); QLabel* const label = new QLabel(i18n("Note: these settings require \"Use File Metadata\" option " "from Camera Setup Behavior page."), d->photoSettingBox); d->showItemPhotoMakeBox = new QCheckBox(i18n("Camera make and model"), d->photoSettingBox); d->showItemPhotoMakeBox->setWhatsThis(i18n("Set this option to display the make and model of the " "camera with which the image has been taken.")); d->showItemPhotoLensBox = new QCheckBox(i18n("Camera lens model"), d->photoSettingBox); d->showItemPhotoLensBox->setWhatsThis(i18n("Set this option to display the lens model with " "which the image was taken.")); d->showItemPhotoFocalBox = new QCheckBox(i18n("Camera aperture and focal length"), d->photoSettingBox); d->showPhotoFocalBox->setWhatsThis(i18n("Set this option to display the camera aperture and focal settings " "used to take the image.")); d->showItemPhotoExpoBox = new QCheckBox(i18n("Camera exposure and sensitivity"), d->photoSettingBox); d->showPhotoExpoBox->setWhatsThis(i18n("Set this option to display the camera exposure and sensitivity " "used to take the image.")); d->showItemPhotoFlashBox = new QCheckBox(i18n("Camera flash settings"), d->photoSettingBox); d->showPhotoFlashBox->setWhatsThis(i18n("Set this option to display the camera flash settings " "used to take the image.")); d->showItemPhotoWBBox = new QCheckBox(i18n("Camera white balance settings"), d->photoSettingBox); d->showItemPhotoWBBox->setWhatsThis(i18n("Set this option to display the camera white balance settings " "used to take the image.")); QGridLayout* const importSettingBoxLayout = new QGridLayout; importSettingBoxLayout->addWidget(d->showItemTitleBox, 0, 0, 1, 1); importSettingBoxLayout->addWidget(d->showItemDateBox, 1, 0, 1, 1); importSettingBoxLayout->addWidget(d->showItemSizeBox, 2, 0, 1, 1); importSettingBoxLayout->addWidget(d->showItemTypeBox, 0, 1, 1, 1); importSettingBoxLayout->addWidget(d->showItemDimensionsBox, 1, 1, 1, 1); importSettingBoxLayout->addWidget(line, 3, 0, 1, 2); importSettingBoxLayout->addWidget(label, 4, 0, 1, 2); importSettingBoxLayout->addWidget(d->showItemPhotoMakeBox, 5, 0, 1, 1); importSettingBoxLayout->addWidget(d->showItemPhotoLensBox, 6, 0, 1, 1); importSettingBoxLayout->addWidget(d->showItemPhotoFocalBox, 7, 0, 1, 1); importSettingBoxLayout->addWidget(d->showItemPhotoExpoBox, 5, 1, 1, 1); importSettingBoxLayout->addWidget(d->showItemPhotoFlashBox, 6, 1, 1, 1); importSettingBoxLayout->addWidget(d->showItemPhotoWBBox, 7, 1, 1, 1); d->importSettingBox->setLayout(importSettingBoxLayout); QWidget* const space3 = new QWidget(vbox3); vbox3->setStretchFactor(space3, 10); vbox3->setContentsMargins(spacing, spacing, spacing, spacing); vbox3->setSpacing(spacing); // -------------------------------------------------------- d->tab->insertTab(0, vbox, i18n("Icon Items")); d->tab->insertTab(1, vbox2, i18n("Album Items")); d->tab->insertTab(2, vbox3, i18n("Import Items")); vlay->addWidget(d->fontSelect); vlay->addWidget(d->tab); vlay->addStretch(); vlay->setContentsMargins(spacing, spacing, spacing, spacing); vlay->setSpacing(spacing); // -------------------------------------------------------- connect(d->showToolTipsBox, SIGNAL(toggled(bool)), d->fileSettingBox, SLOT(setEnabled(bool))); connect(d->showToolTipsBox, SIGNAL(toggled(bool)), d->photoSettingBox, SLOT(setEnabled(bool))); connect(d->showToolTipsBox, SIGNAL(toggled(bool)), d->videoSettingBox, SLOT(setEnabled(bool))); connect(d->showToolTipsBox, SIGNAL(toggled(bool)), d->digikamSettingBox, SLOT(setEnabled(bool))); connect(d->showAlbumToolTipsBox, SIGNAL(toggled(bool)), d->albumSettingBox, SLOT(setEnabled(bool))); connect(d->showImportToolTipsBox, SIGNAL(toggled(bool)), this, SLOT(slotImportToolTipsChanged())); // -------------------------------------------------------- readSettings(); adjustSize(); } SetupToolTip::~SetupToolTip() { delete d; } void SetupToolTip::applySettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } settings->setToolTipsFont(d->fontSelect->font()); settings->setShowToolTips(d->showToolTipsBox->isChecked()); settings->setToolTipsShowFileName(d->showFileNameBox->isChecked()); settings->setToolTipsShowFileDate(d->showFileDateBox->isChecked()); settings->setToolTipsShowFileSize(d->showFileSizeBox->isChecked()); settings->setToolTipsShowImageAR(d->showImageARBox->isChecked()); settings->setToolTipsShowImageType(d->showImageTypeBox->isChecked()); settings->setToolTipsShowImageDim(d->showImageDimBox->isChecked()); settings->setToolTipsShowPhotoMake(d->showPhotoMakeBox->isChecked()); settings->setToolTipsShowPhotoLens(d->showPhotoLensBox->isChecked()); settings->setToolTipsShowPhotoDate(d->showPhotoDateBox->isChecked()); settings->setToolTipsShowPhotoFocal(d->showPhotoFocalBox->isChecked()); settings->setToolTipsShowPhotoExpo(d->showPhotoExpoBox->isChecked()); settings->setToolTipsShowPhotoMode(d->showPhotoModeBox->isChecked()); settings->setToolTipsShowPhotoFlash(d->showPhotoFlashBox->isChecked()); settings->setToolTipsShowPhotoWB(d->showPhotoWbBox->isChecked()); settings->setToolTipsShowVideoAspectRatio(d->showVideoAspectRatio->isChecked()); settings->setToolTipsShowVideoAudioBitRate(d->showVideoAudioBitRate->isChecked()); settings->setToolTipsShowVideoAudioChannelType(d->showVideoAudioChannelType->isChecked()); settings->setToolTipsShowVideoAudioCodec(d->showVideoAudioCodec->isChecked()); settings->setToolTipsShowVideoDuration(d->showVideoDuration->isChecked()); settings->setToolTipsShowVideoFrameRate(d->showVideoFrameRate->isChecked()); settings->setToolTipsShowVideoVideoCodec(d->showVideoVideoCodec->isChecked()); settings->setToolTipsShowAlbumName(d->showAlbumNameBox->isChecked()); settings->setToolTipsShowTitles(d->showTitlesBox->isChecked()); settings->setToolTipsShowComments(d->showCommentsBox->isChecked()); settings->setToolTipsShowTags(d->showTagsBox->isChecked()); settings->setToolTipsShowLabelRating(d->showLabelsBox->isChecked()); settings->setShowAlbumToolTips(d->showAlbumToolTipsBox->isChecked()); settings->setToolTipsShowAlbumTitle(d->showAlbumTitleBox->isChecked()); settings->setToolTipsShowAlbumDate(d->showAlbumDateBox->isChecked()); settings->setToolTipsShowAlbumCollection(d->showAlbumCollectionBox->isChecked()); settings->setToolTipsShowAlbumCategory(d->showAlbumCategoryBox->isChecked()); settings->setToolTipsShowAlbumCaption(d->showAlbumCaptionBox->isChecked()); settings->setToolTipsShowAlbumPreview(d->showAlbumPreviewBox->isChecked()); settings->saveSettings(); // -- Import Settings ------------------------------------------------------------------------ ImportSettings* const importSettings = ImportSettings::instance(); if (!importSettings) { return; } importSettings->setShowToolTips(d->showImportToolTipsBox->isChecked()); importSettings->setToolTipsShowFileName(d->showItemTitleBox->isChecked()); importSettings->setToolTipsShowFileDate(d->showItemDateBox->isChecked()); importSettings->setToolTipsShowFileSize(d->showItemSizeBox->isChecked()); importSettings->setToolTipsShowImageType(d->showItemTypeBox->isChecked()); importSettings->setToolTipsShowImageDim(d->showItemDimensionsBox->isChecked()); importSettings->setToolTipsShowPhotoMake(d->showItemPhotoMakeBox->isChecked()); importSettings->setToolTipsShowPhotoLens(d->showItemPhotoLensBox->isChecked()); importSettings->setToolTipsShowPhotoFocal(d->showItemPhotoFocalBox->isChecked()); importSettings->setToolTipsShowPhotoExpo(d->showItemPhotoExpoBox->isChecked()); importSettings->setToolTipsShowPhotoFlash(d->showItemPhotoFlashBox->isChecked()); importSettings->setToolTipsShowPhotoWB(d->showItemPhotoWBBox->isChecked()); importSettings->saveSettings(); } void SetupToolTip::readSettings() { ApplicationSettings* const settings = ApplicationSettings::instance(); if (!settings) { return; } d->fontSelect->setFont(settings->getToolTipsFont()); d->showToolTipsBox->setChecked(settings->getShowToolTips()); d->showFileNameBox->setChecked(settings->getToolTipsShowFileName()); d->showFileDateBox->setChecked(settings->getToolTipsShowFileDate()); d->showFileSizeBox->setChecked(settings->getToolTipsShowFileSize()); d->showImageARBox->setChecked(settings->getToolTipsShowImageAR()); d->showImageTypeBox->setChecked(settings->getToolTipsShowImageType()); d->showImageDimBox->setChecked(settings->getToolTipsShowImageDim()); d->showPhotoMakeBox->setChecked(settings->getToolTipsShowPhotoMake()); d->showPhotoLensBox->setChecked(settings->getToolTipsShowPhotoLens()); d->showPhotoDateBox->setChecked(settings->getToolTipsShowPhotoDate()); d->showPhotoFocalBox->setChecked(settings->getToolTipsShowPhotoFocal()); d->showPhotoExpoBox->setChecked(settings->getToolTipsShowPhotoExpo()); d->showPhotoModeBox->setChecked(settings->getToolTipsShowPhotoMode()); d->showPhotoFlashBox->setChecked(settings->getToolTipsShowPhotoFlash()); d->showPhotoWbBox->setChecked(settings->getToolTipsShowPhotoWB()); d->showVideoAspectRatio->setChecked(settings->getToolTipsShowVideoAspectRatio()); d->showVideoAudioBitRate->setChecked(settings->getToolTipsShowVideoAudioBitRate()); d->showVideoAudioChannelType->setChecked(settings->getToolTipsShowVideoAudioChannelType()); d->showVideoAudioCodec->setChecked(settings->getToolTipsShowVideoAudioCodec()); d->showVideoDuration->setChecked(settings->getToolTipsShowVideoDuration()); d->showVideoFrameRate->setChecked(settings->getToolTipsShowVideoFrameRate()); d->showVideoVideoCodec->setChecked(settings->getToolTipsShowVideoVideoCodec()); d->showAlbumNameBox->setChecked(settings->getToolTipsShowAlbumName()); d->showTitlesBox->setChecked(settings->getToolTipsShowTitles()); d->showCommentsBox->setChecked(settings->getToolTipsShowComments()); d->showTagsBox->setChecked(settings->getToolTipsShowTags()); d->showLabelsBox->setChecked(settings->getToolTipsShowLabelRating()); d->fileSettingBox->setEnabled(d->showToolTipsBox->isChecked()); d->photoSettingBox->setEnabled(d->showToolTipsBox->isChecked()); d->digikamSettingBox->setEnabled(d->showToolTipsBox->isChecked()); d->videoSettingBox->setEnabled(d->showToolTipsBox->isChecked()); d->albumSettingBox->setEnabled(d->showAlbumToolTipsBox->isChecked()); d->showAlbumToolTipsBox->setChecked(settings->getShowAlbumToolTips()); d->showAlbumTitleBox->setChecked(settings->getToolTipsShowAlbumTitle()); d->showAlbumDateBox->setChecked(settings->getToolTipsShowAlbumDate()); d->showAlbumCollectionBox->setChecked(settings->getToolTipsShowAlbumCollection()); d->showAlbumCategoryBox->setChecked(settings->getToolTipsShowAlbumCategory()); d->showAlbumCaptionBox->setChecked(settings->getToolTipsShowAlbumCaption()); d->showAlbumPreviewBox->setChecked(settings->getToolTipsShowAlbumPreview()); // -- Import Settings ------------------------------------------------------------------------ ImportSettings* const importSettings = ImportSettings::instance(); if (!importSettings) { return; } d->showImportToolTipsBox->setChecked(importSettings->getShowToolTips()); d->showItemTitleBox->setChecked(importSettings->getToolTipsShowFileName()); d->showItemDateBox->setChecked(importSettings->getToolTipsShowFileDate()); d->showItemSizeBox->setChecked(importSettings->getToolTipsShowFileSize()); d->showItemTypeBox->setChecked(importSettings->getToolTipsShowImageType()); d->showItemDimensionsBox->setChecked(importSettings->getToolTipsShowImageDim()); d->showItemPhotoMakeBox->setChecked(importSettings->getToolTipsShowPhotoMake()); d->showItemPhotoLensBox->setChecked(importSettings->getToolTipsShowPhotoLens()); d->showItemPhotoFocalBox->setChecked(importSettings->getToolTipsShowPhotoFocal()); d->showItemPhotoExpoBox->setChecked(importSettings->getToolTipsShowPhotoExpo()); d->showItemPhotoFlashBox->setChecked(importSettings->getToolTipsShowPhotoFlash()); d->showItemPhotoWBBox->setChecked(importSettings->getToolTipsShowPhotoWB()); refreshCameraOptions(); } void SetupToolTip::slotUseFileMetadataChanged(bool b) { d->cameraUseFileMetadata = b; refreshCameraOptions(); } void SetupToolTip::slotImportToolTipsChanged() { refreshCameraOptions(); } void SetupToolTip::refreshCameraOptions() { bool b = d->showImportToolTipsBox->isChecked(); d->importSettingBox->setEnabled(b); d->showItemPhotoMakeBox->setEnabled(b && d->cameraUseFileMetadata); d->showItemPhotoLensBox->setEnabled(b && d->cameraUseFileMetadata); d->showItemPhotoFocalBox->setEnabled(b && d->cameraUseFileMetadata); d->showItemPhotoExpoBox->setEnabled(b && d->cameraUseFileMetadata); d->showItemPhotoFlashBox->setEnabled(b && d->cameraUseFileMetadata); d->showItemPhotoWBBox->setEnabled(b && d->cameraUseFileMetadata); } } // namespace Digikam diff --git a/project/bundles/mxe/04-build-installer.sh b/project/bundles/mxe/04-build-installer.sh index 226e9ccea1..5997018373 100755 --- a/project/bundles/mxe/04-build-installer.sh +++ b/project/bundles/mxe/04-build-installer.sh @@ -1,328 +1,329 @@ #! /bin/bash # Script to bundle data using previously-built KDE and digiKam installation # and create a Windows installer file with NSIS application # Dependency : NSIS makensis program for Linux. # # Copyright (c) 2015-2020 by Gilles Caulier # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # # Halt and catch errors set -eE trap 'PREVIOUS_COMMAND=$THIS_COMMAND; THIS_COMMAND=$BASH_COMMAND' DEBUG trap 'echo "FAILED COMMAND: $PREVIOUS_COMMAND"' ERR export LANG=C ################################################################################################# # Manage script traces to log file mkdir -p ./logs exec > >(tee ./logs/build-installer.full.log) 2>&1 ################################################################################################# echo "04-build-installer.sh : build digiKam Windows installer." echo "--------------------------------------------------------" ################################################################################################# # Pre-processing checks . ./config.sh . ./common.sh StartScript ChecksCPUCores RegisterRemoteServers ################################################################################################# # Check if NSIS CLI tools is installed if ! which makensis ; then echo "NSIS CLI tool is not installed" echo "See http://nsis.sourceforge.net/ for details." exit 1 else echo "Check NSIS CLI tools passed..." fi ################################################################################################# # Configurations # Directory where this script is located (default - current directory) BUILDDIR="$PWD" # Directory where bundle files are located BUNDLEDIR="$BUILDDIR/temp" ORIG_WD="`pwd`" DK_RELEASEID=`cat $ORIG_WD/data/RELEASEID.txt` ################################################################################################# # Build icons-set ressource echo -e "\n---------- Build icons-set ressource\n" cd $ORIG_WD/icon-rcc rm -f CMakeCache.txt > /dev/null cmake -DCMAKE_INSTALL_PREFIX="$MXE_INSTALL_PREFIX" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DCMAKE_COLOR_MAKEFILE=ON \ -Wno-dev \ . make -j$CPU_CORES ################################################################################################# # Copy files echo -e "\n---------- Copy files in bundle directory\n" # Directories creation ----------------------------------------------------------------------- cd $ORIG_WD if [ -d "$BUNDLEDIR" ]; then rm -fr $BUNDLEDIR mkdir $BUNDLEDIR fi mkdir -p $BUNDLEDIR/data mkdir -p $BUNDLEDIR/etc mkdir -p $BUNDLEDIR/share mkdir -p $BUNDLEDIR/translations # Data files --------------------------------------------------------------------------------- echo -e "\n---------- Marble data" cp -r $MXE_INSTALL_PREFIX/data/* $BUNDLEDIR/data 2>/dev/null echo -e "\n---------- Generics data" cp -r $MXE_INSTALL_PREFIX/share/lensfun $BUNDLEDIR/data 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/data/digikam $BUNDLEDIR/data 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/data/showfoto $BUNDLEDIR/data 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/data/solid $BUNDLEDIR/data 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/data/k* $BUNDLEDIR/data 2>/dev/null echo -e "\n---------- Qt config" cp $BUILDDIR/data/qt.conf $BUNDLEDIR/ 2>/dev/null echo -e "\n---------- icons-set" cp $BUILDDIR/icon-rcc/breeze.rcc $BUNDLEDIR/ 2>/dev/null cp $BUILDDIR/icon-rcc/breeze-dark.rcc $BUNDLEDIR/ 2>/dev/null echo -e "\n---------- i18n" cp -r $MXE_INSTALL_PREFIX/qt5/translations/qt_* $BUNDLEDIR/translations 2>/dev/null cp -r $MXE_INSTALL_PREFIX/qt5/translations/qtbase* $BUNDLEDIR/translations 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/data/locale $BUNDLEDIR/data 2>/dev/null echo -e "\n---------- Xdg" cp -r $MXE_INSTALL_PREFIX/etc/xdg $BUNDLEDIR/etc 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/data/xdg $BUNDLEDIR/share 2>/dev/null # Plugins Shared libraries ------------------------------------------------------------------- echo -e "\n---------- Qt5 plugins" cp -r $MXE_INSTALL_PREFIX/qt5/plugins $BUNDLEDIR/ 2>/dev/null echo -e "\n---------- Marble plugins" cp -r $MXE_INSTALL_PREFIX/plugins/*.dll $BUNDLEDIR/plugins 2>/dev/null echo -e "\n---------- digiKam and KF5 plugins" cp -r $MXE_INSTALL_PREFIX/lib/plugins $BUNDLEDIR/ 2>/dev/null echo -e "\n---------- OpenAL for QtAV" cp -r $MXE_INSTALL_PREFIX/bin/OpenAL32.dll $BUNDLEDIR/ 2>/dev/null echo -e "\n---------- DrMinGw run-time" cp -r $MXE_INSTALL_PREFIX/bin/exchndl.dll $BUNDLEDIR/ 2>/dev/null cp -r $MXE_INSTALL_PREFIX/bin/mgwhelp.dll $BUNDLEDIR/ 2>/dev/null echo -e "\n---------- Copy executables with recursive dependencies in bundle directory\n" # Executables and plugins shared libraries dependencies scan --------------------------------- EXE_FILES="\ $MXE_INSTALL_PREFIX/bin/digikam.exe \ $MXE_INSTALL_PREFIX/bin/showfoto.exe \ $MXE_INSTALL_PREFIX/bin/kbuildsycoca5.exe \ $MXE_INSTALL_PREFIX/qt5/bin/QtWebNetworkProcess.exe \ $MXE_INSTALL_PREFIX/qt5/bin/QtWebProcess.exe \ $MXE_INSTALL_PREFIX/qt5/bin/QtWebStorageProcess.exe \ " if [[ $DK_DEBUG = 1 ]] ; then EXE_FILES="$EXE_FILES $MXE_INSTALL_PREFIX/bin/gdb.exe" fi for app in $EXE_FILES ; do cp $app $BUNDLEDIR/ $ORIG_WD/rll.py --copy --installprefix $MXE_INSTALL_PREFIX --odir $BUNDLEDIR --efile $app done DLL_FILES="\ `find $MXE_INSTALL_PREFIX/lib/plugins -name "*.dll" -type f | sed 's|$MXE_INSTALL_PREFIX/libs/plugins||'` \ `find $MXE_INSTALL_PREFIX/qt5/plugins -name "*.dll" -type f | sed 's|$MXE_INSTALL_PREFIX/qt5/plugins||'` \ `find $MXE_INSTALL_PREFIX/plugins -name "*.dll" -type f | sed 's|$MXE_INSTALL_PREFIX/plugins/||'` \ $MXE_INSTALL_PREFIX/bin/OpenAL32.dll \ $MXE_INSTALL_PREFIX/bin/exchndl.dll \ $MXE_INSTALL_PREFIX/bin/mgwhelp.dll \ " for app in $DLL_FILES ; do $ORIG_WD/rll.py --copy --installprefix $MXE_INSTALL_PREFIX --odir $BUNDLEDIR --efile $app done # Remove this dll as it require the Microsoft debug SDK. Even if this dll is redistributable we won't be be relevant of this stuff. # This will not breal DrMinGw as backtraces will generated in a text file from home directory instead into a crash-course dialog. rm -f $BUNDLEDIR/dbghelp.dll ################################################################################################# # Cleanup symbols in binary files to free space. echo -e "\n---------- Strip symbols in binary files\n" if [[ $DK_DEBUG = 1 ]] ; then find $BUNDLEDIR -name \*exe | grep -Ev '(digikam|showfoto|exiv2)' | xargs ${MXE_BUILDROOT}/usr/bin/${MXE_BUILD_TARGETS}-strip find $BUNDLEDIR -name \*dll | grep -Ev '(digikam|showfoto|exiv2)' | xargs ${MXE_BUILDROOT}/usr/bin/${MXE_BUILD_TARGETS}-strip else find $BUNDLEDIR -name \*exe | xargs ${MXE_BUILDROOT}/usr/bin/${MXE_BUILD_TARGETS}-strip find $BUNDLEDIR -name \*dll | xargs ${MXE_BUILDROOT}/usr/bin/${MXE_BUILD_TARGETS}-strip fi if [[ $DK_DEBUG = 1 ]] ; then DEBUG_SUF="-debug" fi ################################################################################################# # Build NSIS installer and Portable archive. echo -e "\n---------- Build NSIS installer and Portable archive\n" mkdir -p $ORIG_WD/bundle if [ $MXE_BUILD_TARGETS == "i686-w64-mingw32.shared" ]; then TARGET_INSTALLER=digiKam-$DK_RELEASEID$DK_EPOCH-Win32$DEBUG_SUF.exe PORTABLE_FILE=digiKam-$DK_RELEASEID$DK_EPOCH-Win32$DEBUG_SUF.tar.xz CHECKSUM_FILE=digiKam-$DK_RELEASEID$DK_EPOCH-Win32$DEBUG_SUF.sum rm -f $ORIG_WD/bundle/*Win32* || true else TARGET_INSTALLER=digiKam-$DK_RELEASEID$DK_EPOCH-Win64$DEBUG_SUF.exe PORTABLE_FILE=digiKam-$DK_RELEASEID$DK_EPOCH-Win64$DEBUG_SUF.tar.xz CHECKSUM_FILE=digiKam-$DK_RELEASEID$DK_EPOCH-Win64$DEBUG_SUF.sum rm -f $ORIG_WD/bundle/*Win64* || true fi cd $ORIG_WD/installer makensis -DVERSION=$DK_RELEASEID -DBUNDLEPATH=$BUNDLEDIR -DTARGETARCH=$MXE_ARCHBITS -DOUTPUT=$ORIG_WD/bundle/$TARGET_INSTALLER ./digikam.nsi -tar cf - $(basename $BUNDLEDIR) --transform s/temp/digiKam/ | xz -4e > $ORIG_WD/bundle/$PORTABLE_FILE +cd $ORIG_WD +tar cf - `basename $BUNDLEDIR` --transform s/temp/digiKam/ | xz -4e > $ORIG_WD/bundle/$PORTABLE_FILE ################################################################################################# # Show resume information and future instructions to host target files on remote server echo -e "\n---------- Compute installer checksums for digiKam $DK_RELEASEID\n" > $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo "File : $TARGET_INSTALLER" >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo -n "Size : " >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum du -h "$ORIG_WD/bundle/$TARGET_INSTALLER" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo -n "MD5 sum : " >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum md5sum "$ORIG_WD/bundle/$TARGET_INSTALLER" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo -n "SHA1 sum : " >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum shasum -a1 "$ORIG_WD/bundle/$TARGET_INSTALLER" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo -n "SHA256 sum : " >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum shasum -a256 "$ORIG_WD/bundle/$TARGET_INSTALLER" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum # Checksums to post on Phabricator at release time. shasum -a256 "$ORIG_WD/bundle/$TARGET_INSTALLER" > $ORIG_WD/bundle/$CHECKSUM_FILE echo -e "\n---------- Compute Portable archive checksums for digiKam $DK_RELEASEID\n" > $ORIG_WD/bundle/$PORTABLE_FILE.sum echo "File : $PORTABLE_FILE" >> $ORIG_WD/bundle/$PORTABLE_FILE.sum echo -n "Size : " >> $ORIG_WD/bundle/$PORTABLE_FILE.sum du -h "$ORIG_WD/bundle/$PORTABLE_FILE" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$PORTABLE_FILE.sum echo -n "MD5 sum : " >> $ORIG_WD/bundle/$PORTABLE_FILE.sum md5sum "$ORIG_WD/bundle/$PORTABLE_FILE" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$PORTABLE_FILE.sum echo -n "SHA1 sum : " >> $ORIG_WD/bundle/$PORTABLE_FILE.sum shasum -a1 "$ORIG_WD/bundle/$PORTABLE_FILE" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$PORTABLE_FILE.sum echo -n "SHA256 sum : " >> $ORIG_WD/bundle/$PORTABLE_FILE.sum shasum -a256 "$ORIG_WD/bundle/$PORTABLE_FILE" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$PORTABLE_FILE.sum # Checksums to post on Phabricator at release time. shasum -a256 "$ORIG_WD/bundle/$PORTABLE_FILE" >> $ORIG_WD/bundle/$CHECKSUM_FILE if [[ $DK_SIGN = 1 ]] ; then echo -e "\n---------- Compute Signature checksums for digiKam installer $DK_RELEASEID\n" > $ORIG_WD/bundle/$TARGET_INSTALLER.sum cat ~/.gnupg/dkorg-gpg-pwd.txt | gpg --batch --yes --passphrase-fd 0 -sabv "$ORIG_WD/bundle/$TARGET_INSTALLER" mv -f $ORIG_WD/bundle/$TARGET_INSTALLER.asc $ORIG_WD/bundle/$TARGET_INSTALLER.sig echo "File : $TARGET_INSTALLER.sig" >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo -n "Size : " >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum du -h "$ORIG_WD/bundle/$TARGET_INSTALLER.sig" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum echo -n "SHA256 sum : " >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum shasum -a256 "$ORIG_WD/bundle/$TARGET_INSTALLER.sig" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$TARGET_INSTALLER.sum # Checksums to post on Phabricator at release time. shasum -a256 "$ORIG_WD/bundle/$TARGET_INSTALLER.sig" >> $ORIG_WD/bundle/$CHECKSUM_FILE echo -e "\n---------- Compute Signature checksums for digiKam Portable $DK_RELEASEID\n" > $ORIG_WD/bundle/$PORTABLE_FILE.sum cat ~/.gnupg/dkorg-gpg-pwd.txt | gpg --batch --yes --passphrase-fd 0 -sabv "$ORIG_WD/bundle/$PORTABLE_FILE" mv -f $ORIG_WD/bundle/$PORTABLE_FILE.asc $ORIG_WD/bundle/$PORTABLE_FILE.sig echo "File : $PORTABLE_FILE.sig" >> $ORIG_WD/bundle/$PORTABLE_FILE.sum echo -n "Size : " >> $ORIG_WD/bundle/$PORTABLE_FILE.sum du -h "$ORIG_WD/bundle/$PORTABLE_FILE.sig" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$PORTABLE_FILE.sum echo -n "SHA256 sum : " >> $ORIG_WD/bundle/$PORTABLE_FILE.sum shasum -a256 "$ORIG_WD/bundle/$PORTABLE_FILE.sig" | { read first rest ; echo $first ; } >> $ORIG_WD/bundle/$PORTABLE_FILE.sum # Checksums to post on Phabricator at release time. shasum -a256 "$ORIG_WD/bundle/$PORTABLE_FILE.sig" >> $ORIG_WD/bundle/$CHECKSUM_FILE fi cat $ORIG_WD/bundle/$TARGET_INSTALLER.sum cat $ORIG_WD/bundle/$PORTABLE_FILE.sum if [[ $DK_UPLOAD = 1 ]] ; then echo -e "---------- Cleanup older Windows bundle files from files.kde.org repository \n" if [ $MXE_BUILD_TARGETS == "i686-w64-mingw32.shared" ]; then ssh $DK_UPLOADURL rm -f $DK_UPLOADDIR*-Win32$DEBUG_SUF.exe* ssh $DK_UPLOADURL rm -f $DK_UPLOADDIR*-Win32$DEBUG_SUF.tar.xz* else ssh $DK_UPLOADURL rm -f $DK_UPLOADDIR*-Win64$DEBUG_SUF.exe* ssh $DK_UPLOADURL rm -f $DK_UPLOADDIR*-Win64$DEBUG_SUF.tar.xz* fi echo -e "---------- Upload new Windows bundle files to files.kde.org repository \n" rsync -r -v --progress -e ssh $ORIG_WD/bundle/$TARGET_INSTALLER $DK_UPLOADURL:$DK_UPLOADDIR rsync -r -v --progress -e ssh $ORIG_WD/bundle/$PORTABLE_FILE $DK_UPLOADURL:$DK_UPLOADDIR scp $ORIG_WD/bundle/$TARGET_INSTALLER.sum $DK_UPLOADURL:$DK_UPLOADDIR scp $ORIG_WD/bundle/$PORTABLE_FILE.sum $DK_UPLOADURL:$DK_UPLOADDIR if [[ $DK_SIGN = 1 ]] ; then scp $ORIG_WD/bundle/$TARGET_INSTALLER.sig $DK_UPLOADURL:$DK_UPLOADDIR scp $ORIG_WD/bundle/$PORTABLE_FILE.sig $DK_UPLOADURL:$DK_UPLOADDIR fi else echo -e "\n------------------------------------------------------------------" curl https://download.kde.org/README_UPLOAD echo -e "------------------------------------------------------------------\n" fi ################################################################################################# TerminateScript