• Skip to content
  • Skip to link menu
KDE API Documentation - mergedialog.cpp Source File (KPeople)
  • KDE Home
  • Contact Us
 

KPeople

  • frameworks
  • kpeople
  • src
  • widgets
mergedialog.cpp
1 /*
2  KPeople - Duplicates
3  Copyright (C) 2013 Franck Arrecot <franck.arrecot@gmail.com>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
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"
26 
27 #include <QObject>
28 #include <QLabel>
29 #include <QLayout>
30 #include <QPushButton>
31 #include <QDialogButtonBox>
32 #include <QListView>
33 #include <QDebug>
34 #include <QStandardItemModel>
35 
36 #include <KLocalizedString>
37 #include <KPixmapSequence>
38 #include <KPixmapSequenceWidget>
39 
40 using namespace KPeople;
41 
42 class MergeDialogPrivate
43 {
44 public:
45  PersonsModel *personsModel;
46  QListView *view;
47  MergeDelegate *delegate;
48 
49  QStandardItemModel *model;
50  DuplicatesFinder *duplicatesFinder;
51  KPixmapSequenceWidget *sequence;
52 };
53 
54 MergeDialog::MergeDialog(QWidget *parent)
55  : QDialog(parent)
56  , d_ptr(new MergeDialogPrivate)
57 {
58  Q_D(MergeDialog);
59 
60  d_ptr->personsModel = 0;
61  d_ptr->delegate = 0;
62  d_ptr->duplicatesFinder = 0;
63 
64  setWindowTitle(i18n("Duplicates Manager"));
65  setLayout(new QVBoxLayout());
66  setMinimumSize(450, 350);
67 
68  d->model = new QStandardItemModel(this);
69  d->view = new QListView(this);
70  d->view->setModel(d->model);
71  d->view->setEditTriggers(QAbstractItemView::NoEditTriggers);
72 
73  QLabel *topLabel = new QLabel(i18n("Select contacts to be merged"));
74 
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()));
80 
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);
85 
86  layout()->addWidget(topLabel);
87  layout()->addWidget(d->view);
88  layout()->addWidget(d->sequence);
89  layout()->addWidget(buttons);
90 }
91 
92 MergeDialog::~MergeDialog()
93 {
94  delete d_ptr;
95 }
96 
97 void MergeDialog::setPersonsModel(PersonsModel *model)
98 {
99  Q_D(MergeDialog);
100  d->personsModel = model;
101  if (d->personsModel) {
102  searchForDuplicates();
103  connect(d->personsModel, SIGNAL(modelInitialized(bool)), SLOT(searchForDuplicates()));
104  }
105 }
106 
107 void MergeDialog::searchForDuplicates()
108 {
109  Q_D(MergeDialog);
110  if (!d->personsModel || !d->personsModel->rowCount() || d->duplicatesFinder) {
111  qWarning() << "MergeDialog failed to launch the duplicates research";
112  return;
113  }
114  d->duplicatesFinder = new DuplicatesFinder(d->personsModel);
115  connect(d->duplicatesFinder, SIGNAL(result(KJob*)), SLOT(searchForDuplicatesFinished(KJob*)));
116  d->duplicatesFinder->start();
117 }
118 
119 void MergeDialog::onMergeButtonClicked()
120 {
121  Q_D(MergeDialog);
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>();
129  }
130  }
131  }
132 
133  MatchesSolver *solverJob = new MatchesSolver(matches, d->personsModel, this);
134  solverJob->start();
135  d->sequence->setVisible(true);
136  d->view->setEnabled(false);
137  connect(solverJob, SIGNAL(finished(KJob*)), this, SLOT(accept()));
138 }
139 
140 void MergeDialog::searchForDuplicatesFinished(KJob *)
141 {
142  Q_D(MergeDialog);
143  feedDuplicateModelFromMatches(d->duplicatesFinder->results());
144 
145  d->delegate = new MergeDelegate(d->view);
146  d->view->setItemDelegate(d->delegate);
147 
148  // To extend the selected item
149  connect(d->view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
150  d->delegate, SLOT(onSelectedContactsChanged(QItemSelection,QItemSelection)));
151  // To contract an already selected item
152  connect(d->view, SIGNAL(doubleClicked(QModelIndex)),
153  d->delegate, SLOT(onClickContactParent(QModelIndex)));
154 }
155 
156 void MergeDialog::feedDuplicateModelFromMatches(const QList<Match> &matches)
157 {
158  Q_D(MergeDialog);
159  QHash<QPersistentModelIndex, QList<Match> > compareTable;
160  QHash<QPersistentModelIndex, QPersistentModelIndex> doneIndexes;
161 
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);
165 
166  if (currentValue == compareTable.end()) { // new parent, create it
167  compareTable[match.indexA] = QList<Match>() << match;
168  } else { //know parent, add child
169  currentValue->append(match);
170  }
171  doneIndexes[match.indexB] = destination;
172  }
173  // now build the model : 1st dimension = person candidate, 2nd dimension = match
174  QStandardItem *rootItem = d->model->invisibleRootItem();
175  QHash<QPersistentModelIndex, QList< Match > >::const_iterator i;
176 
177  for (i = compareTable.constBegin(); i != compareTable.constEnd(); ++i) {
178  // Build the merge Contact in the model
179  QStandardItem *parent = itemMergeContactFromMatch(true, i->first());
180  rootItem->appendRow(parent);
181 
182  Q_FOREACH (const Match &matchChild, *i) {
183  parent->appendRow(itemMergeContactFromMatch(false, matchChild));
184  }
185  }
186 
187  rootItem->sortChildren(0);
188 }
189 
190 QStandardItem *MergeDialog::itemMergeContactFromMatch(bool isParent, const Match &match)
191 {
192  QStandardItem *item = new QStandardItem;
193 
194  item->setCheckable(true);
195  item->setCheckState(Qt::Unchecked);
196  item->setSizeHint(MergeDelegate::pictureSize());
197  item->setData(true, KExtendableItemDelegate::ShowExtensionIndicatorRole);
198 
199  QVariant deco;
200  if (!isParent) { // child
201  QString uri = match.indexB.data(PersonsModel::PersonUriRole).toString();
202  item->setData(uri, UriRole);
203 
204  item->setData(qVariantFromValue<Match>(match), MergeReasonRole);
205  item->setText(match.indexB.data(Qt::DisplayRole).toString());
206  deco = match.indexB.data(Qt::DecorationRole);
207 
208  } else { // parent
209  QString uri = match.indexA.data(PersonsModel::PersonUriRole).toString();
210  item->setData(uri, UriRole);
211 
212  item->setText(match.indexA.data(Qt::DisplayRole).toString());
213  deco = match.indexA.data(Qt::DecorationRole);
214  }
215 
216  QIcon icon;
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>()));
223  } else {
224  qWarning() << "unknown decoration type" << deco.typeName();
225  }
226  item->setIcon(icon);
227  return item;
228 }
KPeople
The KPeople namespace contains all the classes for Libkpeople.
KPeople::PersonsModel
This class creates a model of all known contacts from all sources Contacts are represented as a tree ...
Definition: personsmodel.h:42
KPeople::MergeDialog::setPersonsModel
void setPersonsModel(PersonsModel *model)
Specifies which PersonsModel will be used to look for duplicates.
Definition: mergedialog.cpp:97
KPeople::MergeDialog
The merge dialog will be used to provide a GUI to attempt to figure out what contacts should be merge...
Definition: mergedialog.h:44
This file is part of the KDE documentation.
Documentation copyright © 1996-2015 The KDE developers.
Generated on Fri Feb 13 2015 15:16:39 by doxygen 1.8.9.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KPeople

Skip menu "KPeople"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • File List

Class Picker

Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal