File indexing completed on 2024-05-12 15:55:38
0001 /* SPDX-FileCopyrightText: 2012-2020 The KPhotoAlbum Development Team 0002 0003 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 #include "DuplicateMerger.h" 0007 0008 #include "DuplicateMatch.h" 0009 #include "MergeToolTip.h" 0010 0011 #include <DB/ImageDB.h> 0012 #include <DB/ImageInfo.h> 0013 #include <DB/MD5.h> 0014 #include <Utilities/DeleteFiles.h> 0015 #include <Utilities/ShowBusyCursor.h> 0016 #include <kpabase/FileName.h> 0017 #include <kpabase/FileNameList.h> 0018 0019 #include <KLocalizedString> 0020 #include <QDebug> 0021 #include <QDialogButtonBox> 0022 #include <QLabel> 0023 #include <QPushButton> 0024 #include <QRadioButton> 0025 #include <QScrollArea> 0026 #include <QVBoxLayout> 0027 0028 namespace MainWindow 0029 { 0030 0031 DuplicateMerger::DuplicateMerger(QWidget *parent) 0032 : QDialog(parent) 0033 { 0034 setAttribute(Qt::WA_DeleteOnClose); 0035 resize(800, 600); 0036 0037 QWidget *top = new QWidget(this); 0038 QVBoxLayout *topLayout = new QVBoxLayout(top); 0039 setLayout(topLayout); 0040 topLayout->addWidget(top); 0041 0042 QString txt = i18n("<p>Below is a list of all images that are duplicate in your database.<br/>" 0043 "Select which you want merged, and which of the duplicates should be kept.<br/>" 0044 "The tag and description from the deleted images will be transferred to the kept image</p>"); 0045 QLabel *label = new QLabel(txt); 0046 QFont fnt = font(); 0047 fnt.setPixelSize(18); 0048 label->setFont(fnt); 0049 topLayout->addWidget(label); 0050 0051 m_trash = new QRadioButton(i18n("Move to &trash")); 0052 m_deleteFromDisk = new QRadioButton(i18n("&Delete from disk")); 0053 QRadioButton *blockFromDB = new QRadioButton(i18n("&Block from database")); 0054 m_trash->setChecked(true); 0055 0056 topLayout->addSpacing(10); 0057 topLayout->addWidget(m_trash); 0058 topLayout->addWidget(m_deleteFromDisk); 0059 topLayout->addWidget(blockFromDB); 0060 topLayout->addSpacing(10); 0061 0062 QScrollArea *scrollArea = new QScrollArea; 0063 topLayout->addWidget(scrollArea); 0064 scrollArea->setWidgetResizable(true); 0065 0066 m_container = new QWidget(scrollArea); 0067 m_scrollLayout = new QVBoxLayout(m_container); 0068 scrollArea->setWidget(m_container); 0069 0070 m_selectionCount = new QLabel; 0071 topLayout->addWidget(m_selectionCount); 0072 0073 QDialogButtonBox *buttonBox = new QDialogButtonBox(); 0074 0075 m_selectAllButton = buttonBox->addButton(i18n("Select &All"), QDialogButtonBox::YesRole); 0076 m_selectNoneButton = buttonBox->addButton(i18n("Select &None"), QDialogButtonBox::NoRole); 0077 m_okButton = buttonBox->addButton(QDialogButtonBox::Ok); 0078 m_cancelButton = buttonBox->addButton(QDialogButtonBox::Cancel); 0079 0080 connect(m_selectAllButton, &QPushButton::clicked, this, QOverload<>::of(&DuplicateMerger::selectAll)); 0081 connect(m_selectNoneButton, &QPushButton::clicked, this, &DuplicateMerger::selectNone); 0082 connect(m_okButton, &QPushButton::clicked, this, &DuplicateMerger::go); 0083 connect(m_cancelButton, &QPushButton::clicked, this, &DuplicateMerger::reject); 0084 0085 topLayout->addWidget(buttonBox); 0086 0087 findDuplicates(); 0088 } 0089 0090 MainWindow::DuplicateMerger::~DuplicateMerger() 0091 { 0092 MergeToolTip::destroy(); 0093 } 0094 0095 void DuplicateMerger::selectAll() 0096 { 0097 selectAll(true); 0098 } 0099 0100 void DuplicateMerger::selectNone() 0101 { 0102 selectAll(false); 0103 } 0104 0105 void DuplicateMerger::go() 0106 { 0107 Utilities::DeleteMethod method = Utilities::BlockFromDatabase; 0108 0109 if (m_trash->isChecked()) { 0110 method = Utilities::MoveToTrash; 0111 } else if (m_deleteFromDisk->isChecked()) { 0112 method = Utilities::DeleteFromDisk; 0113 } 0114 0115 for (DuplicateMatch *selector : qAsConst(m_selectors)) { 0116 selector->execute(method); 0117 } 0118 0119 accept(); 0120 } 0121 0122 void DuplicateMerger::updateSelectionCount() 0123 { 0124 int total = 0; 0125 int selected = 0; 0126 0127 for (const DuplicateMatch *selector : qAsConst(m_selectors)) { 0128 ++total; 0129 if (selector->selected()) 0130 ++selected; 0131 } 0132 0133 m_selectionCount->setText(i18n("%1 of %2 selected", selected, total)); 0134 m_okButton->setEnabled(selected > 0); 0135 } 0136 0137 void DuplicateMerger::findDuplicates() 0138 { 0139 Utilities::ShowBusyCursor dummy; 0140 0141 const auto images = DB::ImageDB::instance()->files(); 0142 for (const DB::FileName &fileName : images) { 0143 const DB::ImageInfoPtr info = DB::ImageDB::instance()->info(fileName); 0144 const DB::MD5 md5 = info->MD5Sum(); 0145 m_matches[md5].append(fileName); 0146 } 0147 0148 bool anyFound = false; 0149 for (QMap<DB::MD5, DB::FileNameList>::const_iterator it = m_matches.constBegin(); 0150 it != m_matches.constEnd(); ++it) { 0151 if (it.value().count() > 1) { 0152 addRow(it.key()); 0153 anyFound = true; 0154 } 0155 } 0156 0157 if (!anyFound) { 0158 tellThatNoDuplicatesWereFound(); 0159 } 0160 0161 updateSelectionCount(); 0162 } 0163 0164 void DuplicateMerger::addRow(const DB::MD5 &md5) 0165 { 0166 DuplicateMatch *match = new DuplicateMatch(m_matches[md5]); 0167 connect(match, &DuplicateMatch::selectionChanged, this, &DuplicateMerger::updateSelectionCount); 0168 m_scrollLayout->addWidget(match); 0169 m_selectors.append(match); 0170 } 0171 0172 void DuplicateMerger::selectAll(bool b) 0173 { 0174 for (DuplicateMatch *selector : qAsConst(m_selectors)) { 0175 selector->setSelected(b); 0176 } 0177 } 0178 0179 void DuplicateMerger::tellThatNoDuplicatesWereFound() 0180 { 0181 QLabel *label = new QLabel(i18n("No duplicates found")); 0182 QFont fnt = font(); 0183 fnt.setPixelSize(30); 0184 label->setFont(fnt); 0185 m_scrollLayout->addWidget(label); 0186 0187 m_selectAllButton->setEnabled(false); 0188 m_selectNoneButton->setEnabled(false); 0189 m_okButton->setEnabled(false); 0190 } 0191 0192 } // namespace MainWindow 0193 0194 // vi:expandtab:tabstop=4 shiftwidth=4: 0195 0196 #include "moc_DuplicateMerger.cpp"