diff --git a/core/utilities/lighttable/lighttablepreview.cpp b/core/utilities/lighttable/lighttablepreview.cpp index 018b1403c4..aec0f5113b 100644 --- a/core/utilities/lighttable/lighttablepreview.cpp +++ b/core/utilities/lighttable/lighttablepreview.cpp @@ -1,164 +1,165 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-21-12 * Description : digiKam light table preview item. * * 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 "lighttablepreview.h" // Qt includes #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "coredb.h" #include "ddragobjects.h" #include "dimg.h" #include "dimgpreviewitem.h" namespace Digikam { LightTablePreview::LightTablePreview(QWidget* const parent) : ItemPreviewView(parent, ItemPreviewView::LightTablePreview) { setDragAndDropEnabled(true); showDragAndDropMessage(); } LightTablePreview::~LightTablePreview() { } void LightTablePreview::setDragAndDropEnabled(bool b) { setAcceptDrops(b); viewport()->setAcceptDrops(b); } void LightTablePreview::showDragAndDropMessage() { if (acceptDrops()) { QString msg = i18n("Drag and drop an image here"); QFontMetrics fontMt(font()); QRect fontRect = fontMt.boundingRect(0, 0, width(), height(), 0, msg); QPixmap pix(fontRect.size()); pix.fill(qApp->palette().color(QPalette::Base)); QPainter p(&pix); p.setPen(QPen(qApp->palette().color(QPalette::Text))); p.drawText(0, 0, pix.width(), pix.height(), Qt::AlignCenter | Qt::TextWordWrap, msg); p.end(); previewItem()->setImage(DImg(pix.toImage())); } } void LightTablePreview::dragEnterEvent(QDragEnterEvent* e) { if (dragEventWrapper(e->mimeData())) { e->accept(); } } void LightTablePreview::dragMoveEvent(QDragMoveEvent* e) { if (dragEventWrapper(e->mimeData())) { e->accept(); } } bool LightTablePreview::dragEventWrapper(const QMimeData* data) const { if (acceptDrops()) { int albumID; QList albumIDs; QList imageIDs; QList urls; if (DItemDrag::decode(data, urls, albumIDs, imageIDs) || - DAlbumDrag::decode(data, urls, albumID) || + DAlbumDrag::decode(data, urls, albumID) || DTagListDrag::canDecode(data)) { return true; } } return false; } void LightTablePreview::dropEvent(QDropEvent* e) { if (acceptDrops()) { int albumID; QList albumIDs; QList imageIDs; QList urls; - if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) + if (DItemDrag::decode(e->mimeData(), urls, albumIDs, imageIDs)) { emit signalDroppedItems(ItemInfoList(imageIDs)); e->accept(); return; } else if (DAlbumDrag::decode(e->mimeData(), urls, albumID)) { QList itemIDs = CoreDbAccess().db()->getItemIDsInAlbum(albumID); emit signalDroppedItems(ItemInfoList(itemIDs)); e->accept(); return; } else if (DTagListDrag::canDecode(e->mimeData())) { QList tagIDs; if (!DTagListDrag::decode(e->mimeData(), tagIDs)) { return; } QList itemIDs = CoreDbAccess().db()->getItemIDsInTag(tagIDs.first(), true); ItemInfoList imageInfoList; emit signalDroppedItems(ItemInfoList(itemIDs)); e->accept(); + return; } } } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttablepreview.h b/core/utilities/lighttable/lighttablepreview.h index 576bf5a94b..bd14c6d6b4 100644 --- a/core/utilities/lighttable/lighttablepreview.h +++ b/core/utilities/lighttable/lighttablepreview.h @@ -1,68 +1,68 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2006-21-12 * Description : digiKam light table preview item. * * 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_LIGHT_TABLE_PREVIEW_H #define DIGIKAM_LIGHT_TABLE_PREVIEW_H // Qt includes #include #include #include #include // Local includes #include "iteminfo.h" #include "itempreviewview.h" namespace Digikam { class LightTablePreview : public ItemPreviewView { Q_OBJECT public: explicit LightTablePreview(QWidget* const parent = nullptr); ~LightTablePreview(); void setDragAndDropEnabled(bool b); void showDragAndDropMessage(); Q_SIGNALS: void signalDroppedItems(const ItemInfoList&); private: - void dragMoveEvent(QDragMoveEvent*) override; + void dragMoveEvent(QDragMoveEvent*) override; void dragEnterEvent(QDragEnterEvent*) override; - void dropEvent(QDropEvent*) override; + void dropEvent(QDropEvent*) override; bool dragEventWrapper(const QMimeData*) const; }; } // namespace Digikam #endif // DIGIKAM_LIGHT_TABLE_PREVIEW_H diff --git a/core/utilities/lighttable/lighttablethumbbar.cpp b/core/utilities/lighttable/lighttablethumbbar.cpp index 08b483447f..ac1dcddb2c 100644 --- a/core/utilities/lighttable/lighttablethumbbar.cpp +++ b/core/utilities/lighttable/lighttablethumbbar.cpp @@ -1,488 +1,488 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-04-11 * Description : light table thumbs bar * * 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 "lighttablethumbbar.h" // Qt includes #include #include #include #include #include #include #include #include // KDE includes #include // Local includes #include "digikam_debug.h" #include "coredb.h" #include "applicationsettings.h" #include "contextmenuhelper.h" #include "itemfiltermodel.h" #include "itemdragdrop.h" #include "fileactionmngr.h" #include "thumbnailloadthread.h" namespace Digikam { template void removeAnyInInterval(Container& list, const T& begin, const T& end) { typename Container::iterator it; for (it = list.begin() ; it != list.end() ; ) { - if ((*it) >= begin && (*it) <= end) + if (((*it) >= begin) && ((*it) <= end)) { it = list.erase(it); } else { ++it; } } } class Q_DECL_HIDDEN LightTableItemListModel : public ItemListModel { public: explicit LightTableItemListModel(QObject* const parent = nullptr) : ItemListModel(parent), m_exclusive(false) { } void clearLightTableState() { m_leftIndexes.clear(); m_rightIndexes.clear(); } void setExclusiveLightTableState(bool exclusive) { m_exclusive = exclusive; } virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const { - if (role == LTLeftPanelRole) + if (role == LTLeftPanelRole) { return m_leftIndexes.contains(index.row()); } else if (role == LTRightPanelRole) { return m_rightIndexes.contains(index.row()); } return ItemListModel::data(index, role); } virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::DisplayRole) { if (!index.isValid()) { return false; } - if (role == LTLeftPanelRole) + if (role == LTLeftPanelRole) { if (m_exclusive) { m_leftIndexes.clear(); } m_leftIndexes << index.row(); return true; } else if (role == LTRightPanelRole) { if (m_exclusive) { m_rightIndexes.clear(); } m_rightIndexes << index.row(); return true; } return ItemListModel::setData(index, value, role); } virtual void imageInfosAboutToBeRemoved(int begin, int end) { removeAnyInInterval(m_leftIndexes, begin, end); removeAnyInInterval(m_rightIndexes, begin, end); } virtual void imageInfosCleared() { clearLightTableState(); } protected: QSet m_leftIndexes; QSet m_rightIndexes; bool m_exclusive; }; class Q_DECL_HIDDEN LightTableThumbBar::Private { public: explicit Private() : navigateByPair(false), imageInfoModel(nullptr), imageFilterModel(nullptr), dragDropHandler(nullptr) { } bool navigateByPair; LightTableItemListModel* imageInfoModel; ItemFilterModel* imageFilterModel; ItemDragDropHandler* dragDropHandler; }; LightTableThumbBar::LightTableThumbBar(QWidget* const parent) : ItemThumbnailBar(parent), d(new Private) { d->imageInfoModel = new LightTableItemListModel(this); // only one is left, only one is right at a time d->imageInfoModel->setExclusiveLightTableState(true); d->imageFilterModel = new ItemFilterModel(this); d->imageFilterModel->setSourceItemModel(d->imageInfoModel); d->imageInfoModel->setWatchFlags(d->imageFilterModel->suggestedWatchFlags()); d->imageInfoModel->setThumbnailLoadThread(ThumbnailLoadThread::defaultIconViewThread()); d->imageFilterModel->setCategorizationMode(ItemSortSettings::NoCategories); d->imageFilterModel->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); d->imageFilterModel->setSortRole((ItemSortSettings::SortRole)ApplicationSettings::instance()->getImageSortOrder()); d->imageFilterModel->setSortOrder((ItemSortSettings::SortOrder)ApplicationSettings::instance()->getImageSorting()); d->imageFilterModel->setAllGroupsOpen(true); // disable filtering out by group, see bug #308948 d->imageFilterModel->sort(0); // an initial sorting is necessary d->dragDropHandler = new ItemDragDropHandler(d->imageInfoModel); d->dragDropHandler->setReadOnlyDrop(true); d->imageInfoModel->setDragDropHandler(d->dragDropHandler); setModels(d->imageInfoModel, d->imageFilterModel); setSelectionMode(QAbstractItemView::SingleSelection); connect(d->dragDropHandler, SIGNAL(itemInfosDropped(QList)), this, SIGNAL(signalDroppedItems(QList))); connect(d->imageInfoModel, SIGNAL(imageInfosAdded(QList)), this, SIGNAL(signalContentChanged())); connect(d->imageInfoModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(signalContentChanged())); connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotSetupChanged())); } LightTableThumbBar::~LightTableThumbBar() { delete d; } void LightTableThumbBar::setItems(const ItemInfoList& list) { foreach (const ItemInfo& info, list) { if (!d->imageInfoModel->hasImage(info)) { d->imageInfoModel->addItemInfo(info); } } } void LightTableThumbBar::slotDockLocationChanged(Qt::DockWidgetArea area) { if ((area == Qt::LeftDockWidgetArea) || (area == Qt::RightDockWidgetArea)) { setFlow(TopToBottom); } else { setFlow(LeftToRight); } scrollTo(currentIndex()); } void LightTableThumbBar::clear() { d->imageInfoModel->clearItemInfos(); emit signalContentChanged(); } void LightTableThumbBar::setNavigateByPair(bool b) { d->navigateByPair = b; } void LightTableThumbBar::showContextMenuOnInfo(QContextMenuEvent* e, const ItemInfo& info) { // temporary actions ---------------------------------- QAction* const leftPanelAction = new QAction(QIcon::fromTheme(QLatin1String("go-previous")), i18n("Show on left panel"), this); QAction* const rightPanelAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), i18n("Show on right panel"), this); QAction* const editAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Edit"), this); QAction* const removeAction = new QAction(QIcon::fromTheme(QLatin1String("window-close")), i18n("Remove item"), this); QAction* const clearAllAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Clear all"), this); leftPanelAction->setEnabled(d->navigateByPair ? false : true); rightPanelAction->setEnabled(d->navigateByPair ? false : true); clearAllAction->setEnabled(countItems() ? true : false); // ---------------------------------------------------- QMenu popmenu(this); ContextMenuHelper cmhelper(&popmenu); cmhelper.addAction(leftPanelAction, true); cmhelper.addAction(rightPanelAction, true); cmhelper.addSeparator(); cmhelper.addAction(editAction); cmhelper.addServicesMenu(QList() << info.fileUrl()); cmhelper.addSeparator(); cmhelper.addLabelsAction(); cmhelper.addSeparator(); cmhelper.addAction(removeAction); cmhelper.addAction(clearAllAction, true); // special action handling -------------------------------- connect(&cmhelper, SIGNAL(signalAssignPickLabel(int)), this, SLOT(slotAssignPickLabel(int))); connect(&cmhelper, SIGNAL(signalAssignColorLabel(int)), this, SLOT(slotAssignColorLabel(int))); connect(&cmhelper, SIGNAL(signalAssignRating(int)), this, SLOT(slotAssignRating(int))); QAction* const choice = cmhelper.exec(e->globalPos()); if (choice) { if (choice == leftPanelAction) { emit signalSetItemOnLeftPanel(info); } else if (choice == rightPanelAction) { emit signalSetItemOnRightPanel(info); } else if (choice == editAction) { emit signalEditItem(info); } else if (choice == removeAction) { emit signalRemoveItem(info); } else if (choice == clearAllAction) { emit signalClearAll(); } } } void LightTableThumbBar::slotColorLabelChanged(const QUrl& url, int color) { assignColorLabel(ItemInfo::fromUrl(url), color); } void LightTableThumbBar::slotPickLabelChanged(const QUrl& url, int pick) { assignPickLabel(ItemInfo::fromUrl(url), pick); } void LightTableThumbBar::slotAssignPickLabel(int pickId) { assignPickLabel(currentInfo(), pickId); } void LightTableThumbBar::slotAssignColorLabel(int colorId) { assignColorLabel(currentInfo(), colorId); } void LightTableThumbBar::slotRatingChanged(const QUrl& url, int rating) { assignRating(ItemInfo::fromUrl(url), rating); } void LightTableThumbBar::slotAssignRating(int rating) { assignRating(currentInfo(), rating); } void LightTableThumbBar::assignPickLabel(const ItemInfo& info, int pickId) { FileActionMngr::instance()->assignPickLabel(info, pickId); } void LightTableThumbBar::assignRating(const ItemInfo& info, int rating) { rating = qMin(RatingMax, qMax(RatingMin, rating)); FileActionMngr::instance()->assignRating(info, rating); } void LightTableThumbBar::assignColorLabel(const ItemInfo& info, int colorId) { FileActionMngr::instance()->assignColorLabel(info, colorId); } void LightTableThumbBar::slotToggleTag(const QUrl& url, int tagID) { toggleTag(ItemInfo::fromUrl(url), tagID); } void LightTableThumbBar::toggleTag(int tagID) { toggleTag(currentInfo(), tagID); } void LightTableThumbBar::toggleTag(const ItemInfo& info, int tagID) { if (!info.isNull()) { if (!info.tagIds().contains(tagID)) { FileActionMngr::instance()->assignTag(info, tagID); } else { FileActionMngr::instance()->removeTag(info, tagID); } } } void LightTableThumbBar::setOnLeftPanel(const ItemInfo& info) { QModelIndex index = d->imageInfoModel->indexForItemInfo(info); // model has exclusiveLightTableState, so any previous index will be reset d->imageInfoModel->setData(index, true, ItemModel::LTLeftPanelRole); viewport()->update(); } void LightTableThumbBar::setOnRightPanel(const ItemInfo& info) { QModelIndex index = d->imageInfoModel->indexForItemInfo(info); // model has exclusiveLightTableState, so any previous index will be reset d->imageInfoModel->setData(index, true, ItemModel::LTRightPanelRole); viewport()->update(); } bool LightTableThumbBar::isOnLeftPanel(const ItemInfo& info) const { return d->imageInfoModel->indexForItemInfo(info).data(ItemModel::LTLeftPanelRole).toBool(); } bool LightTableThumbBar::isOnRightPanel(const ItemInfo& info) const { return d->imageInfoModel->indexForItemInfo(info).data(ItemModel::LTRightPanelRole).toBool(); } QModelIndex LightTableThumbBar::findItemByInfo(const ItemInfo& info) const { if (!info.isNull()) { return d->imageInfoModel->indexForItemInfo(info); } return QModelIndex(); } ItemInfo LightTableThumbBar::findItemByIndex(const QModelIndex& index) const { if (index.isValid()) { return d->imageInfoModel->imageInfo(index); } return ItemInfo(); } void LightTableThumbBar::removeItemByInfo(const ItemInfo& info) { if (info.isNull()) { return; } d->imageInfoModel->removeItemInfo(info); } int LightTableThumbBar::countItems() const { return d->imageInfoModel->rowCount(); } void LightTableThumbBar::paintEvent(QPaintEvent* e) { if (!countItems()) { QPainter p(viewport()); p.setPen(QPen(qApp->palette().color(QPalette::Text))); p.drawText(0, 0, width(), height(), Qt::AlignCenter | Qt::TextWordWrap, i18n("Drag and drop images here")); p.end(); return; } ItemThumbnailBar::paintEvent(e); } void LightTableThumbBar::slotSetupChanged() { d->imageFilterModel->setStringTypeNatural(ApplicationSettings::instance()->isStringTypeNatural()); } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttableview.cpp b/core/utilities/lighttable/lighttableview.cpp index cfdaa4fe9e..cb5c65cb39 100644 --- a/core/utilities/lighttable/lighttableview.cpp +++ b/core/utilities/lighttable/lighttableview.cpp @@ -1,472 +1,474 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-03-05 * Description : a widget to display 2 preview image on * lightable to compare pictures. * * 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 "lighttableview.h" // Qt includes #include #include #include // Local includes #include "digikam_debug.h" #include "dimg.h" #include "dzoombar.h" #include "thumbnailsize.h" #include "lighttablepreview.h" #include "previewlayout.h" #include "dimgpreviewitem.h" namespace Digikam { class Q_DECL_HIDDEN LightTableView::Private { public: explicit Private() : syncPreview(false), grid(nullptr), leftFrame(nullptr), rightFrame(nullptr), leftPreview(nullptr), rightPreview(nullptr) { } bool syncPreview; QGridLayout* grid; - // These labels are used to draw a frame around preview views to identify easily which item has the focus. + /// These labels are used to draw a frame around preview views to identify easily which item has the focus. QLabel* leftFrame; QLabel* rightFrame; LightTablePreview* leftPreview; LightTablePreview* rightPreview; }; LightTableView::LightTableView(QWidget* const parent) : QFrame(parent), d(new Private) { setAttribute(Qt::WA_DeleteOnClose); setFrameStyle(QFrame::NoFrame); setLineWidth(0); d->grid = new QGridLayout(); setLayout(d->grid); d->leftFrame = new QLabel(this); d->leftPreview = new LightTablePreview(this); QVBoxLayout* const llay = new QVBoxLayout(d->leftFrame); llay->addWidget(d->leftPreview); llay->setContentsMargins(3, 3, 3, 3); llay->setSpacing(0); d->rightFrame = new QLabel(this); d->rightPreview = new LightTablePreview(this); QVBoxLayout* const rlay = new QVBoxLayout(d->rightFrame); rlay->addWidget(d->rightPreview); rlay->setContentsMargins(3, 3, 3, 3); rlay->setSpacing(0); d->grid->addWidget(d->leftFrame, 0, 0, 1, 1); d->grid->addWidget(d->rightFrame, 0, 1, 1, 1); d->grid->setColumnStretch(0, 10); d->grid->setColumnStretch(1, 10); d->grid->setRowStretch(0, 10); // Left panel connections ------------------------------------------------ connect(d->leftPreview, SIGNAL(signalPopupTagsView()), this, SIGNAL(signalLeftPopupTagsView())); connect(d->leftPreview->layout(), SIGNAL(zoomFactorChanged(double)), this, SLOT(slotLeftZoomFactorChanged(double))); connect(d->leftPreview, SIGNAL(contentsMoving(int,int)), this, SLOT(slotLeftContentsMoved(int,int))); connect(d->leftPreview, SIGNAL(signalSlideShowCurrent()), this, SIGNAL(signalLeftSlideShowCurrent())); connect(d->leftPreview, SIGNAL(signalDroppedItems(ItemInfoList)), this, SIGNAL(signalLeftDroppedItems(ItemInfoList))); connect(d->leftPreview, SIGNAL(signalPreviewLoaded(bool)), this, SLOT(slotLeftPreviewLoaded(bool))); connect(d->leftPreview, SIGNAL(leftButtonClicked()), this, SIGNAL(signalLeftPanelLeftButtonClicked())); connect(d->leftPreview, SIGNAL(signalDeleteItem()), this, SLOT(slotDeleteLeftItem())); // Right panel connections ------------------------------------------------ connect(d->rightPreview, SIGNAL(signalPopupTagsView()), this, SIGNAL(signalRightPopupTagsView())); connect(d->rightPreview->layout(), SIGNAL(zoomFactorChanged(double)), this, SLOT(slotRightZoomFactorChanged(double))); connect(d->rightPreview, SIGNAL(contentsMoving(int,int)), this, SLOT(slotRightContentsMoved(int,int))); connect(d->rightPreview, SIGNAL(signalDroppedItems(ItemInfoList)), this, SIGNAL(signalRightDroppedItems(ItemInfoList))); connect(d->rightPreview, SIGNAL(signalSlideShowCurrent()), this, SIGNAL(signalRightSlideShowCurrent())); connect(d->rightPreview, SIGNAL(signalPreviewLoaded(bool)), this, SLOT(slotRightPreviewLoaded(bool))); connect(d->rightPreview, SIGNAL(leftButtonClicked()), this, SIGNAL(signalRightPanelLeftButtonClicked())); connect(d->rightPreview, SIGNAL(signalDeleteItem()), this, SLOT(slotDeleteRightItem())); } LightTableView::~LightTableView() { delete d; } void LightTableView::setPreviewSettings(const PreviewSettings& settings) { d->leftPreview->previewItem()->setPreviewSettings(settings); d->rightPreview->previewItem()->setPreviewSettings(settings); } void LightTableView::setSyncPreview(bool sync) { d->syncPreview = sync; // Left panel like a reference to resync preview. + if (d->syncPreview) { slotLeftZoomFactorChanged(d->leftPreview->layout()->zoomFactor()); slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY()); } } void LightTableView::setNavigateByPair(bool b) { d->leftPreview->setDragAndDropEnabled(!b); d->rightPreview->setDragAndDropEnabled(!b); } void LightTableView::slotDecreaseLeftZoom() { d->leftPreview->layout()->decreaseZoom(); } void LightTableView::slotIncreaseLeftZoom() { d->leftPreview->layout()->increaseZoom(); } void LightTableView::slotDecreaseRightZoom() { d->rightPreview->layout()->decreaseZoom(); } void LightTableView::slotIncreaseRightZoom() { d->rightPreview->layout()->increaseZoom(); } void LightTableView::setLeftZoomFactor(double z) { d->leftPreview->layout()->setZoomFactor(z); } void LightTableView::setRightZoomFactor(double z) { d->rightPreview->layout()->setZoomFactor(z); } void LightTableView::slotLeftZoomTo100() { d->leftPreview->layout()->toggleFitToWindowOr100(); } void LightTableView::slotRightZoomTo100() { d->rightPreview->layout()->toggleFitToWindowOr100(); } void LightTableView::slotLeftFitToWindow() { d->leftPreview->layout()->fitToWindow(); } void LightTableView::slotRightFitToWindow() { d->rightPreview->layout()->fitToWindow(); } double LightTableView::leftZoomMax() const { return d->leftPreview->layout()->maxZoomFactor(); } double LightTableView::leftZoomMin() const { return d->leftPreview->layout()->minZoomFactor(); } bool LightTableView::leftMaxZoom() const { return d->leftPreview->layout()->atMaxZoom(); } bool LightTableView::leftMinZoom() const { return d->leftPreview->layout()->atMinZoom(); } double LightTableView::rightZoomMax() const { return d->rightPreview->layout()->maxZoomFactor(); } double LightTableView::rightZoomMin() const { return d->rightPreview->layout()->minZoomFactor(); } bool LightTableView::rightMaxZoom() const { return d->rightPreview->layout()->atMaxZoom(); } bool LightTableView::rightMinZoom() const { return d->rightPreview->layout()->atMinZoom(); } void LightTableView::slotLeftZoomSliderChanged(int size) { double zmin = d->leftPreview->layout()->minZoomFactor(); double zmax = d->leftPreview->layout()->maxZoomFactor(); double z = DZoomBar::zoomFromSize(size, zmin, zmax); d->leftPreview->layout()->setZoomFactorSnapped(z); } void LightTableView::slotRightZoomSliderChanged(int size) { double zmin = d->rightPreview->layout()->minZoomFactor(); double zmax = d->rightPreview->layout()->maxZoomFactor(); double z = DZoomBar::zoomFromSize(size, zmin, zmax); d->rightPreview->layout()->setZoomFactorSnapped(z); } void LightTableView::leftReload() { d->leftPreview->previewItem()->reload(); } void LightTableView::rightReload() { d->rightPreview->previewItem()->reload(); } void LightTableView::slotLeftContentsMoved(int x, int y) { if (d->syncPreview && !leftPreviewLoading()) { d->rightPreview->blockSignals(true); d->rightPreview->setContentsPos(x, y); d->rightPreview->blockSignals(false); } } void LightTableView::slotRightContentsMoved(int x, int y) { if (d->syncPreview && !rightPreviewLoading()) { d->leftPreview->blockSignals(true); d->leftPreview->setContentsPos(x, y); d->leftPreview->blockSignals(false); } } void LightTableView::slotLeftZoomFactorChanged(double zoom) { if (d->syncPreview && !leftPreviewLoading()) { d->rightPreview->layout()->blockSignals(true); d->rightPreview->blockSignals(true); setRightZoomFactor(zoom); emit signalRightZoomFactorChanged(zoom); d->rightPreview->blockSignals(false); d->rightPreview->layout()->blockSignals(false); } emit signalLeftZoomFactorChanged(zoom); } void LightTableView::slotRightZoomFactorChanged(double zoom) { if (d->syncPreview && !rightPreviewLoading()) { d->leftPreview->layout()->blockSignals(true); d->leftPreview->blockSignals(true); setLeftZoomFactor(zoom); emit signalLeftZoomFactorChanged(zoom); d->leftPreview->blockSignals(false); d->leftPreview->layout()->blockSignals(false); } emit signalRightZoomFactorChanged(zoom); } ItemInfo LightTableView::leftItemInfo() const { return d->leftPreview->getItemInfo(); } ItemInfo LightTableView::rightItemInfo() const { return d->rightPreview->getItemInfo(); } void LightTableView::setLeftItemInfo(const ItemInfo& info) { d->leftPreview->setItemInfo(info); if (info.isNull()) { d->leftPreview->showDragAndDropMessage(); } } void LightTableView::setRightItemInfo(const ItemInfo& info) { d->rightPreview->setItemInfo(info); if (info.isNull()) { d->rightPreview->showDragAndDropMessage(); } } void LightTableView::slotLeftPreviewLoaded(bool success) { checkForSyncPreview(); slotRightContentsMoved(d->rightPreview->contentsX(), d->rightPreview->contentsY()); emit signalLeftPreviewLoaded(success); } void LightTableView::slotRightPreviewLoaded(bool success) { checkForSyncPreview(); slotLeftContentsMoved(d->leftPreview->contentsX(), d->leftPreview->contentsY()); emit signalRightPreviewLoaded(success); } void LightTableView::checkForSyncPreview() { if (!d->leftPreview->getItemInfo().isNull() && !d->rightPreview->getItemInfo().isNull() && - d->leftPreview->previewItem()->image().size() == d->rightPreview->previewItem()->image().size()) + (d->leftPreview->previewItem()->image().size() == d->rightPreview->previewItem()->image().size())) { d->syncPreview = true; } else { d->syncPreview = false; } emit signalToggleOnSyncPreview(d->syncPreview); } void LightTableView::checkForSelection(const ItemInfo& info) { QString selected = QString::fromUtf8("QLabel { background-color: %1; }") .arg(qApp->palette().color(QPalette::Highlight).name()); QString notSelected = QString::fromUtf8("QLabel { background-color: %1; }") .arg(qApp->palette().color(QPalette::Base).name()); if (info.isNull()) { d->leftFrame->setStyleSheet(notSelected); d->rightFrame->setStyleSheet(notSelected); + return; } if (!d->leftPreview->getItemInfo().isNull()) { bool onLeft = (d->leftPreview->getItemInfo() == info); d->leftFrame->setStyleSheet(onLeft ? selected : notSelected); } if (!d->rightPreview->getItemInfo().isNull()) { bool onRight = (d->rightPreview->getItemInfo() == info); d->rightFrame->setStyleSheet(onRight ? selected : notSelected); } } void LightTableView::slotDeleteLeftItem() { emit signalDeleteItem(d->leftPreview->getItemInfo()); } void LightTableView::slotDeleteRightItem() { emit signalDeleteItem(d->rightPreview->getItemInfo()); } bool LightTableView::leftPreviewLoading() const { return (d->leftPreview->previewItem()->state() == DImgPreviewItem::Loading); } bool LightTableView::rightPreviewLoading() const { return (d->rightPreview->previewItem()->state() == DImgPreviewItem::Loading); } void LightTableView::toggleFullScreen(bool set) { d->leftPreview->toggleFullScreen(set); d->rightPreview->toggleFullScreen(set); } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttablewindow.cpp b/core/utilities/lighttable/lighttablewindow.cpp index 72ee4f725e..84794f78e0 100644 --- a/core/utilities/lighttable/lighttablewindow.cpp +++ b/core/utilities/lighttable/lighttablewindow.cpp @@ -1,1121 +1,1125 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-03-05 * Description : digiKam light table GUI * * 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 "lighttablewindow_p.h" namespace Digikam { LightTableWindow* LightTableWindow::m_instance = nullptr; LightTableWindow* LightTableWindow::lightTableWindow() { if (!m_instance) { new LightTableWindow(); } return m_instance; } bool LightTableWindow::lightTableWindowCreated() { return m_instance; } LightTableWindow::LightTableWindow() : DXmlGuiWindow(nullptr), d(new Private) { setConfigGroupName(QLatin1String("LightTable Settings")); setXMLFile(QLatin1String("lighttablewindowui5.rc")); m_instance = this; setWindowFlags(Qt::Window); setCaption(i18n("Light Table")); + // We don't want to be deleted on close + setAttribute(Qt::WA_DeleteOnClose, false); setFullScreenOptions(FS_LIGHTTABLE); // -- Build the GUI ------------------------------- setupUserArea(); setupActions(); setupStatusBar(); // ------------------------------------------------ setupConnections(); slotColorManagementOptionsChanged(); readSettings(); d->leftSideBar->populateTags(); d->rightSideBar->populateTags(); applySettings(); setAutoSaveSettings(configGroupName(), true); } LightTableWindow::~LightTableWindow() { m_instance = nullptr; delete d->thumbView; delete d->rightSideBar; delete d->leftSideBar; delete d; } void LightTableWindow::refreshView() { d->leftSideBar->refreshTagsView(); d->rightSideBar->refreshTagsView(); } void LightTableWindow::closeEvent(QCloseEvent* e) { if (!e) { return; } if (d->clearOnCloseAction->isChecked()) { slotClearItemsList(); } // There is one nasty habit with the thumbnail bar if it is floating: it // doesn't close when the parent window does, so it needs to be manually // closed. If the light table is opened again, its original state needs to // be restored. // This only needs to be done when closing a visible window and not when // destroying a closed window, since the latter case will always report that // the thumbnail bar isn't visible. if (isVisible()) { d->barViewDock->hide(); } writeSettings(); DXmlGuiWindow::closeEvent(e); } void LightTableWindow::showEvent(QShowEvent*) { // Restore the visibility of the thumbbar and start autosaving again. + d->barViewDock->restoreVisibility(); } /** * Deal with items dropped onto the thumbbar (e.g. from the Album view) */ void LightTableWindow::slotThumbbarDroppedItems(const QList& list) { // Setting the third parameter of loadItemInfos to true // means that the images are added to the presently available images. loadItemInfos(ItemInfoList(list), ItemInfo(), true); } /** * We get here either * - via CTRL+L (from the albumview) * a) digikamapp.cpp: CTRL+key_L leads to slotImageLightTable()) * b) digikamview.cpp: void ItemIconView::slotImageLightTable() * calls d->iconView->insertToLightTable(list, info); * c) albumiconview.cpp: AlbumIconView::insertToLightTable * calls ltview->loadItemInfos(list, current); * - via drag&drop, i.e. calls issued by the ...Dropped... routines */ void LightTableWindow::loadItemInfos(const ItemInfoList& list, const ItemInfo& givenItemInfoCurrent, bool addTo) { // Clear all items before adding new images to the light table. qCDebug(DIGIKAM_GENERAL_LOG) << "Clearing LT" << (!addTo); if (!addTo) { slotClearItemsList(); } ItemInfoList l = list; ItemInfo imageInfoCurrent = givenItemInfoCurrent; if (imageInfoCurrent.isNull() && !l.isEmpty()) { imageInfoCurrent = l.first(); } d->thumbView->setItems(l); QModelIndex index = d->thumbView->findItemByInfo(imageInfoCurrent); if (index.isValid()) { d->thumbView->setCurrentIndex(index); } else { d->thumbView->setCurrentWhenAvailable(imageInfoCurrent.id()); } } bool LightTableWindow::isEmpty() const { return (d->thumbView->countItems() == 0); } void LightTableWindow::slotRefreshStatusBar() { d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18np("%1 item on Light Table", "%1 items on Light Table", d->thumbView->countItems())); } void LightTableWindow::slotFileChanged(const QString& path) { QUrl url = QUrl::fromLocalFile(path); // NOTE: Thumbbar handle change through ItemCategorizedView if (!d->previewView->leftItemInfo().isNull()) { if (d->previewView->leftItemInfo().fileUrl() == url) { d->previewView->leftReload(); d->leftSideBar->itemChanged(d->previewView->leftItemInfo()); } } if (!d->previewView->rightItemInfo().isNull()) { if (d->previewView->rightItemInfo().fileUrl() == url) { d->previewView->rightReload(); d->rightSideBar->itemChanged(d->previewView->rightItemInfo()); } } } void LightTableWindow::slotLeftPanelLeftButtonClicked() { if (d->navigateByPairAction->isChecked()) { return; } d->thumbView->setCurrentInfo(d->previewView->leftItemInfo()); } void LightTableWindow::slotRightPanelLeftButtonClicked() { // With navigate by pair option, only the left panel can be selected. if (d->navigateByPairAction->isChecked()) { return; } d->thumbView->setCurrentInfo(d->previewView->rightItemInfo()); } void LightTableWindow::slotLeftPreviewLoaded(bool b) { d->leftZoomBar->setEnabled(b); d->leftFileName->setAdjustedText(); if (b) { d->leftFileName->setAdjustedText(d->previewView->leftItemInfo().name()); d->previewView->checkForSelection(d->thumbView->currentInfo()); d->thumbView->setOnLeftPanel(d->previewView->leftItemInfo()); QModelIndex index = d->thumbView->findItemByInfo(d->previewView->leftItemInfo()); if (d->navigateByPairAction->isChecked() && index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(next)); slotSetItemOnRightPanel(d->thumbView->findItemByIndex(next)); } else { QModelIndex first = d->thumbView->firstIndex(); slotSetItemOnRightPanel(first.isValid() ? d->thumbView->findItemByIndex(first) : ItemInfo()); } } } } void LightTableWindow::slotRightPreviewLoaded(bool b) { d->rightZoomBar->setEnabled(b); d->rightFileName->setAdjustedText(); if (b) { d->rightFileName->setAdjustedText(d->previewView->rightItemInfo().name()); d->previewView->checkForSelection(d->thumbView->currentInfo()); d->thumbView->setOnRightPanel(d->previewView->rightItemInfo()); QModelIndex index = d->thumbView->findItemByInfo(d->previewView->rightItemInfo()); if (index.isValid()) { d->thumbView->setOnRightPanel(d->thumbView->findItemByIndex(index)); } } } void LightTableWindow::slotItemSelected(const ItemInfo& info) { bool hasInfo = !info.isNull(); d->setItemLeftAction->setEnabled(hasInfo); d->setItemRightAction->setEnabled(hasInfo); d->editItemAction->setEnabled(hasInfo); d->removeItemAction->setEnabled(hasInfo); d->clearListAction->setEnabled(hasInfo); d->fileDeleteAction->setEnabled(hasInfo); d->fileDeleteFinalAction->setEnabled(hasInfo); d->backwardAction->setEnabled(hasInfo); d->forwardAction->setEnabled(hasInfo); d->firstAction->setEnabled(hasInfo); d->lastAction->setEnabled(hasInfo); d->syncPreviewAction->setEnabled(hasInfo); d->navigateByPairAction->setEnabled(hasInfo); d->slideShowAction->setEnabled(hasInfo); if (hasInfo) { QModelIndex curr = d->thumbView->findItemByInfo(info); if (curr.isValid()) { if (!d->thumbView->previousIndex(curr).isValid()) { d->firstAction->setEnabled(false); } if (!d->thumbView->nextIndex(curr).isValid()) { d->lastAction->setEnabled(false); } - if (d->navigateByPairAction->isChecked()) + if (d->navigateByPairAction->isChecked()) { d->setItemLeftAction->setEnabled(false); d->setItemRightAction->setEnabled(false); d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); } else if (d->autoLoadOnRightPanel && !d->thumbView->isOnLeftPanel(info)) { d->thumbView->setOnRightPanel(info); slotSetItemOnRightPanel(info); } } } d->previewView->checkForSelection(info); } /** * Deal with one (or more) items dropped onto the left panel */ void LightTableWindow::slotLeftDroppedItems(const ItemInfoList& list) { ItemInfo info = list.first(); // add the image to the existing images loadItemInfos(list, info, true); // We will check if first item from list is already stored in thumbbar // Note that the thumbbar stores all ItemInfo reference // in memory for preview object. QModelIndex index = d->thumbView->findItemByInfo(info); if (index.isValid()) { slotSetItemOnLeftPanel(info); } } /** * Deal with one (or more) items dropped onto the right panel */ void LightTableWindow::slotRightDroppedItems(const ItemInfoList& list) { ItemInfo info = list.first(); // add the image to the existing images loadItemInfos(list, info, true); // We will check if first item from list is already stored in thumbbar // Note that the thumbbar stores all ItemInfo reference // in memory for preview object. QModelIndex index = d->thumbView->findItemByInfo(info); if (index.isValid()) { slotSetItemOnRightPanel(info); // Make this item the current one. d->thumbView->setCurrentInfo(info); } } /** * Set the images for the left and right panel. */ void LightTableWindow::setLeftRightItems(const ItemInfoList& list, bool addTo) { ItemInfoList l = list; if (l.count() == 0) { return; } - ItemInfo info = l.first(); + ItemInfo info = l.first(); QModelIndex index = d->thumbView->findItemByInfo(info); - if (l.count() == 1 && !addTo) + if ((l.count() == 1) && !addTo) { // Just one item; this is used for the left panel. d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); d->thumbView->setCurrentInfo(info); + return; } if (index.isValid()) { // The first item is used for the left panel. if (!addTo) { d->thumbView->setOnLeftPanel(info); slotSetItemOnLeftPanel(info); } // The subsequent item is used for the right panel. QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid() && !addTo) { ItemInfo nextInf = d->thumbView->findItemByIndex(next); d->thumbView->setOnRightPanel(nextInf); slotSetItemOnRightPanel(nextInf); if (!d->navigateByPairAction->isChecked()) { d->thumbView->setCurrentInfo(nextInf); } } // If navigate by pairs is active, the left panel item is selected. // (Fixes parts of bug #150296) if (d->navigateByPairAction->isChecked()) { d->thumbView->setCurrentInfo(info); } } } void LightTableWindow::slotSetItemLeft() { if (!d->thumbView->currentInfo().isNull()) { slotSetItemOnLeftPanel(d->thumbView->currentInfo()); } } void LightTableWindow::slotSetItemRight() { if (!d->thumbView->currentInfo().isNull()) { slotSetItemOnRightPanel(d->thumbView->currentInfo()); } } void LightTableWindow::slotSetItemOnLeftPanel(const ItemInfo& info) { d->previewView->setLeftItemInfo(info); if (!info.isNull()) { d->leftSideBar->itemChanged(info); } else { d->leftSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotSetItemOnRightPanel(const ItemInfo& info) { d->previewView->setRightItemInfo(info); if (!info.isNull()) { d->rightSideBar->itemChanged(info); } else { d->rightSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotClearItemsList() { if (!d->previewView->leftItemInfo().isNull()) { d->previewView->setLeftItemInfo(); d->leftSideBar->slotNoCurrentItem(); } if (!d->previewView->rightItemInfo().isNull()) { d->previewView->setRightItemInfo(); d->rightSideBar->slotNoCurrentItem(); } d->thumbView->clear(); } void LightTableWindow::slotDeleteItem() { deleteItem(false); } void LightTableWindow::slotDeleteItem(const ItemInfo& info) { deleteItem(info, false); } void LightTableWindow::slotDeleteFinalItem() { deleteItem(true); } void LightTableWindow::slotDeleteFinalItem(const ItemInfo& info) { deleteItem(info, true); } void LightTableWindow::deleteItem(bool permanently) { if (!d->thumbView->currentInfo().isNull()) { deleteItem(d->thumbView->currentInfo(), permanently); } } void LightTableWindow::deleteItem(const ItemInfo& info, bool permanently) { QUrl u = info.fileUrl(); PAlbum* const palbum = AlbumManager::instance()->findPAlbum(u.adjusted(QUrl::RemoveFilename)); if (!palbum) { return; } qCDebug(DIGIKAM_GENERAL_LOG) << "Item to delete: " << u; bool useTrash; bool preselectDeletePermanently = permanently; DeleteDialog dialog(this); QList urlList; urlList.append(u); if (!dialog.confirmDeleteList(urlList, DeleteDialogMode::Files, preselectDeletePermanently ? DeleteDialogMode::NoChoiceDeletePermanently : DeleteDialogMode::NoChoiceTrash)) { return; } useTrash = !dialog.shouldDelete(); DIO::del(info, useTrash); } void LightTableWindow::slotRemoveItem() { if (!d->thumbView->currentInfo().isNull()) { slotRemoveItem(d->thumbView->currentInfo()); } } void LightTableWindow::slotRemoveItem(const ItemInfo& info) { /* if (!d->previewView->leftItemInfo().isNull()) { if (d->previewView->leftItemInfo() == info) { d->previewView->setLeftItemInfo(); d->leftSideBar->slotNoCurrentItem(); } } if (!d->previewView->rightItemInfo().isNull()) { if (d->previewView->rightItemInfo() == info) { d->previewView->setRightItemInfo(); d->rightSideBar->slotNoCurrentItem(); } } d->thumbView->removeItemByInfo(info); d->thumbView->setSelected(d->thumbView->currentItem()); */ // When either the image from the left or right panel is removed, // there are various situations to account for. // To describe them, 4 images A B C D are used // and the subscript _L and _ R mark the currently // active item on the left and right panel ItemInfo new_linfo; ItemInfo new_rinfo; bool leftPanelActive = false; ItemInfo curr_linfo = d->previewView->leftItemInfo(); ItemInfo curr_rinfo = d->previewView->rightItemInfo(); qint64 infoId = info.id(); // First determine the next images to the current left and right image: ItemInfo next_linfo; ItemInfo next_rinfo; if (!curr_linfo.isNull()) { QModelIndex index = d->thumbView->findItemByInfo(curr_linfo); if (index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { next_linfo = d->thumbView->findItemByIndex(next); } } } if (!curr_rinfo.isNull()) { QModelIndex index = d->thumbView->findItemByInfo(curr_rinfo); if (index.isValid()) { QModelIndex next = d->thumbView->nextIndex(index); if (next.isValid()) { next_rinfo = d->thumbView->findItemByIndex(next); } } } d->thumbView->removeItemByInfo(info); // Make sure that next_linfo and next_rinfo are still available: if (!d->thumbView->findItemByInfo(next_linfo).isValid()) { next_linfo = ItemInfo(); } if (!d->thumbView->findItemByInfo(next_rinfo).isValid()) { next_rinfo = ItemInfo(); } // removal of the left panel item? if (!curr_linfo.isNull()) { if (curr_linfo.id() == infoId) { leftPanelActive = true; // Delete the item A_L of the left panel: // 1) A_L B_R C D -> B_L C_R D // 2) A_L B C_R D -> B C_L D_R // 3) A_L B C D_R -> B_R C D_L // 4) A_L B_R -> A_L // some more corner cases: // 5) A B_L C_R D -> A C_L D_R // 6) A B_L C_R -> A_R C_L // 7) A_LR B C D -> B_L C_R D (does not yet work) // I.e. in 3) we wrap around circularly. // When removing the left panel image, // put the right panel image into the left panel. // Check if this one is not the same (i.e. also removed). if (!curr_rinfo.isNull()) { if (curr_rinfo.id() != infoId) { new_linfo = curr_rinfo; // Set the right panel to the next image: new_rinfo = next_rinfo; // set the right panel active, but not in pair mode if (!d->navigateByPairAction->isChecked()) { leftPanelActive = false; } } } } } // removal of the right panel item? if (!curr_rinfo.isNull()) { if (curr_rinfo.id() == infoId) { // Leave the left panel as the current one new_linfo = curr_linfo; // Set the right panel to the next image new_rinfo = next_rinfo; } } // Now we deal with the corner cases, where no left or right item exists. // If the right panel would be set, but not the left-one, then swap if (new_linfo.isNull() && !new_rinfo.isNull()) { new_linfo = new_rinfo; new_rinfo = ItemInfo(); leftPanelActive = true; } if (new_linfo.isNull()) { if (d->thumbView->countItems() > 0) { QModelIndex first = d->thumbView->firstIndex(); - new_linfo = d->thumbView->findItemByIndex(first); + new_linfo = d->thumbView->findItemByIndex(first); } } // Make sure that new_linfo and new_rinfo exist. // This addresses a crash occurring if the last image is removed // in the navigate by pairs mode. if (!d->thumbView->findItemByInfo(new_linfo).isValid()) { new_linfo = ItemInfo(); } if (!d->thumbView->findItemByInfo(new_rinfo).isValid()) { new_rinfo = ItemInfo(); } // no right item defined? if (new_rinfo.isNull()) { // If there are at least two items, we can find reasonable right image. if (d->thumbView->countItems() > 1) { // See if there is an item next to the left one: QModelIndex index = d->thumbView->findItemByInfo(new_linfo); QModelIndex next; if (index.isValid()) { next = d->thumbView->nextIndex(index); } if (next.isValid()) { new_rinfo = d->thumbView->findItemByIndex(next); } else { // If there is no item to the right of new_linfo // then we can choose the first item for new_rinfo // (as we made sure that there are at least two items) QModelIndex first = d->thumbView->firstIndex(); new_rinfo = d->thumbView->findItemByIndex(first); } } } // Check if left and right are set to the same if (!new_linfo.isNull() && !new_rinfo.isNull()) { if (new_linfo.id() == new_rinfo.id()) { // Only keep the left one new_rinfo = ItemInfo(); } } // If the right panel would be set, but not the left-one, then swap // (note that this has to be done here again!) if (new_linfo.isNull() && !new_rinfo.isNull()) { new_linfo = new_rinfo; new_rinfo = ItemInfo(); leftPanelActive = true; } // set the image for the left panel if (!new_linfo.isNull()) { d->thumbView->setOnLeftPanel(new_linfo); slotSetItemOnLeftPanel(new_linfo); // make this the selected item if the left was active before if (leftPanelActive) { d->thumbView->setCurrentInfo(new_linfo); } } else { d->previewView->setLeftItemInfo(); d->leftSideBar->slotNoCurrentItem(); } // set the image for the right panel if (!new_rinfo.isNull()) { d->thumbView->setOnRightPanel(new_rinfo); slotSetItemOnRightPanel(new_rinfo); // make this the selected item if the left was active before if (!leftPanelActive) { d->thumbView->setCurrentInfo(new_rinfo); } } else { d->previewView->setRightItemInfo(); d->rightSideBar->slotNoCurrentItem(); } } void LightTableWindow::slotLeftZoomFactorChanged(double zoom) { double zmin = d->previewView->leftZoomMin(); double zmax = d->previewView->leftZoomMax(); d->leftZoomBar->setZoom(zoom, zmin, zmax); d->leftZoomPlusAction->setEnabled(!d->previewView->leftMaxZoom()); d->leftZoomMinusAction->setEnabled(!d->previewView->leftMinZoom()); } void LightTableWindow::slotRightZoomFactorChanged(double zoom) { double zmin = d->previewView->rightZoomMin(); double zmax = d->previewView->rightZoomMax(); d->rightZoomBar->setZoom(zoom, zmin, zmax); d->rightZoomPlusAction->setEnabled(!d->previewView->rightMaxZoom()); d->rightZoomMinusAction->setEnabled(!d->previewView->rightMinZoom()); } void LightTableWindow::slotToggleSyncPreview() { d->previewView->setSyncPreview(d->syncPreviewAction->isChecked()); } void LightTableWindow::slotToggleOnSyncPreview(bool t) { d->syncPreviewAction->setEnabled(t); if (!t) { d->syncPreviewAction->setChecked(false); } else { if (d->autoSyncPreview) { d->syncPreviewAction->setChecked(true); } } } void LightTableWindow::slotBackward() { d->thumbView->toPreviousIndex(); } void LightTableWindow::slotForward() { d->thumbView->toNextIndex(); } void LightTableWindow::slotFirst() { d->thumbView->toFirstIndex(); } void LightTableWindow::slotLast() { d->thumbView->toLastIndex(); } void LightTableWindow::slotToggleNavigateByPair() { d->thumbView->setNavigateByPair(d->navigateByPairAction->isChecked()); d->previewView->setNavigateByPair(d->navigateByPairAction->isChecked()); slotItemSelected(d->thumbView->currentInfo()); } void LightTableWindow::slotComponentsInfo() { showDigikamComponentsInfo(); } void LightTableWindow::slotDBStat() { showDigikamDatabaseStat(); } void LightTableWindow::moveEvent(QMoveEvent* e) { Q_UNUSED(e) emit signalWindowHasMoved(); } void LightTableWindow::toggleTag(int tagID) { d->thumbView->toggleTag(tagID); } void LightTableWindow::slotAssignPickLabel(int pickId) { d->thumbView->slotAssignPickLabel(pickId); } void LightTableWindow::slotAssignColorLabel(int colorId) { d->thumbView->slotAssignColorLabel(colorId); } void LightTableWindow::slotAssignRating(int rating) { d->thumbView->slotAssignRating(rating); } void LightTableWindow::showSideBars(bool visible) { if (visible) { d->leftSideBar->restore(); d->rightSideBar->restore(); } else { d->leftSideBar->backup(); d->rightSideBar->backup(); } } void LightTableWindow::slotToggleLeftSideBar() { d->leftSideBar->isExpanded() ? d->leftSideBar->shrink() : d->leftSideBar->expand(); } void LightTableWindow::slotToggleRightSideBar() { d->rightSideBar->isExpanded() ? d->rightSideBar->shrink() : d->rightSideBar->expand(); } void LightTableWindow::slotPreviousLeftSideBarTab() { d->leftSideBar->activePreviousTab(); } void LightTableWindow::slotNextLeftSideBarTab() { d->leftSideBar->activeNextTab(); } void LightTableWindow::slotPreviousRightSideBarTab() { d->rightSideBar->activePreviousTab(); } void LightTableWindow::slotNextRightSideBarTab() { d->rightSideBar->activeNextTab(); } void LightTableWindow::customizedFullScreenMode(bool set) { showStatusBarAction()->setEnabled(!set); toolBarMenuAction()->setEnabled(!set); showMenuBarAction()->setEnabled(!set); d->showBarAction->setEnabled(!set); d->previewView->toggleFullScreen(set); } void LightTableWindow::slotFileWithDefaultApplication() { if (!d->thumbView->currentInfo().isNull()) { DFileOperations::openFilesWithDefaultApplication(QList() << d->thumbView->currentInfo().fileUrl()); } } void LightTableWindow::slotRightSideBarActivateTitles() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void LightTableWindow::slotRightSideBarActivateComments() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void LightTableWindow::slotRightSideBarActivateAssignedTags() { d->rightSideBar->setActiveTab(d->rightSideBar->imageDescEditTab()); d->rightSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void LightTableWindow::slotLeftSideBarActivateTitles() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->setFocusToTitlesEdit(); } void LightTableWindow::slotLeftSideBarActivateComments() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->setFocusToCommentsEdit(); } void LightTableWindow::slotLeftSideBarActivateAssignedTags() { d->leftSideBar->setActiveTab(d->leftSideBar->imageDescEditTab()); d->leftSideBar->imageDescEditTab()->activateAssignedTagsButton(); } void LightTableWindow::slotToggleColorManagedView() { if (!IccSettings::instance()->isEnabled()) { return; } bool cmv = !IccSettings::instance()->settings().useManagedPreviews; IccSettings::instance()->setUseManagedPreviews(cmv); } DInfoInterface* LightTableWindow::infoIface(DPluginAction* const ac) { ApplicationSettings::OperationType aset = ApplicationSettings::Unspecified; switch (ac->actionCategory()) { case DPluginAction::GenericExport: case DPluginAction::GenericImport: aset = ApplicationSettings::ImportExport; break; case DPluginAction::GenericMetadata: aset = ApplicationSettings::Metadata; break; case DPluginAction::GenericTool: aset = ApplicationSettings::Tools; break; case DPluginAction::GenericView: aset = ApplicationSettings::Slideshow; break; default: break; } DBInfoIface* const iface = new DBInfoIface(this, d->thumbView->allUrls(), aset); connect(iface, SIGNAL(signalImportedImage(QUrl)), this, SLOT(slotImportedImagefromScanner(QUrl))); return iface; } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttablewindow_config.cpp b/core/utilities/lighttable/lighttablewindow_config.cpp index 45144c55b0..5397dfa876 100644 --- a/core/utilities/lighttable/lighttablewindow_config.cpp +++ b/core/utilities/lighttable/lighttablewindow_config.cpp @@ -1,112 +1,114 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-11-22 * Description : digiKam light table - Configure * * 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 "lighttablewindow_p.h" namespace Digikam { void LightTableWindow::slotSetup() { Setup::execDialog(this); } void LightTableWindow::slotColorManagementOptionsChanged() { ICCSettingsContainer settings = IccSettings::instance()->settings(); d->viewCMViewAction->blockSignals(true); d->viewCMViewAction->setEnabled(settings.enableCM); d->viewCMViewAction->setChecked(settings.useManagedPreviews); d->viewCMViewAction->blockSignals(false); } void LightTableWindow::slotThemeChanged() { d->previewView->checkForSelection(d->previewView->leftItemInfo()); d->previewView->checkForSelection(d->previewView->rightItemInfo()); } void LightTableWindow::slotApplicationSettingsChanged() { d->leftSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); d->rightSideBar->setStyle(ApplicationSettings::instance()->getSidebarTitleStyle()); /// @todo Which part of the settings has to be reloaded? // d->rightSideBar->applySettings(); d->previewView->setPreviewSettings(ApplicationSettings::instance()->getPreviewSettings()); } void LightTableWindow::readSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->hSplitter->restoreState(group, QLatin1String("Horizontal Splitter State")); d->barViewDock->setShouldBeVisible(group.readEntry(QLatin1String("Show Thumbbar"), true)); d->navigateByPairAction->setChecked(group.readEntry(QLatin1String("Navigate By Pair"), false)); slotToggleNavigateByPair(); d->leftSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Left Sidebar"))); d->leftSideBar->loadState(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->loadState(); readFullScreenSettings(group); } void LightTableWindow::writeSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->hSplitter->saveState(group, QLatin1String("Horizontal Splitter State")); group.writeEntry(QLatin1String("Show Thumbbar"), d->barViewDock->shouldBeVisible()); group.writeEntry(QLatin1String("Navigate By Pair"), d->navigateByPairAction->isChecked()); group.writeEntry(QLatin1String("Clear On Close"), d->clearOnCloseAction->isChecked()); d->leftSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Left Sidebar"))); d->leftSideBar->saveState(); d->rightSideBar->setConfigGroup(KConfigGroup(&group, QLatin1String("Right Sidebar"))); d->rightSideBar->saveState(); config->sync(); } void LightTableWindow::applySettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup group = config->group(configGroupName()); d->autoLoadOnRightPanel = group.readEntry(QLatin1String("Auto Load Right Panel"), true); d->autoSyncPreview = group.readEntry(QLatin1String("Auto Sync Preview"), true); d->clearOnCloseAction->setChecked(group.readEntry(QLatin1String("Clear On Close"), false)); slotApplicationSettingsChanged(); // Restore full screen Mode + readFullScreenSettings(group); // NOTE: Image orientation settings in thumbbar is managed by image model. + refreshView(); } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttablewindow_p.h b/core/utilities/lighttable/lighttablewindow_p.h index 9e0ef5fdc3..1154355772 100644 --- a/core/utilities/lighttable/lighttablewindow_p.h +++ b/core/utilities/lighttable/lighttablewindow_p.h @@ -1,206 +1,206 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-03-05 * Description : digiKam light table GUI * * 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. * * ============================================================ */ #ifndef DIGIKAM_LIGHT_TABLE_WINDOW_PRIVATE_H #define DIGIKAM_LIGHT_TABLE_WINDOW_PRIVATE_H #include "lighttablewindow.h" // Qt includes #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include // Local includes #include "digikam_globals.h" #include "itempropertiessidebardb.h" #include "statusprogressbar.h" #include "dzoombar.h" #include "lighttableview.h" #include "lighttablethumbbar.h" #include "thumbbardock.h" #include "drawdecoder.h" #include "digikam_debug.h" #include "componentsinfodlg.h" #include "digikamapp.h" #include "thememanager.h" #include "dimg.h" #include "dio.h" #include "dmetadata.h" #include "dfileoperations.h" #include "metaenginesettings.h" #include "applicationsettings.h" #include "albummanager.h" #include "loadingcacheinterface.h" #include "deletedialog.h" #include "iccsettings.h" #include "imagewindow.h" #include "itemdescedittab.h" #include "slideshowbuilder.h" #include "slideshow.h" #include "setup.h" #include "syncjob.h" #include "lighttablepreview.h" #include "albummodel.h" #include "albumfiltermodel.h" #include "coredbchangesets.h" #include "collectionscanner.h" #include "scancontroller.h" #include "tagsactionmngr.h" #include "thumbnailsize.h" #include "thumbnailloadthread.h" #include "dexpanderbox.h" #include "dbinfoiface.h" namespace Digikam { class DAdjustableLabel; class Q_DECL_HIDDEN LightTableWindow::Private { public: Private() : autoLoadOnRightPanel(true), autoSyncPreview(true), fromLeftPreview(true), setItemLeftAction(nullptr), setItemRightAction(nullptr), clearListAction(nullptr), editItemAction(nullptr), removeItemAction(nullptr), fileDeleteAction(nullptr), fileDeleteFinalAction(nullptr), slideShowAction(nullptr), leftZoomPlusAction(nullptr), leftZoomMinusAction(nullptr), leftZoomTo100percents(nullptr), leftZoomFitToWindowAction(nullptr), rightZoomPlusAction(nullptr), rightZoomMinusAction(nullptr), rightZoomTo100percents(nullptr), rightZoomFitToWindowAction(nullptr), forwardAction(nullptr), backwardAction(nullptr), firstAction(nullptr), lastAction(nullptr), showBarAction(nullptr), viewCMViewAction(nullptr), syncPreviewAction(nullptr), navigateByPairAction(nullptr), clearOnCloseAction(nullptr), leftFileName(nullptr), rightFileName(nullptr), hSplitter(nullptr), barViewDock(nullptr), thumbView(nullptr), previewView(nullptr), leftZoomBar(nullptr), rightZoomBar(nullptr), statusProgressBar(nullptr), leftSideBar(nullptr), rightSideBar(nullptr) { } void addPageUpDownActions(LightTableWindow* const q, QWidget* const w) { defineShortcut(w, Qt::Key_Down, q, SLOT(slotForward())); defineShortcut(w, Qt::Key_Right, q, SLOT(slotForward())); defineShortcut(w, Qt::Key_Up, q, SLOT(slotBackward())); defineShortcut(w, Qt::Key_Left, q, SLOT(slotBackward())); } public: bool autoLoadOnRightPanel; bool autoSyncPreview; bool fromLeftPreview; QAction* setItemLeftAction; QAction* setItemRightAction; QAction* clearListAction; QAction* editItemAction; QAction* removeItemAction; QAction* fileDeleteAction; QAction* fileDeleteFinalAction; QAction* slideShowAction; QAction* leftZoomPlusAction; QAction* leftZoomMinusAction; QAction* leftZoomTo100percents; QAction* leftZoomFitToWindowAction; QAction* rightZoomPlusAction; QAction* rightZoomMinusAction; QAction* rightZoomTo100percents; QAction* rightZoomFitToWindowAction; QAction* forwardAction; QAction* backwardAction; QAction* firstAction; QAction* lastAction; QAction* showBarAction; QAction* viewCMViewAction; QAction* syncPreviewAction; QAction* navigateByPairAction; QAction* clearOnCloseAction; DAdjustableLabel* leftFileName; DAdjustableLabel* rightFileName; SidebarSplitter* hSplitter; ThumbBarDock* barViewDock; LightTableThumbBar* thumbView; LightTableView* previewView; DZoomBar* leftZoomBar; DZoomBar* rightZoomBar; StatusProgressBar* statusProgressBar; - ItemPropertiesSideBarDB* leftSideBar; - ItemPropertiesSideBarDB* rightSideBar; + ItemPropertiesSideBarDB* leftSideBar; + ItemPropertiesSideBarDB* rightSideBar; }; } // namespace Digikam #endif // DIGIKAM_LIGHT_TABLE_WINDOW_PRIVATE_H diff --git a/core/utilities/lighttable/lighttablewindow_setup.cpp b/core/utilities/lighttable/lighttablewindow_setup.cpp index 0cecbecca3..c090e34bf1 100644 --- a/core/utilities/lighttable/lighttablewindow_setup.cpp +++ b/core/utilities/lighttable/lighttablewindow_setup.cpp @@ -1,462 +1,472 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-11-22 * Description : digiKam light table - Configure * * 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 "lighttablewindow_p.h" namespace Digikam { void LightTableWindow::setupActions() { // -- Standard 'File' menu actions --------------------------------------------- KActionCollection* const ac = actionCollection(); d->backwardAction = buildStdAction(StdBackAction, this, SLOT(slotBackward()), this); ac->addAction(QLatin1String("lighttable_backward"), d->backwardAction); ac->setDefaultShortcuts(d->backwardAction, QList() << Qt::Key_PageUp << Qt::Key_Backspace); d->forwardAction = buildStdAction(StdForwardAction, this, SLOT(slotForward()), this); ac->addAction(QLatin1String("lighttable_forward"), d->forwardAction); ac->setDefaultShortcuts(d->forwardAction, QList() << Qt::Key_PageDown << Qt::Key_Space); d->forwardAction->setEnabled(false); d->firstAction = new QAction(QIcon::fromTheme(QLatin1String("go-first")), i18n("&First"), this); d->firstAction->setEnabled(false); connect(d->firstAction, SIGNAL(triggered()), this, SLOT(slotFirst())); ac->addAction(QLatin1String("lighttable_first"), d->firstAction); ac->setDefaultShortcuts(d->firstAction, QList() << Qt::CTRL + Qt::Key_Home); d->lastAction = new QAction(QIcon::fromTheme(QLatin1String("go-last")), i18n("&Last"), this); d->lastAction->setEnabled(false); connect(d->lastAction, SIGNAL(triggered()), this, SLOT(slotLast())); ac->addAction(QLatin1String("lighttable_last"), d->lastAction); ac->setDefaultShortcuts(d->lastAction, QList() << Qt::CTRL + Qt::Key_End); d->setItemLeftAction = new QAction(QIcon::fromTheme(QLatin1String("go-previous")), i18n("On left"), this); d->setItemLeftAction->setEnabled(false); d->setItemLeftAction->setWhatsThis(i18n("Show item on left panel")); connect(d->setItemLeftAction, SIGNAL(triggered()), this, SLOT(slotSetItemLeft())); ac->addAction(QLatin1String("lighttable_setitemleft"), d->setItemLeftAction); ac->setDefaultShortcut(d->setItemLeftAction, Qt::CTRL + Qt::Key_L); d->setItemRightAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), i18n("On right"), this); d->setItemRightAction->setEnabled(false); d->setItemRightAction->setWhatsThis(i18n("Show item on right panel")); connect(d->setItemRightAction, SIGNAL(triggered()), this, SLOT(slotSetItemRight())); ac->addAction(QLatin1String("lighttable_setitemright"), d->setItemRightAction); ac->setDefaultShortcut(d->setItemRightAction, Qt::CTRL + Qt::Key_R); d->editItemAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Edit"), this); d->editItemAction->setEnabled(false); connect(d->editItemAction, SIGNAL(triggered()), this, SLOT(slotEditItem())); ac->addAction(QLatin1String("lighttable_edititem"), d->editItemAction); ac->setDefaultShortcut(d->editItemAction, Qt::Key_F4); QAction* const openWithAction = new QAction(QIcon::fromTheme(QLatin1String("preferences-desktop-filetype-association")), i18n("Open With Default Application"), this); openWithAction->setWhatsThis(i18n("Open the item with default assigned application.")); connect(openWithAction, SIGNAL(triggered()), this, SLOT(slotFileWithDefaultApplication())); ac->addAction(QLatin1String("open_with_default_application"), openWithAction); ac->setDefaultShortcut(openWithAction, Qt::CTRL + Qt::Key_F4); d->removeItemAction = new QAction(QIcon::fromTheme(QLatin1String("list-remove")), i18n("Remove item from LightTable"), this); d->removeItemAction->setEnabled(false); connect(d->removeItemAction, SIGNAL(triggered()), this, SLOT(slotRemoveItem())); ac->addAction(QLatin1String("lighttable_removeitem"), d->removeItemAction); ac->setDefaultShortcut(d->removeItemAction, Qt::CTRL + Qt::Key_K); d->clearListAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Remove all items from LightTable"), this); d->clearListAction->setEnabled(false); connect(d->clearListAction, SIGNAL(triggered()), this, SLOT(slotClearItemsList())); ac->addAction(QLatin1String("lighttable_clearlist"), d->clearListAction); ac->setDefaultShortcut(d->clearListAction, Qt::CTRL + Qt::SHIFT + Qt::Key_K); d->fileDeleteAction = new QAction(QIcon::fromTheme(QLatin1String("user-trash-full")), i18nc("Non-pluralized", "Move to Trash"), this); d->fileDeleteAction->setEnabled(false); connect(d->fileDeleteAction, SIGNAL(triggered()), this, SLOT(slotDeleteItem())); ac->addAction(QLatin1String("lighttable_filedelete"), d->fileDeleteAction); ac->setDefaultShortcut(d->fileDeleteAction, Qt::Key_Delete); d->fileDeleteFinalAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Delete immediately"), this); d->fileDeleteFinalAction->setEnabled(false); connect(d->fileDeleteFinalAction, SIGNAL(triggered()), this, SLOT(slotDeleteFinalItem())); ac->addAction(QLatin1String("lighttable_filefinaldelete"), d->fileDeleteFinalAction); ac->setDefaultShortcut(d->fileDeleteFinalAction, Qt::SHIFT + Qt::Key_Delete); QAction* const closeAction = buildStdAction(StdCloseAction, this, SLOT(close()), this); ac->addAction(QLatin1String("lighttable_close"), closeAction); // -- Standard 'View' menu actions --------------------------------------------- d->syncPreviewAction = new QAction(QIcon::fromTheme(QLatin1String("view-split-left-right")), i18n("Synchronize"), this); d->syncPreviewAction->setEnabled(false); d->syncPreviewAction->setCheckable(true); d->syncPreviewAction->setWhatsThis(i18n("Synchronize preview from left and right panels")); connect(d->syncPreviewAction, SIGNAL(triggered()), this, SLOT(slotToggleSyncPreview())); ac->addAction(QLatin1String("lighttable_syncpreview"), d->syncPreviewAction); ac->setDefaultShortcut(d->syncPreviewAction, Qt::CTRL + Qt::SHIFT + Qt::Key_Y); d->navigateByPairAction = new QAction(QIcon::fromTheme(QLatin1String("system-run")), i18n("By Pair"), this); d->navigateByPairAction->setEnabled(false); d->navigateByPairAction->setCheckable(true); d->navigateByPairAction->setWhatsThis(i18n("Navigate by pairs with all items")); connect(d->navigateByPairAction, SIGNAL(triggered()), this, SLOT(slotToggleNavigateByPair())); ac->addAction(QLatin1String("lighttable_navigatebypair"), d->navigateByPairAction); ac->setDefaultShortcut(d->navigateByPairAction, Qt::CTRL + Qt::SHIFT + Qt::Key_P); d->clearOnCloseAction = new QAction(QIcon::fromTheme(QLatin1String("edit-clear")), i18n("Clear On Close"), this); d->clearOnCloseAction->setEnabled(true); d->clearOnCloseAction->setCheckable(true); d->clearOnCloseAction->setToolTip(i18n("Clear light table when it is closed")); d->clearOnCloseAction->setWhatsThis(i18n("Remove all images from the light table when it is closed")); ac->addAction(QLatin1String("lighttable_clearonclose"), d->clearOnCloseAction); ac->setDefaultShortcut(d->clearOnCloseAction, Qt::CTRL + Qt::SHIFT + Qt::Key_C); d->showBarAction = d->barViewDock->getToggleAction(this); ac->addAction(QLatin1String("lighttable_showthumbbar"), d->showBarAction); ac->setDefaultShortcut(d->showBarAction, Qt::CTRL + Qt::Key_T); createFullScreenAction(QLatin1String("lighttable_fullscreen")); createSidebarActions(); d->slideShowAction = new QAction(QIcon::fromTheme(QLatin1String("view-presentation")), i18n("Slideshow"), this); connect(d->slideShowAction, SIGNAL(triggered()), this, SLOT(slotSlideShowAll())); ac->addAction(QLatin1String("lighttable_slideshow"), d->slideShowAction); ac->setDefaultShortcut(d->slideShowAction, Qt::Key_F9); // Left Panel Zoom Actions d->leftZoomPlusAction = buildStdAction(StdZoomInAction, d->previewView, SLOT(slotIncreaseLeftZoom()), this); d->leftZoomPlusAction->setEnabled(false); ac->addAction(QLatin1String("lighttable_zoomplus_left"), d->leftZoomPlusAction); d->leftZoomMinusAction = buildStdAction(StdZoomOutAction, d->previewView, SLOT(slotDecreaseLeftZoom()), this); d->leftZoomMinusAction->setEnabled(false); ac->addAction(QLatin1String("lighttable_zoomminus_left"), d->leftZoomMinusAction); d->leftZoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->leftZoomTo100percents, SIGNAL(triggered()), d->previewView, SLOT(slotLeftZoomTo100())); ac->addAction(QLatin1String("lighttable_zoomto100percents_left"), d->leftZoomTo100percents); ac->setDefaultShortcut(d->leftZoomTo100percents, Qt::CTRL + Qt::Key_Period); d->leftZoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->leftZoomFitToWindowAction, SIGNAL(triggered()), d->previewView, SLOT(slotLeftFitToWindow())); ac->addAction(QLatin1String("lighttable_zoomfit2window_left"), d->leftZoomFitToWindowAction); ac->setDefaultShortcut(d->leftZoomFitToWindowAction, Qt::CTRL + Qt::ALT + Qt::Key_E); // Right Panel Zoom Actions d->rightZoomPlusAction = buildStdAction(StdZoomInAction, d->previewView, SLOT(slotIncreaseRightZoom()), this); d->rightZoomPlusAction->setEnabled(false); ac->addAction(QLatin1String("lighttable_zoomplus_right"), d->rightZoomPlusAction); ac->setDefaultShortcut(d->rightZoomPlusAction, Qt::SHIFT + d->rightZoomPlusAction->shortcut()[0]); d->rightZoomMinusAction = buildStdAction(StdZoomOutAction, d->previewView, SLOT(slotDecreaseRightZoom()), this); d->rightZoomMinusAction->setEnabled(false); ac->addAction(QLatin1String("lighttable_zoomminus_right"), d->rightZoomMinusAction); ac->setDefaultShortcut(d->rightZoomMinusAction, Qt::SHIFT + d->rightZoomMinusAction->shortcut()[0]); d->rightZoomTo100percents = new QAction(QIcon::fromTheme(QLatin1String("zoom-original")), i18n("Zoom to 100%"), this); connect(d->rightZoomTo100percents, SIGNAL(triggered()), d->previewView, SLOT(slotRightZoomTo100())); ac->addAction(QLatin1String("lighttable_zoomto100percents_right"), d->rightZoomTo100percents); ac->setDefaultShortcut(d->rightZoomTo100percents, Qt::CTRL + Qt::SHIFT + Qt::Key_Period); d->rightZoomFitToWindowAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18n("Fit to &Window"), this); connect(d->rightZoomFitToWindowAction, SIGNAL(triggered()), d->previewView, SLOT(slotRightFitToWindow())); ac->addAction(QLatin1String("lighttable_zoomfit2window_right"), d->rightZoomFitToWindowAction); ac->setDefaultShortcut(d->rightZoomFitToWindowAction, Qt::CTRL + Qt::SHIFT + Qt::Key_E); // ----------------------------------------------------------- d->viewCMViewAction = new QAction(QIcon::fromTheme(QLatin1String("video-display")), i18n("Color-Managed View"), this); d->viewCMViewAction->setCheckable(true); connect(d->viewCMViewAction, SIGNAL(triggered()), this, SLOT(slotToggleColorManagedView())); ac->addAction(QLatin1String("color_managed_view"), d->viewCMViewAction); ac->setDefaultShortcut(d->viewCMViewAction, Qt::Key_F12); // ----------------------------------------------------------------------------- ThemeManager::instance()->registerThemeActions(this); // Standard 'Help' menu actions + createHelpActions(); // Provides a menu entry that allows showing/hiding the toolbar(s) + setStandardToolBarMenuEnabled(true); // Provides a menu entry that allows showing/hiding the statusbar + createStandardStatusBarAction(); // Standard 'Configure' menu actions + createSettingsActions(); // -- Keyboard-only actions ---------------------------------------------------- d->addPageUpDownActions(this, this); QAction* const altBackwardAction = new QAction(i18n("Previous Image"), this); ac->addAction(QLatin1String("lighttable_backward_shift_space"), altBackwardAction); ac->setDefaultShortcut(altBackwardAction, Qt::SHIFT + Qt::Key_Space); connect(altBackwardAction, SIGNAL(triggered()), this, SLOT(slotBackward())); // Labels shortcuts must be registered here to be saved in XML GUI files if user customize it. + TagsActionMngr::defaultManager()->registerLabelsActions(ac); QAction* const editTitlesRight = new QAction(i18n("Edit Titles on the Right"), this); ac->addAction(QLatin1String("edit_titles_right"), editTitlesRight); ac->setDefaultShortcut(editTitlesRight, Qt::ALT + Qt::SHIFT + Qt::Key_T); connect(editTitlesRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateTitles())); QAction* const editCommentsRight = new QAction(i18n("Edit Comments on the Right"), this); ac->addAction(QLatin1String("edit_comments_right"), editCommentsRight); ac->setDefaultShortcut(editCommentsRight, Qt::ALT + Qt::SHIFT + Qt::Key_C); connect(editCommentsRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateComments())); QAction* const assignedTagsRight = new QAction(i18n("Show Assigned Tags on the Right"), this); ac->addAction(QLatin1String("assigned_tags_right"), assignedTagsRight); ac->setDefaultShortcut(assignedTagsRight, Qt::ALT + Qt::SHIFT + Qt::Key_A); connect(assignedTagsRight, SIGNAL(triggered()), this, SLOT(slotRightSideBarActivateAssignedTags())); QAction* const editTitlesLeft = new QAction(i18n("Edit Titles on the Left"), this); ac->addAction(QLatin1String("edit_titles_left"), editTitlesLeft); ac->setDefaultShortcut(editTitlesLeft, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_T); connect(editTitlesLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateTitles())); QAction* const editCommentsLeft = new QAction(i18n("Edit Comments on the Left"), this); ac->addAction(QLatin1String("edit_comments_left"), editCommentsLeft); ac->setDefaultShortcut(editCommentsLeft, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_C); connect(editCommentsLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateComments())); QAction* const assignedTagsLeft = new QAction(i18n("Show Assigned Tags on the Left"), this); ac->addAction(QLatin1String("assigned_tags_left"), assignedTagsLeft); ac->setDefaultShortcut(assignedTagsLeft, Qt::CTRL + Qt::ALT + Qt::SHIFT + Qt::Key_A); connect(assignedTagsLeft, SIGNAL(triggered()), this, SLOT(slotLeftSideBarActivateAssignedTags())); // --------------------------------------------------------------------------------- createGUI(xmlFile()); registerPluginsActions(); cleanupActions(); showMenuBarAction()->setChecked(!menuBar()->isHidden()); // NOTE: workaround for bug #171080 } void LightTableWindow::setupStatusBar() { d->leftZoomBar = new DZoomBar(statusBar()); d->leftZoomBar->setZoomToFitAction(d->leftZoomFitToWindowAction); d->leftZoomBar->setZoomTo100Action(d->leftZoomTo100percents); d->leftZoomBar->setZoomPlusAction(d->leftZoomPlusAction); d->leftZoomBar->setZoomMinusAction(d->leftZoomMinusAction); d->leftZoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->leftZoomBar->setEnabled(false); statusBar()->addWidget(d->leftZoomBar, 1); d->leftFileName = new DAdjustableLabel(statusBar()); d->leftFileName->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); statusBar()->addWidget(d->leftFileName, 10); d->statusProgressBar = new StatusProgressBar(statusBar()); d->statusProgressBar->setAlignment(Qt::AlignCenter); statusBar()->addWidget(d->statusProgressBar, 10); d->rightFileName = new DAdjustableLabel(statusBar()); d->rightFileName->setAlignment(Qt::AlignRight | Qt::AlignVCenter); statusBar()->addWidget(d->rightFileName, 10); d->rightZoomBar = new DZoomBar(statusBar()); d->rightZoomBar->setZoomToFitAction(d->rightZoomFitToWindowAction); d->rightZoomBar->setZoomTo100Action(d->rightZoomTo100percents); d->rightZoomBar->setZoomPlusAction(d->rightZoomPlusAction); d->rightZoomBar->setZoomMinusAction(d->rightZoomMinusAction); d->rightZoomBar->setBarMode(DZoomBar::PreviewZoomCtrl); d->rightZoomBar->setEnabled(false); statusBar()->addWidget(d->rightZoomBar, 1); } void LightTableWindow::setupConnections() { connect(ApplicationSettings::instance(), SIGNAL(setupChanged()), this, SLOT(slotApplicationSettingsChanged())); connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); connect(IccSettings::instance(), SIGNAL(settingsChanged()), this, SLOT(slotColorManagementOptionsChanged())); // Thumbs bar connections --------------------------------------- connect(d->thumbView, SIGNAL(signalSetItemOnLeftPanel(ItemInfo)), this, SLOT(slotSetItemOnLeftPanel(ItemInfo))); connect(d->thumbView, SIGNAL(signalSetItemOnRightPanel(ItemInfo)), this, SLOT(slotSetItemOnRightPanel(ItemInfo))); connect(d->thumbView, SIGNAL(signalRemoveItem(ItemInfo)), this, SLOT(slotRemoveItem(ItemInfo))); connect(d->thumbView, SIGNAL(signalEditItem(ItemInfo)), this, SLOT(slotEditItem(ItemInfo))); connect(d->thumbView, SIGNAL(signalClearAll()), this, SLOT(slotClearItemsList())); connect(d->thumbView, SIGNAL(signalDroppedItems(QList)), this, SLOT(slotThumbbarDroppedItems(QList))); connect(d->thumbView, SIGNAL(currentChanged(ItemInfo)), this, SLOT(slotItemSelected(ItemInfo))); connect(d->thumbView, SIGNAL(signalContentChanged()), this, SLOT(slotRefreshStatusBar())); // Zoom bars connections ----------------------------------------- connect(d->leftZoomBar, SIGNAL(signalZoomSliderChanged(int)), d->previewView, SLOT(slotLeftZoomSliderChanged(int))); connect(d->leftZoomBar, SIGNAL(signalZoomValueEdited(double)), d->previewView, SLOT(setLeftZoomFactor(double))); connect(d->rightZoomBar, SIGNAL(signalZoomSliderChanged(int)), d->previewView, SLOT(slotRightZoomSliderChanged(int))); connect(d->rightZoomBar, SIGNAL(signalZoomValueEdited(double)), d->previewView, SLOT(setRightZoomFactor(double))); // View connections --------------------------------------------- connect(d->previewView, SIGNAL(signalLeftPopupTagsView()), d->leftSideBar, SLOT(slotPopupTagsView())); connect(d->previewView, SIGNAL(signalRightPopupTagsView()), d->rightSideBar, SLOT(slotPopupTagsView())); connect(d->previewView, SIGNAL(signalLeftZoomFactorChanged(double)), this, SLOT(slotLeftZoomFactorChanged(double))); connect(d->previewView, SIGNAL(signalRightZoomFactorChanged(double)), this, SLOT(slotRightZoomFactorChanged(double))); connect(d->previewView, SIGNAL(signalEditItem(ItemInfo)), this, SLOT(slotEditItem(ItemInfo))); connect(d->previewView, SIGNAL(signalDeleteItem(ItemInfo)), this, SLOT(slotDeleteItem(ItemInfo))); connect(d->previewView, SIGNAL(signalLeftSlideShowCurrent()), this, SLOT(slotLeftSlideShowManualFromCurrent())); connect(d->previewView, SIGNAL(signalRightSlideShowCurrent()), this, SLOT(slotRightSlideShowManualFromCurrent())); connect(d->previewView, SIGNAL(signalLeftDroppedItems(ItemInfoList)), this, SLOT(slotLeftDroppedItems(ItemInfoList))); connect(d->previewView, SIGNAL(signalRightDroppedItems(ItemInfoList)), this, SLOT(slotRightDroppedItems(ItemInfoList))); connect(d->previewView, SIGNAL(signalToggleOnSyncPreview(bool)), this, SLOT(slotToggleOnSyncPreview(bool))); connect(d->previewView, SIGNAL(signalLeftPreviewLoaded(bool)), this, SLOT(slotLeftPreviewLoaded(bool))); connect(d->previewView, SIGNAL(signalRightPreviewLoaded(bool)), this, SLOT(slotRightPreviewLoaded(bool))); connect(d->previewView, SIGNAL(signalLeftPanelLeftButtonClicked()), this, SLOT(slotLeftPanelLeftButtonClicked())); connect(d->previewView, SIGNAL(signalRightPanelLeftButtonClicked()), this, SLOT(slotRightPanelLeftButtonClicked())); connect(this, SIGNAL(signalWindowHasMoved()), d->leftZoomBar, SLOT(slotUpdateTrackerPos())); connect(this, SIGNAL(signalWindowHasMoved()), d->rightZoomBar, SLOT(slotUpdateTrackerPos())); // -- FileWatch connections ------------------------------ LoadingCacheInterface::connectToSignalFileChanged(this, SLOT(slotFileChanged(QString))); } void LightTableWindow::setupUserArea() { QWidget* const mainW = new QWidget(this); d->hSplitter = new SidebarSplitter(Qt::Horizontal, mainW); QHBoxLayout* const hlay = new QHBoxLayout(mainW); // The left sidebar + d->leftSideBar = new ItemPropertiesSideBarDB(mainW, d->hSplitter, Qt::LeftEdge, true); // The central preview is wrapped in a KMainWindow so that the thumbnail // bar can float around it. + KMainWindow* const viewContainer = new KMainWindow(mainW, Qt::Widget); d->hSplitter->addWidget(viewContainer); d->previewView = new LightTableView(viewContainer); viewContainer->setCentralWidget(d->previewView); // The right sidebar. + d->rightSideBar = new ItemPropertiesSideBarDB(mainW, d->hSplitter, Qt::RightEdge, true); hlay->addWidget(d->leftSideBar); hlay->addWidget(d->hSplitter); hlay->addWidget(d->rightSideBar); hlay->setSpacing(0); hlay->setContentsMargins(QMargins()); hlay->setStretchFactor(d->hSplitter, 10); d->hSplitter->setFrameStyle(QFrame::NoFrame); d->hSplitter->setFrameShadow(QFrame::Plain); d->hSplitter->setFrameShape(QFrame::NoFrame); d->hSplitter->setOpaqueResize(false); d->hSplitter->setStretchFactor(1, 10); // set previewview+thumbbar container default size to max. // The thumb bar is placed in a detachable/dockable widget. + d->barViewDock = new ThumbBarDock(viewContainer, Qt::Tool); d->barViewDock->setObjectName(QLatin1String("lighttable_thumbbar")); d->barViewDock->setWindowTitle(i18n("Light Table Thumbnail Dock")); d->thumbView = new LightTableThumbBar(d->barViewDock); d->barViewDock->setWidget(d->thumbView); viewContainer->addDockWidget(Qt::TopDockWidgetArea, d->barViewDock); d->barViewDock->setFloating(false); // Restore the previous state. This doesn't emit the proper signals to the // dock widget, so it has to be manually reinitialized. + viewContainer->setAutoSaveSettings(QLatin1String("LightTable Thumbbar"), true); connect(d->barViewDock, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), d->thumbView, SLOT(slotDockLocationChanged(Qt::DockWidgetArea))); d->barViewDock->reInitialize(); setCentralWidget(mainW); } } // namespace Digikam diff --git a/core/utilities/lighttable/lighttablewindow_tools.cpp b/core/utilities/lighttable/lighttablewindow_tools.cpp index e7497fe9cb..98484e37ac 100644 --- a/core/utilities/lighttable/lighttablewindow_tools.cpp +++ b/core/utilities/lighttable/lighttablewindow_tools.cpp @@ -1,146 +1,146 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2004-11-22 * Description : digiKam light table - Extra tools * * 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 "lighttablewindow_p.h" namespace Digikam { void LightTableWindow::slotEditItem() { if (!d->thumbView->currentInfo().isNull()) { slotEditItem(d->thumbView->currentInfo()); } } void LightTableWindow::slotEditItem(const ItemInfo& info) { ImageWindow* const im = ImageWindow::imageWindow(); - ItemInfoList list = d->thumbView->allItemInfos(); + ItemInfoList list = d->thumbView->allItemInfos(); im->loadItemInfos(list, info, i18n("Light Table")); if (im->isHidden()) { im->show(); } else { im->raise(); } im->setFocus(); } void LightTableWindow::slotSlideShowAll() { SlideShowBuilder* const builder = new SlideShowBuilder(d->thumbView->allItemInfos()); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18n("Preparing slideshow. Please wait...")); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void LightTableWindow::slotLeftSlideShowManualFromCurrent() { slotSlideShowManualFrom(d->previewView->leftItemInfo()); d->fromLeftPreview = true; } void LightTableWindow::slotRightSlideShowManualFromCurrent() { slotSlideShowManualFrom(d->previewView->rightItemInfo()); d->fromLeftPreview = false; } void LightTableWindow::slotSlideShowManualFrom(const ItemInfo& info) { SlideShowBuilder* const builder = new SlideShowBuilder(d->thumbView->allItemInfos()); builder->setOverrideStartFrom(info); builder->setAutoPlayEnabled(false); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, i18n("Preparing slideshow. Please wait...")); connect(builder, SIGNAL(signalComplete(SlideShowSettings)), this, SLOT(slotSlideShowBuilderComplete(SlideShowSettings))); builder->run(); } void LightTableWindow::slotSlideShowBuilderComplete(const SlideShowSettings& settings) { QPointer slide = new SlideShow(new DBInfoIface(this, QList()), settings); TagsActionMngr::defaultManager()->registerActionsToWidget(slide); d->statusProgressBar->setProgressBarMode(StatusProgressBar::TextMode, QString()); slotRefreshStatusBar(); if (settings.imageUrl.isValid()) { slide->setCurrentItem(settings.imageUrl); } else if (settings.startWithCurrent) { slide->setCurrentItem(d->thumbView->currentInfo().fileUrl()); } connect(slide, SIGNAL(signalRatingChanged(QUrl,int)), d->thumbView, SLOT(slotRatingChanged(QUrl,int))); connect(slide, SIGNAL(signalColorLabelChanged(QUrl,int)), d->thumbView, SLOT(slotColorLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalPickLabelChanged(QUrl,int)), d->thumbView, SLOT(slotPickLabelChanged(QUrl,int))); connect(slide, SIGNAL(signalToggleTag(QUrl,int)), d->thumbView, SLOT(slotToggleTag(QUrl,int))); connect(slide, SIGNAL(signalLastItemUrl(QUrl)), this, SLOT(slotSlideShowLastItemUrl(QUrl))); slide->show(); } void LightTableWindow::slotSlideShowLastItemUrl(const QUrl& url) { if (d->fromLeftPreview && !d->navigateByPairAction->isChecked()) { d->thumbView->blockSignals(true); d->thumbView->setCurrentUrl(url); d->thumbView->blockSignals(false); slotSetItemLeft(); } else { d->thumbView->setCurrentUrl(url); } } } // namespace Digikam