diff --git a/core/utilities/import/dialogs/camerafolderdialog.cpp b/core/utilities/import/dialogs/camerafolderdialog.cpp index 5fcad5b804..ace2fb9b37 100644 --- a/core/utilities/import/dialogs/camerafolderdialog.cpp +++ b/core/utilities/import/dialogs/camerafolderdialog.cpp @@ -1,204 +1,206 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-07-24 * Description : a dialog to select a camera folders. * * 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 "camerafolderdialog.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "camerafolderitem.h" #include "camerafolderview.h" #include "dxmlguiwindow.h" namespace Digikam { class Q_DECL_HIDDEN CameraFolderDialog::Private { public: explicit Private() : buttons(nullptr), folderView(nullptr) { } QString rootPath; QDialogButtonBox* buttons; CameraFolderView* folderView; }; CameraFolderDialog::CameraFolderDialog(QWidget* const parent, const QMap& map, const QString& cameraName, const QString& rootPath) : QDialog(parent), d(new Private) { setModal(true); setWindowTitle(i18nc("@title:window %1: name of the camera", "%1 - Select Camera Folder", cameraName)); - const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); + const int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); - d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Ok)->setDefault(true); d->buttons->button(QDialogButtonBox::Ok)->setEnabled(false); - d->rootPath = rootPath; - QFrame* const page = new QFrame(this); + d->rootPath = rootPath; + QFrame* const page = new QFrame(this); QGridLayout* const grid = new QGridLayout(page); d->folderView = new CameraFolderView(page); QLabel* const logo = new QLabel(page); QLabel* const message = new QLabel(page); logo->setPixmap(QIcon::fromTheme(QLatin1String("digikam")).pixmap(QSize(48,48))); message->setText(i18n("

Please select the camera folder " "where you want to upload the images.

")); message->setWordWrap(true); grid->addWidget(logo, 0, 0, 1, 1); grid->addWidget(message, 1, 0, 1, 1); grid->addWidget(d->folderView, 0, 1, 3, 1); grid->setRowStretch(2, 10); grid->setContentsMargins(spacing, spacing, spacing, spacing); grid->setSpacing(spacing); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(page); vbx->addWidget(d->buttons); setLayout(vbx); d->folderView->addVirtualFolder(cameraName); d->folderView->addRootFolder(QLatin1String("/")); - for (QMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it) + for (QMap::const_iterator it = map.constBegin() ; it != map.constEnd() ; ++it) { QString folder(it.key()); if (folder != QLatin1String("/")) { if (folder.startsWith(rootPath) && rootPath != QLatin1String("/")) { folder.remove(0, rootPath.length()); } QString path(QLatin1Char('/')); foreach (const QString& sub, folder.split(QLatin1Char('/'), QString::SkipEmptyParts)) { qCDebug(DIGIKAM_IMPORTUI_LOG) << "Camera folder:" << path << "Subfolder:" << sub; d->folderView->addFolder(path, sub, it.value()); path += sub + QLatin1Char('/'); } } } connect(d->folderView, SIGNAL(signalFolderChanged(CameraFolderItem*)), this, SLOT(slotFolderPathSelectionChanged(CameraFolderItem*))); connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject())); connect(d->buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotHelp())); adjustSize(); // make sure the ok button is properly set up + d->buttons->button(QDialogButtonBox::Ok)->setEnabled(d->folderView->currentItem() != nullptr); } CameraFolderDialog::~CameraFolderDialog() { delete d; } QString CameraFolderDialog::selectedFolderPath() const { QTreeWidgetItem* const item = d->folderView->currentItem(); if (!item) { return QString(); } CameraFolderItem* const folderItem = dynamic_cast(item); if (!folderItem) { return QString(); } if (folderItem->isVirtualFolder()) { return QString(d->rootPath); } // Case of Gphoto2 cameras. No need to duplicate root '/'. + if (d->rootPath == QLatin1String("/")) { return(folderItem->folderPath()); } return (d->rootPath + folderItem->folderPath()); } void CameraFolderDialog::slotFolderPathSelectionChanged(CameraFolderItem* item) { if (item) { d->buttons->button(QDialogButtonBox::Ok)->setEnabled(true); qCDebug(DIGIKAM_IMPORTUI_LOG) << "Camera folder path: " << selectedFolderPath(); } else { d->buttons->button(QDialogButtonBox::Ok)->setEnabled(false); } } void CameraFolderDialog::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/core/utilities/import/dialogs/camerainfodialog.cpp b/core/utilities/import/dialogs/camerainfodialog.cpp index de7c51e313..cb945ac4cb 100644 --- a/core/utilities/import/dialogs/camerainfodialog.cpp +++ b/core/utilities/import/dialogs/camerainfodialog.cpp @@ -1,105 +1,105 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-01-28 * Description : a dialog to display camera information. * * 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 "camerainfodialog.h" // Qt includes #include #include #include #include #include #include // KDE includes #include // Local includes #include "dxmlguiwindow.h" namespace Digikam { CameraInfoDialog::CameraInfoDialog(QWidget* const parent, const QString& summary, const QString& manual, const QString& about) : QDialog(parent) { setModal(true); setWindowTitle(i18nc("@title:window", "Device Information")); QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok, this); buttons->button(QDialogButtonBox::Ok)->setDefault(true); resize(500, 400); - QTabWidget* const tab = new QTabWidget(this); + QTabWidget* const tab = new QTabWidget(this); // ---------------------------------------------------------- QTextEdit* const summaryView = new QTextEdit(summary); summaryView->setWordWrapMode(QTextOption::WordWrap); summaryView->setReadOnly(true); tab->insertTab(0, summaryView, QIcon::fromTheme(QLatin1String("dialog-information")), i18n("Device Summary")); // ---------------------------------------------------------- QTextEdit* const manualView = new QTextEdit(manual); manualView->setWordWrapMode(QTextOption::WordWrap); manualView->setReadOnly(true); tab->insertTab(1, manualView, QIcon::fromTheme(QLatin1String("help-contents")), i18n("Device Manual")); // ---------------------------------------------------------- QTextEdit* const aboutView = new QTextEdit(about); aboutView->setWordWrapMode(QTextOption::WordWrap); aboutView->setReadOnly(true); tab->insertTab(2, aboutView, QIcon::fromTheme(QLatin1String("camera-photo")), i18n("About Driver")); // ---------------------------------------------------------- - QVBoxLayout* const vbx = new QVBoxLayout(this); + QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(tab); vbx->addWidget(buttons); setLayout(vbx); connect(buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); connect(buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotHelp())); } CameraInfoDialog::~CameraInfoDialog() { } void CameraInfoDialog::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/core/utilities/import/dialogs/cameramessagebox.cpp b/core/utilities/import/dialogs/cameramessagebox.cpp index a8a7664148..35cc5896f4 100644 --- a/core/utilities/import/dialogs/cameramessagebox.cpp +++ b/core/utilities/import/dialogs/cameramessagebox.cpp @@ -1,236 +1,238 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-01-04 * Description : a message box to manage camera items * * 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 "cameramessagebox.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "dmessagebox.h" #include "digikam_debug.h" namespace Digikam { class Q_DECL_HIDDEN CameraItem::Private { public: explicit Private() + : hasThumb(false) { - hasThumb = false; } bool hasThumb; CamItemInfo info; }; CameraItem::CameraItem(QTreeWidget* const parent, const CamItemInfo& info) : QTreeWidgetItem(parent), d(new Private) { d->info = info; setThumb(QIcon::fromTheme(QLatin1String("view-preview")).pixmap(parent->iconSize().width(), QIcon::Disabled), false); setText(1, d->info.name); } CameraItem::~CameraItem() { delete d; } bool CameraItem::hasValidThumbnail() const { return d->hasThumb; } CamItemInfo CameraItem::info() const { return d->info; } void CameraItem::setThumb(const QPixmap& pix, bool hasThumb) { int iconSize = treeWidget()->iconSize().width(); QPixmap pixmap(iconSize + 2, iconSize + 2); pixmap.fill(Qt::transparent); QPainter p(&pixmap); p.drawPixmap((pixmap.width() / 2) - (pix.width() / 2), (pixmap.height() / 2) - (pix.height() / 2), pix); QIcon icon = QIcon(pixmap); + // We make sure the preview icon stays the same regardless of the role + icon.addPixmap(pixmap, QIcon::Selected, QIcon::On); icon.addPixmap(pixmap, QIcon::Selected, QIcon::Off); icon.addPixmap(pixmap, QIcon::Active, QIcon::On); icon.addPixmap(pixmap, QIcon::Active, QIcon::Off); icon.addPixmap(pixmap, QIcon::Normal, QIcon::On); icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off); setIcon(0, icon); d->hasThumb = hasThumb; } //---------------------------------------------------------------------------- class Q_DECL_HIDDEN CameraItemList::Private { public: explicit Private() - : iconSize(64) + : iconSize(64), + ctrl(nullptr) { - ctrl = nullptr; } const int iconSize; CameraThumbsCtrl* ctrl; }; CameraItemList::CameraItemList(QWidget* const parent) : QTreeWidget(parent), d(new Private) { setRootIsDecorated(false); setSelectionMode(QAbstractItemView::SingleSelection); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setAllColumnsShowFocus(true); setIconSize(QSize(d->iconSize, d->iconSize)); setColumnCount(2); setHeaderLabels(QStringList() << i18n("Thumb") << i18n("File Name")); header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); header()->setSectionResizeMode(1, QHeaderView::Stretch); } CameraItemList::~CameraItemList() { delete d; } void CameraItemList::setItems(const CamItemInfoList& items) { foreach (const CamItemInfo& info, items) { new CameraItem(this, info); } } void CameraItemList::setThumbCtrl(CameraThumbsCtrl* const ctrl) { d->ctrl = ctrl; connect(d->ctrl, SIGNAL(signalThumbInfoReady(CamItemInfo)), this, SLOT(slotThumbnailLoaded(CamItemInfo))); } void CameraItemList::slotThumbnailLoaded(const CamItemInfo& info) { QTreeWidgetItemIterator it(this); bool valid; CachedItem citem; while (*it) { CameraItem* const item = dynamic_cast(*it); if (item && item->info().url() == info.url()) { valid = d->ctrl->getThumbInfo(info, citem); item->setThumb(citem.second.scaled(d->iconSize, d->iconSize, Qt::KeepAspectRatio), valid); return; } ++it; } } void CameraItemList::drawRow(QPainter* p, const QStyleOptionViewItem& opt, const QModelIndex& index) const { CameraItem* const item = dynamic_cast(itemFromIndex(index)); if (item && !item->hasValidThumbnail()) { CachedItem citem; bool valid = d->ctrl->getThumbInfo(item->info(), citem); item->setThumb(citem.second.scaled(d->iconSize, d->iconSize, Qt::KeepAspectRatio), valid); } QTreeWidget::drawRow(p, opt, index); } // -------------------------------------------------------------------------------------------------------- void CameraMessageBox::informationList(CameraThumbsCtrl* const ctrl, QWidget* const parent, const QString& caption, const QString& text, const CamItemInfoList& items, const QString& dontShowAgainName) { CameraItemList* const listWidget = new CameraItemList(); listWidget->setThumbCtrl(ctrl); listWidget->setItems(items); DMessageBox::showInformationWidget(QMessageBox::Information, parent, caption, text, listWidget, dontShowAgainName); } int CameraMessageBox::warningContinueCancelList(CameraThumbsCtrl* const ctrl, QWidget* const parent, const QString& caption, const QString& text, const CamItemInfoList& items, const QString& dontAskAgainName) { CameraItemList* const listWidget = new CameraItemList(); listWidget->setThumbCtrl(ctrl); listWidget->setItems(items); return (DMessageBox::showContinueCancelWidget(QMessageBox::Warning, parent, caption, text, listWidget, dontAskAgainName)); } } // namespace Digikam diff --git a/core/utilities/import/dialogs/cameramessagebox.h b/core/utilities/import/dialogs/cameramessagebox.h index 5262fd8b95..b36dc64829 100644 --- a/core/utilities/import/dialogs/cameramessagebox.h +++ b/core/utilities/import/dialogs/cameramessagebox.h @@ -1,119 +1,121 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-01-04 * Description : a message box to manage camera items * * 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. * * ============================================================ */ #ifndef DIGIKAM_CAMERA_MESSAGE_BOX_H #define DIGIKAM_CAMERA_MESSAGE_BOX_H // Qt includes #include #include // Local includes #include "camerathumbsctrl.h" #include "digikam_export.h" class QDialog; class QDialogButtonBox; namespace Digikam { class DIGIKAM_EXPORT CameraItem : public QTreeWidgetItem { public: CameraItem(QTreeWidget* const parent, const CamItemInfo& info); virtual ~CameraItem(); bool hasValidThumbnail() const; CamItemInfo info() const; void setThumb(const QPixmap& pix, bool hasThumb = true); private: class Private; Private* const d; }; // ----------------------------------------------------------- class DIGIKAM_EXPORT CameraItemList : public QTreeWidget { Q_OBJECT public: explicit CameraItemList(QWidget* const parent = nullptr); virtual ~CameraItemList(); void setThumbCtrl(CameraThumbsCtrl* const ctrl); void setItems(const CamItemInfoList& items); private : void drawRow(QPainter* p, const QStyleOptionViewItem& opt, const QModelIndex& index) const; private Q_SLOTS: void slotThumbnailLoaded(const CamItemInfo&); private: class Private; Private* const d; }; // ----------------------------------------------------------- class DIGIKAM_EXPORT CameraMessageBox { public: - /** Show List of camera items into an informative message box. + /** + * Show List of camera items into an informative message box. */ static void informationList(CameraThumbsCtrl* const ctrl, QWidget* const parent, const QString& caption, const QString& text, const CamItemInfoList& items, const QString& dontShowAgainName = QString()); - /** Show List of camera items to process into a message box and wait user feedback. - * Return QMessageBox::Yes or QMessageBox::Cancel + /** + * Show List of camera items to process into a message box and wait user feedback. + * Return QMessageBox::Yes or QMessageBox::Cancel */ static int warningContinueCancelList(CameraThumbsCtrl* const ctrl, QWidget* const parent, const QString& caption, const QString& text, const CamItemInfoList& items, const QString& dontAskAgainName = QString()); }; } // namespace Digikam #endif // DIGIKAM_CAMERA_MESSAGE_BOX_H diff --git a/core/utilities/import/dialogs/capturedlg.cpp b/core/utilities/import/dialogs/capturedlg.cpp index 7706e619d6..9721ea8721 100644 --- a/core/utilities/import/dialogs/capturedlg.cpp +++ b/core/utilities/import/dialogs/capturedlg.cpp @@ -1,202 +1,203 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-09-06 * Description : a dialog to control camera capture. * * 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 "capturedlg.h" // Qt includes #include #include #include #include // KDE includes #include #include #include // Local includes #include "cameracontroller.h" #include "capturewidget.h" #include "dxmlguiwindow.h" namespace Digikam { class Q_DECL_HIDDEN CaptureDlg::Private { public: explicit Private() : stopPreview(false), timer(nullptr), buttons(nullptr), controller(nullptr), captureWidget(nullptr) { } bool stopPreview; QTimer* timer; QDialogButtonBox* buttons; CameraController* controller; CaptureWidget* captureWidget; }; CaptureDlg::CaptureDlg(QWidget* const parent, CameraController* const controller, const QString& cameraTitle) : QDialog(parent), d(new Private) { - d->controller = controller; + d->controller = controller; setWindowTitle(i18nc("@title:window %1: name of the camera", "Capture from %1", cameraTitle)); setModal(true); - d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); + d->buttons = new QDialogButtonBox(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); d->buttons->button(QDialogButtonBox::Cancel)->setDefault(true); d->buttons->button(QDialogButtonBox::Ok)->setText(i18nc("@action:button", "Capture")); - d->captureWidget = new CaptureWidget(this); + d->captureWidget = new CaptureWidget(this); QVBoxLayout* const vbx = new QVBoxLayout(this); vbx->addWidget(d->captureWidget); vbx->addWidget(d->buttons); setLayout(vbx); - KConfigGroup group = KSharedConfig::openConfig()->group("Capture Tool Dialog"); + KConfigGroup group = KSharedConfig::openConfig()->group("Capture Tool Dialog"); winId(); DXmlGuiWindow::restoreWindowSize(windowHandle(), group); resize(windowHandle()->size()); // ------------------------------------------------------------- connect(d->buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(slotCapture())); connect(d->buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(slotCancel())); connect(d->buttons->button(QDialogButtonBox::Help), SIGNAL(clicked()), this, SLOT(slotHelp())); connect(d->controller, SIGNAL(signalPreview(QImage)), this, SLOT(slotPreviewDone(QImage))); // ------------------------------------------------------------- if (d->controller->cameraCaptureImagePreviewSupport()) { d->timer = new QTimer(this); - connect( d->timer, SIGNAL(timeout()), - this, SLOT(slotPreview()) ); + connect(d->timer, SIGNAL(timeout()), + this, SLOT(slotPreview())); d->timer->setSingleShot(true); d->timer->start(0); } } CaptureDlg::~CaptureDlg() { - delete d->timer; // TODO is there a need to call this even separately? As parent is set to this widget in any case, so it should be destroyed? + // TODO is there a need to call this even separately? As parent is set to this widget in any case, so it should be destroyed? + delete d->timer; delete d; } void CaptureDlg::closeEvent(QCloseEvent* e) { d->stopPreview = true; if (d->timer) { d->timer->stop(); } KConfigGroup group = KSharedConfig::openConfig()->group(QLatin1String("Capture Tool Dialog")); DXmlGuiWindow::saveWindowSize(windowHandle(), group); e->accept(); } void CaptureDlg::slotCancel() { d->stopPreview = true; if (d->timer) { d->timer->stop(); } KConfigGroup group = KSharedConfig::openConfig()->group(QLatin1String("Capture Tool Dialog")); DXmlGuiWindow::saveWindowSize(windowHandle(), group); reject(); } void CaptureDlg::slotPreview() { d->controller->getPreview(); } void CaptureDlg::slotCapture() { d->stopPreview = true; if (d->timer) { d->timer->stop(); } disconnect(d->controller, SIGNAL(signalPreview(QImage)), this, SLOT(slotPreviewDone(QImage))); KConfigGroup group = KSharedConfig::openConfig()->group("Capture Tool Dialog"); DXmlGuiWindow::saveWindowSize(windowHandle(), group); d->controller->capture(); accept(); } void CaptureDlg::slotPreviewDone(const QImage& preview) { d->captureWidget->setPreview(preview); if (!d->stopPreview && d->timer) { d->timer->start(0); } } void CaptureDlg::slotHelp() { DXmlGuiWindow::openHandbook(); } } // namespace Digikam diff --git a/core/utilities/import/items/camerafolderitem.h b/core/utilities/import/items/camerafolderitem.h index 3fec30a4f2..6ce9e45243 100644 --- a/core/utilities/import/items/camerafolderitem.h +++ b/core/utilities/import/items/camerafolderitem.h @@ -1,69 +1,70 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2003-01-23 * Description : A widget to display a camera folder. * * 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_FOLDER_ITEM_H #define DIGIKAM_CAMERA_FOLDER_ITEM_H // Qt includes #include #include #include #include namespace Digikam { class CameraFolderItem : public QTreeWidgetItem { public: CameraFolderItem(QTreeWidget* const parent, const QString& name, const QIcon &icon = QIcon::fromTheme(QLatin1String("folder"))); CameraFolderItem(QTreeWidgetItem* const parent, const QString& folderName, const QString& folderPath, const QIcon& icon = QIcon::fromTheme(QLatin1String("folder"))); ~CameraFolderItem(); - QString folderName() const; - QString folderPath() const; - bool isVirtualFolder() const; + QString folderName() const; + QString folderPath() const; + bool isVirtualFolder() const; + void changeCount(int val); void setCount(int val); - int count() const; + int count() const; private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_CAMERA_FOLDER_ITEM_H diff --git a/core/utilities/import/items/importcategorydrawer.cpp b/core/utilities/import/items/importcategorydrawer.cpp index 72b1eb572a..bf6be82ba5 100644 --- a/core/utilities/import/items/importcategorydrawer.cpp +++ b/core/utilities/import/items/importcategorydrawer.cpp @@ -1,279 +1,289 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-17 * Description : Qt item view for images - category drawer * * Copyright (C) 2012 by Islam Wazery * * 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 "importcategorydrawer.h" // Qt includes #include #include // KDE includes #include // Local includes #include "importcategorizedview.h" #include "camitemsortsettings.h" #include "importfiltermodel.h" #include "itemscanner.h" namespace Digikam { class Q_DECL_HIDDEN ImportCategoryDrawer::Private { public: explicit Private() : lowerSpacing(0), view(nullptr) { } QFont font; QRect rect; QPixmap pixmap; int lowerSpacing; ImportCategorizedView* view; }; ImportCategoryDrawer::ImportCategoryDrawer(ImportCategorizedView* const parent) : DCategoryDrawer(nullptr), d(new Private) { d->view = parent; } ImportCategoryDrawer::~ImportCategoryDrawer() { delete d; } int ImportCategoryDrawer::categoryHeight(const QModelIndex& /*index*/, const QStyleOption& /*option*/) const { - return d->rect.height() + d->lowerSpacing; + return (d->rect.height() + d->lowerSpacing); } int ImportCategoryDrawer::maximumHeight() const { - return d->rect.height() + d->lowerSpacing; + return (d->rect.height() + d->lowerSpacing); } void ImportCategoryDrawer::setLowerSpacing(int spacing) { d->lowerSpacing = spacing; } void ImportCategoryDrawer::setDefaultViewOptions(const QStyleOptionViewItem& option) { d->font = option.font; if (option.rect.width() != d->rect.width()) { updateRectsAndPixmaps(option.rect.width()); } } void ImportCategoryDrawer::invalidatePaintingCache() { if (d->rect.isEmpty()) { return; } updateRectsAndPixmaps(d->rect.width()); } void ImportCategoryDrawer::drawCategory(const QModelIndex& index, int /*sortRole*/, const QStyleOption& option, QPainter* p) const { if (option.rect.width() != d->rect.width()) { const_cast(this)->updateRectsAndPixmaps(option.rect.width()); } p->save(); p->translate(option.rect.topLeft()); CamItemSortSettings::CategorizationMode mode = (CamItemSortSettings::CategorizationMode)index.data(ImportFilterModel::CategorizationModeRole).toInt(); p->drawPixmap(0, 0, d->pixmap); QFont fontBold(d->font); QFont fontNormal(d->font); fontBold.setBold(true); int fnSize = fontBold.pointSize(); - // bool usePointSize; +/* + bool usePointSize; +*/ + if (fnSize > 0) { fontBold.setPointSize(fnSize+2); - // usePointSize = true; +/* + usePointSize = true; +*/ } else { fnSize = fontBold.pixelSize(); fontBold.setPixelSize(fnSize+2); - // usePointSize = false; +/* + usePointSize = false; +*/ } QString header; QString subLine; switch (mode) { case CamItemSortSettings::NoCategories: break; + case CamItemSortSettings::CategoryByFolder: viewHeaderText(index, &header, &subLine); break; + case CamItemSortSettings::CategoryByFormat: textForFormat(index, &header, &subLine); break; + case CamItemSortSettings::CategoryByDate: textForDate(index, &header, &subLine); break; } p->setPen(qApp->palette().color(QPalette::HighlightedText)); p->setFont(fontBold); QRect tr; p->drawText(5, 5, d->rect.width(), d->rect.height(), Qt::AlignLeft | Qt::AlignTop, header, &tr); int y = tr.height() + 2; p->setFont(fontNormal); p->drawText(5, y, d->rect.width(), d->rect.height() - y, Qt::AlignLeft | Qt::AlignVCenter, subLine); p->restore(); } void ImportCategoryDrawer::viewHeaderText(const QModelIndex& index, QString* header, QString* subLine) const { ImportItemModel* sourceModel = index.data(ImportItemModel::ImportItemModelPointerRole).value(); if (!sourceModel) { return; } CamItemInfo info = sourceModel->retrieveCamItemInfo(index); if (!info.isNull()) { *header = info.url().adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).fileName(); int count = d->view->categoryRange(index).height(); *subLine = i18np("1 Item", "%1 Items", count); } } void ImportCategoryDrawer::textForFormat(const QModelIndex& index, QString* header, QString* subLine) const { QString format = index.data(ImportFilterModel::CategoryFormatRole).toString(); if (!format.isEmpty()) { format = format.split(QLatin1Char('/')).at(1); format = ItemScanner::formatToString(format); *header = format; } else { format = i18n("Unknown Format"); *header = format; } int count = d->view->categoryRange(index).height(); *subLine = i18np("1 Item", "%1 Items", count); } void ImportCategoryDrawer::textForDate(const QModelIndex& index, QString* header, QString* subLine) const { QDate date = index.data(ImportFilterModel::CategoryDateRole).toDate(); *header = date.toString(QLatin1String("dd MMM yyyy")); int count = d->view->categoryRange(index).height(); *subLine = i18np("1 Item", "%1 Items", count); } void ImportCategoryDrawer::updateRectsAndPixmaps(int width) { d->rect = QRect(0, 0, 0, 0); // Title -------------------------------------------------------- QFont fn(d->font); int fnSize = fn.pointSize(); bool usePointSize; if (fnSize > 0) { fn.setPointSize(fnSize+2); usePointSize = true; } else { fnSize = fn.pixelSize(); fn.setPixelSize(fnSize+2); usePointSize = false; } fn.setBold(true); QFontMetrics fm(fn); QRect tr = fm.boundingRect(0, 0, width, 0xFFFFFFFF, Qt::AlignLeft | Qt::AlignVCenter, QLatin1String("XXX")); d->rect.setHeight(tr.height()); if (usePointSize) { fn.setPointSize(d->font.pointSize()); } else { fn.setPixelSize(d->font.pixelSize()); } fn.setBold(false); fm = QFontMetrics(fn); tr = fm.boundingRect(0, 0, width, 0xFFFFFFFF, Qt::AlignLeft | Qt::AlignVCenter, QLatin1String("XXX")); d->rect.setHeight(d->rect.height() + tr.height() + 10); d->rect.setWidth(width); d->pixmap = QPixmap(d->rect.width(), d->rect.height()); d->pixmap.fill(qApp->palette().color(QPalette::Highlight)); } } // namespace Digikam diff --git a/core/utilities/import/items/importcategorydrawer.h b/core/utilities/import/items/importcategorydrawer.h index ce3efef7b5..1a3ef9598e 100644 --- a/core/utilities/import/items/importcategorydrawer.h +++ b/core/utilities/import/items/importcategorydrawer.h @@ -1,70 +1,71 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-17 * Description : Qt item view for images - category drawer * * Copyright (C) 2012 by Islam Wazery * * 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_IMPORT_CATEGORY_DRAWER_H #define DIGIKAM_IMPORT_CATEGORY_DRAWER_H // Qt includes #include // Local includes #include "dcategorydrawer.h" namespace Digikam { class ImportCategorizedView; class ImportCategoryDrawer : public DCategoryDrawer { public: explicit ImportCategoryDrawer(ImportCategorizedView* const parent); ~ImportCategoryDrawer(); void setLowerSpacing(int spacing); void setDefaultViewOptions(const QStyleOptionViewItem& option); void invalidatePaintingCache(); - virtual int categoryHeight(const QModelIndex& index, const QStyleOption& option) const; - virtual void drawCategory(const QModelIndex& index, int sortRole, const QStyleOption& option, QPainter* painter) const; - virtual int maximumHeight() const; + virtual int categoryHeight(const QModelIndex& index, const QStyleOption& option) const; + virtual void drawCategory(const QModelIndex& index, int sortRole, + const QStyleOption& option, QPainter* painter) const; + virtual int maximumHeight() const; private: void updateRectsAndPixmaps(int width); - void viewHeaderText(const QModelIndex& index, QString* header, QString* subLine) const; - void textForFormat(const QModelIndex& index, QString* header, QString* subLine) const; - void textForDate(const QModelIndex& index, QString* header, QString* subLine) const; + void viewHeaderText(const QModelIndex& index, QString* header, QString* subLine) const; + void textForFormat(const QModelIndex& index, QString* header, QString* subLine) const; + void textForDate(const QModelIndex& index, QString* header, QString* subLine) const; private: class Private; Private* const d; }; } // namespace Digikam #endif // DIGIKAM_IMPORT_CATEGORY_DRAWER_H diff --git a/core/utilities/import/items/importdelegate.cpp b/core/utilities/import/items/importdelegate.cpp index c734a1517f..0002031053 100644 --- a/core/utilities/import/items/importdelegate.cpp +++ b/core/utilities/import/items/importdelegate.cpp @@ -1,801 +1,826 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-08 * Description : Qt item view to import items - the delegate * * Copyright (C) 2012 by Islam Wazery * 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 "importdelegate.h" #include "importdelegate_p.h" // C++ includes #include // Qt includes #include #include #include #include // Local includes #include "importimagemodel.h" #include "importfiltermodel.h" #include "importsettings.h" #include "importcategorizedview.h" #include "albummanager.h" namespace Digikam { void ImportDelegate::ImportDelegatePrivate::clearRects() { ItemViewImportDelegatePrivate::clearRects(); dateRect = QRect(0, 0, 0, 0); pixmapRect = QRect(0, 0, 0, 0); nameRect = QRect(0, 0, 0, 0); -// titleRect = QRect(0, 0, 0, 0); -// commentsRect = QRect(0, 0, 0, 0); +/* + titleRect = QRect(0, 0, 0, 0); + commentsRect = QRect(0, 0, 0, 0); +*/ resolutionRect = QRect(0, 0, 0, 0); sizeRect = QRect(0, 0, 0, 0); downloadRect = QRect(0, 0, 0, 0); lockRect = QRect(0, 0, 0, 0); coordinatesRect = QRect(0, 0, 0, 0); tagRect = QRect(0, 0, 0, 0); ratingRect = QRect(0, 0, 0, 0); imageInformationRect = QRect(0, 0, 0, 0); pickLabelRect = QRect(0, 0, 0, 0); groupRect = QRect(0, 0, 0, 0); } ImportDelegate::ImportDelegate(QObject* const parent) : ItemViewImportDelegate(*new ImportDelegatePrivate, parent) { } ImportDelegate::ImportDelegate(ImportDelegate::ImportDelegatePrivate& dd, QObject* const parent) : ItemViewImportDelegate(dd, parent) { } ImportDelegate::~ImportDelegate() { Q_D(ImportDelegate); Q_UNUSED(d); // To please compiler about warnings. } void ImportDelegate::setView(ImportCategorizedView* view) { Q_D(ImportDelegate); setViewOnAllOverlays(view); if (d->currentView) { disconnect(d->currentView, SIGNAL(modelChanged()), this, SLOT(modelChanged())); } d->currentView = view; setModel(view ? view->model() : nullptr); if (d->currentView) { connect(d->currentView, SIGNAL(modelChanged()), this, SLOT(modelChanged())); } } void ImportDelegate::setModel(QAbstractItemModel* model) { Q_D(ImportDelegate); // 1) We only need the model to invalidate model-index based caches on change // 2) We do not need to care for overlays. The view calls setActive() on them on model change if (model == d->currentModel) { return; } if (d->currentModel) { disconnect(d->currentModel, nullptr, this, nullptr); } d->currentModel = model; if (d->currentModel) { connect(d->currentModel, SIGNAL(layoutAboutToBeChanged()), this, SLOT(modelContentsChanged())); connect(d->currentModel, SIGNAL(modelAboutToBeReset()), this, SLOT(modelContentsChanged())); connect(d->currentModel, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(modelContentsChanged())); connect(d->currentModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(modelContentsChanged())); connect(d->currentModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(modelContentsChanged())); } } void ImportDelegate::setSpacing(int spacing) { Q_D(ImportDelegate); if (d->categoryDrawer) { d->categoryDrawer->setLowerSpacing(spacing); } ItemViewImportDelegate::setSpacing(spacing); } ImportCategoryDrawer* ImportDelegate::categoryDrawer() const { Q_D(const ImportDelegate); return d->categoryDrawer; } /* QRect ImportDelegate::commentsRect() const { Q_D(const ImportDelegate); return d->commentsRect; } */ QRect ImportDelegate::tagsRect() const { Q_D(const ImportDelegate); return d->tagRect; } QRect ImportDelegate::pixmapRect() const { Q_D(const ImportDelegate); return d->pixmapRect; } QRect ImportDelegate::imageInformationRect() const { Q_D(const ImportDelegate); return d->imageInformationRect; } QRect ImportDelegate::groupIndicatorRect() const { Q_D(const ImportDelegate); return d->groupRect; } QRect ImportDelegate::downloadIndicatorRect() const { Q_D(const ImportDelegate); return d->downloadRect; } QRect ImportDelegate::lockIndicatorRect() const { Q_D(const ImportDelegate); return d->lockRect; } QRect ImportDelegate::coordinatesIndicatorRect() const { Q_D(const ImportDelegate); return d->coordinatesRect; } QPixmap ImportDelegate::retrieveThumbnailPixmap(const QModelIndex& index, int thumbnailSize) { // work around constness + QAbstractItemModel* const model = const_cast(index.model()); + // set requested thumbnail size + model->setData(index, thumbnailSize, ImportItemModel::ThumbnailRole); + // get data from model + QVariant thumbData = index.data(ImportItemModel::ThumbnailRole); + return (thumbData.value()); } QPixmap ImportDelegate::thumbnailPixmap(const QModelIndex& index) const { Q_D(const ImportDelegate); return retrieveThumbnailPixmap(index, d->thumbSize.size()); } void ImportDelegate::paint(QPainter* p, const QStyleOptionViewItem& option, const QModelIndex& index) const { Q_D(const ImportDelegate); CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); if (info.isNull()) { return; } // state of painter must not be changed + p->save(); p->translate(option.rect.topLeft()); bool isSelected = (option.state & QStyle::State_Selected); // Thumbnail + QPixmap pix; if (isSelected) { pix = d->selPixmap; } else { pix = d->regPixmap; } QRect actualPixmapRect = drawThumbnail(p, d->pixmapRect, pix, thumbnailPixmap(index)); if (!actualPixmapRect.isNull()) { const_cast(this)->updateActualPixmapRect(index, actualPixmapRect); } if (!d->ratingRect.isNull()) { drawRating(p, index, d->ratingRect, info.rating, isSelected); } // Draw Color Label rectangle + drawColorLabelRect(p, option, isSelected, info.colorLabel); p->setPen(isSelected ? qApp->palette().color(QPalette::HighlightedText) : qApp->palette().color(QPalette::Text)); /* // If there is ImageHistory present, paint a small icon over the thumbnail to indicate that this is derived image - if (info.hasImageHistory()) + if (info.hasImageHistory()) { p->drawPixmap(d->pixmapRect.right()-24, d->pixmapRect.bottom()-24, QIcon::fromTheme(QLatin1String("svn_switch")).pixmap(22)); } */ if (!d->nameRect.isNull()) { drawName(p, d->nameRect, info.downloadName); } if (!d->dateRect.isNull()) { drawCreationDate(p, d->dateRect, info.ctime); } if (!d->sizeRect.isNull()) { drawFileSize(p, d->sizeRect, info.size); } if (!d->downloadRect.isNull()) { drawDownloadIndicator(p, d->downloadRect, info.downloaded); } if (!d->lockRect.isNull()) { drawLockIndicator(p, d->lockRect, info.writePermissions); } if (!d->resolutionRect.isNull()) { QSize dimensions(info.width, info.height); drawImageSize(p, d->resolutionRect, dimensions); } //TODO: Implement grouping in import tool. + /* if (!d->groupRect.isNull()) { drawGroupIndicator(p, d->groupRect, info.numberOfGroupedImages(), index.data(ImportFilterModel::GroupIsOpenRole).toBool()); } */ if (!d->tagRect.isNull()) { QStringList tagsList = AlbumManager::instance()->tagNames(info.tagIds); tagsList.sort(); QString tags = tagsList.join(QLatin1String(", ")); drawTags(p, d->tagRect, tags, isSelected); } if (!d->pickLabelRect.isNull()) { drawPickLabelIcon(p, d->pickLabelRect, info.pickLabel); } if (d->drawImageFormat) { QString frm = info.mime; drawImageFormat(p, actualPixmapRect, frm); } if (d->drawCoordinates && info.photoInfo.hasCoordinates) { drawGeolocationIndicator(p, d->coordinatesRect); } if (d->drawFocusFrame) { drawFocusRect(p, option, isSelected); } if (d->drawMouseOverFrame) { drawMouseOverRect(p, option); } p->restore(); drawOverlays(p, option, index); } QPixmap ImportDelegate::pixmapForDrag(const QStyleOptionViewItem& option, const QList& indexes) const { QPixmap icon; if (!indexes.isEmpty()) { icon = thumbnailPixmap(indexes.first()); } return makeDragPixmap(option, indexes, icon); } bool ImportDelegate::acceptsToolTip(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* toolTipRect) const { return onActualPixmapRect(pos, visualRect, index, toolTipRect); } bool ImportDelegate::acceptsActivation(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* activationRect) const { return onActualPixmapRect(pos, visualRect, index, activationRect); } bool ImportDelegate::onActualPixmapRect(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* returnRect) const { QRect actualRect = actualPixmapRect(index); if (actualRect.isNull()) { return false; } actualRect.translate(visualRect.topLeft()); if (returnRect) { *returnRect = actualRect; } return actualRect.contains(pos); } void ImportDelegate::setDefaultViewOptions(const QStyleOptionViewItem& option) { Q_D(ImportDelegate); if (d->categoryDrawer) { d->categoryDrawer->setDefaultViewOptions(option); } ItemViewImportDelegate::setDefaultViewOptions(option); } void ImportDelegate::invalidatePaintingCache() { Q_D(ImportDelegate); if (d->categoryDrawer) { d->categoryDrawer->invalidatePaintingCache(); } ItemViewImportDelegate::invalidatePaintingCache(); } void ImportDelegate::updateContentWidth() { Q_D(ImportDelegate); d->contentWidth = d->thumbSize.size() + 2*d->radius; } void ImportDelegate::updateSizeRectsAndPixmaps() { Q_D(ImportDelegate); // ---- Reset rects and prepare fonts ---- d->clearRects(); prepareFonts(); // ---- Fixed sizes and metrics ---- updateContentWidth(); prepareMetrics(d->contentWidth); // ---- Calculate rects ---- updateRects(); // ---- Cached pixmaps ---- prepareBackground(); if (!d->ratingRect.isNull()) { - //Normally we prepare the pixmaps over the background of the rating rect. - //If the rating is drawn over the thumbnail, we can only draw over a transparent pixmap. + // Normally we prepare the pixmaps over the background of the rating rect. + // If the rating is drawn over the thumbnail, we can only draw over a transparent pixmap. + prepareRatingPixmaps(!d->ratingOverThumbnail); } // ---- Drawing related caches ---- clearCaches(); } void ImportDelegate::clearCaches() { Q_D(ImportDelegate); ItemViewImportDelegate::clearCaches(); d->actualPixmapRectCache.clear(); } void ImportDelegate::clearModelDataCaches() { Q_D(ImportDelegate); d->actualPixmapRectCache.clear(); } void ImportDelegate::modelChanged() { Q_D(ImportDelegate); clearModelDataCaches(); setModel(d->currentView ? d->currentView->model() : nullptr); } void ImportDelegate::modelContentsChanged() { clearModelDataCaches(); } QRect ImportDelegate::actualPixmapRect(const QModelIndex& index) const { Q_D(const ImportDelegate); + // We do not recompute if not found. Assumption is cache is always properly updated. + QRect* const rect = d->actualPixmapRectCache.object(index.row()); if (rect) { return *rect; } else { return d->pixmapRect; } } void ImportDelegate::updateActualPixmapRect(const QModelIndex& index, const QRect& rect) { Q_D(ImportDelegate); QRect* const old = d->actualPixmapRectCache.object(index.row()); - if (!old || *old != rect) + if (!old || (*old != rect)) { d->actualPixmapRectCache.insert(index.row(), new QRect(rect)); } } int ImportDelegate::calculatethumbSizeToFit(int ws) { Q_D(ImportDelegate); int ts = thumbnailSize().size(); int gs = gridSize().width(); int sp = spacing(); ws = ws - 2*sp; // Thumbnails size loop to check (upper/lower) + int ts1, ts2; + // New grid size used in loop + int ngs; double rs1 = fmod((double)ws, (double)gs); for (ts1 = ts ; ts1 < ThumbnailSize::maxThumbsSize() ; ++ts1) { ngs = ts1 + 2*(d->margin + d->radius) + sp; double nrs = fmod((double)ws, (double)ngs); if (nrs <= rs1) { rs1 = nrs; } else { break; } } double rs2 = fmod((double)ws, (double)gs); for (ts2 = ts ; ts2 > ThumbnailSize::Small ; --ts2) { ngs = ts2 + 2*(d->margin + d->radius) + sp; double nrs = fmod((double)ws, (double)ngs); if (nrs >= rs2) { rs2 = nrs; } else { rs2 = nrs; break; } } if (rs1 > rs2) + { return (ts2); + } return (ts1); } // --- ImportThumbnailDelegate --------------------------------------- void ImportThumbnailDelegatePrivate::init(ImportThumbnailDelegate* const q) { QObject::connect(ImportSettings::instance(), SIGNAL(setupChanged()), q, SLOT(slotSetupChanged())); } // ------------------------------------------------------------------------------------------------ ImportThumbnailDelegate::ImportThumbnailDelegate(ImportCategorizedView* const parent) : ImportDelegate(*new ImportThumbnailDelegatePrivate, parent) { Q_D(ImportThumbnailDelegate); d->init(this); } ImportThumbnailDelegate::~ImportThumbnailDelegate() { } void ImportThumbnailDelegate::setFlow(QListView::Flow flow) { Q_D(ImportThumbnailDelegate); d->flow = flow; } void ImportThumbnailDelegate::setDefaultViewOptions(const QStyleOptionViewItem& option) { Q_D(ImportThumbnailDelegate); + // store before calling parent class + d->viewSize = option.rect; ImportDelegate::setDefaultViewOptions(option); } int ImportThumbnailDelegate::maximumSize() const { Q_D(const ImportThumbnailDelegate); return ThumbnailSize::maxThumbsSize() + (2*d->radius + 2*d->margin); } int ImportThumbnailDelegate::minimumSize() const { Q_D(const ImportThumbnailDelegate); + return ThumbnailSize::Small + 2*d->radius + 2*d->margin; } bool ImportThumbnailDelegate::acceptsActivation(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* activationRect) const { - // reuse implementation from grandparent + // reuse implementation from grand-parent + return ItemViewImportDelegate::acceptsActivation(pos, visualRect, index, activationRect); } void ImportThumbnailDelegate::updateContentWidth() { Q_D(ImportThumbnailDelegate); int maxSize; if (d->flow == QListView::LeftToRight) { maxSize = d->viewSize.height(); } else { maxSize = d->viewSize.width(); } d->thumbSize = ThumbnailSize(thumbnailPixmapSize(true, maxSize - 2*d->radius - 2*d->margin)); ImportDelegate::updateContentWidth(); } int ImportThumbnailDelegate::thumbnailPixmapSize(bool withHighlight, int size) { - if (withHighlight && size >= 10) + if (withHighlight && (size >= 10)) { return size + 2; } return size; } void ImportThumbnailDelegate::updateRects() { Q_D(ImportThumbnailDelegate); d->pixmapRect = QRect(d->margin, d->margin, d->contentWidth, d->contentWidth); d->rect = QRect(0, 0, d->contentWidth + 2*d->margin, d->contentWidth + 2*d->margin); d->drawImageFormat = ImportSettings::instance()->getIconShowImageFormat(); d->drawCoordinates = ImportSettings::instance()->getIconShowCoordinates(); const int iconSize = qBound(16, (d->contentWidth + 2*d->margin) / 8 - 2, 48); int pos = iconSize + 2; d->downloadRect = QRect(d->contentWidth - pos, d->pixmapRect.top(), iconSize, iconSize); pos += iconSize; d->lockRect = QRect(d->contentWidth - pos, d->pixmapRect.top(), iconSize, iconSize); pos += iconSize; d->coordinatesRect = QRect(d->contentWidth - pos, d->pixmapRect.top(), iconSize, iconSize); if (ImportSettings::instance()->getIconShowRating()) { int top = d->rect.bottom() - d->margin - d->starPolygonSize.height() - 2; d->ratingRect = QRect(d->margin, top, d->contentWidth, d->starPolygonSize.height()); } if (d->flow == QListView::LeftToRight) { d->gridSize = QSize(d->rect.width() + d->spacing, d->rect.height()); } else { d->gridSize = QSize(d->rect.width(), d->rect.height() + d->spacing); } } // --- ImportNormalDelegate ----------------------------------------------------------------------- void ImportNormalDelegatePrivate::init(ImportNormalDelegate* const q, ImportCategorizedView* const parent) { categoryDrawer = new ImportCategoryDrawer(parent); QObject::connect(ImportSettings::instance(), SIGNAL(setupChanged()), q, SLOT(slotSetupChanged())); } ImportNormalDelegatePrivate::~ImportNormalDelegatePrivate() { delete categoryDrawer; } // ------------------------------------------------------------------------------------------------ ImportNormalDelegate::ImportNormalDelegate(ImportCategorizedView* const parent) : ImportDelegate(*new ImportNormalDelegatePrivate, parent) { Q_D(ImportNormalDelegate); d->init(this, parent); } ImportNormalDelegate::ImportNormalDelegate(ImportNormalDelegatePrivate& dd, ImportCategorizedView* const parent) : ImportDelegate(dd, parent) { Q_D(ImportNormalDelegate); d->init(this, parent); } ImportNormalDelegate::~ImportNormalDelegate() { } void ImportNormalDelegate::updateRects() { Q_D(ImportNormalDelegate); int y = d->margin; d->pixmapRect = QRect(d->margin, y, d->contentWidth, d->contentWidth); y = d->pixmapRect.bottom(); d->imageInformationRect = QRect(d->margin, y, d->contentWidth, 0); const ImportSettings* const importSettings = ImportSettings::instance(); d->drawImageFormat = importSettings->getIconShowImageFormat(); d->drawCoordinates = ImportSettings::instance()->getIconShowCoordinates(); const int iconSize = qBound(16, (d->contentWidth + 2*d->margin) / 8 - 2, 48); d->pickLabelRect = QRect(d->margin, y, iconSize, iconSize); -// d->groupRect = QRect(d->contentWidth - iconSize, y, iconSize, iconSize); // TODO - +/* + d->groupRect = QRect(d->contentWidth - iconSize, y, iconSize, iconSize); // TODO +*/ int pos = iconSize + 2; d->downloadRect = QRect(d->contentWidth - pos, d->pixmapRect.top(), iconSize, iconSize); pos += iconSize; d->lockRect = QRect(d->contentWidth - pos, d->pixmapRect.top(), iconSize, iconSize); pos += iconSize; d->coordinatesRect = QRect(d->contentWidth - pos, d->pixmapRect.top(), iconSize, iconSize); if (importSettings->getIconShowRating()) { d->ratingRect = QRect(d->margin, y, d->contentWidth, d->starPolygonSize.height()); y = d->ratingRect.bottom(); } if (importSettings->getIconShowName()) { d->nameRect = QRect(d->margin, y, d->contentWidth-d->margin, d->oneRowRegRect.height()); y = d->nameRect.bottom(); } if (importSettings->getIconShowDate()) { d->dateRect = QRect(d->margin, y, d->contentWidth, d->oneRowXtraRect.height()); y = d->dateRect.bottom(); } //TODO: Add resolution entry in importSettings. + /* if (importSettings->getIconShowResolution()) { d->resolutionRect = QRect(d->margin, y, d->contentWidth, d->oneRowXtraRect.height()); y = d->resolutionRect.bottom() ; } */ if (importSettings->getIconShowSize()) { d->sizeRect = QRect(d->margin, y, d->contentWidth, d->oneRowXtraRect.height()); y = d->sizeRect.bottom(); } if (importSettings->getIconShowTags()) { d->tagRect = QRect(d->margin, y, d->contentWidth, d->oneRowComRect.height()); y = d->tagRect.bottom(); } d->imageInformationRect.setBottom(y); d->rect = QRect(0, 0, d->contentWidth + 2*d->margin, y+d->margin+d->radius); d->gridSize = QSize(d->rect.width() + d->spacing, d->rect.height() + d->spacing); } } // namespace Digikam diff --git a/core/utilities/import/items/importdelegate.h b/core/utilities/import/items/importdelegate.h index d971d8cc84..721ad1d95b 100644 --- a/core/utilities/import/items/importdelegate.h +++ b/core/utilities/import/items/importdelegate.h @@ -1,191 +1,197 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-08 * Description : Qt item view to import items - the delegate * * Copyright (C) 2012 by Islam Wazery * 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. * * ============================================================ */ #ifndef DIGIKAM_IMPORT_DELEGATE_H #define DIGIKAM_IMPORT_DELEGATE_H #include #include // Local includes #include "itemviewimportdelegate.h" #include "importthumbnailmodel.h" #include "importcategorydrawer.h" namespace Digikam { class ImportCategorizedView; class ImportThumbnailDelegatePrivate; class ImportNormalDelegatePrivate; class ImportDelegate : public ItemViewImportDelegate { Q_OBJECT public: explicit ImportDelegate(QObject* const parent = nullptr); ~ImportDelegate(); void setView(ImportCategorizedView* view); ImportCategoryDrawer* categoryDrawer() const; - //QRect commentsRect() const; +/* + QRect commentsRect() const; +*/ QRect tagsRect() const; QRect actualPixmapRect(const QModelIndex& index) const; QRect groupIndicatorRect() const; QRect downloadIndicatorRect() const; QRect lockIndicatorRect() const; QRect coordinatesIndicatorRect() const; int calculatethumbSizeToFit(int ws); virtual void setSpacing(int spacing) override; virtual void setDefaultViewOptions(const QStyleOptionViewItem& option) override; virtual bool acceptsToolTip(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* tooltipRect = nullptr) const override; virtual bool acceptsActivation(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* activationRect = nullptr) const override; virtual QRect pixmapRect() const override; virtual QRect imageInformationRect() const override; virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override; virtual QPixmap pixmapForDrag(const QStyleOptionViewItem& option, const QList& indexes) const override; /** * Retrieve the thumbnail pixmap in given size for the ImportItemModel::ThumbnailRole for * the given index from the given index, which must adhere to ImportThumbnailModel semantics. */ static QPixmap retrieveThumbnailPixmap(const QModelIndex& index, int thumbnailSize); public: // Declared as public because of use in ImportNormalDelegate class. class ImportDelegatePrivate; protected: bool onActualPixmapRect(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* actualRect) const; void updateActualPixmapRect(const QModelIndex& index, const QRect& rect); void setModel(QAbstractItemModel* model); ImportDelegate(ImportDelegate::ImportDelegatePrivate& dd, QObject* const parent); - /** Reimplement this to set contentWidth. This is the maximum width of all - * content rectangles, typically excluding margins on both sides. + /** + * Reimplement this to set contentWidth. This is the maximum width of all + * content rectangles, typically excluding margins on both sides. */ virtual void updateContentWidth(); - /** In a subclass, you need to implement this method to set up the rects - * for drawing. The paint() method operates depending on these rects. + /** + * In a subclass, you need to implement this method to set up the rects + * for drawing. The paint() method operates depending on these rects. */ virtual void updateRects() = 0; virtual void clearCaches() override; - /** Reimplement to clear caches based on model indexes (hash on row number etc.) - * Change signals are listened to this is called whenever such properties become invalid. + /** + * Reimplement to clear caches based on model indexes (hash on row number etc.) + * Change signals are listened to this is called whenever such properties become invalid. */ virtual void clearModelDataCaches(); virtual QPixmap thumbnailPixmap(const QModelIndex& index) const; virtual void invalidatePaintingCache() override; virtual void updateSizeRectsAndPixmaps() override; protected Q_SLOTS: void modelChanged(); void modelContentsChanged(); private: Q_DECLARE_PRIVATE(ImportDelegate) }; // ------ ImportThumbnailDelegate ---------------------------------------- class ImportThumbnailDelegate : public ImportDelegate { Q_OBJECT public: explicit ImportThumbnailDelegate(ImportCategorizedView* const parent); ~ImportThumbnailDelegate(); void setFlow(QListView::Flow flow); - /** Returns the minimum or maximum viewport size in the limiting dimension, - * width or height, depending on current flow. + /** + * Returns the minimum or maximum viewport size in the limiting dimension, + * width or height, depending on current flow. */ int maximumSize() const; int minimumSize() const; virtual void setDefaultViewOptions(const QStyleOptionViewItem& option) override; virtual bool acceptsActivation(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* activationRect) const override; protected: virtual void updateContentWidth() override; virtual void updateRects() override; int thumbnailPixmapSize(bool withHighlight, int size); private: Q_DECLARE_PRIVATE(ImportThumbnailDelegate) }; // ------ ImportNormalDelegate ---------------------------------------- class ImportNormalDelegate : public ImportDelegate { Q_OBJECT public: explicit ImportNormalDelegate(ImportCategorizedView* const parent); ~ImportNormalDelegate(); protected: ImportNormalDelegate(ImportNormalDelegatePrivate& dd, ImportCategorizedView* const parent); virtual void updateRects() override; private: Q_DECLARE_PRIVATE(ImportNormalDelegate) }; } // namespace Digikam #endif // DIGIKAM_IMPORT_DELEGATE_H diff --git a/core/utilities/import/items/importdelegate_p.h b/core/utilities/import/items/importdelegate_p.h index bc9adc6499..71225c0714 100644 --- a/core/utilities/import/items/importdelegate_p.h +++ b/core/utilities/import/items/importdelegate_p.h @@ -1,136 +1,135 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-08 * Description : Qt item view to import items - the delegate (private container) * * Copyright (C) 2012 by Islam Wazery * 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. * * ============================================================ */ #ifndef DIGIKAM_IMPORT_DELEGATE_P_H #define DIGIKAM_IMPORT_DELEGATE_P_H +#include "importdelegate.h" + // Qt includes #include #include // Local includes #include "importcategorizedview.h" #include "itemviewimportdelegate_p.h" namespace Digikam { class ImportCategoryDrawer; class Q_DECL_HIDDEN ImportDelegate::ImportDelegatePrivate : public ItemViewImportDelegatePrivate { public: explicit ImportDelegatePrivate() + : contentWidth(0), + drawImageFormat(false), + drawCoordinates(false), + drawFocusFrame(true), + drawMouseOverFrame(true), + ratingOverThumbnail(false), + categoryDrawer(nullptr), + currentView(nullptr), + currentModel(nullptr) { - categoryDrawer = nullptr; - contentWidth = 0; - drawImageFormat = false; - drawCoordinates = false; - drawMouseOverFrame = true; - drawFocusFrame = true; - ratingOverThumbnail = false; - currentModel = nullptr; - currentView = nullptr; - actualPixmapRectCache.setMaxCost(250); } int contentWidth; QRect dateRect; QRect pixmapRect; QRect nameRect; -// QRect titleRect; -// QRect commentsRect; +/* + QRect titleRect; + QRect commentsRect; +*/ QRect resolutionRect; QRect sizeRect; QRect downloadRect; QRect lockRect; QRect coordinatesRect; QRect tagRect; QRect imageInformationRect; QRect pickLabelRect; QRect groupRect; bool drawImageFormat; bool drawCoordinates; bool drawFocusFrame; bool drawMouseOverFrame; bool ratingOverThumbnail; QCache actualPixmapRectCache; ImportCategoryDrawer* categoryDrawer; ImportCategorizedView* currentView; QAbstractItemModel* currentModel; public: virtual void clearRects(); }; // --- ImportThumbnailDelegate ---------------------------------------------------- class Q_DECL_HIDDEN ImportThumbnailDelegatePrivate : public ImportDelegate::ImportDelegatePrivate { public: explicit ImportThumbnailDelegatePrivate() + : flow(QListView::LeftToRight) { - flow = QListView::LeftToRight; - - // switch off drawing of frames + drawFocusFrame = false; // switch off drawing of frames drawMouseOverFrame = false; - drawFocusFrame = false; - - // switch off composing rating over background - ratingOverThumbnail = true; + ratingOverThumbnail = true; // switch off composing rating over background } void init(ImportThumbnailDelegate* const q); public: QListView::Flow flow; QRect viewSize; }; // --- ImportNormalDelegate ---------------------------------------------------- class Q_DECL_HIDDEN ImportNormalDelegatePrivate : public ImportDelegate::ImportDelegatePrivate { public: explicit ImportNormalDelegatePrivate() {}; virtual ~ImportNormalDelegatePrivate(); void init(ImportNormalDelegate* const q, ImportCategorizedView* const parent); }; } // namespace Digikam #endif // DIGIKAM_IMPORT_DELEGATE_P_H diff --git a/core/utilities/import/items/importoverlays.cpp b/core/utilities/import/items/importoverlays.cpp index 5793722cd7..837f08a997 100644 --- a/core/utilities/import/items/importoverlays.cpp +++ b/core/utilities/import/items/importoverlays.cpp @@ -1,505 +1,513 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-08-21 * Description : Overlays for the import interface * * Copyright (C) 2012 by Islam Wazery * 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 "importoverlays.h" // KDE includes #include // Local includes #include "importcategorizedview.h" #include "importdelegate.h" #include "camiteminfo.h" #include "ratingwidget.h" namespace Digikam { ImportOverlayWidget::ImportOverlayWidget(QWidget* const parent) : QAbstractButton(parent) { } void ImportOverlayWidget::paintEvent(QPaintEvent*) { } // -- Coordinates Overlay ------------------------------------------------------------------ ImportCoordinatesOverlay::ImportCoordinatesOverlay(QObject* const parent) : AbstractWidgetDelegateOverlay(parent) { } ImportOverlayWidget* ImportCoordinatesOverlay::buttonWidget() const { return static_cast(m_widget); } QWidget* ImportCoordinatesOverlay::createWidget() { QAbstractButton* const button = new ImportOverlayWidget(parentWidget()); - //button->setCursor(Qt::PointingHandCursor); +/* + button->setCursor(Qt::PointingHandCursor); +*/ return button; } void ImportCoordinatesOverlay::setActive(bool active) { AbstractWidgetDelegateOverlay::setActive(active); } void ImportCoordinatesOverlay::visualChange() { if (m_widget && m_widget->isVisible()) { updatePosition(); } } void ImportCoordinatesOverlay::updatePosition() { if (!m_index.isValid()) { return; } QRect rect = static_cast(delegate())->coordinatesIndicatorRect(); QRect visualRect = m_view->visualRect(m_index); rect.translate(visualRect.topLeft()); m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); m_widget->move(rect.topLeft()); } bool ImportCoordinatesOverlay::checkIndex(const QModelIndex& index) const { CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); QRect rect = static_cast(delegate())->coordinatesIndicatorRect(); if (!rect.isNull() && info.photoInfo.hasCoordinates) { m_widget->setToolTip(i18nc("@info:tooltip", "This item has geolocation information.")); return true; } // If info.photoInfo.hasCoordinates = false, no need to show a tooltip, because there is no icon over thumbnail. return false; } void ImportCoordinatesOverlay::slotEntered(const QModelIndex& index) { AbstractWidgetDelegateOverlay::slotEntered(index); m_index = index; updatePosition(); } // -- Lock Overlay ------------------------------------------------------------------ ImportLockOverlay::ImportLockOverlay(QObject* const parent) : AbstractWidgetDelegateOverlay(parent) { } ImportOverlayWidget* ImportLockOverlay::buttonWidget() const { return static_cast(m_widget); } QWidget* ImportLockOverlay::createWidget() { QAbstractButton* const button = new ImportOverlayWidget(parentWidget()); - //button->setCursor(Qt::PointingHandCursor); +/* + button->setCursor(Qt::PointingHandCursor); +*/ return button; } void ImportLockOverlay::setActive(bool active) { AbstractWidgetDelegateOverlay::setActive(active); } void ImportLockOverlay::visualChange() { if (m_widget && m_widget->isVisible()) { updatePosition(); } } void ImportLockOverlay::updatePosition() { if (!m_index.isValid()) { return; } QRect rect = static_cast(delegate())->lockIndicatorRect(); QRect visualRect = m_view->visualRect(m_index); rect.translate(visualRect.topLeft()); m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); m_widget->move(rect.topLeft()); } bool ImportLockOverlay::checkIndex(const QModelIndex& index) const { CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); if (info.writePermissions == 0) { m_widget->setToolTip(i18nc("@info:tooltip", "This item is locked.")); return true; } // If info.writePermissions = 1, no need to show a tooltip, because there is no icon over thumbnail. return false; } void ImportLockOverlay::slotEntered(const QModelIndex& index) { AbstractWidgetDelegateOverlay::slotEntered(index); m_index = index; updatePosition(); } // -- Download Overlay ------------------------------------------------------------------ ImportDownloadOverlay::ImportDownloadOverlay(QObject* const parent) : AbstractWidgetDelegateOverlay(parent) { } ImportOverlayWidget* ImportDownloadOverlay::buttonWidget() const { return static_cast(m_widget); } QWidget* ImportDownloadOverlay::createWidget() { QAbstractButton* const button = new ImportOverlayWidget(parentWidget()); - //button->setCursor(Qt::PointingHandCursor); +/* + button->setCursor(Qt::PointingHandCursor); +*/ return button; } void ImportDownloadOverlay::setActive(bool active) { AbstractWidgetDelegateOverlay::setActive(active); } void ImportDownloadOverlay::visualChange() { if (m_widget && m_widget->isVisible()) { updatePosition(); } } void ImportDownloadOverlay::updatePosition() { if (!m_index.isValid()) { return; } QRect rect = static_cast(delegate())->downloadIndicatorRect(); QRect visualRect = m_view->visualRect(m_index); rect.translate(visualRect.topLeft()); m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); m_widget->move(rect.topLeft()); } bool ImportDownloadOverlay::checkIndex(const QModelIndex& index) const { CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); if (info.downloaded == CamItemInfo::DownloadUnknown) { m_widget->setToolTip(i18nc("@info:tooltip", "This item has an unknown download status")); return true; } if (info.downloaded == CamItemInfo::DownloadedNo) // TODO: CamItemInfo::NewPicture { m_widget->setToolTip(i18nc("@info:tooltip", "This item has never been downloaded")); return true; } if (info.downloaded == CamItemInfo::DownloadedYes) { m_widget->setToolTip(i18nc("@info:tooltip", "This item has already been downloaded")); return true; } return false; } void ImportDownloadOverlay::slotEntered(const QModelIndex& index) { AbstractWidgetDelegateOverlay::slotEntered(index); m_index = index; updatePosition(); } // -- Rating Overlay ------------------------------------------------------------------ ImportRatingOverlay::ImportRatingOverlay(QObject* const parent) : AbstractWidgetDelegateOverlay(parent) { } RatingWidget* ImportRatingOverlay::ratingWidget() const { return static_cast(m_widget); } QWidget* ImportRatingOverlay::createWidget() { RatingWidget* const w = new RatingWidget(parentWidget()); w->setFading(true); w->setTracking(false); + return w; } void ImportRatingOverlay::setActive(bool active) { AbstractWidgetDelegateOverlay::setActive(active); if (active) { connect(ratingWidget(), SIGNAL(signalRatingChanged(int)), this, SLOT(slotRatingChanged(int))); if (view()->model()) { connect(view()->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(slotDataChanged(QModelIndex,QModelIndex))); } } else { // widget is deleted if (view() && view()->model()) { disconnect(view()->model(), nullptr, this, nullptr); } } } void ImportRatingOverlay::visualChange() { if (m_widget && m_widget->isVisible()) { updatePosition(); } } void ImportRatingOverlay::widgetEnterEvent() { widgetEnterNotifyMultiple(m_index); } void ImportRatingOverlay::widgetLeaveEvent() { widgetLeaveNotifyMultiple(); } void ImportRatingOverlay::hide() { delegate()->setRatingEdited(QModelIndex()); AbstractWidgetDelegateOverlay::hide(); } void ImportRatingOverlay::updatePosition() { if (!m_index.isValid() || !m_widget) { return; } QRect rect = delegate()->ratingRect(); if (rect.width() > ratingWidget()->maximumVisibleWidth()) { int offset = (rect.width() - ratingWidget()->maximumVisibleWidth()) / 2; rect.adjust(offset, 0, -offset, 0); } QRect visualRect = m_view->visualRect(m_index); rect.translate(visualRect.topLeft()); m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); m_widget->move(rect.topLeft()); } void ImportRatingOverlay::updateRating() { if (!m_index.isValid() || !m_widget) { return; } ImportItemModel* const model = m_index.data(ImportItemModel::ImportItemModelPointerRole).value(); ratingWidget()->setRating(model->camItemInfoRef(m_index).rating); } void ImportRatingOverlay::slotRatingChanged(int rating) { if (m_widget && m_widget->isVisible() && m_index.isValid()) { emit ratingEdited(affectedIndexes(m_index), rating); } } void ImportRatingOverlay::slotEntered(const QModelIndex& index) { AbstractWidgetDelegateOverlay::slotEntered(index); // see bug 228810, this is a small workaround - if (m_widget && m_widget->isVisible() && m_index.isValid() && index == m_index) + + if (m_widget && m_widget->isVisible() && m_index.isValid() && (index == m_index)) { ratingWidget()->setVisibleImmediately(); } m_index = index; updatePosition(); updateRating(); delegate()->setRatingEdited(m_index); view()->update(m_index); } void ImportRatingOverlay::slotDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (m_widget && m_widget->isVisible() && QItemSelectionRange(topLeft, bottomRight).contains(m_index)) { updateRating(); } } // -- Rotate Overlay ---------------------------------------------------------------- ImportRotateOverlayButton::ImportRotateOverlayButton(ImportRotateOverlayDirection dir, QAbstractItemView* const parentView) : ItemViewHoverButton(parentView), m_direction(dir) { setup(); } QSize ImportRotateOverlayButton::sizeHint() const { return QSize(32, 32); } QIcon ImportRotateOverlayButton::icon() { if (m_direction == ImportRotateOverlayLeft) { return QIcon::fromTheme(QLatin1String("object-rotate-left")); } else { return QIcon::fromTheme(QLatin1String("object-rotate-right")); } } void ImportRotateOverlayButton::updateToolTip() { if (m_direction == ImportRotateOverlayLeft) { setToolTip(i18nc("@info:tooltip", "Rotate Left")); } else { setToolTip(i18nc("@info:tooltip", "Rotate Right")); } } // -------------------------------------------------------------------- ImportRotateOverlay::ImportRotateOverlay(ImportRotateOverlayDirection dir, QObject* const parent) : HoverButtonDelegateOverlay(parent), m_direction(dir) { } void ImportRotateOverlay::setActive(bool active) { HoverButtonDelegateOverlay::setActive(active); if (active) { connect(button(), SIGNAL(clicked(bool)), this, SLOT(slotClicked())); } } ItemViewHoverButton* ImportRotateOverlay::createButton() { return new ImportRotateOverlayButton(m_direction, view()); } void ImportRotateOverlay::updateButton(const QModelIndex& index) { const QRect rect = m_view->visualRect(index); const int size = qBound(16, rect.width() / 8 - 2, 48); const int gap = 5; const int x = rect.right() - 2*gap - (isLeft() ? size*5 + 2 : size*4 + 2); const int y = rect.top() + gap; button()->resize(size, size); button()->move(QPoint(x, y)); } void ImportRotateOverlay::slotClicked() { QModelIndex index = button()->index(); if (index.isValid()) { emit signalRotate(affectedIndexes(index)); } } bool ImportRotateOverlay::checkIndex(const QModelIndex& index) const { CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); return (info.mime.contains(QLatin1String("image/"))); } void ImportRotateOverlay::widgetEnterEvent() { widgetEnterNotifyMultiple(button()->index()); } void ImportRotateOverlay::widgetLeaveEvent() { widgetLeaveNotifyMultiple(); } } // namespace Digikam diff --git a/core/utilities/import/items/importoverlays.h b/core/utilities/import/items/importoverlays.h index d2b8b4e758..dfce421523 100644 --- a/core/utilities/import/items/importoverlays.h +++ b/core/utilities/import/items/importoverlays.h @@ -1,240 +1,240 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-08-21 * Description : Overlays for the import interface * * Copyright (C) 2012 by Islam Wazery * 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. * * ============================================================ */ #ifndef DIGIKAM_IMPORT_OVERLAYS_H #define DIGIKAM_IMPORT_OVERLAYS_H // Qt includes #include #include // Local includes #include "itemviewhoverbutton.h" #include "itemdelegateoverlay.h" #include "itemviewimportdelegate.h" #include "ratingwidget.h" namespace Digikam { class ImportOverlayWidget : public QAbstractButton { Q_OBJECT public: explicit ImportOverlayWidget(QWidget* const parent = nullptr); protected: virtual void paintEvent(QPaintEvent*) override; }; // -------------------------------------------------------------------- class ImportCoordinatesOverlay : public AbstractWidgetDelegateOverlay { Q_OBJECT REQUIRE_DELEGATE(ItemViewImportDelegate) public: explicit ImportCoordinatesOverlay(QObject* const parent); ImportOverlayWidget* buttonWidget() const; protected: void updatePosition(); virtual QWidget* createWidget() override; virtual void setActive(bool active) override; virtual void visualChange() override; virtual bool checkIndex(const QModelIndex& index) const override; virtual void slotEntered(const QModelIndex& index) override; protected: QPersistentModelIndex m_index; }; // -------------------------------------------------------------------- class ImportLockOverlay : public AbstractWidgetDelegateOverlay { Q_OBJECT REQUIRE_DELEGATE(ItemViewImportDelegate) public: explicit ImportLockOverlay(QObject* const parent); ImportOverlayWidget* buttonWidget() const; protected: void updatePosition(); virtual QWidget* createWidget() override; virtual void setActive(bool active) override; virtual void visualChange() override; virtual bool checkIndex(const QModelIndex& index) const override; virtual void slotEntered(const QModelIndex& index) override; protected: QPersistentModelIndex m_index; }; // -------------------------------------------------------------------- class ImportDownloadOverlay : public AbstractWidgetDelegateOverlay { Q_OBJECT REQUIRE_DELEGATE(ItemViewImportDelegate) public: explicit ImportDownloadOverlay(QObject* const parent); - ImportOverlayWidget* buttonWidget() const; + ImportOverlayWidget* buttonWidget() const; protected: void updatePosition(); - virtual QWidget* createWidget() override; - virtual void setActive(bool active) override; - virtual void visualChange() override; + virtual QWidget* createWidget() override; + virtual void setActive(bool active) override; + virtual void visualChange() override; virtual bool checkIndex(const QModelIndex& index) const override; - virtual void slotEntered(const QModelIndex& index) override; + virtual void slotEntered(const QModelIndex& index) override; protected: QPersistentModelIndex m_index; }; // ------------------------------------------------------------------------------------------------ class ImportRatingOverlay : public AbstractWidgetDelegateOverlay { Q_OBJECT REQUIRE_DELEGATE(ItemViewImportDelegate) public: explicit ImportRatingOverlay(QObject* const parent); RatingWidget* ratingWidget() const; Q_SIGNALS: void ratingEdited(const QList& indexes, int rating); protected Q_SLOTS: void slotRatingChanged(int); void slotDataChanged(const QModelIndex&, const QModelIndex&); protected: virtual QWidget* createWidget() override; virtual void setActive(bool) override; virtual void visualChange() override; virtual void hide() override; virtual void slotEntered(const QModelIndex& index) override; virtual void widgetEnterEvent() override; virtual void widgetLeaveEvent() override; void updatePosition(); void updateRating(); QPersistentModelIndex m_index; }; // ------------------------------------------------------------------------------------------------ enum ImportRotateOverlayDirection { ImportRotateOverlayLeft, ImportRotateOverlayRight }; class ImportRotateOverlayButton : public ItemViewHoverButton { public: explicit ImportRotateOverlayButton(ImportRotateOverlayDirection dir, QAbstractItemView* const parentView); virtual QSize sizeHint() const; protected: virtual QIcon icon(); virtual void updateToolTip(); protected: ImportRotateOverlayDirection const m_direction; }; // -------------------------------------------------------------------- class ImportRotateOverlay : public HoverButtonDelegateOverlay { Q_OBJECT public: explicit ImportRotateOverlay(ImportRotateOverlayDirection dir, QObject* const parent); virtual void setActive(bool active); - ImportRotateOverlayDirection direction() const { return m_direction; } - bool isLeft() const { return m_direction == ImportRotateOverlayLeft; } - bool isRight() const { return m_direction == ImportRotateOverlayRight; } + ImportRotateOverlayDirection direction() const { return m_direction; } + bool isLeft() const { return m_direction == ImportRotateOverlayLeft; } + bool isRight() const { return m_direction == ImportRotateOverlayRight; } static ImportRotateOverlay* left (QObject* const parent) { return new ImportRotateOverlay(ImportRotateOverlayLeft, parent); } static ImportRotateOverlay* right(QObject* const parent) { return new ImportRotateOverlay(ImportRotateOverlayRight, parent); } Q_SIGNALS: void signalRotate(const QList& indexes); protected: virtual ItemViewHoverButton* createButton(); virtual void updateButton(const QModelIndex& index); virtual bool checkIndex(const QModelIndex& index) const; virtual void widgetEnterEvent(); virtual void widgetLeaveEvent(); private Q_SLOTS: void slotClicked(); private: ImportRotateOverlayDirection const m_direction; }; } // namespace Digikam #endif // DIGIKAM_IMPORT_OVERLAYS_H diff --git a/core/utilities/import/items/importtooltipfiller.cpp b/core/utilities/import/items/importtooltipfiller.cpp index 53cec77d85..570f47b75d 100644 --- a/core/utilities/import/items/importtooltipfiller.cpp +++ b/core/utilities/import/items/importtooltipfiller.cpp @@ -1,237 +1,238 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-28-07 * Description : Import icon view tool tip * * Copyright (C) 2012 by Islam Wazery * Copyright (C) 2008-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 "importtooltipfiller.h" // Qt includes #include #include #include // KDE includes #include // Local includes #include "importsettings.h" #include "itempropertiestab.h" #include "ditemtooltip.h" #include "camiteminfo.h" namespace Digikam { QString ImportToolTipFiller::CamItemInfoTipContents(const CamItemInfo& info) { QString str; ImportSettings* const settings = ImportSettings::instance(); DToolTipStyleSheet cnt(settings->getToolTipsFont()); PhotoInfoContainer photoInfo = info.photoInfo; QString tip = cnt.tipHeader; // -- File properties ---------------------------------------------- if (settings->getToolTipsShowFileName() || settings->getToolTipsShowFileDate() || settings->getToolTipsShowFileSize() || settings->getToolTipsShowImageType() || settings->getToolTipsShowImageDim()) { tip += cnt.headBeg + i18n("File Properties") + cnt.headEnd; if (settings->getToolTipsShowFileName()) { tip += cnt.cellBeg + i18nc("filename", "Name:") + cnt.cellMid; tip += info.name + cnt.cellEnd; } if (settings->getToolTipsShowFileDate()) { QDateTime createdDate = info.ctime; str = QLocale().toString(createdDate, QLocale::ShortFormat); tip += cnt.cellBeg + i18n("Date:") + cnt.cellMid + str + cnt.cellEnd; } if (settings->getToolTipsShowFileSize()) { tip += cnt.cellBeg + i18n("Size:") + cnt.cellMid; QString localeFileSize = QLocale().toString(info.size); str = i18n("%1 (%2)", ItemPropertiesTab::humanReadableBytesCount(info.size), localeFileSize); tip += str + cnt.cellEnd; } if (settings->getToolTipsShowImageType()) { tip += cnt.cellBeg + i18n("Type:") + cnt.cellMid + info.mime + cnt.cellEnd; } if (settings->getToolTipsShowImageDim()) { - if (info.width == 0 || info.height == 0 || info.width == -1 || info.height == -1) + if ((info.width == 0) || (info.height == 0) || (info.width == -1) || (info.height == -1)) { str = i18nc("unknown / invalid image dimension", "Unknown"); } else { QString mpixels; mpixels.setNum(info.width*info.height/1000000.0, 'f', 2); str = i18nc("width x height (megapixels Mpx)", "%1x%2 (%3Mpx)", info.width, info.height, mpixels); } tip += cnt.cellBeg + i18n("Dimensions:") + cnt.cellMid + str + cnt.cellEnd; } } // -- Photograph Info ----------------------------------------------------------------------- + // NOTE: these info require \"Use File Metadata\" option from Camera Setup Behavior page. if (settings->getToolTipsShowPhotoMake() || settings->getToolTipsShowPhotoLens() || settings->getToolTipsShowPhotoFocal() || settings->getToolTipsShowPhotoExpo() || settings->getToolTipsShowPhotoFlash() || settings->getToolTipsShowPhotoWB()) { if (!photoInfo.isNull()) { QString metaStr; tip += cnt.headBeg + i18n("Photograph Properties") + cnt.headEnd; if (settings->getToolTipsShowPhotoMake()) { ItemPropertiesTab::shortenedMakeInfo(photoInfo.make); ItemPropertiesTab::shortenedModelInfo(photoInfo.model); str = QString::fromUtf8("%1 / %2").arg(photoInfo.make.isEmpty() ? cnt.unavailable : photoInfo.make) .arg(photoInfo.model.isEmpty() ? cnt.unavailable : photoInfo.model); if (str.length() > cnt.maxStringLength) { str = str.left(cnt.maxStringLength-3) + QLatin1String("..."); } metaStr += cnt.cellBeg + i18n("Make/Model:") + cnt.cellMid + str.toHtmlEscaped() + cnt.cellEnd; } if (settings->getToolTipsShowPhotoLens()) { str = photoInfo.lens.isEmpty() ? cnt.unavailable : photoInfo.lens; QString lens = i18nc("camera lens", "Lens:"); if (str.length() > cnt.maxStringLength) { int space = str.lastIndexOf(QLatin1Char(' '), cnt.maxStringLength); if (space == -1) space = cnt.maxStringLength; metaStr += cnt.cellBeg + lens + cnt.cellMid + str.left(space).toHtmlEscaped() + cnt.cellEnd; str = str.mid(space+1); lens = QString(); } if (str.length() > cnt.maxStringLength) { str = str.left(cnt.maxStringLength-3) + QLatin1String("..."); } metaStr += cnt.cellBeg + lens + cnt.cellMid + str.toHtmlEscaped() + cnt.cellEnd; } if (settings->getToolTipsShowPhotoFocal()) { str = photoInfo.aperture.isEmpty() ? cnt.unavailable : photoInfo.aperture; if (photoInfo.focalLength35mm.isEmpty()) { str += QString::fromUtf8(" / %1").arg(photoInfo.focalLength.isEmpty() ? cnt.unavailable : photoInfo.focalLength); } else { str += QString::fromUtf8(" / %1").arg(i18n("%1 (%2)",photoInfo.focalLength, photoInfo.focalLength35mm)); } if (str.length() > cnt.maxStringLength) { str = str.left(cnt.maxStringLength-3) + QLatin1String("..."); } metaStr += cnt.cellBeg + i18n("Aperture/Focal:") + cnt.cellMid + str.toHtmlEscaped() + cnt.cellEnd; } if (settings->getToolTipsShowPhotoExpo()) { str = QString::fromUtf8("%1 / %2").arg(photoInfo.exposureTime.isEmpty() ? cnt.unavailable : photoInfo.exposureTime) .arg(photoInfo.sensitivity.isEmpty() ? cnt.unavailable : i18n("%1 ISO",photoInfo.sensitivity)); if (str.length() > cnt.maxStringLength) { str = str.left(cnt.maxStringLength-3) + QLatin1String("..."); } metaStr += cnt.cellBeg + i18n("Exposure/Sensitivity:") + cnt.cellMid + str.toHtmlEscaped() + cnt.cellEnd; } if (settings->getToolTipsShowPhotoFlash()) { str = photoInfo.flash.isEmpty() ? cnt.unavailable : photoInfo.flash; if (str.length() > cnt.maxStringLength) { str = str.left(cnt.maxStringLength-3) + QLatin1String("..."); } metaStr += cnt.cellBeg + i18nc("camera flash settings", "Flash:") + cnt.cellMid + str.toHtmlEscaped() + cnt.cellEnd; } if (settings->getToolTipsShowPhotoWB()) { str = photoInfo.whiteBalance.isEmpty() ? cnt.unavailable : photoInfo.whiteBalance; if (str.length() > cnt.maxStringLength) { str = str.left(cnt.maxStringLength-3) + QLatin1String("..."); } metaStr += cnt.cellBeg + i18n("White Balance:") + cnt.cellMid + str.toHtmlEscaped() + cnt.cellEnd; } tip += metaStr; } } tip += cnt.tipFooter; return tip; } } // namespace Digikam diff --git a/core/utilities/import/items/itemviewimportdelegate.cpp b/core/utilities/import/items/itemviewimportdelegate.cpp index 07519f6cee..276dbd2d51 100644 --- a/core/utilities/import/items/itemviewimportdelegate.cpp +++ b/core/utilities/import/items/itemviewimportdelegate.cpp @@ -1,707 +1,726 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-08 * Description : Item delegate for import interface items. * * Copyright (C) 2012 by Islam Wazery * 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 "itemviewimportdelegate.h" #include "itemviewimportdelegate_p.h" // Qt includes #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "itemdelegateoverlay.h" #include "thememanager.h" #include "itemscanner.h" #include "itempropertiestab.h" #include "camiteminfo.h" #include "colorlabelwidget.h" #include "ratingwidget.h" namespace Digikam { ItemViewImportDelegatePrivate::ItemViewImportDelegatePrivate() + : spacing(0), + thumbSize(ThumbnailSize(0)), + q(nullptr), + radius(3), // painting constants + margin(5) { - q = nullptr; - spacing = 0; - thumbSize = ThumbnailSize(0); - - // painting constants - radius = 3; - margin = 5; - makeStarPolygon(); ratingPixmaps = QVector(10); } void ItemViewImportDelegatePrivate::init(ItemViewImportDelegate* const _q) { q = _q; q->connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()), q, SLOT(slotThemeChanged())); } void ItemViewImportDelegatePrivate::clearRects() { gridSize = QSize(0, 0); rect = QRect(0, 0, 0, 0); ratingRect = QRect(0, 0, 0, 0); } void ItemViewImportDelegatePrivate::makeStarPolygon() { // Pre-computed star polygon for a 15x15 pixmap. + starPolygon = RatingWidget::starPolygon(); starPolygonSize = QSize(15, 15); } // ---- ItemViewImportDelegate ----------------------------------------------- ItemViewImportDelegate::ItemViewImportDelegate(QObject* const parent) : DItemDelegate(parent), d_ptr(new ItemViewImportDelegatePrivate) { d_ptr->init(this); } ItemViewImportDelegate::ItemViewImportDelegate(ItemViewImportDelegatePrivate& dd, QObject* const parent) : DItemDelegate(parent), d_ptr(&dd) { d_ptr->init(this); } ItemViewImportDelegate::~ItemViewImportDelegate() { Q_D(ItemViewImportDelegate); removeAllOverlays(); delete d; } ThumbnailSize ItemViewImportDelegate::thumbnailSize() const { Q_D(const ItemViewImportDelegate); return d->thumbSize; } void ItemViewImportDelegate::setThumbnailSize(const ThumbnailSize& thumbSize) { Q_D(ItemViewImportDelegate); if (d->thumbSize != thumbSize) { d->thumbSize = thumbSize; invalidatePaintingCache(); } } void ItemViewImportDelegate::setSpacing(int spacing) { Q_D(ItemViewImportDelegate); if (d->spacing == spacing) { return; } d->spacing = spacing; invalidatePaintingCache(); } int ItemViewImportDelegate::spacing() const { Q_D(const ItemViewImportDelegate); return d->spacing; } QRect ItemViewImportDelegate::rect() const { Q_D(const ItemViewImportDelegate); return d->rect; } QRect ItemViewImportDelegate::pixmapRect() const { return QRect(); } QRect ItemViewImportDelegate::imageInformationRect() const { return QRect(); } QRect ItemViewImportDelegate::ratingRect() const { Q_D(const ItemViewImportDelegate); return d->ratingRect; } void ItemViewImportDelegate::setRatingEdited(const QModelIndex& index) { Q_D(ItemViewImportDelegate); d->editingRating = index; } QSize ItemViewImportDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const { Q_D(const ItemViewImportDelegate); return d->rect.size(); } QSize ItemViewImportDelegate::gridSize() const { Q_D(const ItemViewImportDelegate); return d->gridSize; } bool ItemViewImportDelegate::acceptsToolTip(const QPoint&, const QRect& visualRect, const QModelIndex&, QRect* retRect) const { if (retRect) { *retRect = visualRect; } return true; } bool ItemViewImportDelegate::acceptsActivation(const QPoint& , const QRect& visualRect, const QModelIndex&, QRect* retRect) const { if (retRect) { *retRect = visualRect; } return true; } QAbstractItemDelegate* ItemViewImportDelegate::asDelegate() { return this; } void ItemViewImportDelegate::overlayDestroyed(QObject* o) { ItemDelegateOverlayContainer::overlayDestroyed(o); } void ItemViewImportDelegate::mouseMoved(QMouseEvent* e, const QRect& visualRect, const QModelIndex& index) { // 3-way indirection AbstractImportItemDelegate -> ItemViewImportDelegate -> ItemDelegateOverlayContainer + ItemDelegateOverlayContainer::mouseMoved(e, visualRect, index); } void ItemViewImportDelegate::setDefaultViewOptions(const QStyleOptionViewItem& option) { Q_D(ItemViewImportDelegate); d->font = option.font; invalidatePaintingCache(); } void ItemViewImportDelegate::slotThemeChanged() { invalidatePaintingCache(); } void ItemViewImportDelegate::slotSetupChanged() { invalidatePaintingCache(); } void ItemViewImportDelegate::invalidatePaintingCache() { Q_D(ItemViewImportDelegate); QSize oldGridSize = d->gridSize; updateSizeRectsAndPixmaps(); if (oldGridSize != d->gridSize) { emit gridSizeChanged(d->gridSize); - // emit sizeHintChanged(QModelIndex()); +/* + emit sizeHintChanged(QModelIndex()); +*/ } emit visualChange(); } QRect ItemViewImportDelegate::drawThumbnail(QPainter* p, const QRect& thumbRect, const QPixmap& background, const QPixmap& thumbnail) const { p->drawPixmap(0, 0, background); if (thumbnail.isNull()) { return QRect(); } QRect r = thumbRect; QRect actualPixmapRect(r.x() + (r.width()-thumbnail.width())/2, r.y() + (r.height()-thumbnail.height())/2, thumbnail.width(), thumbnail.height()); QPixmap borderPix = thumbnailBorderPixmap(actualPixmapRect.size()); p->drawPixmap(actualPixmapRect.x()-3, actualPixmapRect.y()-3, borderPix); p->drawPixmap(r.x() + (r.width()-thumbnail.width())/2, r.y() + (r.height()-thumbnail.height())/2, thumbnail); return actualPixmapRect; } void ItemViewImportDelegate::drawRating(QPainter* p, const QModelIndex& index, const QRect& ratingRect, int rating, bool isSelected) const { Q_D(const ItemViewImportDelegate); if (d->editingRating != index) { p->drawPixmap(ratingRect, ratingPixmap(rating, isSelected)); } } void ItemViewImportDelegate::drawName(QPainter* p,const QRect& nameRect, const QString& name) const { Q_D(const ItemViewImportDelegate); p->setFont(d->fontReg); p->drawText(nameRect, Qt::AlignCenter, name);//squeezedTextCached(p, nameRect.width(), name)); } void ItemViewImportDelegate::drawCreationDate(QPainter* p, const QRect& dateRect, const QDateTime& date) const { Q_D(const ItemViewImportDelegate); p->setFont(d->fontXtra); QString str = dateToString(date); str = i18nc("date of image creation", "created: %1", str); p->drawText(dateRect, Qt::AlignCenter, str);//squeezedTextCached(p, dateRect.width(), str)); } void ItemViewImportDelegate::drawImageFormat(QPainter* p, const QRect& r, const QString& mime) const { Q_D(const ItemViewImportDelegate); if (!mime.isEmpty() && !r.isNull()) { QString type = mime.split(QLatin1Char('/')).at(1); type = ItemScanner::formatToString(type); p->save(); QFont fnt(d->fontReg); fnt.setWeight(QFont::Black); fnt.setItalic(false); p->setFont(fnt); p->setPen(QPen(Qt::gray)); p->setOpacity(0.50); QRect bRect = p->boundingRect(r, Qt::AlignBottom | Qt::AlignHCenter, type.toUpper()); bRect.adjust(1, 1, -1, -1); bRect.translate(0, 1); p->fillRect(bRect, Qt::SolidPattern); p->setPen(QPen(Qt::white)); p->setOpacity(1.0); p->drawText(bRect, Qt::AlignBottom | Qt::AlignHCenter, type.toUpper()); p->restore(); } } void ItemViewImportDelegate::drawImageSize(QPainter* p, const QRect& dimsRect, const QSize& dims) const { Q_D(const ItemViewImportDelegate); if (dims.isValid()) { p->setFont(d->fontXtra); QString mpixels, resolution; mpixels.setNum(dims.width()*dims.height()/1000000.0, 'f', 2); if (dims.isValid()) { resolution = i18nc("%1 width, %2 height, %3 mpixels", "%1x%2 (%3Mpx)", dims.width(), dims.height(), mpixels); } else { resolution = i18nc("unknown image resolution", "Unknown"); } p->drawText(dimsRect, Qt::AlignCenter, resolution); } } void ItemViewImportDelegate::drawFileSize(QPainter* p, const QRect& r, qlonglong bytes) const { Q_D(const ItemViewImportDelegate); p->setFont(d->fontXtra); p->drawText(r, Qt::AlignCenter, ItemPropertiesTab::humanReadableBytesCount(bytes)); } void ItemViewImportDelegate::drawTags(QPainter* p, const QRect& r, const QString& tagsString, bool isSelected) const { Q_D(const ItemViewImportDelegate); p->setFont(d->fontCom); p->setPen(isSelected ? qApp->palette().color(QPalette::HighlightedText) : qApp->palette().color(QPalette::Link)); p->drawText(r, Qt::AlignCenter, squeezedTextCached(p, r.width(), tagsString)); } void ItemViewImportDelegate::drawPickLabelIcon(QPainter* p, const QRect& r, int pickId) const { // Draw Pick Label icon + if (pickId != NoPickLabel) { QIcon icon; - if (pickId == RejectedLabel) + if (pickId == RejectedLabel) { icon = QIcon::fromTheme(QLatin1String("flag-red")); } else if (pickId == PendingLabel) { icon = QIcon::fromTheme(QLatin1String("flag-yellow")); } else if (pickId == AcceptedLabel) { icon = QIcon::fromTheme(QLatin1String("flag-green")); } icon.paint(p, r); } } void ItemViewImportDelegate::drawColorLabelRect(QPainter* p, const QStyleOptionViewItem& option, bool isSelected, int colorId) const { Q_D(const ItemViewImportDelegate); Q_UNUSED(option); Q_UNUSED(isSelected); if (colorId > NoColorLabel) { // This draw a simple rectangle around item. + p->setPen(QPen(ColorLabelWidget::labelColor((ColorLabel)colorId), 5, Qt::SolidLine)); p->drawRect(3, 3, d->rect.width()-7, d->rect.height()-7); } } void ItemViewImportDelegate::drawGeolocationIndicator(QPainter* p, const QRect& r) const { if (!r.isNull()) { QIcon icon(QIcon::fromTheme(QLatin1String("globe")).pixmap(r.size())); qreal op = p->opacity(); p->setOpacity(0.5); icon.paint(p, r); p->setOpacity(op); } } void ItemViewImportDelegate::drawDownloadIndicator(QPainter* p, const QRect& r, int itemType) const { QIcon icon; if (itemType == CamItemInfo::DownloadUnknown) { icon = QIcon::fromTheme(QLatin1String("dialog-information")); } if (itemType == CamItemInfo::DownloadedNo) // TODO: CamItemInfo::NewPicture { icon = QIcon::fromTheme(QLatin1String("folder-favorites")); } if (itemType == CamItemInfo::DownloadedYes) { icon = QIcon::fromTheme(QLatin1String("dialog-ok-apply")); } qreal op = p->opacity(); p->setOpacity(0.5); icon.paint(p, r); p->setOpacity(op); } void ItemViewImportDelegate::drawLockIndicator(QPainter* p, const QRect& r, int lockStatus) const { QIcon icon; if (lockStatus == 1) { return; // draw lock only when image is locked - //icon = QIcon::fromTheme(QLatin1String("object-unlocked")); +/* + icon = QIcon::fromTheme(QLatin1String("object-unlocked")); +*/ } if (lockStatus == 0) { icon = QIcon::fromTheme(QLatin1String("object-locked")); } qreal op = p->opacity(); p->setOpacity(0.5); icon.paint(p, r); p->setOpacity(op); } void ItemViewImportDelegate::drawFocusRect(QPainter* p, const QStyleOptionViewItem& option, bool isSelected) const { Q_D(const ItemViewImportDelegate); if (option.state & QStyle::State_HasFocus) //?? is current item { p->setPen(QPen(isSelected ? qApp->palette().color(QPalette::HighlightedText) : qApp->palette().color(QPalette::Text), 1, Qt::DotLine)); p->drawRect(1, 1, d->rect.width()-3, d->rect.height()-3); } } void ItemViewImportDelegate::drawGroupIndicator(QPainter* p, const QRect& r, int numberOfGroupedImages, bool open) const { if (numberOfGroupedImages) { QIcon icon; if (open) { icon = QIcon::fromTheme(QLatin1String("document-import")); } else { icon = QIcon::fromTheme(QLatin1String("document-multiple")); } qreal op = p->opacity(); p->setOpacity(0.5); icon.paint(p, r); p->setOpacity(op); QString text = QString::number(numberOfGroupedImages); p->drawText(r, Qt::AlignCenter, text); } } void ItemViewImportDelegate::drawMouseOverRect(QPainter* p, const QStyleOptionViewItem& option) const { Q_D(const ItemViewImportDelegate); if (option.state & QStyle::State_MouseOver) { p->setPen(QPen(option.palette.color(QPalette::Highlight), 3, Qt::SolidLine)); p->drawRect(1, 1, d->rect.width()-3, d->rect.height()-3); } } void ItemViewImportDelegate::prepareFonts() { Q_D(ItemViewImportDelegate); d->fontReg = d->font; d->fontCom = d->font; d->fontXtra = d->font; d->fontCom.setItalic(true); int fnSz = d->fontReg.pointSize(); if (fnSz > 0) { d->fontCom.setPointSize(fnSz-1); d->fontXtra.setPointSize(fnSz-2); } else { fnSz = d->fontReg.pixelSize(); d->fontCom.setPixelSize(fnSz-1); d->fontXtra.setPixelSize(fnSz-2); } } void ItemViewImportDelegate::prepareMetrics(int maxWidth) { Q_D(ItemViewImportDelegate); QFontMetrics fm(d->fontReg); d->oneRowRegRect = fm.boundingRect(0, 0, maxWidth, 0xFFFFFFFF, Qt::AlignTop | Qt::AlignHCenter, QLatin1String("XXXXXXXXX")); fm = QFontMetrics(d->fontCom); d->oneRowComRect = fm.boundingRect(0, 0, maxWidth, 0xFFFFFFFF, Qt::AlignTop | Qt::AlignHCenter, QLatin1String("XXXXXXXXX")); fm = QFontMetrics(d->fontXtra); d->oneRowXtraRect = fm.boundingRect(0, 0, maxWidth, 0xFFFFFFFF, Qt::AlignTop | Qt::AlignHCenter, QLatin1String("XXXXXXXXX")); } void ItemViewImportDelegate::prepareBackground() { Q_D(ItemViewImportDelegate); if (!d->rect.isValid()) { d->regPixmap = QPixmap(); d->selPixmap = QPixmap(); } else { d->regPixmap = QPixmap(d->rect.width(), d->rect.height()); d->regPixmap.fill(qApp->palette().color(QPalette::Base)); QPainter p1(&d->regPixmap); p1.setPen(qApp->palette().color(QPalette::Midlight)); p1.drawRect(0, 0, d->rect.width()-1, d->rect.height()-1); d->selPixmap = QPixmap(d->rect.width(), d->rect.height()); d->selPixmap.fill(qApp->palette().color(QPalette::Highlight)); QPainter p2(&d->selPixmap); p2.setPen(qApp->palette().color(QPalette::Midlight)); p2.drawRect(0, 0, d->rect.width()-1, d->rect.height()-1); } } void ItemViewImportDelegate::prepareRatingPixmaps(bool composeOverBackground) { /// Please call this method after prepareBackground() and when d->ratingPixmap is set Q_D(ItemViewImportDelegate); if (!d->ratingRect.isValid()) { return; } // We use antialiasing and want to pre-render the pixmaps. // So we need the background at the time of painting, // and the background may be a gradient, and will be different for selected items. // This makes 5*2 (small) pixmaps. - for (int sel=0; sel<2; ++sel) + + for (int sel = 0 ; sel < 2 ; ++sel) { QPixmap basePix; if (composeOverBackground) { // do this once for regular, once for selected backgrounds + if (sel) { basePix = d->selPixmap.copy(d->ratingRect); } else { basePix = d->regPixmap.copy(d->ratingRect); } } else { basePix = QPixmap(d->ratingRect.size()); basePix.fill(Qt::transparent); } for (int rating=1; rating<=5; ++rating) { // we store first the 5 regular, then the 5 selected pixmaps, for simplicity + int index = (sel * 5 + rating) - 1; // copy background + d->ratingPixmaps[index] = basePix; + // open a painter + QPainter painter(&d->ratingPixmaps[index]); // use antialiasing + painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(qApp->palette().color(QPalette::Link)); QPen pen(qApp->palette().color(QPalette::Text)); + // set a pen which joins the lines at a filled angle + pen.setJoinStyle(Qt::MiterJoin); painter.setPen(pen); // move painter while drawing polygons + painter.translate( lround((d->ratingRect.width() - d->margin - rating*(d->starPolygonSize.width()+1))/2.0) + 2, 1 ); - for (int s=0; sstarPolygon, Qt::WindingFill); painter.translate(d->starPolygonSize.width() + 1, 0); } } } } QPixmap ItemViewImportDelegate::ratingPixmap(int rating, bool selected) const { Q_D(const ItemViewImportDelegate); - if (rating < 1 || rating > 5) + if ((rating < 1) || (rating > 5)) { - /* +/* QPixmap pix; + if (selected) + { pix = d->selPixmap.copy(d->ratingRect); + } else + { pix = d->regPixmap.copy(d->ratingRect); + } return pix; - */ +*/ return QPixmap(); } --rating; if (selected) { return d->ratingPixmaps.at(5 + rating); } else { return d->ratingPixmaps.at(rating); } } } // namespace Digikam diff --git a/core/utilities/import/items/itemviewimportdelegate.h b/core/utilities/import/items/itemviewimportdelegate.h index 54031ab357..5905a74b96 100644 --- a/core/utilities/import/items/itemviewimportdelegate.h +++ b/core/utilities/import/items/itemviewimportdelegate.h @@ -1,151 +1,157 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-05-07 * Description : Item delegate for import interface items. * * Copyright (C) 2012 by Islam Wazery * 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. * * ============================================================ */ #ifndef DIGIKAM_ITEM_VIEW_IMPORT_DELEGATE_H #define DIGIKAM_ITEM_VIEW_IMPORT_DELEGATE_H // Local includes #include "thumbnailsize.h" #include "ditemdelegate.h" #include "itemdelegateoverlay.h" namespace Digikam { class ImportCategoryDrawer; class ImportCategorizedView; class ImportFilterModel; class ImportItemModel; class ItemViewImportDelegatePrivate; -// Some reuse of the existing model-view classes. +/// NOTE: Some reuse of the existing model-view classes. + class ItemViewImportDelegate : public DItemDelegate, public ItemDelegateOverlayContainer { Q_OBJECT public: explicit ItemViewImportDelegate(QObject* const parent = nullptr); ~ItemViewImportDelegate(); ThumbnailSize thumbnailSize() const; int spacing() const; QRect rect() const; virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; virtual QSize gridSize() const; - // reimplemented from DItemDelegate + /// reimplemented from DItemDelegate + virtual void setThumbnailSize(const ThumbnailSize& thumbSize); virtual void setSpacing(int spacing); virtual void setDefaultViewOptions(const QStyleOptionViewItem& option); virtual bool acceptsToolTip(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* tooltipRect = nullptr) const; virtual bool acceptsActivation(const QPoint& pos, const QRect& visualRect, const QModelIndex& index, QRect* activationRect = nullptr) const; - /** Returns the area where the pixmap is drawn, - * or null if not supported + /** + * Returns the area where the pixmap is drawn, + * or null if not supported */ virtual QRect pixmapRect() const; - /** Returns the area where the image information is drawn, - * or null if empty / not supported. - * The image information is textual or graphical information, - * but not the pixmap. The ratingRect() will e.g. typically - * be contained in this area. + /** + * Returns the area where the image information is drawn, + * or null if empty / not supported. + * The image information is textual or graphical information, + * but not the pixmap. The ratingRect() will e.g. typically + * be contained in this area. */ virtual QRect imageInformationRect() const; - /** Can be used to temporarily disable drawing of the rating. - * Call with QModelIndex() afterwards. + /** + * Can be used to temporarily disable drawing of the rating. + * Call with QModelIndex() afterwards. */ void setRatingEdited(const QModelIndex& index); - /** Returns the rectangle where the rating is drawn, - * or a null rectangle if not supported. + /** + * Returns the rectangle where the rating is drawn, + * or a null rectangle if not supported. */ virtual QRect ratingRect() const; virtual void mouseMoved(QMouseEvent* e, const QRect& visualRect, const QModelIndex& index); protected Q_SLOTS: void slotThemeChanged(); void slotSetupChanged(); virtual void overlayDestroyed(QObject* o); Q_SIGNALS: void requestNotification(const QModelIndex& index, const QString& message); void hideNotification(); protected: /// Use the tool methods for painting in subclasses QRect drawThumbnail(QPainter* p, const QRect& thumbRect, const QPixmap& background, const QPixmap& thumbnail) const; void drawRating(QPainter* p, const QModelIndex& index, const QRect& ratingRect, int rating, bool isSelected) const; void drawName(QPainter* p,const QRect& nameRect, const QString& name) const; void drawCreationDate(QPainter* p, const QRect& dateRect, const QDateTime& date) const; void drawImageSize(QPainter* p, const QRect& dimsRect, const QSize& dims) const; void drawImageFormat(QPainter* p, const QRect& dimsRect, const QString& mime) const; void drawFileSize(QPainter* p, const QRect& r, qlonglong bytes) const; void drawTags(QPainter* p, const QRect& r, const QString& tagsString, bool isSelected) const; void drawGroupIndicator(QPainter* p, const QRect& r, int numberOfGroupedImages, bool open) const; void drawPickLabelIcon(QPainter* p, const QRect& r, int pickLabel) const; void drawColorLabelRect(QPainter* p, const QStyleOptionViewItem& option,bool isSelected, int colorId) const; void drawGeolocationIndicator(QPainter* p, const QRect& r) const; void drawDownloadIndicator(QPainter* p, const QRect& r, int itemType) const; void drawLockIndicator(QPainter* p, const QRect& r, int lockStatus) const; void drawFocusRect(QPainter* p, const QStyleOptionViewItem& option, bool isSelected) const; void drawMouseOverRect(QPainter* p, const QStyleOptionViewItem& option) const; void prepareFonts(); void prepareMetrics(int maxWidth); void prepareBackground(); void prepareRatingPixmaps(bool composeOverBackground = true); /// Returns the relevant pixmap from the cached rating pixmaps QPixmap ratingPixmap(int rating, bool selected) const; virtual QAbstractItemDelegate* asDelegate(); - // reimplement these in subclasses + /// reimplement these in subclasses virtual void invalidatePaintingCache(); virtual void updateSizeRectsAndPixmaps() = 0; protected: ItemViewImportDelegatePrivate* const d_ptr; ItemViewImportDelegate(ItemViewImportDelegatePrivate& dd, QObject* const parent); private: Q_DECLARE_PRIVATE(ItemViewImportDelegate) }; } // namespace Digikam #endif // DIGIKAM_ITEM_VIEW_IMPORT_DELEGATE_H diff --git a/core/utilities/import/items/itemviewimportdelegate_p.h b/core/utilities/import/items/itemviewimportdelegate_p.h index 9052728ecc..772944346a 100644 --- a/core/utilities/import/items/itemviewimportdelegate_p.h +++ b/core/utilities/import/items/itemviewimportdelegate_p.h @@ -1,99 +1,101 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2012-07-08 * Description : Item delegate for import interface items - private container. * * Copyright (C) 2012 by Islam Wazery * * 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_ITEM_VIEW_IMPORT_DELEGATE_P_H #define DIGIKAM_ITEM_VIEW_IMPORT_DELEGATE_P_H +#include "itemviewimportdelegate.h" + // Qt includes #include #include #include #include #include // Local includes #include "digikam_debug.h" #include "thumbnailsize.h" namespace Digikam { class ItemDelegateOverlay; class ItemViewImportDelegate; class Q_DECL_HIDDEN ItemViewImportDelegatePrivate { public: explicit ItemViewImportDelegatePrivate(); virtual ~ItemViewImportDelegatePrivate() { } void init(ItemViewImportDelegate* const _q); void makeStarPolygon(); /// Resets cached rects. Remember to reimplement in subclass for added rects. virtual void clearRects(); public: int spacing; QSize gridSize; QRect rect; QRect ratingRect; QPixmap regPixmap; QPixmap selPixmap; QVector ratingPixmaps; QFont font; QFont fontReg; QFont fontCom; QFont fontXtra; QPolygon starPolygon; QSize starPolygonSize; ThumbnailSize thumbSize; QPersistentModelIndex editingRating; ItemViewImportDelegate* q; QRect oneRowRegRect; QRect oneRowComRect; QRect oneRowXtraRect; - // constant values for drawing + /// constant values for drawing int radius; int margin; }; } // namespace Digikam #endif // DIGIKAM_ITEM_VIEW_IMPORT_DELEGATE_P_H