• Skip to content
  • Skip to link menu
  • KDE API Reference
  • KDE Home
  • Contact Us
 

Nepomuk-Core

  • KTp
contact-info-dialog.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 Dan Vrátil <dvratil@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "contact-info-dialog.h"
20 #include "contact.h"
21 
22 #include <QGridLayout>
23 #include <QPicture>
24 #include <QLabel>
25 #include <QVBoxLayout>
26 #include <QFormLayout>
27 
28 #include <TelepathyQt/Contact>
29 #include <TelepathyQt/PendingContactInfo>
30 #include <TelepathyQt/AvatarData>
31 #include <TelepathyQt/Presence>
32 #include <TelepathyQt/SharedPtr>
33 #include <TelepathyQt/ContactManager>
34 #include <TelepathyQt/Connection>
35 #include <TelepathyQt/Account>
36 #include <TelepathyQt/PendingContacts>
37 
38 #include <KDebug>
39 #include <KMessageWidget>
40 #include <KTitleWidget>
41 #include <KLocalizedString>
42 #include <KPushButton>
43 #include <KLineEdit>
44 #include <KDateComboBox>
45 #include <KFileDialog>
46 #include <KImageFilePreview>
47 #include <KMessageBox>
48 
49 namespace KTp {
50 
51 enum InfoRowIndex {
52  FullName = 0,
53  Nickname,
54  Email,
55  Phone,
56  Homepage,
57  Birthday,
58  Organization,
59  _InfoRowCount
60 };
61 
62 static struct InfoRow {
63  const InfoRowIndex index;
64  const QString fieldName;
65  const QString title;
66 } InfoRows[] = {
67  { FullName, QLatin1String("fn"), i18n("Full name:") },
68  { Nickname, QLatin1String("nickname"), i18n("Nickname:") },
69  { Email, QLatin1String("email"), i18n("Email:") },
70  { Phone, QLatin1String("tel"), i18n("Phone:") },
71  { Homepage, QLatin1String("url"), i18n("Homepage:") },
72  { Birthday, QLatin1String("bday"), i18n("Birthday:") },
73  { Organization, QLatin1String("org"), i18n("Organization:") }
74 };
75 
76 class ContactInfoDialog::Private
77 {
78  public:
79  Private(ContactInfoDialog *parent):
80  editable(false),
81  infoDataChanged(false),
82  avatarChanged(false),
83  messageWidget(0),
84  columnsLayout(0),
85  infoLayout(0),
86  stateLayout(0),
87  changeAvatarButton(0),
88  clearAvatarButton(0),
89  avatarLabel(0),
90  q(parent)
91  {}
92 
93  void onContactUpgraded(Tp::PendingOperation *op);
94  void onContactInfoReceived(Tp::PendingOperation *op);
95  void onChangeAvatarButtonClicked();
96  void onClearAvatarButtonClicked();
97  void onInfoDataChanged();
98 
99  void addInfoRow(InfoRowIndex index, const QString &value);
100  void addStateRow(const QString &description, Tp::Contact::PresenceState state);
101 
102  Tp::AccountPtr account;
103  Tp::ContactPtr contact;
104  bool editable;
105 
106  bool infoDataChanged;
107  bool avatarChanged;
108  QString newAvatarFile;
109 
110  QMap<InfoRowIndex,QWidget*> infoValueWidgets;
111 
112  KMessageWidget *messageWidget;
113  QHBoxLayout *columnsLayout;
114  QFormLayout *infoLayout;
115  QFormLayout *stateLayout;
116  KPushButton *changeAvatarButton;
117  KPushButton *clearAvatarButton;
118  QLabel *avatarLabel;
119 
120  private:
121  ContactInfoDialog *q;
122 };
123 
124 void ContactInfoDialog::Private::onContactUpgraded(Tp::PendingOperation* op)
125 {
126  if (op->isError()) {
127  messageWidget->setMessageType(KMessageWidget::Error);
128  messageWidget->setText(op->errorMessage());
129  messageWidget->setCloseButtonVisible(false);
130  messageWidget->setWordWrap(true);
131  messageWidget->animatedShow();
132  return;
133  }
134 
135  Tp::PendingContacts *contacts = qobject_cast<Tp::PendingContacts*>(op);
136  Q_ASSERT(contacts->contacts().count() == 1);
137 
138  contact = contacts->contacts().first();
139 
140  /* Show avatar immediatelly */
141  if (contacts->features().contains(Tp::Contact::FeatureAvatarData)) {
142  QVBoxLayout *avatarLayout = new QVBoxLayout();
143  avatarLayout->setSpacing(5);
144  avatarLayout->setAlignment(Qt::AlignHCenter);
145  columnsLayout->addLayout(avatarLayout);
146 
147  avatarLabel = new QLabel(q);
148  avatarLabel->setMaximumSize(150, 150);
149  avatarLayout->addWidget(avatarLabel, 0, Qt::AlignTop);
150 
151  if (editable) {
152  changeAvatarButton = new KPushButton(i18n("Change Avatar"), q);
153  connect(changeAvatarButton, SIGNAL(clicked(bool)),
154  q, SLOT(onChangeAvatarButtonClicked()));
155  avatarLayout->addWidget(changeAvatarButton);
156 
157  clearAvatarButton = new KPushButton(i18n("Clear Avatar"), q);
158  connect(clearAvatarButton, SIGNAL(clicked(bool)),
159  q, SLOT(onClearAvatarButtonClicked()));
160  avatarLayout->addWidget(clearAvatarButton);
161 
162  avatarLayout->addStretch(1);
163  }
164 
165  QPixmap avatar(contact->avatarData().fileName);
166  if (avatar.isNull()) {
167  avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::Desktop, 128);
168  if (clearAvatarButton) {
169  clearAvatarButton->setEnabled(false);
170  }
171  }
172  avatarLabel->setPixmap(avatar.scaled(avatarLabel->maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
173  }
174 
175  /* Request detailed contact info */
176  if (contacts->features().contains(Tp::Contact::FeatureInfo)) {
177  infoLayout = new QFormLayout();
178  infoLayout->setSpacing(10);
179  columnsLayout->addLayout(infoLayout);
180 
181  Tp::PendingContactInfo *op = contact->requestInfo();
182  connect(op, SIGNAL(finished(Tp::PendingOperation*)),
183  q, SLOT(onContactInfoReceived(Tp::PendingOperation*)));
184  }
185 }
186 
187 void ContactInfoDialog::Private::onContactInfoReceived(Tp::PendingOperation* op)
188 {
189  if (op->isError()) {
190  messageWidget->setMessageType(KMessageWidget::Error);
191  messageWidget->setText(op->errorMessage());
192  messageWidget->setCloseButtonVisible(false);
193  messageWidget->setWordWrap(true);
194  messageWidget->animatedShow();
195  return;
196  }
197 
198  Tp::PendingContactInfo *ci = qobject_cast<Tp::PendingContactInfo*>(op);
199  const Tp::ContactInfoFieldList fieldList = ci->infoFields().allFields();
200 
201  for (InfoRowIndex index = (InfoRowIndex) 0; index < _InfoRowCount; index = (InfoRowIndex)(index + 1)) {
202  QString value;
203 
204  Q_FOREACH(const Tp::ContactInfoField &field, fieldList) {
205  if (field.fieldValue.count() == 0) {
206  continue;
207  }
208 
209  if (field.fieldName == InfoRows[index].fieldName) {
210  value = field.fieldValue.first();
211  break;
212  }
213  }
214 
215  /* Show edits for all values when in editable mode */
216  if (!editable && value.isEmpty()) {
217  continue;
218  }
219 
220  addInfoRow(index, value);
221  }
222 }
223 
224 void ContactInfoDialog::Private::onChangeAvatarButtonClicked()
225 {
226  QPointer<KFileDialog> fileDialog = new KFileDialog(KUrl(), QString(), q);
227  fileDialog->setOperationMode(KFileDialog::Opening);
228  fileDialog->setPreviewWidget(new KImageFilePreview(fileDialog));
229  fileDialog->setMimeFilter(QStringList() << QLatin1String("image/*"));
230 
231  int c = fileDialog->exec();
232  if (fileDialog && c) {
233  newAvatarFile = fileDialog->selectedFile();
234 
235  QPixmap avatar(newAvatarFile);
236  if (avatar.isNull()) {
237  KMessageBox::error(q, i18n("Failed to load the new avatar image"));
238  newAvatarFile.clear();
239  delete fileDialog;
240  return;
241  }
242  avatarLabel->setPixmap(avatar.scaled(avatarLabel->maximumSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
243  avatarChanged = true;
244  clearAvatarButton->setEnabled(true);
245  }
246 
247  delete fileDialog;
248 }
249 
250 void ContactInfoDialog::Private::onClearAvatarButtonClicked()
251 {
252  QPixmap avatar;
253  avatar = KIconLoader::global()->loadIcon(QLatin1String("im-user"), KIconLoader::Desktop, 128);
254 
255  newAvatarFile.clear();
256  avatarChanged = true;
257 }
258 
259 void ContactInfoDialog::Private::onInfoDataChanged()
260 {
261  infoDataChanged = true;
262 }
263 
264 void ContactInfoDialog::Private::addInfoRow(InfoRowIndex index, const QString &value)
265 {
266  InfoRow *row = &InfoRows[index];
267 
268  QLabel *descriptionLabel = new QLabel(row->title, q);
269  QFont font = descriptionLabel->font();
270  font.setBold(true);
271  descriptionLabel->setFont(font);
272 
273  if (editable) {
274  if (index == Birthday) {
275  KDateComboBox *combo = new KDateComboBox(q);
276  combo->setOptions(KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker);
277  combo->setMinimumWidth(200);
278  combo->setDate(QDate::fromString(value));
279  connect(combo, SIGNAL(dateChanged(QDate)), q, SLOT(onInfoDataChanged()));
280 
281  infoValueWidgets.insert(index, combo);
282  } else {
283  KLineEdit *edit = new KLineEdit(q);
284  edit->setMinimumWidth(200);
285  edit->setText(value);
286  connect(edit, SIGNAL(textChanged(QString)), q, SLOT(onInfoDataChanged()));
287 
288  infoValueWidgets.insert(index, edit);
289  }
290  } else {
291  QLabel *label = new QLabel(q);
292  label->setOpenExternalLinks(true);
293  label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse);
294  if (index == Email) {
295  label->setText(QString::fromLatin1("<a href=\"mailto:%1\">%1</a>").arg(value));
296  } else if (index == Homepage) {
297  QString format;
298  if (!value.startsWith(QLatin1String("http"), Qt::CaseInsensitive)) {
299  format = QLatin1String("<a href=\"http://%1\">%1</a>");
300  } else {
301  format = QLatin1String("<a href=\"%1\">%1</a>");
302  }
303  label->setText(format.arg(value));
304  } else {
305  label->setText(value);
306  }
307 
308  infoValueWidgets.insert(index, label);
309  }
310 
311  infoLayout->addRow(descriptionLabel, infoValueWidgets.value(index));
312 }
313 
314 void ContactInfoDialog::Private::addStateRow(const QString& description, Tp::Contact::PresenceState state)
315 {
316  QLabel *descriptionLabel = new QLabel(description, q);
317 
318  KIcon icon;
319  switch (state) {
320  case Tp::Contact::PresenceStateYes:
321  icon = KIcon(QLatin1String("task-complete"));
322  break;
323  case Tp::Contact::PresenceStateNo:
324  icon = KIcon(QLatin1String("task-reject"));
325  break;
326  case Tp::Contact::PresenceStateAsk:
327  default:
328  icon = KIcon(QLatin1String("task-attempt"));
329  break;
330  }
331 
332  QLabel *stateLabel = new QLabel(q);
333  stateLabel->setPixmap(icon.pixmap(16));
334 
335  stateLayout->addRow(descriptionLabel, stateLabel);
336 }
337 
338 ContactInfoDialog::ContactInfoDialog(const Tp::AccountPtr& account, const Tp::ContactPtr& contact, QWidget* parent)
339  : KDialog(parent)
340  , d(new Private(this))
341 {
342 #if 0 // Editing contacts is not yet supported in TpQt
343  /* Whether contact is the user himself */
344  d->editable = (contact == account->connection()->selfContact());
345 #endif
346  d->editable = false;
347  d->account = account;
348  d->contact = contact;
349 
350 
351  if (d->editable) {
352  setButtons(User1 | Close);
353  setButtonGuiItem(User1, KGuiItem(i18n("Save"), QLatin1String("document-save")));
354  } else {
355  setButtons(Close);
356  }
357 
358  setMaximumSize(sizeHint());
359 
360  QVBoxLayout *layout = new QVBoxLayout(mainWidget());
361  layout->setSpacing(30);
362 
363  /* Title - presence icon, alias, id */
364  KTitleWidget *titleWidget = new KTitleWidget(this);
365  KTp::Presence presence(contact->presence());
366  titleWidget->setPixmap(presence.icon().pixmap(32, 32), KTitleWidget::ImageLeft);
367  titleWidget->setText(contact->alias());
368  titleWidget->setComment(contact->id());
369  layout->addWidget(titleWidget);
370 
371  /* Error message to show when an async operation fails */
372  d->messageWidget = new KMessageWidget(this);
373  d->messageWidget->setVisible(false);
374  layout->addWidget(d->messageWidget);
375 
376  /* 1st column: avatar; 2nd column: details */
377  d->columnsLayout = new QHBoxLayout();
378  d->columnsLayout->setSpacing(30);
379  layout->addLayout(d->columnsLayout);
380 
381  /* Make sure the contact has all neccessary features ready */
382  Tp::PendingContacts *op = contact->manager()->upgradeContacts(
383  QList<Tp::ContactPtr>() << contact,
384  Tp::Features() << Tp::Contact::FeatureAvatarData
385  << Tp::Contact::FeatureInfo);
386  connect(op, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onContactUpgraded(Tp::PendingOperation*)));
387 
388  /* State Info - there is no point showing this information when it's about ourselves */
389  if (!d->editable) {
390  d->stateLayout = new QFormLayout();
391  d->stateLayout->setSpacing(10);
392  layout->addLayout(d->stateLayout);
393  d->addStateRow(i18n("Contact can see when you are online:"), contact->publishState());
394  d->addStateRow(i18n("You can see when the contact is online:"), contact->subscriptionState());
395  d->addStateRow(i18n("Contact is blocked:"), contact->isBlocked() ? Tp::Contact::PresenceStateYes : Tp::Contact::PresenceStateNo);
396  }
397 }
398 
399 ContactInfoDialog::~ContactInfoDialog()
400 {
401  delete d;
402 }
403 
404 void ContactInfoDialog::slotButtonClicked(int button)
405 {
406  if (button == User1) {
407  if (d->avatarChanged) {
408  Tp::Avatar avatar;
409  if (!d->newAvatarFile.isEmpty()) {
410  QFile file(d->newAvatarFile);
411  file.open(QIODevice::ReadOnly);
412 
413  QFileInfo fi(file);
414 
415  avatar.avatarData = file.readAll();
416  file.seek(0); // reset before passing to KMimeType
417  avatar.MIMEType = KMimeType::findByNameAndContent(d->newAvatarFile, &file)->defaultMimeType();
418  }
419 
420  d->account->setAvatar(avatar);
421  }
422 
423  if (d->infoDataChanged) {
424  Tp::ContactInfoFieldList fieldList;
425 
426  for (InfoRowIndex index = (InfoRowIndex) 0; index < _InfoRowCount; index = (InfoRowIndex) (index + 1)) {
427  InfoRow *row = &InfoRows[index];
428 
429  Tp::ContactInfoField field;
430  field.fieldName = row->fieldName;
431 
432  if (index == Birthday) {
433  KDateComboBox *combo = qobject_cast<KDateComboBox*>(d->infoValueWidgets.value(index));
434  field.fieldValue << combo->date().toString();
435  } else {
436  KLineEdit *lineEdit = qobject_cast<KLineEdit*>(d->infoValueWidgets.value(index));
437  field.fieldValue << lineEdit->text();
438  }
439 
440  fieldList << field;
441  }
442 
443 #if 0 // This method does not exist in TpQt (yet)
444  d->account->connection()->setContactInfo(fieldList);
445 #endif
446  }
447 
448  accept();
449  return;
450  }
451 
452  KDialog::slotButtonClicked(button);
453 }
454 
455 
456 } /* namespace KTp */
457 
458 #include "contact-info-dialog.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Fri Mar 22 2013 10:58:52 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

ktp-common-internals API Reference

Skip menu "ktp-common-internals API Reference"
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