20 #include "mergedialog.h"
21 #include "mergedelegate.h"
22 #include "duplicatesfinder_p.h"
23 #include "persondata.h"
24 #include "personsmodel.h"
25 #include "matchessolver_p.h"
30 #include <QPushButton>
31 #include <QDialogButtonBox>
34 #include <QStandardItemModel>
36 #include <KLocalizedString>
37 #include <KPixmapSequence>
38 #include <KPixmapSequenceWidget>
42 class MergeDialogPrivate
47 MergeDelegate *delegate;
49 QStandardItemModel *model;
50 DuplicatesFinder *duplicatesFinder;
51 KPixmapSequenceWidget *sequence;
54 MergeDialog::MergeDialog(QWidget *parent)
56 , d_ptr(new MergeDialogPrivate)
60 d_ptr->personsModel = 0;
62 d_ptr->duplicatesFinder = 0;
64 setWindowTitle(i18n(
"Duplicates Manager"));
65 setLayout(
new QVBoxLayout());
66 setMinimumSize(450, 350);
68 d->model =
new QStandardItemModel(
this);
69 d->view =
new QListView(
this);
70 d->view->setModel(d->model);
71 d->view->setEditTriggers(QAbstractItemView::NoEditTriggers);
73 QLabel *topLabel =
new QLabel(i18n(
"Select contacts to be merged"));
75 QDialogButtonBox *buttons =
new QDialogButtonBox(
this);
76 buttons->addButton(QDialogButtonBox::Ok);
77 buttons->addButton(QDialogButtonBox::Cancel);
78 connect(buttons, SIGNAL(accepted()), SLOT(onMergeButtonClicked()));
79 connect(buttons, SIGNAL(rejected()), SLOT(reject()));
81 d->sequence =
new KPixmapSequenceWidget(
this);
82 d->sequence->setSequence(KPixmapSequence(QStringLiteral(
"process-working"), 22));
83 d->sequence->setInterval(100);
84 d->sequence->setVisible(
false);
86 layout()->addWidget(topLabel);
87 layout()->addWidget(d->view);
88 layout()->addWidget(d->sequence);
89 layout()->addWidget(buttons);
92 MergeDialog::~MergeDialog()
100 d->personsModel = model;
101 if (d->personsModel) {
102 searchForDuplicates();
103 connect(d->personsModel, SIGNAL(modelInitialized(
bool)), SLOT(searchForDuplicates()));
107 void MergeDialog::searchForDuplicates()
110 if (!d->personsModel || !d->personsModel->rowCount() || d->duplicatesFinder) {
111 qWarning() <<
"MergeDialog failed to launch the duplicates research";
114 d->duplicatesFinder =
new DuplicatesFinder(d->personsModel);
115 connect(d->duplicatesFinder, SIGNAL(result(KJob*)), SLOT(searchForDuplicatesFinished(KJob*)));
116 d->duplicatesFinder->start();
119 void MergeDialog::onMergeButtonClicked()
122 QList<Match> matches;
123 for (
int i = 0, rows = d->model->rowCount(); i < rows; i++) {
124 QStandardItem *item = d->model->item(i, 0);
125 if (item->checkState() == Qt::Checked) {
126 for (
int j = 0, contactsCount = item->rowCount(); j < contactsCount; ++j) {
127 QStandardItem *matchItem = item->child(j);
128 matches << matchItem->data(MergeDialog::MergeReasonRole).value<Match>();
133 MatchesSolver *solverJob =
new MatchesSolver(matches, d->personsModel,
this);
135 d->sequence->setVisible(
true);
136 d->view->setEnabled(
false);
137 connect(solverJob, SIGNAL(finished(KJob*)),
this, SLOT(accept()));
140 void MergeDialog::searchForDuplicatesFinished(KJob *)
143 feedDuplicateModelFromMatches(d->duplicatesFinder->results());
145 d->delegate =
new MergeDelegate(d->view);
146 d->view->setItemDelegate(d->delegate);
149 connect(d->view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
150 d->delegate, SLOT(onSelectedContactsChanged(QItemSelection,QItemSelection)));
152 connect(d->view, SIGNAL(doubleClicked(QModelIndex)),
153 d->delegate, SLOT(onClickContactParent(QModelIndex)));
156 void MergeDialog::feedDuplicateModelFromMatches(
const QList<Match> &matches)
159 QHash<QPersistentModelIndex, QList<Match> > compareTable;
160 QHash<QPersistentModelIndex, QPersistentModelIndex> doneIndexes;
162 Q_FOREACH (
const Match &match, matches) {
163 QPersistentModelIndex destination = doneIndexes.value(match.indexA, match.indexA);
164 QHash<QPersistentModelIndex, QList< Match > >::iterator currentValue = compareTable.find(destination);
166 if (currentValue == compareTable.end()) {
167 compareTable[match.indexA] = QList<Match>() << match;
169 currentValue->append(match);
171 doneIndexes[match.indexB] = destination;
174 QStandardItem *rootItem = d->model->invisibleRootItem();
175 QHash<QPersistentModelIndex, QList< Match > >::const_iterator i;
177 for (i = compareTable.constBegin(); i != compareTable.constEnd(); ++i) {
179 QStandardItem *parent = itemMergeContactFromMatch(
true, i->first());
180 rootItem->appendRow(parent);
182 Q_FOREACH (
const Match &matchChild, *i) {
183 parent->appendRow(itemMergeContactFromMatch(
false, matchChild));
187 rootItem->sortChildren(0);
190 QStandardItem *MergeDialog::itemMergeContactFromMatch(
bool isParent,
const Match &match)
192 QStandardItem *item =
new QStandardItem;
194 item->setCheckable(
true);
195 item->setCheckState(Qt::Unchecked);
196 item->setSizeHint(MergeDelegate::pictureSize());
197 item->setData(
true, KExtendableItemDelegate::ShowExtensionIndicatorRole);
201 QString uri = match.indexB.data(PersonsModel::PersonUriRole).toString();
202 item->setData(uri, UriRole);
204 item->setData(qVariantFromValue<Match>(match), MergeReasonRole);
205 item->setText(match.indexB.data(Qt::DisplayRole).toString());
206 deco = match.indexB.data(Qt::DecorationRole);
209 QString uri = match.indexA.data(PersonsModel::PersonUriRole).toString();
210 item->setData(uri, UriRole);
212 item->setText(match.indexA.data(Qt::DisplayRole).toString());
213 deco = match.indexA.data(Qt::DecorationRole);
217 if (deco.type() == (QVariant::Icon)) {
218 icon = deco.value<QIcon>();
219 }
else if (deco.type() == (QVariant::Pixmap)) {
220 icon = QIcon(deco.value<QPixmap>());
221 }
else if (deco.type() == (QVariant::Image)) {
222 icon = QIcon(QPixmap::fromImage(deco.value<QImage>()));
224 qWarning() <<
"unknown decoration type" << deco.typeName();
The KPeople namespace contains all the classes for Libkpeople.
This class creates a model of all known contacts from all sources Contacts are represented as a tree ...
void setPersonsModel(PersonsModel *model)
Specifies which PersonsModel will be used to look for duplicates.
The merge dialog will be used to provide a GUI to attempt to figure out what contacts should be merge...