1 #ifndef LIBKOPETE_UI_AVATARSELECTORWIDGET_CPP
2 #define LIBKOPETE_UI_AVATARSELECTORWIDGET_CPP
3 /*
4 avatarselectorwidget.cpp - Widget to manage and select user avatar
5
6 Copyright (c) 2007 by Michaël Larouche <larouche@kde.org>
7 Copyright (c) 2007 Gustavo Pichorim Boiko <gustavo.boiko@kdemail.net>
8
9 Kopete (c) 2002-2007 by the Kopete developers <kopete-devel@kde.org>
10
11 *************************************************************************
12 * *
13 * This library is free software; you can redistribute it and/or *
14 * modify it under the terms of the GNU Lesser General Public *
15 * License as published by the Free Software Foundation; either *
16 * version 2 of the License, or (at your option) any later version. *
17 * *
18 *************************************************************************
19 */
20 #include "avatarselectorwidget.h"
21 #include "avatarwebcamdialog.h"
22
23 // Qt includes
24 #include <QListWidget>
25 #include <QListWidgetItem>
26 #include <QIcon>
27 #include <QPainter>
28 #include <QUrl>
29
30 // KDE includes
31 #include <kfiledialog.h>
32 #include <kpixmapregionselectordialog.h>
33
34 #include "ui_avatarselectorwidget.h"
35 #ifndef VIDEOSUPPORT_DISABLED
36 #include "avdevice/videodevicepool.h"
37
38 using namespace Kopete::AV;
39 #endif
40
41 namespace Kopete {
42 namespace UI {
43 class AvatarSelectorWidgetItem : public QListWidgetItem
44 {
45 public:
AvatarSelectorWidgetItem(QListWidget * parent)46 AvatarSelectorWidgetItem(QListWidget *parent)
47 : QListWidgetItem(parent, QListWidgetItem::UserType)
48 {
49 }
50
setAvatarEntry(Kopete::AvatarManager::AvatarEntry entry)51 void setAvatarEntry(Kopete::AvatarManager::AvatarEntry entry)
52 {
53 m_entry = entry;
54
55 QSize s(96, 96);
56
57 if (listWidget()) {
58 s = listWidget()->iconSize();
59 }
60
61 QPixmap pix;
62 if (entry.path.isEmpty()) {
63 // draw a fake image telling there is no avatar
64 pix = QPixmap(s);
65 QPainter p(&pix);
66 p.fillRect(pix.rect(), Qt::white);
67 p.drawText(pix.rect(), Qt::TextWordWrap | Qt::AlignCenter, i18n("No Avatar"));
68 } else {
69 pix = QPixmap(entry.path).scaled(s);
70 }
71
72 // draw a border around the avatar
73 QPainter p(&pix);
74 p.setBrush(Qt::NoBrush);
75 p.drawRect(0, 0, pix.width()-1, pix.height()-1);
76
77 setIcon(pix);
78 }
79
avatarEntry() const80 Kopete::AvatarManager::AvatarEntry avatarEntry() const
81 {
82 return m_entry;
83 }
84
85 private:
86 Kopete::AvatarManager::AvatarEntry m_entry;
87 };
88
89 class AvatarSelectorWidget::Private
90 {
91 public:
Private()92 Private()
93 : selectedItem(0)
94 , noAvatarItem(0)
95 {
96 }
97
98 Ui::AvatarSelectorWidget mainWidget;
99 QListWidgetItem *selectedItem;
100 QString currentAvatar;
101 AvatarSelectorWidgetItem *noAvatarItem;
102 AvatarSelectorWidgetItem *addItem(Kopete::AvatarManager::AvatarEntry entry);
103 };
104
AvatarSelectorWidget(QWidget * parent)105 AvatarSelectorWidget::AvatarSelectorWidget(QWidget *parent)
106 : QWidget(parent)
107 , d(new Private)
108 {
109 d->mainWidget.setupUi(this);
110
111 // use icons on buttons
112 d->mainWidget.buttonAddAvatar->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
113 d->mainWidget.buttonRemoveAvatar->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete")));
114 d->mainWidget.buttonFromWebcam->setIcon(QIcon::fromTheme(QStringLiteral("camera-web")));
115
116 #ifndef VIDEOSUPPORT_DISABLED
117 VideoDevicePool *devicePool = VideoDevicePool::self();
118 if (devicePool->size() == 0) {
119 d->mainWidget.buttonFromWebcam->hide();
120 }
121 #else
122 //If windows, just hide it
123 d->mainWidget.buttonFromWebcam->hide();
124 #endif
125
126 // Connect signals/slots
127 connect(d->mainWidget.buttonAddAvatar, SIGNAL(clicked()), this, SLOT(buttonAddAvatarClicked()));
128 connect(d->mainWidget.buttonRemoveAvatar, SIGNAL(clicked()), this, SLOT(buttonRemoveAvatarClicked()));
129 connect(d->mainWidget.buttonFromWebcam, SIGNAL(clicked()), this, SLOT(buttonFromWebcamClicked()));
130 connect(d->mainWidget.listUserAvatar, SIGNAL(itemClicked(QListWidgetItem*)),
131 this, SLOT(listSelectionChanged(QListWidgetItem*)));
132 connect(Kopete::AvatarManager::self(), SIGNAL(avatarAdded(Kopete::AvatarManager::AvatarEntry)),
133 this, SLOT(avatarAdded(Kopete::AvatarManager::AvatarEntry)));
134 connect(Kopete::AvatarManager::self(), SIGNAL(avatarRemoved(Kopete::AvatarManager::AvatarEntry)),
135 this, SLOT(avatarRemoved(Kopete::AvatarManager::AvatarEntry)));
136
137 // Add a "No Avatar" option
138 Kopete::AvatarManager::AvatarEntry empty;
139 empty.name = i18n("No Avatar");
140 empty.contact = 0;
141 empty.category = Kopete::AvatarManager::User;
142 d->noAvatarItem = d->addItem(empty);
143
144 // List avatars of User category
145 Kopete::AvatarQueryJob *queryJob = new Kopete::AvatarQueryJob(this);
146 connect(queryJob, SIGNAL(result(KJob*)), this, SLOT(queryJobFinished(KJob*)));
147 queryJob->setQueryFilter(Kopete::AvatarManager::User);
148
149 queryJob->start();
150 }
151
~AvatarSelectorWidget()152 AvatarSelectorWidget::~AvatarSelectorWidget()
153 {
154 delete d;
155 }
156
selectedEntry() const157 Kopete::AvatarManager::AvatarEntry AvatarSelectorWidget::selectedEntry() const
158 {
159 Kopete::AvatarManager::AvatarEntry result;
160
161 if (d->selectedItem) {
162 result = static_cast<AvatarSelectorWidgetItem *>(d->selectedItem)->avatarEntry();
163 }
164
165 return result;
166 }
167
setCurrentAvatar(const QString & path)168 void AvatarSelectorWidget::setCurrentAvatar(const QString &path)
169 {
170 d->currentAvatar = path;
171
172 //try to find the avatar in the list
173 QList<QListWidgetItem *> itemList = d->mainWidget.listUserAvatar->findItems(QLatin1String(""), Qt::MatchContains);
174 QList<QListWidgetItem *>::iterator it = itemList.begin();
175
176 while (it != itemList.end())
177 {
178 AvatarSelectorWidgetItem *item = static_cast<AvatarSelectorWidgetItem *>(*it);
179 if (item->avatarEntry().path == path) {
180 item->setSelected(true);
181 listSelectionChanged(item);
182 return;
183 }
184 ++it;
185 }
186 }
187
buttonAddAvatarClicked()188 void AvatarSelectorWidget::buttonAddAvatarClicked()
189 {
190 QUrl imageUrl = KFileDialog::getImageOpenUrl(QUrl(), this);
191 if (!imageUrl.isEmpty()) {
192 // TODO: Download image
193 if (!imageUrl.isLocalFile()) {
194 return;
195 }
196
197 QPixmap pixmap(imageUrl.toLocalFile());
198 if (pixmap.isNull()) {
199 return;
200 }
201 QString imageName = imageUrl.fileName();
202 cropAndSaveAvatar(pixmap, imageName);
203 }
204 }
205
buttonRemoveAvatarClicked()206 void AvatarSelectorWidget::buttonRemoveAvatarClicked()
207 {
208 // if no item was selected, just exit
209 if (!d->mainWidget.listUserAvatar->selectedItems().count()) {
210 return;
211 }
212
213 AvatarSelectorWidgetItem *selectedItem = dynamic_cast<AvatarSelectorWidgetItem *>(d->mainWidget.listUserAvatar->selectedItems().first());
214 if (selectedItem) {
215 if (selectedItem != d->noAvatarItem) {
216 if (!Kopete::AvatarManager::self()->remove(selectedItem->avatarEntry())) {
217 qCDebug(LIBKOPETE_LOG) << "Removing of avatar failed for unknown reason.";
218 }
219 }
220 }
221 }
222
cropAndSaveAvatar(QPixmap & pixmap,const QString & imageName)223 void AvatarSelectorWidget::cropAndSaveAvatar(QPixmap &pixmap, const QString &imageName)
224 {
225 // Crop the image
226 QImage avatar = KPixmapRegionSelectorDialog::getSelectedImage(pixmap, 96, 96, this);
227
228 Kopete::AvatarManager::AvatarEntry newEntry;
229 // Remove extension from filename
230 const int extIndex = imageName.lastIndexOf('.');
231 newEntry.name = (extIndex > 0) ? imageName.left(extIndex) : imageName;
232 newEntry.image = avatar;
233 newEntry.category = Kopete::AvatarManager::User;
234
235 Kopete::AvatarManager::AvatarEntry addedEntry = Kopete::AvatarManager::self()->add(newEntry);
236 if (addedEntry.path.isEmpty()) {
237 //TODO add a real error message
238 //d->mainWidget.labelErrorMessage->setText( i18n("Kopete cannot add this new avatar because it could not save the avatar image in user directory.") );
239 return;
240 }
241
242 // select the added entry and show the user tab
243 QList<QListWidgetItem *> foundItems = d->mainWidget.listUserAvatar->findItems(addedEntry.name, Qt::MatchContains);
244 if (!foundItems.isEmpty()) {
245 AvatarSelectorWidgetItem *item = dynamic_cast<AvatarSelectorWidgetItem *>(foundItems.first());
246 if (!item) {
247 return;
248 }
249 item->setSelected(true);
250 }
251 }
252
buttonFromWebcamClicked()253 void AvatarSelectorWidget::buttonFromWebcamClicked()
254 {
255 Kopete::UI::AvatarWebcamDialog *dialog = new Kopete::UI::AvatarWebcamDialog();
256 int result = dialog->exec();
257 if (result == QDialog::Accepted) {
258 QString avatarName(QStringLiteral("Webcam"));
259 int increment = 1;
260 qCDebug(LIBKOPETE_LOG) << "Trying with: " << avatarName;
261 while ((Kopete::AvatarManager::self()->exists(avatarName))) {
262 avatarName = "Webcam_"+QString::number(increment);
263 ++increment;
264 qCDebug(LIBKOPETE_LOG) << "Trying with: " << avatarName;
265 }
266 cropAndSaveAvatar(dialog->getLastPixmap(), avatarName);
267 }
268 dialog->close();
269 delete dialog;
270 }
271
queryJobFinished(KJob * job)272 void AvatarSelectorWidget::queryJobFinished(KJob *job)
273 {
274 Kopete::AvatarQueryJob *queryJob = static_cast<Kopete::AvatarQueryJob *>(job);
275 if (!queryJob->error()) {
276 QList<Kopete::AvatarManager::AvatarEntry> avatarList = queryJob->avatarList();
277 foreach (const Kopete::AvatarManager::AvatarEntry &entry, avatarList) {
278 d->addItem(entry);
279 }
280 } else {
281 //TODO add a real error message
282 //d->mainWidget.labelErrorMessage->setText( queryJob->errorText() );
283 }
284 }
285
avatarAdded(Kopete::AvatarManager::AvatarEntry newEntry)286 void AvatarSelectorWidget::avatarAdded(Kopete::AvatarManager::AvatarEntry newEntry)
287 {
288 d->addItem(newEntry);
289 setCurrentAvatar(newEntry.path);
290 }
291
avatarRemoved(Kopete::AvatarManager::AvatarEntry entryRemoved)292 void AvatarSelectorWidget::avatarRemoved(Kopete::AvatarManager::AvatarEntry entryRemoved)
293 {
294 // Same here, avatar can be only removed from listUserAvatar
295 foreach (QListWidgetItem *item, d->mainWidget.listUserAvatar->findItems("", Qt::MatchContains)) {
296 // checks if this is the right item
297 AvatarSelectorWidgetItem *avatar = dynamic_cast<AvatarSelectorWidgetItem *>(item);
298 if (!avatar || avatar->avatarEntry().name != entryRemoved.name) {
299 continue;
300 }
301
302 qCDebug(LIBKOPETE_LOG) << "Removing " << entryRemoved.name << " from list.";
303
304 int deletedRow = d->mainWidget.listUserAvatar->row(item);
305 QListWidgetItem *removedItem = d->mainWidget.listUserAvatar->takeItem(deletedRow);
306 delete removedItem;
307
308 int newRow = --deletedRow;
309 if (newRow < 0) {
310 newRow = 0;
311 }
312
313 // Select the previous avatar in the list, thus selecting a new avatar
314 // and deselecting the avatar being removed.
315 d->mainWidget.listUserAvatar->setCurrentRow(newRow);
316 // Force update
317 listSelectionChanged(d->mainWidget.listUserAvatar->item(newRow));
318 }
319 }
320
listSelectionChanged(QListWidgetItem * item)321 void AvatarSelectorWidget::listSelectionChanged(QListWidgetItem *item)
322 {
323 d->mainWidget.buttonRemoveAvatar->setEnabled(item != d->noAvatarItem);
324 d->selectedItem = item;
325 }
326
addItem(Kopete::AvatarManager::AvatarEntry entry)327 AvatarSelectorWidgetItem *AvatarSelectorWidget::Private::addItem(Kopete::AvatarManager::AvatarEntry entry)
328 {
329 qCDebug(LIBKOPETE_LOG) << "Entry(" << entry.name << "): " << entry.category;
330
331 // only use User avatars
332 if (!(entry.category & Kopete::AvatarManager::User)) {
333 return 0;
334 }
335
336 AvatarSelectorWidgetItem *item = new AvatarSelectorWidgetItem(mainWidget.listUserAvatar);
337 item->setAvatarEntry(entry);
338 if (entry.path == currentAvatar) {
339 item->setSelected(true);
340 }
341 return item;
342 }
343 } // Namespace Kopete::UI
344 } // Namespace Kopete
345
346 #endif // LIBKOPETE_UI/AVATARSELECTORWIDGET_CPP
347