blob: ef33a9b95f379e627657d8307ce187565d0673ab [file] [log] [blame]
Edric Milareta0ebd062016-01-13 12:18:23 -05001/***************************************************************************
Anthony Léonard2fde81d2017-04-17 10:06:55 -04002 * Copyright (C) 2015-2017 by Savoir-faire Linux *
Edric Milareta0ebd062016-01-13 12:18:23 -05003 * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>*
Olivier SOLDANO47aa97f2017-04-04 10:40:00 -04004 * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> *
5 * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> *
Edric Milareta0ebd062016-01-13 12:18:23 -05006 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 **************************************************************************/
20
21#include "pixbufmanipulator.h"
22
Edric Milaret25236d92016-03-28 09:40:58 -040023#include <QSize>
24#include <QMetaType>
25#include <QImage>
26#include <QIODevice>
27#include <QByteArray>
28#include <QBuffer>
Anthony Léonard3d920d82017-07-31 13:51:16 -040029#include <QPainter>
Edric Milareta0ebd062016-01-13 12:18:23 -050030
Edric Milaret25236d92016-03-28 09:40:58 -040031#include "person.h"
32#include "call.h"
33#include "contactmethod.h"
34#include "profilemodel.h"
35#include "profile.h"
36
37#include "utils.h"
Anthony Léonard3d920d82017-07-31 13:51:16 -040038#include "ringthemeutils.h"
Edric Milaret25236d92016-03-28 09:40:58 -040039#undef interface
40
41/*Namespace Interfaces collide with QBuffer*/
42QByteArray QImageToByteArray(QImage image)
43{
44 QByteArray ba;
45 QBuffer buffer(&ba);
46 buffer.open(QIODevice::WriteOnly);
47 image.save(&buffer, "PNG");
48 return ba;
49}
Edric Milareta0ebd062016-01-13 12:18:23 -050050
Edric Milareta0ebd062016-01-13 12:18:23 -050051QImage
52PixbufManipulator::scaleAndFrame(const QImage photo, const QSize& size)
53{
54 return photo.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
55}
56
57QVariant
58PixbufManipulator::callPhoto(Call* c, const QSize& size, bool displayPresence)
59{
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -050060 if (!c || c->type() == Call::Type::CONFERENCE){
Anthony Léonard3d920d82017-07-31 13:51:16 -040061 return QVariant::fromValue(fallbackAvatar(size,
62 c->peerContactMethod()->uri().userinfo().at(0).toLatin1(),
63 c->peerContactMethod()->bestName().at(0).toUpper().toLatin1()));
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -050064 }
Edric Milareta0ebd062016-01-13 12:18:23 -050065 return callPhoto(c->peerContactMethod(), size, displayPresence);
66}
67
68QVariant
69PixbufManipulator::callPhoto(const ContactMethod* n, const QSize& size, bool displayPresence)
70{
71 if (n && n->contact()) {
72 return contactPhoto(n->contact(), size, displayPresence);
73 } else {
Anthony Léonard3d920d82017-07-31 13:51:16 -040074 return QVariant::fromValue(fallbackAvatar(size,
75 n->uri().userinfo().at(0).toLatin1(),
76 n->bestName().at(0).toUpper().toLatin1()));
Edric Milareta0ebd062016-01-13 12:18:23 -050077 }
78}
79
80QVariant
81PixbufManipulator::contactPhoto(Person* c, const QSize& size, bool displayPresence)
82{
83 Q_UNUSED(displayPresence);
84
85 /**
86 * try to get the photo
87 * otherwise use the fallback avatar
88 */
89
90 QImage photo;
91
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -050092 if (c->photo().isValid()){
Edric Milareta0ebd062016-01-13 12:18:23 -050093 photo = c->photo().value<QImage>();
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -050094 } else {
Anthony Léonard3d920d82017-07-31 13:51:16 -040095 photo = fallbackAvatar(size,
96 c->phoneNumbers().at(0)->uri().userinfo().at(0).toLatin1(),
97 c->phoneNumbers().at(0)->bestName().at(0).toUpper().toLatin1());
Olivier SOLDANOad0fabb2016-11-25 09:08:01 -050098 }
Edric Milareta0ebd062016-01-13 12:18:23 -050099 return QVariant::fromValue(scaleAndFrame(photo, size));
100}
101
102QVariant PixbufManipulator::personPhoto(const QByteArray& data, const QString& type)
103{
Edric Milaret25236d92016-03-28 09:40:58 -0400104 QImage avatar;
105 QByteArray ba = type.toLatin1();
106 const char* c_str2 = ba.data();
107 if (avatar.loadFromData(data.fromBase64(data), c_str2))
108 return Utils::getCirclePhoto(avatar, avatar.size().width());
Anthony Léonard3d920d82017-07-31 13:51:16 -0400109 return fallbackAvatar(imgSize_, '?', '?');
Edric Milareta0ebd062016-01-13 12:18:23 -0500110}
111
112QVariant
113PixbufManipulator::numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence, bool isPresent)
114{
115 Q_UNUSED(p)
116 Q_UNUSED(size)
117 Q_UNUSED(displayPresence)
118 Q_UNUSED(isPresent)
119 return QVariant();
120}
121
122QVariant
123PixbufManipulator::securityIssueIcon(const QModelIndex& index)
124{
125 Q_UNUSED(index)
126 return QVariant();
127}
128
Edric Milaret25236d92016-03-28 09:40:58 -0400129
130
Edric Milareta0ebd062016-01-13 12:18:23 -0500131QByteArray
132PixbufManipulator::toByteArray(const QVariant& pxm)
133{
Edric Milaret25236d92016-03-28 09:40:58 -0400134 auto image = pxm.value<QImage>();
135 QByteArray ba = QImageToByteArray(image);
136 return ba;
Edric Milareta0ebd062016-01-13 12:18:23 -0500137}
138
139QVariant
Olivier SOLDANO41e61ab2017-08-04 16:47:16 -0400140PixbufManipulator::collectionIcon(const CollectionInterface* colItf, PixmapManipulatorI::CollectionIconHint hint) const
Edric Milareta0ebd062016-01-13 12:18:23 -0500141{
Olivier SOLDANO41e61ab2017-08-04 16:47:16 -0400142 Q_UNUSED(colItf)
Edric Milareta0ebd062016-01-13 12:18:23 -0500143 Q_UNUSED(hint)
144 return QVariant();
145}
146QVariant
147PixbufManipulator::securityLevelIcon(const SecurityEvaluationModel::SecurityLevel level) const
148{
149 Q_UNUSED(level)
150 return QVariant();
151}
152QVariant
153PixbufManipulator::historySortingCategoryIcon(const CategorizedHistoryModel::SortedProxy::Categories cat) const
154{
155 Q_UNUSED(cat)
156 return QVariant();
157}
158QVariant
159PixbufManipulator::contactSortingCategoryIcon(const CategorizedContactModel::SortedProxy::Categories cat) const
160{
161 Q_UNUSED(cat)
162 return QVariant();
163}
164QVariant
165PixbufManipulator::userActionIcon(const UserActionElement& state) const
166{
167 Q_UNUSED(state)
168 return QVariant();
169}
170
171QVariant PixbufManipulator::decorationRole(const QModelIndex& index)
172{
173 Q_UNUSED(index)
174 return QVariant();
175}
176
177QVariant PixbufManipulator::decorationRole(const Call* c)
178{
Edric Milareta13b48c2016-01-18 14:42:35 -0500179 QImage photo;
Edric Milareta0ebd062016-01-13 12:18:23 -0500180 if (c && c->peerContactMethod()
181 && c->peerContactMethod()->contact()
182 && c->peerContactMethod()->contact()->photo().isValid()) {
Edric Milareta13b48c2016-01-18 14:42:35 -0500183 photo = c->peerContactMethod()->contact()->photo().value<QImage>();
Edric Milareta0ebd062016-01-13 12:18:23 -0500184 }
Edric Milareta13b48c2016-01-18 14:42:35 -0500185 else
Anthony Léonard3d920d82017-07-31 13:51:16 -0400186 photo = fallbackAvatar(imgSize_,
187 c->peerContactMethod()->uri().userinfo().at(0).toLatin1(),
188 c->peerContactMethod()->bestName().at(0).toUpper().toLatin1());
Edric Milareta13b48c2016-01-18 14:42:35 -0500189 return QVariant::fromValue(scaleAndFrame(photo, imgSize_));
Edric Milareta0ebd062016-01-13 12:18:23 -0500190}
191
192QVariant PixbufManipulator::decorationRole(const ContactMethod* cm)
193{
Edric Milareta13b48c2016-01-18 14:42:35 -0500194 QImage photo;
Edric Milareta0ebd062016-01-13 12:18:23 -0500195 if (cm && cm->contact() && cm->contact()->photo().isValid())
Edric Milareta13b48c2016-01-18 14:42:35 -0500196 photo = cm->contact()->photo().value<QImage>();
197 else
Anthony Léonard3d920d82017-07-31 13:51:16 -0400198 photo = fallbackAvatar(imgSize_,
199 cm->uri().userinfo().at(0).toLatin1(),
200 cm->bestName().at(0).toUpper().toLatin1());
Edric Milareta13b48c2016-01-18 14:42:35 -0500201 return QVariant::fromValue(scaleAndFrame(photo, imgSize_));
Edric Milareta0ebd062016-01-13 12:18:23 -0500202}
203
204QVariant PixbufManipulator::decorationRole(const Person* p)
205{
Edric Milareta13b48c2016-01-18 14:42:35 -0500206 QImage photo;
Edric Milareta0ebd062016-01-13 12:18:23 -0500207 if (p && p->photo().isValid())
Edric Milareta13b48c2016-01-18 14:42:35 -0500208 photo = p->photo().value<QImage>();
209 else
Anthony Léonard3d920d82017-07-31 13:51:16 -0400210 photo = fallbackAvatar(imgSize_,
211 p->phoneNumbers().at(0)->uri().userinfo().at(0).toLatin1(),
212 p->phoneNumbers().at(0)->bestName().at(0).toUpper().toLatin1());
Edric Milareta13b48c2016-01-18 14:42:35 -0500213 return QVariant::fromValue(scaleAndFrame(photo, imgSize_));
Edric Milareta0ebd062016-01-13 12:18:23 -0500214}
215
Edric Milareta7cf8652016-04-19 15:37:51 -0400216QVariant PixbufManipulator::decorationRole(const Account* acc)
217{
218 Q_UNUSED(acc)
Edric Milaret25236d92016-03-28 09:40:58 -0400219 return Utils::getCirclePhoto(ProfileModel::instance().
220 selectedProfile()->person()->photo().value<QImage>(),
221 imgSize_.width());
Edric Milareta7cf8652016-04-19 15:37:51 -0400222}
223
Anthony Léonard3d920d82017-07-31 13:51:16 -0400224QImage PixbufManipulator::fallbackAvatar(const QSize size, const char color, const char letter)
225{
226 // We start with a transparent avatar
227 QImage avatar(size, QImage::Format_ARGB32);
228 avatar.fill(Qt::transparent);
229
230 // We pick a color based on the passed character
231 QColor avColor = RingTheme::avatarColors_[color % 16];
232
233 // We draw a circle with this color
234 QPainter painter(&avatar);
235 painter.setRenderHints(QPainter::Antialiasing|QPainter::SmoothPixmapTransform);
236 painter.setPen(Qt::transparent);
237 painter.setBrush(avColor);
238 painter.drawEllipse(avatar.rect());
239
240 // Then we paint a letter in the circle
241 QFont segoeFont("Segoe UI", avatar.height()/2); // We use Segoe UI as recommended by Windows guidelines
242 painter.setFont(segoeFont);
243 painter.setPen(Qt::white);
244 QRect textRect = avatar.rect();
245 textRect.moveTop(textRect.top()-(avatar.height()/20)); // Empirical value that seems to correct centering nicely
246 painter.drawText(textRect, QString(letter), QTextOption(Qt::AlignCenter));
247
248 return avatar;
249}