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