File indexing completed on 2025-03-09 03:58:45
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2007-03-05 0007 * Description : a widget to display 2 preview image on 0008 * lightable to compare pictures. 0009 * 0010 * SPDX-FileCopyrightText: 2007-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 "lighttableview.h" 0017 0018 // Qt includes 0019 0020 #include <QGridLayout> 0021 #include <QLabel> 0022 #include <QApplication> 0023 0024 // Local includes 0025 0026 #include "digikam_debug.h" 0027 #include "dimg.h" 0028 #include "dzoombar.h" 0029 #include "thumbnailsize.h" 0030 #include "lighttablepreview.h" 0031 #include "previewlayout.h" 0032 #include "dimgpreviewitem.h" 0033 0034 namespace Digikam 0035 { 0036 0037 class Q_DECL_HIDDEN LightTableView::Private 0038 { 0039 public: 0040 0041 explicit Private() 0042 : syncPreview (false), 0043 grid (nullptr), 0044 leftFrame (nullptr), 0045 rightFrame (nullptr), 0046 leftPreview (nullptr), 0047 rightPreview(nullptr) 0048 { 0049 } 0050 0051 bool syncPreview; 0052 0053 QGridLayout* grid; 0054 0055 /// These labels are used to draw a frame around preview views to identify easily which item has the focus. 0056 QLabel* leftFrame; 0057 QLabel* rightFrame; 0058 0059 LightTablePreview* leftPreview; 0060 LightTablePreview* rightPreview; 0061 }; 0062 0063 LightTableView::LightTableView(QWidget* const parent) 0064 : QFrame(parent), 0065 d (new Private) 0066 { 0067 setAttribute(Qt::WA_DeleteOnClose); 0068 setFrameStyle(QFrame::NoFrame); 0069 setLineWidth(0); 0070 0071 d->grid = new QGridLayout(); 0072 setLayout(d->grid); 0073 0074 d->leftFrame = new QLabel(this); 0075 d->leftPreview = new LightTablePreview(this); 0076 QVBoxLayout* const llay = new QVBoxLayout(d->leftFrame); 0077 llay->addWidget(d->leftPreview); 0078 llay->setContentsMargins(3, 3, 3, 3); 0079 llay->setSpacing(0); 0080 0081 d->rightFrame = new QLabel(this); 0082 d->rightPreview = new LightTablePreview(this); 0083 QVBoxLayout* const rlay = new QVBoxLayout(d->rightFrame); 0084 rlay->addWidget(d->rightPreview); 0085 rlay->setContentsMargins(3, 3, 3, 3); 0086 rlay->setSpacing(0); 0087 0088 d->grid->addWidget(d->leftFrame, 0, 0, 1, 1); 0089 d->grid->addWidget(d->rightFrame, 0, 1, 1, 1); 0090 d->grid->setColumnStretch(0, 10); 0091 d->grid->setColumnStretch(1, 10); 0092 d->grid->setRowStretch(0, 10); 0093 0094 // Left panel connections ------------------------------------------------ 0095 0096 connect(d->leftPreview, SIGNAL(signalPopupTagsView()), 0097 this, SIGNAL(signalLeftPopupTagsView())); 0098 0099 connect(d->leftPreview->layout(), SIGNAL(zoomFactorChanged(double)), 0100 this, SLOT(slotLeftZoomFactorChanged(double))); 0101 0102 connect(d->leftPreview, SIGNAL(contentsMoving(int,int)), 0103 this, SLOT(slotLeftContentsMoved(int,int))); 0104 0105 connect(d->leftPreview, SIGNAL(signalSlideShowCurrent()), 0106 this, SIGNAL(signalLeftSlideShowCurrent())); 0107 0108 connect(d->leftPreview, SIGNAL(signalDroppedItems(ItemInfoList)), 0109 this, SIGNAL(signalLeftDroppedItems(ItemInfoList))); 0110 0111 connect(d->leftPreview, SIGNAL(signalPreviewLoaded(bool)), 0112 this, SLOT(slotLeftPreviewLoaded(bool))); 0113 0114 connect(d->leftPreview, SIGNAL(leftButtonClicked()), 0115 this, SIGNAL(signalLeftPanelLeftButtonClicked())); 0116 0117 connect(d->leftPreview, SIGNAL(signalDeleteItem()), 0118 this, SLOT(slotDeleteLeftItem())); 0119 0120 // Right panel connections ------------------------------------------------ 0121 0122 connect(d->rightPreview, SIGNAL(signalPopupTagsView()), 0123 this, SIGNAL(signalRightPopupTagsView())); 0124 0125 connect(d->rightPreview->layout(), SIGNAL(zoomFactorChanged(double)), 0126 this, SLOT(slotRightZoomFactorChanged(double))); 0127 0128 connect(d->rightPreview, SIGNAL(contentsMoving(int,int)), 0129 this, SLOT(slotRightContentsMoved(int,int))); 0130 0131 connect(d->rightPreview, SIGNAL(signalDroppedItems(ItemInfoList)), 0132 this, SIGNAL(signalRightDroppedItems(ItemInfoList))); 0133 0134 connect(d->rightPreview, SIGNAL(signalSlideShowCurrent()), 0135 this, SIGNAL(signalRightSlideShowCurrent())); 0136 0137 connect(d->rightPreview, SIGNAL(signalPreviewLoaded(bool)), 0138 this, SLOT(slotRightPreviewLoaded(bool))); 0139 0140 connect(d->rightPreview, SIGNAL(leftButtonClicked()), 0141 this, SIGNAL(signalRightPanelLeftButtonClicked())); 0142 0143 connect(d->rightPreview, SIGNAL(signalDeleteItem()), 0144 this, SLOT(slotDeleteRightItem())); 0145 } 0146 0147 LightTableView::~LightTableView() 0148 { 0149 delete d; 0150 } 0151 0152 void LightTableView::setPreviewSettings(const PreviewSettings& settings) 0153 { 0154 d->leftPreview->previewItem()->setPreviewSettings(settings); 0155 d->rightPreview->previewItem()->setPreviewSettings(settings); 0156 } 0157 0158 void LightTableView::setSyncPreview(bool sync) 0159 { 0160 d->syncPreview = sync; 0161 0162 // Left panel like a reference to resync preview. 0163 0164 if (d->syncPreview) 0165 { 0166 slotLeftZoomFactorChanged(d->leftPreview->layout()->zoomFactor()); 0167 slotLeftContentsMoved(d->leftPreview->contentsX(), 0168 d->leftPreview->contentsY()); 0169 } 0170 } 0171 0172 void LightTableView::setNavigateByPair(bool b) 0173 { 0174 d->leftPreview->setDragAndDropEnabled(!b); 0175 d->rightPreview->setDragAndDropEnabled(!b); 0176 } 0177 0178 void LightTableView::slotDecreaseLeftZoom() 0179 { 0180 d->leftPreview->layout()->decreaseZoom(); 0181 } 0182 0183 void LightTableView::slotIncreaseLeftZoom() 0184 { 0185 d->leftPreview->layout()->increaseZoom(); 0186 } 0187 0188 void LightTableView::slotDecreaseRightZoom() 0189 { 0190 d->rightPreview->layout()->decreaseZoom(); 0191 } 0192 0193 void LightTableView::slotIncreaseRightZoom() 0194 { 0195 d->rightPreview->layout()->increaseZoom(); 0196 } 0197 0198 void LightTableView::setLeftZoomFactor(double z) 0199 { 0200 d->leftPreview->layout()->setZoomFactor(z); 0201 } 0202 0203 void LightTableView::setRightZoomFactor(double z) 0204 { 0205 d->rightPreview->layout()->setZoomFactor(z); 0206 } 0207 0208 void LightTableView::slotLeftZoomTo100() 0209 { 0210 d->leftPreview->layout()->toggleFitToWindowOr100(); 0211 } 0212 0213 void LightTableView::slotRightZoomTo100() 0214 { 0215 d->rightPreview->layout()->toggleFitToWindowOr100(); 0216 } 0217 0218 void LightTableView::slotLeftFitToWindow() 0219 { 0220 d->leftPreview->layout()->fitToWindow(); 0221 } 0222 0223 void LightTableView::slotRightFitToWindow() 0224 { 0225 d->rightPreview->layout()->fitToWindow(); 0226 } 0227 0228 double LightTableView::leftZoomMax() const 0229 { 0230 return d->leftPreview->layout()->maxZoomFactor(); 0231 } 0232 0233 double LightTableView::leftZoomMin() const 0234 { 0235 return d->leftPreview->layout()->minZoomFactor(); 0236 } 0237 0238 bool LightTableView::leftMaxZoom() const 0239 { 0240 return d->leftPreview->layout()->atMaxZoom(); 0241 } 0242 0243 bool LightTableView::leftMinZoom() const 0244 { 0245 return d->leftPreview->layout()->atMinZoom(); 0246 } 0247 0248 double LightTableView::rightZoomMax() const 0249 { 0250 return d->rightPreview->layout()->maxZoomFactor(); 0251 } 0252 0253 double LightTableView::rightZoomMin() const 0254 { 0255 return d->rightPreview->layout()->minZoomFactor(); 0256 } 0257 0258 bool LightTableView::rightMaxZoom() const 0259 { 0260 return d->rightPreview->layout()->atMaxZoom(); 0261 } 0262 0263 bool LightTableView::rightMinZoom() const 0264 { 0265 return d->rightPreview->layout()->atMinZoom(); 0266 } 0267 0268 void LightTableView::slotLeftZoomSliderChanged(int size) 0269 { 0270 double zmin = d->leftPreview->layout()->minZoomFactor(); 0271 double zmax = d->leftPreview->layout()->maxZoomFactor(); 0272 double z = DZoomBar::zoomFromSize(size, zmin, zmax); 0273 d->leftPreview->layout()->setZoomFactorSnapped(z); 0274 } 0275 0276 void LightTableView::slotRightZoomSliderChanged(int size) 0277 { 0278 double zmin = d->rightPreview->layout()->minZoomFactor(); 0279 double zmax = d->rightPreview->layout()->maxZoomFactor(); 0280 double z = DZoomBar::zoomFromSize(size, zmin, zmax); 0281 d->rightPreview->layout()->setZoomFactorSnapped(z); 0282 } 0283 0284 void LightTableView::leftReload() 0285 { 0286 d->leftPreview->previewItem()->reload(); 0287 } 0288 0289 void LightTableView::rightReload() 0290 { 0291 d->rightPreview->previewItem()->reload(); 0292 } 0293 0294 void LightTableView::slotLeftContentsMoved(int x, int y) 0295 { 0296 if (d->syncPreview && !leftPreviewLoading()) 0297 { 0298 d->rightPreview->blockSignals(true); 0299 d->rightPreview->setContentsPos(x, y); 0300 d->rightPreview->blockSignals(false); 0301 } 0302 } 0303 0304 void LightTableView::slotRightContentsMoved(int x, int y) 0305 { 0306 if (d->syncPreview && !rightPreviewLoading()) 0307 { 0308 d->leftPreview->blockSignals(true); 0309 d->leftPreview->setContentsPos(x, y); 0310 d->leftPreview->blockSignals(false); 0311 } 0312 } 0313 0314 void LightTableView::slotLeftZoomFactorChanged(double zoom) 0315 { 0316 if (d->syncPreview && !leftPreviewLoading()) 0317 { 0318 d->rightPreview->layout()->blockSignals(true); 0319 d->rightPreview->blockSignals(true); 0320 0321 setRightZoomFactor(zoom); 0322 0323 Q_EMIT signalRightZoomFactorChanged(zoom); 0324 0325 d->rightPreview->blockSignals(false); 0326 d->rightPreview->layout()->blockSignals(false); 0327 } 0328 0329 Q_EMIT signalLeftZoomFactorChanged(zoom); 0330 } 0331 0332 void LightTableView::slotRightZoomFactorChanged(double zoom) 0333 { 0334 if (d->syncPreview && !rightPreviewLoading()) 0335 { 0336 d->leftPreview->layout()->blockSignals(true); 0337 d->leftPreview->blockSignals(true); 0338 0339 setLeftZoomFactor(zoom); 0340 0341 Q_EMIT signalLeftZoomFactorChanged(zoom); 0342 0343 d->leftPreview->blockSignals(false); 0344 d->leftPreview->layout()->blockSignals(false); 0345 } 0346 0347 Q_EMIT signalRightZoomFactorChanged(zoom); 0348 } 0349 0350 ItemInfo LightTableView::leftItemInfo() const 0351 { 0352 return d->leftPreview->getItemInfo(); 0353 } 0354 0355 ItemInfo LightTableView::rightItemInfo() const 0356 { 0357 return d->rightPreview->getItemInfo(); 0358 } 0359 0360 void LightTableView::setLeftItemInfo(const ItemInfo& info) 0361 { 0362 d->leftPreview->setItemInfo(info); 0363 0364 if (info.isNull()) 0365 { 0366 d->leftPreview->showDragAndDropMessage(); 0367 } 0368 } 0369 0370 void LightTableView::setRightItemInfo(const ItemInfo& info) 0371 { 0372 d->rightPreview->setItemInfo(info); 0373 0374 if (info.isNull()) 0375 { 0376 d->rightPreview->showDragAndDropMessage(); 0377 } 0378 } 0379 0380 void LightTableView::slotLeftPreviewLoaded(bool success) 0381 { 0382 checkForSyncPreview(); 0383 slotRightContentsMoved(d->rightPreview->contentsX(), d->rightPreview->contentsY()); 0384 0385 Q_EMIT signalLeftPreviewLoaded(success); 0386 } 0387 0388 void LightTableView::slotRightPreviewLoaded(bool success) 0389 { 0390 checkForSyncPreview(); 0391 slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY()); 0392 0393 Q_EMIT signalRightPreviewLoaded(success); 0394 } 0395 0396 void LightTableView::checkForSyncPreview() 0397 { 0398 if (!d->leftPreview->getItemInfo().isNull() && 0399 !d->rightPreview->getItemInfo().isNull() && 0400 (d->leftPreview->previewItem()->image().size() == d->rightPreview->previewItem()->image().size())) 0401 { 0402 d->syncPreview = true; 0403 } 0404 else 0405 { 0406 d->syncPreview = false; 0407 } 0408 0409 Q_EMIT signalToggleOnSyncPreview(d->syncPreview); 0410 } 0411 0412 void LightTableView::checkForSelection(const ItemInfo& info) 0413 { 0414 QString selected = QString::fromUtf8("QLabel { background-color: %1; }") 0415 .arg(qApp->palette().color(QPalette::Highlight).name()); 0416 0417 QString notSelected = QString::fromUtf8("QLabel { background-color: %1; }") 0418 .arg(qApp->palette().color(QPalette::Base).name()); 0419 0420 if (info.isNull()) 0421 { 0422 d->leftFrame->setStyleSheet(notSelected); 0423 d->rightFrame->setStyleSheet(notSelected); 0424 0425 Q_EMIT signalLeftPreviewSelected(false); 0426 Q_EMIT signalRightPreviewSelected(false); 0427 0428 return; 0429 } 0430 0431 if (!d->leftPreview->getItemInfo().isNull()) 0432 { 0433 bool onLeft = (d->leftPreview->getItemInfo() == info); 0434 d->leftFrame->setStyleSheet(onLeft ? selected : notSelected); 0435 0436 Q_EMIT signalLeftPreviewSelected(onLeft); 0437 } 0438 0439 if (!d->rightPreview->getItemInfo().isNull()) 0440 { 0441 bool onRight = (d->rightPreview->getItemInfo() == info); 0442 d->rightFrame->setStyleSheet(onRight ? selected : notSelected); 0443 0444 Q_EMIT signalRightPreviewSelected(onRight); 0445 } 0446 } 0447 0448 void LightTableView::slotDeleteLeftItem() 0449 { 0450 Q_EMIT signalDeleteItem(d->leftPreview->getItemInfo()); 0451 } 0452 0453 void LightTableView::slotDeleteRightItem() 0454 { 0455 Q_EMIT signalDeleteItem(d->rightPreview->getItemInfo()); 0456 } 0457 0458 bool LightTableView::leftPreviewLoading() const 0459 { 0460 return (d->leftPreview->previewItem()->state() == DImgPreviewItem::Loading); 0461 } 0462 0463 bool LightTableView::rightPreviewLoading() const 0464 { 0465 return (d->rightPreview->previewItem()->state() == DImgPreviewItem::Loading); 0466 } 0467 0468 void LightTableView::toggleFullScreen(bool set) 0469 { 0470 d->leftPreview->toggleFullScreen(set); 0471 d->rightPreview->toggleFullScreen(set); 0472 } 0473 0474 } // namespace Digikam 0475 0476 #include "moc_lighttableview.cpp"