File indexing completed on 2025-01-19 03:59:21
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2012-08-21 0007 * Description : Overlays for the import interface 0008 * 0009 * SPDX-FileCopyrightText: 2012 by Islam Wazery <wazery at ubuntu dot com> 0010 * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "importoverlays.h" 0017 0018 // KDE includes 0019 0020 #include <klocalizedstring.h> 0021 0022 // Local includes 0023 0024 #include "importcategorizedview.h" 0025 #include "importdelegate.h" 0026 #include "camiteminfo.h" 0027 0028 namespace Digikam 0029 { 0030 0031 ImportOverlayWidget::ImportOverlayWidget(QWidget* const parent) 0032 : QAbstractButton(parent) 0033 { 0034 } 0035 0036 void ImportOverlayWidget::paintEvent(QPaintEvent*) 0037 { 0038 } 0039 0040 // -- Coordinates Overlay ------------------------------------------------------------------ 0041 0042 ImportCoordinatesOverlay::ImportCoordinatesOverlay(QObject* const parent) 0043 : AbstractWidgetDelegateOverlay(parent) 0044 { 0045 } 0046 0047 ImportOverlayWidget* ImportCoordinatesOverlay::buttonWidget() const 0048 { 0049 return static_cast<ImportOverlayWidget*>(m_widget); 0050 } 0051 0052 QWidget* ImportCoordinatesOverlay::createWidget() 0053 { 0054 QAbstractButton* const button = new ImportOverlayWidget(parentWidget()); 0055 /* 0056 button->setCursor(Qt::PointingHandCursor); 0057 */ 0058 return button; 0059 } 0060 0061 void ImportCoordinatesOverlay::setActive(bool active) 0062 { 0063 AbstractWidgetDelegateOverlay::setActive(active); 0064 } 0065 0066 void ImportCoordinatesOverlay::visualChange() 0067 { 0068 if (m_widget && m_widget->isVisible()) 0069 { 0070 updatePosition(); 0071 } 0072 } 0073 0074 void ImportCoordinatesOverlay::updatePosition() 0075 { 0076 if (!m_index.isValid()) 0077 { 0078 return; 0079 } 0080 0081 QRect rect = static_cast<ImportDelegate*>(delegate())->coordinatesIndicatorRect(); 0082 QRect visualRect = m_view->visualRect(m_index); 0083 rect.translate(visualRect.topLeft()); 0084 0085 m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); 0086 m_widget->move(rect.topLeft()); 0087 } 0088 0089 bool ImportCoordinatesOverlay::checkIndex(const QModelIndex& index) const 0090 { 0091 CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); 0092 QRect rect = static_cast<ImportDelegate*>(delegate())->coordinatesIndicatorRect(); 0093 0094 if (!rect.isNull() && info.photoInfo.hasCoordinates) 0095 { 0096 m_widget->setToolTip(i18nc("@info:tooltip", "This item has geolocation information.")); 0097 return true; 0098 } 0099 0100 // If info.photoInfo.hasCoordinates = false, no need to show a tooltip, because there is no icon over thumbnail. 0101 0102 return false; 0103 } 0104 0105 void ImportCoordinatesOverlay::slotEntered(const QModelIndex& index) 0106 { 0107 AbstractWidgetDelegateOverlay::slotEntered(index); 0108 m_index = index; 0109 updatePosition(); 0110 } 0111 0112 // -- Lock Overlay ------------------------------------------------------------------ 0113 0114 ImportLockOverlay::ImportLockOverlay(QObject* const parent) 0115 : AbstractWidgetDelegateOverlay(parent) 0116 { 0117 } 0118 0119 ImportOverlayWidget* ImportLockOverlay::buttonWidget() const 0120 { 0121 return static_cast<ImportOverlayWidget*>(m_widget); 0122 } 0123 0124 QWidget* ImportLockOverlay::createWidget() 0125 { 0126 QAbstractButton* const button = new ImportOverlayWidget(parentWidget()); 0127 /* 0128 button->setCursor(Qt::PointingHandCursor); 0129 */ 0130 return button; 0131 } 0132 0133 void ImportLockOverlay::setActive(bool active) 0134 { 0135 AbstractWidgetDelegateOverlay::setActive(active); 0136 } 0137 0138 void ImportLockOverlay::visualChange() 0139 { 0140 if (m_widget && m_widget->isVisible()) 0141 { 0142 updatePosition(); 0143 } 0144 } 0145 0146 void ImportLockOverlay::updatePosition() 0147 { 0148 if (!m_index.isValid()) 0149 { 0150 return; 0151 } 0152 0153 QRect rect = static_cast<ImportDelegate*>(delegate())->lockIndicatorRect(); 0154 QRect visualRect = m_view->visualRect(m_index); 0155 rect.translate(visualRect.topLeft()); 0156 0157 m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); 0158 m_widget->move(rect.topLeft()); 0159 } 0160 0161 bool ImportLockOverlay::checkIndex(const QModelIndex& index) const 0162 { 0163 CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); 0164 0165 if (info.writePermissions == 0) 0166 { 0167 m_widget->setToolTip(i18nc("@info:tooltip", "This item is locked.")); 0168 return true; 0169 } 0170 0171 // If info.writePermissions = 1, no need to show a tooltip, because there is no icon over thumbnail. 0172 0173 return false; 0174 } 0175 0176 void ImportLockOverlay::slotEntered(const QModelIndex& index) 0177 { 0178 AbstractWidgetDelegateOverlay::slotEntered(index); 0179 m_index = index; 0180 updatePosition(); 0181 } 0182 0183 // -- Download Overlay ------------------------------------------------------------------ 0184 0185 ImportDownloadOverlay::ImportDownloadOverlay(QObject* const parent) 0186 : AbstractWidgetDelegateOverlay(parent) 0187 { 0188 } 0189 0190 ImportOverlayWidget* ImportDownloadOverlay::buttonWidget() const 0191 { 0192 return static_cast<ImportOverlayWidget*>(m_widget); 0193 } 0194 0195 QWidget* ImportDownloadOverlay::createWidget() 0196 { 0197 QAbstractButton* const button = new ImportOverlayWidget(parentWidget()); 0198 /* 0199 button->setCursor(Qt::PointingHandCursor); 0200 */ 0201 return button; 0202 } 0203 0204 void ImportDownloadOverlay::setActive(bool active) 0205 { 0206 AbstractWidgetDelegateOverlay::setActive(active); 0207 } 0208 0209 void ImportDownloadOverlay::visualChange() 0210 { 0211 if (m_widget && m_widget->isVisible()) 0212 { 0213 updatePosition(); 0214 } 0215 } 0216 0217 void ImportDownloadOverlay::updatePosition() 0218 { 0219 if (!m_index.isValid()) 0220 { 0221 return; 0222 } 0223 0224 QRect rect = static_cast<ImportDelegate*>(delegate())->downloadIndicatorRect(); 0225 QRect visualRect = m_view->visualRect(m_index); 0226 rect.translate(visualRect.topLeft()); 0227 0228 m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); 0229 m_widget->move(rect.topLeft()); 0230 } 0231 0232 bool ImportDownloadOverlay::checkIndex(const QModelIndex& index) const 0233 { 0234 CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); 0235 0236 if (info.downloaded == CamItemInfo::DownloadUnknown) 0237 { 0238 m_widget->setToolTip(i18nc("@info:tooltip", "This item has an unknown download status")); 0239 return true; 0240 } 0241 0242 if (info.downloaded == CamItemInfo::DownloadedNo) // TODO: CamItemInfo::NewPicture 0243 { 0244 m_widget->setToolTip(i18nc("@info:tooltip", "This item has never been downloaded")); 0245 return true; 0246 } 0247 0248 if (info.downloaded == CamItemInfo::DownloadedYes) 0249 { 0250 m_widget->setToolTip(i18nc("@info:tooltip", "This item has already been downloaded")); 0251 return true; 0252 } 0253 0254 return false; 0255 } 0256 0257 void ImportDownloadOverlay::slotEntered(const QModelIndex& index) 0258 { 0259 AbstractWidgetDelegateOverlay::slotEntered(index); 0260 m_index = index; 0261 updatePosition(); 0262 } 0263 0264 // -- Rating Overlay ------------------------------------------------------------------ 0265 0266 ImportRatingOverlay::ImportRatingOverlay(QObject* const parent) 0267 : AbstractWidgetDelegateOverlay(parent) 0268 { 0269 } 0270 0271 RatingWidget* ImportRatingOverlay::ratingWidget() const 0272 { 0273 return static_cast<RatingWidget*>(m_widget); 0274 } 0275 0276 QWidget* ImportRatingOverlay::createWidget() 0277 { 0278 RatingWidget* const w = new RatingWidget(parentWidget()); 0279 w->setFading(true); 0280 w->setTracking(false); 0281 0282 return w; 0283 } 0284 0285 void ImportRatingOverlay::setActive(bool active) 0286 { 0287 AbstractWidgetDelegateOverlay::setActive(active); 0288 0289 if (active) 0290 { 0291 connect(ratingWidget(), SIGNAL(signalRatingChanged(int)), 0292 this, SLOT(slotRatingChanged(int))); 0293 0294 if (view()->model()) 0295 { 0296 connect(view()->model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), 0297 this, SLOT(slotDataChanged(QModelIndex,QModelIndex))); 0298 } 0299 } 0300 else 0301 { 0302 // widget is deleted 0303 0304 if (view() && view()->model()) 0305 { 0306 disconnect(view()->model(), nullptr, this, nullptr); 0307 } 0308 } 0309 } 0310 0311 void ImportRatingOverlay::visualChange() 0312 { 0313 if (m_widget && m_widget->isVisible()) 0314 { 0315 updatePosition(); 0316 } 0317 } 0318 0319 void ImportRatingOverlay::widgetEnterEvent() 0320 { 0321 widgetEnterNotifyMultiple(m_index); 0322 } 0323 0324 void ImportRatingOverlay::widgetLeaveEvent() 0325 { 0326 widgetLeaveNotifyMultiple(); 0327 } 0328 0329 void ImportRatingOverlay::hide() 0330 { 0331 delegate()->setRatingEdited(QModelIndex()); 0332 AbstractWidgetDelegateOverlay::hide(); 0333 } 0334 0335 void ImportRatingOverlay::updatePosition() 0336 { 0337 if (!m_index.isValid() || !m_widget) 0338 { 0339 return; 0340 } 0341 0342 QRect rect = delegate()->ratingRect(); 0343 0344 if (rect.width() > ratingWidget()->maximumVisibleWidth()) 0345 { 0346 int offset = (rect.width() - ratingWidget()->maximumVisibleWidth()) / 2; 0347 rect.adjust(offset, 0, -offset, 0); 0348 } 0349 0350 QRect visualRect = m_view->visualRect(m_index); 0351 rect.translate(visualRect.topLeft()); 0352 0353 m_widget->setFixedSize(rect.width() + 1, rect.height() + 1); 0354 m_widget->move(rect.topLeft()); 0355 } 0356 0357 void ImportRatingOverlay::updateRating() 0358 { 0359 if (!m_index.isValid() || !m_widget) 0360 { 0361 return; 0362 } 0363 0364 ImportItemModel* const model = m_index.data(ImportItemModel::ImportItemModelPointerRole).value<ImportItemModel*>(); 0365 ratingWidget()->setRating(model->camItemInfoRef(m_index).rating); 0366 } 0367 0368 void ImportRatingOverlay::slotRatingChanged(int rating) 0369 { 0370 if (m_widget && m_widget->isVisible() && m_index.isValid()) 0371 { 0372 Q_EMIT ratingEdited(affectedIndexes(m_index), rating); 0373 } 0374 } 0375 0376 void ImportRatingOverlay::slotEntered(const QModelIndex& index) 0377 { 0378 AbstractWidgetDelegateOverlay::slotEntered(index); 0379 0380 // see bug 228810, this is a small workaround 0381 0382 if (m_widget && m_widget->isVisible() && m_index.isValid() && (index == m_index)) 0383 { 0384 ratingWidget()->setVisibleImmediately(); 0385 } 0386 0387 m_index = index; 0388 0389 updatePosition(); 0390 updateRating(); 0391 0392 delegate()->setRatingEdited(m_index); 0393 view()->update(m_index); 0394 } 0395 0396 void ImportRatingOverlay::slotDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) 0397 { 0398 if (m_widget && m_widget->isVisible() && QItemSelectionRange(topLeft, bottomRight).contains(m_index)) 0399 { 0400 updateRating(); 0401 } 0402 } 0403 0404 // -- Rotate Overlay ---------------------------------------------------------------- 0405 0406 ImportRotateOverlayButton::ImportRotateOverlayButton(ImportRotateOverlayDirection dir, QAbstractItemView* const parentView) 0407 : ItemViewHoverButton(parentView), 0408 m_direction (dir) 0409 { 0410 setup(); 0411 } 0412 0413 QSize ImportRotateOverlayButton::sizeHint() const 0414 { 0415 return QSize(32, 32); 0416 } 0417 0418 QIcon ImportRotateOverlayButton::icon() 0419 { 0420 if (m_direction == ImportRotateOverlayLeft) 0421 { 0422 return QIcon::fromTheme(QLatin1String("object-rotate-left")); 0423 } 0424 else 0425 { 0426 return QIcon::fromTheme(QLatin1String("object-rotate-right")); 0427 } 0428 } 0429 0430 void ImportRotateOverlayButton::updateToolTip() 0431 { 0432 if (m_direction == ImportRotateOverlayLeft) 0433 { 0434 setToolTip(i18nc("@info:tooltip", "Rotate Left")); 0435 } 0436 else 0437 { 0438 setToolTip(i18nc("@info:tooltip", "Rotate Right")); 0439 } 0440 } 0441 0442 // -------------------------------------------------------------------- 0443 0444 ImportRotateOverlay::ImportRotateOverlay(ImportRotateOverlayDirection dir, QObject* const parent) 0445 : HoverButtonDelegateOverlay(parent), 0446 m_direction(dir) 0447 { 0448 } 0449 0450 void ImportRotateOverlay::setActive(bool active) 0451 { 0452 HoverButtonDelegateOverlay::setActive(active); 0453 0454 if (active) 0455 { 0456 connect(button(), SIGNAL(clicked(bool)), 0457 this, SLOT(slotClicked())); 0458 } 0459 } 0460 0461 ItemViewHoverButton* ImportRotateOverlay::createButton() 0462 { 0463 return new ImportRotateOverlayButton(m_direction, view()); 0464 } 0465 0466 void ImportRotateOverlay::updateButton(const QModelIndex& index) 0467 { 0468 const QRect rect = m_view->visualRect(index); 0469 const int size = qBound(16, rect.width() / 8 - 2, 48); 0470 const int gap = 5; 0471 const int x = rect.right() - 2*gap - (isLeft() ? size*5 + 2 : size*4 + 2); 0472 const int y = rect.top() + gap; 0473 button()->resize(size, size); 0474 button()->move(QPoint(x, y)); 0475 } 0476 0477 void ImportRotateOverlay::slotClicked() 0478 { 0479 QModelIndex index = button()->index(); 0480 0481 if (index.isValid()) 0482 { 0483 Q_EMIT signalRotate(affectedIndexes(index)); 0484 } 0485 } 0486 0487 bool ImportRotateOverlay::checkIndex(const QModelIndex& index) const 0488 { 0489 CamItemInfo info = ImportItemModel::retrieveCamItemInfo(index); 0490 return (info.mime.contains(QLatin1String("image/"))); 0491 } 0492 0493 void ImportRotateOverlay::widgetEnterEvent() 0494 { 0495 widgetEnterNotifyMultiple(button()->index()); 0496 } 0497 0498 void ImportRotateOverlay::widgetLeaveEvent() 0499 { 0500 widgetLeaveNotifyMultiple(); 0501 } 0502 0503 } // namespace Digikam 0504 0505 #include "moc_importoverlays.cpp"