File indexing completed on 2023-11-26 04:55:35

0001 /*
0002  * Button representing user's Avatar
0003  *
0004  * Copyright (C) 2011  Martin Klapetek <martin.klapetek@gmail.com>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library; if not, write to the Free Software
0018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0019  */
0020 
0021 #include "avatar-button.h"
0022 
0023 #include <QtGui/QWidgetAction>
0024 #include <QDataStream>
0025 
0026 #include <KFileDialog>
0027 #include <KMenu>
0028 #include <KLocalizedString>
0029 #include <KMessageBox>
0030 #include <KImageFilePreview>
0031 
0032 #include <TelepathyQt/Account>
0033 
0034 #include <KDE/KDebug>
0035 #include <KGlobalSettings>
0036 #include <KPixmapRegionSelectorDialog>
0037 #include <KPixmapRegionSelectorWidget>
0038 
0039 // It has been decided by a fair dice roll that 128px is a reasonable avatar
0040 // size limit in case the server (or Telepathy backend) does not provide
0041 // such information
0042 #define AVATAR_MIN_SIZE 64
0043 #define AVATAR_MAX_SIZE 128
0044 
0045 AvatarButton::AvatarButton(QWidget *parent)
0046     : QToolButton(parent)
0047 {
0048     KMenu *menu = new KMenu(this);
0049 
0050     setPopupMode(QToolButton::InstantPopup);
0051 
0052     setIconSize(QSize(64,64));
0053 
0054     menu->addAction(KIcon(QLatin1String("document-open-folder")), i18n("Load from file..."), this, SLOT(onLoadAvatarFromFile()));
0055     menu->addAction(KIcon(QLatin1String("edit-clear")), i18n("Clear Avatar"), this, SLOT(onClearAvatar()));
0056 
0057     setMenu(menu);
0058 }
0059 
0060 AvatarButton::~AvatarButton()
0061 {
0062 
0063 }
0064 
0065 void AvatarButton::setAvatar(const Tp::Avatar &avatar)
0066 {
0067     m_avatar = avatar;
0068 
0069     if (! avatar.avatarData.isNull()) {
0070         KIcon avatarIcon;
0071         QPixmap avatarPixmap = QPixmap::fromImage(QImage::fromData(avatar.avatarData));
0072         //scale oversized avatars to fit, but don't stretch smaller avatars
0073         avatarIcon.addPixmap(avatarPixmap.scaled(iconSize().boundedTo(avatarPixmap.size()), Qt::KeepAspectRatio, Qt::SmoothTransformation));
0074         setIcon(avatarIcon);
0075     } else {
0076         setIcon(KIcon(QLatin1String("im-user")));
0077     }
0078 }
0079 
0080 Tp::Avatar AvatarButton::avatar() const
0081 {
0082     return m_avatar;
0083 }
0084 
0085 void AvatarButton::setAccount(const Tp::AccountPtr& account)
0086 {
0087     m_account = account;
0088 }
0089 
0090 void AvatarButton::onLoadAvatarFromFile()
0091 {
0092     QStringList mimeTypes;
0093     if (m_account) {
0094         mimeTypes = m_account->avatarRequirements().supportedMimeTypes();
0095     }
0096     if (mimeTypes.isEmpty()) {
0097         mimeTypes << QLatin1String("image/jpeg")
0098                   << QLatin1String("image/png")
0099                   << QLatin1String("imgae/gif");
0100     }
0101 
0102     QPointer<KFileDialog> dialog = new KFileDialog(KUrl::fromPath(KGlobalSettings::picturesPath()),
0103                                                    mimeTypes.join(QLatin1String(" ")), this);
0104     dialog->setOperationMode(KFileDialog::Opening);
0105     dialog->setPreviewWidget(new KImageFilePreview(dialog));
0106     dialog->setCaption(i18n("Please choose your avatar"));
0107 
0108     KUrl fileUrl;
0109     if (dialog->exec()) {
0110         if (!dialog) {
0111             return;
0112         }
0113 
0114         fileUrl = dialog->selectedUrl();
0115     }
0116 
0117     delete dialog;
0118 
0119     if (fileUrl.isEmpty()) {
0120         return;
0121     }
0122 
0123     const QPixmap pixmap(fileUrl.toLocalFile());
0124 
0125     const Tp::AvatarSpec spec = m_account->avatarRequirements();
0126 
0127     const int maxWidth = spec.maximumWidth() > 0 ? spec.maximumWidth() : AVATAR_MAX_SIZE;
0128     const int maxHeight = spec.maximumHeight() > 0 ? spec.maximumHeight() : AVATAR_MAX_SIZE;
0129     const int minWidth = spec.minimumWidth() > 0 ? spec.minimumWidth() : AVATAR_MIN_SIZE;
0130     const int minHeight = spec.minimumHeight() > 0 ? spec.minimumHeight() : AVATAR_MIN_SIZE;
0131 
0132     QPixmap finalPixmap;
0133     if (pixmap.width() > spec.maximumWidth() || pixmap.height() > spec.maximumHeight()) {
0134         finalPixmap = cropPixmap(pixmap, maxWidth, maxHeight, minWidth, minHeight);
0135     } else {
0136         finalPixmap = pixmap;
0137 
0138         if (pixmap.width() < minWidth) {
0139             finalPixmap = finalPixmap.scaledToWidth(minWidth, Qt::SmoothTransformation);
0140         }
0141 
0142         if (pixmap.height() < minHeight) {
0143             finalPixmap = finalPixmap.scaledToHeight(minHeight, Qt::SmoothTransformation);
0144         }
0145     }
0146 
0147     if (finalPixmap.isNull()) {
0148         return;
0149     }
0150 
0151     Tp::Avatar avatar;
0152     avatar.MIMEType = QLatin1String("image/png");
0153     QDataStream stream(&avatar.avatarData, QIODevice::WriteOnly);
0154     if (!finalPixmap.save(stream.device(), "PNG")) {
0155         KMessageBox::error(this, i18n("Failed to load avatar."));
0156         return;
0157     }
0158 
0159     setAvatar(avatar);
0160     Q_EMIT avatarChanged();
0161 }
0162 
0163 QPixmap AvatarButton::cropPixmap(const QPixmap &pixmap, int maxWidth, int maxHeight,
0164                                  int minWidth, int minHeight) const
0165 {
0166     //if there's no image we don't need to select a region
0167     if (pixmap.isNull()) {
0168         return pixmap;
0169     }
0170 
0171     QPointer<KPixmapRegionSelectorDialog> regionDlg = new KPixmapRegionSelectorDialog();
0172     KPixmapRegionSelectorWidget *widget = regionDlg->pixmapRegionSelectorWidget();
0173     widget->setPixmap(pixmap);
0174     widget->setSelectionAspectRatio(maxWidth, maxHeight);
0175 
0176     if (regionDlg->exec()) {
0177         if (!regionDlg) {
0178             return QPixmap();
0179         }
0180 
0181         delete regionDlg;
0182 
0183         QImage selectedImage = widget->selectedImage();
0184         if (selectedImage.width() > maxWidth || selectedImage.height() > maxHeight) {
0185             return QPixmap::fromImage(selectedImage.scaled(maxWidth, maxHeight, Qt::KeepAspectRatio));
0186         } else if (selectedImage.width() < minWidth || selectedImage.height() < minHeight) {
0187             return QPixmap::fromImage(selectedImage.scaled(minWidth, minHeight, Qt::KeepAspectRatio));
0188         } else {
0189             return QPixmap::fromImage(widget->selectedImage());
0190         }
0191     }
0192 
0193     delete regionDlg;
0194 
0195     return QPixmap();
0196 }
0197 
0198 void AvatarButton::onClearAvatar()
0199 {
0200     setAvatar(Tp::Avatar());
0201     Q_EMIT avatarChanged();
0202 }