File indexing completed on 2024-04-28 05:08:19
0001 /*************************************************************************** 0002 Copyright (C) 2007-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "entrymerger.h" 0026 #include "entry.h" 0027 #include "entrycomparison.h" 0028 #include "collection.h" 0029 #include "tellico_kernel.h" 0030 #include "controller.h" 0031 #include "progressmanager.h" 0032 #include "gui/statusbar.h" 0033 #include "tellico_debug.h" 0034 0035 #include <KLocalizedString> 0036 0037 #include <QTimer> 0038 0039 using namespace Tellico; 0040 using Tellico::Merge::AskUserResolver; 0041 using Tellico::EntryMerger; 0042 0043 Merge::ConflictResolver::Result AskUserResolver::resolve(Data::EntryPtr entry1, Data::EntryPtr entry2, Data::FieldPtr field, 0044 const QString& value1, const QString& value2) { 0045 return static_cast<Merge::ConflictResolver::Result>(Kernel::self()->askAndMerge(entry1, entry2, field, value1, value2)); 0046 } 0047 0048 EntryMerger::EntryMerger(Tellico::Data::EntryList entries_, QObject* parent_) 0049 : QObject(parent_), m_entriesToCheck(entries_), m_origCount(entries_.count()), m_cancelled(false) 0050 , m_resolver(new AskUserResolver) { 0051 0052 m_entriesLeft = m_entriesToCheck; 0053 Kernel::self()->beginCommandGroup(i18n("Merge Entries")); 0054 0055 QString label = i18n("Merging entries..."); 0056 ProgressItem& item = ProgressManager::self()->newProgressItem(this, label, true /*canCancel*/); 0057 item.setTotalSteps(m_origCount); 0058 connect(&item, &Tellico::ProgressItem::signalCancelled, 0059 this, &Tellico::EntryMerger::slotCancel); 0060 0061 // done if no entries to merge 0062 if(m_origCount < 2) { 0063 QTimer::singleShot(500, this, &EntryMerger::slotCleanup); 0064 } else { 0065 slotStartNext(); // starts fetching 0066 } 0067 } 0068 0069 EntryMerger::~EntryMerger() { 0070 delete m_resolver; 0071 } 0072 0073 void EntryMerger::slotStartNext() { 0074 QString statusMsg = i18n("Total merged/scanned entries: %1/%2", 0075 m_entriesToRemove.count(), 0076 m_origCount - m_entriesToCheck.count()); 0077 StatusBar::self()->setStatus(statusMsg); 0078 ProgressManager::self()->setProgress(this, m_origCount - m_entriesToCheck.count()); 0079 0080 Data::EntryPtr baseEntry = m_entriesToCheck[0]; 0081 for(int i = 1; i < m_entriesToCheck.count(); ++i) { // skip checking against first 0082 Data::EntryPtr it = m_entriesToCheck[i]; 0083 bool match = cleanMerge(baseEntry, it); 0084 if(!match) { 0085 int score = baseEntry->collection()->sameEntry(baseEntry, it); 0086 match = score >= EntryComparison::ENTRY_GOOD_MATCH; 0087 } 0088 if(match) { 0089 bool merge_ok = Merge::mergeEntry(baseEntry, it, m_resolver); 0090 if(merge_ok) { 0091 m_entriesToRemove.append(it); 0092 m_entriesLeft.removeAll(it); 0093 } 0094 } 0095 } 0096 m_entriesToCheck.removeAll(baseEntry); 0097 0098 if(m_cancelled || m_entriesToCheck.count() < 2) { 0099 QTimer::singleShot(0, this, &EntryMerger::slotCleanup); 0100 } else { 0101 QTimer::singleShot(0, this, &EntryMerger::slotStartNext); 0102 } 0103 } 0104 0105 void EntryMerger::slotCancel() { 0106 m_cancelled = true; 0107 } 0108 0109 void EntryMerger::slotCleanup() { 0110 Kernel::self()->removeEntries(m_entriesToRemove); 0111 Controller::self()->slotUpdateSelection(m_entriesLeft); 0112 StatusBar::self()->clearStatus(); 0113 ProgressManager::self()->setDone(this); 0114 Kernel::self()->endCommandGroup(); 0115 deleteLater(); 0116 } 0117 0118 bool EntryMerger::cleanMerge(Tellico::Data::EntryPtr e1, Tellico::Data::EntryPtr e2) const { 0119 // figure out if there's a clean merge possible 0120 foreach(Data::FieldPtr field, e1->collection()->fields()) { 0121 // do not care about id and dates 0122 if(field->name() == QLatin1String("id") || 0123 field->name() == QLatin1String("cdate") || 0124 field->name() == QLatin1String("mdate")) { 0125 continue; 0126 } 0127 QString val1 = e1->field(field); 0128 QString val2 = e2->field(field); 0129 if(val1 != val2 && !val1.isEmpty() && !val2.isEmpty()) { 0130 return false; 0131 } 0132 } 0133 return true; 0134 }