Codebase list ktp-accounts-kcm / upstream/0.8.0 src / avatar-button.cpp
upstream/0.8.0

Tree @upstream/0.8.0 (Download .tar.gz)

avatar-button.cpp @upstream/0.8.0raw · history · blame

/*
 * Button representing user's Avatar
 *
 * Copyright (C) 2011  Martin Klapetek <martin.klapetek@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "avatar-button.h"

#include <QtGui/QWidgetAction>
#include <QDataStream>

#include <KFileDialog>
#include <KMenu>
#include <KLocalizedString>
#include <KMessageBox>
#include <KImageFilePreview>

#include <TelepathyQt/Account>

#include <KDE/KDebug>
#include <KGlobalSettings>
#include <KPixmapRegionSelectorDialog>
#include <KPixmapRegionSelectorWidget>

// It has been decided by a fair dice roll that 128px is a reasonable avatar
// size limit in case the server (or Telepathy backend) does not provide
// such information
#define AVATAR_MIN_SIZE 64
#define AVATAR_MAX_SIZE 128

AvatarButton::AvatarButton(QWidget *parent)
    : QToolButton(parent)
{
    KMenu *menu = new KMenu(this);

    setPopupMode(QToolButton::InstantPopup);

    setIconSize(QSize(64,64));

    menu->addAction(KIcon(QLatin1String("document-open-folder")), i18n("Load from file..."), this, SLOT(onLoadAvatarFromFile()));
    menu->addAction(KIcon(QLatin1String("edit-clear")), i18n("Clear Avatar"), this, SLOT(onClearAvatar()));

    setMenu(menu);
}

AvatarButton::~AvatarButton()
{

}

void AvatarButton::setAvatar(const Tp::Avatar &avatar)
{
    m_avatar = avatar;

    if (! avatar.avatarData.isNull()) {
        KIcon avatarIcon;
        QPixmap avatarPixmap = QPixmap::fromImage(QImage::fromData(avatar.avatarData));
        //scale oversized avatars to fit, but don't stretch smaller avatars
        avatarIcon.addPixmap(avatarPixmap.scaled(iconSize().boundedTo(avatarPixmap.size()), Qt::KeepAspectRatio));
        setIcon(avatarIcon);
    } else {
        setIcon(KIcon(QLatin1String("im-user")));
    }
}

Tp::Avatar AvatarButton::avatar() const
{
    return m_avatar;
}

void AvatarButton::setAccount(const Tp::AccountPtr& account)
{
    m_account = account;
}

void AvatarButton::onLoadAvatarFromFile()
{
    QStringList mimeTypes;
    if (m_account) {
        mimeTypes = m_account->avatarRequirements().supportedMimeTypes();
    }
    if (mimeTypes.isEmpty()) {
        mimeTypes << QLatin1String("image/jpeg")
                  << QLatin1String("image/png")
                  << QLatin1String("imgae/gif");
    }

    QPointer<KFileDialog> dialog = new KFileDialog(KUrl::fromPath(KGlobalSettings::picturesPath()),
                                                   mimeTypes.join(QLatin1String(" ")), this);
    dialog->setOperationMode(KFileDialog::Opening);
    dialog->setPreviewWidget(new KImageFilePreview(dialog));
    dialog->setCaption(i18n("Please choose your avatar"));

    KUrl fileUrl;
    if (dialog->exec()) {
        if (!dialog) {
            return;
        }

        fileUrl = dialog->selectedUrl();
    }

    delete dialog;

    if (fileUrl.isEmpty()) {
        return;
    }

    const QPixmap pixmap(fileUrl.toLocalFile());

    const Tp::AvatarSpec spec = m_account->avatarRequirements();

    const int maxWidth = spec.maximumWidth() > 0 ? spec.maximumWidth() : AVATAR_MAX_SIZE;
    const int maxHeight = spec.maximumHeight() > 0 ? spec.maximumHeight() : AVATAR_MAX_SIZE;
    const int minWidth = spec.minimumWidth() > 0 ? spec.minimumWidth() : AVATAR_MIN_SIZE;
    const int minHeight = spec.minimumHeight() > 0 ? spec.minimumHeight() : AVATAR_MIN_SIZE;

    QPixmap finalPixmap;
    if (pixmap.width() > spec.maximumWidth() || pixmap.height() > spec.maximumHeight()) {
        finalPixmap = cropPixmap(pixmap, maxWidth, maxHeight, minWidth, minHeight);
    } else {
        finalPixmap = pixmap;

        if (pixmap.width() < minWidth) {
            finalPixmap = finalPixmap.scaledToWidth(minWidth, Qt::SmoothTransformation);
        }

        if (pixmap.height() < minHeight) {
            finalPixmap = finalPixmap.scaledToHeight(minHeight, Qt::SmoothTransformation);
        }
    }

    if (finalPixmap.isNull()) {
        return;
    }

    Tp::Avatar avatar;
    avatar.MIMEType = QLatin1String("image/png");
    QDataStream stream(&avatar.avatarData, QIODevice::WriteOnly);
    if (!finalPixmap.save(stream.device(), "PNG")) {
        KMessageBox::error(this, i18n("Failed to load avatar."));
        return;
    }

    setAvatar(avatar);
    Q_EMIT avatarChanged();
}

QPixmap AvatarButton::cropPixmap(const QPixmap &pixmap, int maxWidth, int maxHeight,
                                 int minWidth, int minHeight) const
{
    //if there's no image we don't need to select a region
    if (pixmap.isNull()) {
        return pixmap;
    }

    QPointer<KPixmapRegionSelectorDialog> regionDlg = new KPixmapRegionSelectorDialog();
    KPixmapRegionSelectorWidget *widget = regionDlg->pixmapRegionSelectorWidget();
    widget->setPixmap(pixmap);
    widget->setSelectionAspectRatio(maxWidth, maxHeight);

    if (regionDlg->exec()) {
        if (!regionDlg) {
            return QPixmap();
        }

        delete regionDlg;

        QImage selectedImage = widget->selectedImage();
        if (selectedImage.width() > maxWidth || selectedImage.height() > maxHeight) {
            return QPixmap::fromImage(selectedImage.scaled(maxWidth, maxHeight, Qt::KeepAspectRatio));
        } else if (selectedImage.width() < minWidth || selectedImage.height() < minHeight) {
            return QPixmap::fromImage(selectedImage.scaled(minWidth, minHeight, Qt::KeepAspectRatio));
        } else {
            return QPixmap::fromImage(widget->selectedImage());
        }
    }

    delete regionDlg;

    return QPixmap();
}

void AvatarButton::onClearAvatar()
{
    setAvatar(Tp::Avatar());
    Q_EMIT avatarChanged();
}