pinned-contacts-model.cpp 9.08 KB
Newer Older
1 2
/*
    Copyright (C) 2012 Aleix Pol <aleixpol@kde.org>
Martin Klapetek's avatar
Martin Klapetek committed
3

4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
    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 Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "pinned-contacts-model.h"
#include "conversations-model.h"
#include "conversation.h"
Martin Klapetek's avatar
Martin Klapetek committed
22

23 24 25 26 27 28 29 30
#include <TelepathyQt/Types>
#include <TelepathyQt/AvatarData>
#include <TelepathyQt/Presence>
#include <TelepathyQt/Account>
#include <TelepathyQt/AccountManager>
#include <TelepathyQt/PendingReady>
#include <TelepathyQt/ContactManager>
#include <TelepathyQt/PendingContacts>
Martin Klapetek's avatar
Martin Klapetek committed
31

32
#include <KConfigGroup>
33
#include "debug.h"
Martin Klapetek's avatar
Martin Klapetek committed
34

David Edmundson's avatar
David Edmundson committed
35 36
#include "KTp/presence.h"
#include "KTp/contact.h"
37
#include "KTp/persistent-contact.h"
38 39 40

class PinnedContactsModelPrivate {
public:
41 42 43 44 45
    PinnedContactsModelPrivate() {
        conversations = 0;
    }

    QList<KTp::PersistentContactPtr> m_pins;
46
    Tp::AccountManagerPtr accountManager;
47
    ConversationsModel *conversations;
48 49 50

    QStringList pinsToString() const {
        QStringList ret;
51 52 53
        Q_FOREACH(const KTp::PersistentContactPtr &p, m_pins) {
            ret += p->accountId();
            ret += p->contactId();
54 55 56 57 58
        }
        return ret;
    }
};

Martin Klapetek's avatar
Martin Klapetek committed
59
PinnedContactsModel::PinnedContactsModel(QObject *parent)
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
    : QAbstractListModel(parent)
    , d(new PinnedContactsModelPrivate)
{
    QHash<int, QByteArray> roles = roleNames();
    roles[PresenceIconRole] = "presenceIcon";
    roles[AvailabilityRole] = "available";
    roles[ContactRole] = "contact";
    roles[AccountRole] = "account";
    roles[AlreadyChattingRole] = "alreadyChatting";
    setRoleNames(roles);

    connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
    connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
}

PinnedContactsModel::~PinnedContactsModel()
{
    delete d;
}

QStringList PinnedContactsModel::state() const
{
    return d->pinsToString();
}

Martin Klapetek's avatar
Martin Klapetek committed
85
void PinnedContactsModel::setState(const QStringList &pins)
86
{
87 88
    for (int i = 0; i < pins.count(); i += 2) {
        appendContactPin(KTp::PersistentContact::create(pins[0], pins[1]));
89 90 91
    }
}

92
QModelIndex PinnedContactsModel::indexForContact(const KTp::ContactPtr &contact) const
93
{
94 95 96
    for (int i=0; i<d->m_pins.size();i++) {
        if (d->m_pins[i]->contact() == contact) {
            return index(i);
97
        }
Martin Klapetek's avatar
Martin Klapetek committed
98
    }
99
    return QModelIndex();
100 101
}

102
void PinnedContactsModel::setPinning(const Tp::AccountPtr &account, const KTp::ContactPtr &contact, bool newState)
103
{
104
    QModelIndex idx = indexForContact(contact);
105 106
    bool found = idx.isValid();
    if (newState && !found) {
107 108
        KTp::PersistentContactPtr p = KTp::PersistentContact::create(account->uniqueIdentifier(), contact->id());
        appendContactPin(p);
109
    } else if (!newState && found) {
110
        removeContactPin(d->m_pins[idx.row()]);
111 112 113
    }
}

Martin Klapetek's avatar
Martin Klapetek committed
114
QVariant PinnedContactsModel::data(const QModelIndex &index, int role) const
115 116
{
    if (index.isValid()) {
117
        KTp::PersistentContactPtr p = d->m_pins[index.row()];
118
        switch(role) {
119 120 121
        case Qt::DisplayRole:
            if (p->contact()) {
                return p->contact()->alias();
122
            }
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
            break;
        case PresenceIconRole:
            if (p->contact()) {
                return KTp::Presence(p->contact()->presence()).icon();
            } else {
                return KTp::Presence(Tp::Presence::offline()).icon();
            }
            break;
        case AvailabilityRole:
            if (!p->contact()) {
                return false;
            }
            else {
                return p->contact()->presence().type()!=Tp::ConnectionPresenceTypeOffline
                        && p->contact()->presence().type()!=Tp::ConnectionPresenceTypeError
                        && p->contact()->presence().type()!=Tp::ConnectionPresenceTypeUnset
                        && p->contact()->presence().type()!=Tp::ConnectionPresenceTypeUnknown;
            }
        case ContactRole:
            return QVariant::fromValue<KTp::ContactPtr>(p->contact());
        case AccountRole:
            return QVariant::fromValue<Tp::AccountPtr>(p->account());
        case AlreadyChattingRole: {
            if (!p->contact()) {
                return false;
            }
            bool found = false;
            for (int i = 0; !found && i < d->conversations->rowCount(); i++) {
                QModelIndex idx = d->conversations->index(i, 0);
152
                KTp::ContactPtr contact = idx.data(ConversationsModel::ConversationRole).value<Conversation*>()->targetContact();
153 154 155 156 157
                found |= contact->id() == p->contact()->id();
            }
            return found;
        }
        case Qt::DecorationRole: {
158
            QIcon icon;
159 160 161
            if (p->contact()) {
                QString file = p->contact()->avatarData().fileName;
                if (!file.isEmpty()) {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
162
                    icon = QIcon::fromTheme(file);
163 164
                }
            }
165
            if (icon.isNull()) {
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
166
                icon = QIcon::fromTheme(QStringLiteral("im-user"));
167 168 169
            }
            return icon;
        }
170 171 172 173 174
        }
    }
    return QVariant();
}

Martin Klapetek's avatar
Martin Klapetek committed
175
int PinnedContactsModel::rowCount(const QModelIndex &parent) const
176 177 178 179 180 181 182
{
    if (parent.isValid()) {
        return 0;
    }
    return d->m_pins.count();
}

183
void PinnedContactsModel::removeContactPin(const KTp::PersistentContactPtr &pin)
184
{
185 186 187
    int row = d->m_pins.indexOf(pin);
    beginRemoveRows(QModelIndex(), row, row);
    d->m_pins.removeAt(row);
188 189 190
    endRemoveRows();
}

191
void PinnedContactsModel::appendContactPin(const KTp::PersistentContactPtr &pin)
192 193 194
{
    int s = d->m_pins.size();
    beginInsertRows(QModelIndex(), s, s);
195
    d->m_pins += pin;
196
    endInsertRows();
Martin Klapetek's avatar
Martin Klapetek committed
197

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
    if (d->accountManager && d->accountManager->isReady()) {
        pin->setAccountManager(d->accountManager);
    }

    if (pin->contact()) {
        contactChanged(pin->contact());
    }
    connect(pin.data(), SIGNAL(contactChanged(KTp::ContactPtr)), SLOT(contactChanged(KTp::ContactPtr)));
}

void PinnedContactsModel::contactChanged(const KTp::ContactPtr &contact)
{
    if (contact) {
        connect(contact.data(),
                SIGNAL(avatarDataChanged(Tp::AvatarData)),
                SLOT(contactDataChanged()));
        connect(contact.data(),
                SIGNAL(aliasChanged(QString)),
                SLOT(contactDataChanged()));
        connect(contact.data(),
                SIGNAL(presenceChanged(Tp::Presence)),
                SLOT(contactDataChanged()));
    }

    QModelIndex index = indexForContact(contact);
    Q_EMIT dataChanged(index, index);
224 225 226 227
}

void PinnedContactsModel::contactDataChanged()
{
228
    KTp::Contact *c = qobject_cast<KTp::Contact*>(sender());
229 230
    QModelIndex index = indexForContact(KTp::ContactPtr(c));
    Q_EMIT dataChanged(index, index);
231 232
}

Martin Klapetek's avatar
Martin Klapetek committed
233
void PinnedContactsModel::setConversationsModel(ConversationsModel *model)
234 235
{
    beginResetModel();
236 237 238
    d->conversations = model;
    connect(d->conversations, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), SLOT(conversationsStateChanged(QModelIndex, int, int)));
    connect(d->conversations, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(conversationsStateChanged(QModelIndex, int, int)));
239 240 241
    endResetModel();
}

Martin Klapetek's avatar
Martin Klapetek committed
242
void PinnedContactsModel::conversationsStateChanged(const QModelIndex &parent, int start, int end)
243
{
Martin Klapetek's avatar
Martin Klapetek committed
244
    for (int i = start; i <= end; i++) {
245
        QModelIndex idx = d->conversations->index(i, 0, parent);
246
        Conversation* conv = idx.data(ConversationsModel::ConversationRole).value<Conversation*>();
247
        KTp::ContactPtr contact = conv->targetContact();
248 249 250
        Q_FOREACH(const KTp::PersistentContactPtr &p, d->m_pins) {
            if (p->contact() == contact) {
                QModelIndex contactIdx = indexForContact(p->contact());
251 252 253
                //We need to delay the dataChanged until the next event loop, when endRowsRemoved has been called
                QMetaObject::invokeMethod(this, "dataChanged", Qt::QueuedConnection, Q_ARG(QModelIndex, contactIdx), Q_ARG(QModelIndex, contactIdx));
            }
254 255 256 257 258 259
        }
    }
}

ConversationsModel* PinnedContactsModel::conversationsModel() const
{
260
    return d->conversations;
261 262 263 264 265 266 267
}

Tp::AccountManagerPtr PinnedContactsModel::accountManager() const
{
    return d->accountManager;
}

Martin Klapetek's avatar
Martin Klapetek committed
268
void PinnedContactsModel::setAccountManager(const Tp::AccountManagerPtr &accounts)
269 270
{
    d->accountManager = accounts;
271 272

    connect(d->accountManager->becomeReady(), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onAccountManagerReady()));
273 274
}

275
void PinnedContactsModel::onAccountManagerReady()
276
{
277 278 279
    Q_FOREACH(const KTp::PersistentContactPtr &p, d->m_pins) {
        p->setAccountManager(d->accountManager);
    }
280
}