conversation.cpp 4.97 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
    Copyright (C) 2011  Lasath Fernando <kde@lasath.org>

    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 "conversation.h"
21
#include "messages-model.h"
22

David Edmundson's avatar
David Edmundson committed
23
#include <TelepathyQt/TextChannel>
24 25 26 27
#include <TelepathyQt/Account>
#include <TelepathyQt/PendingChannelRequest>
#include <TelepathyQt/PendingChannel>

Lasath Fernando's avatar
Lasath Fernando committed
28
#include <KDebug>
29
#include "conversation-target.h"
30

31 32
#include "channel-delegator.h"

Lasath Fernando's avatar
Lasath Fernando committed
33 34
class Conversation::ConversationPrivate
{
35
  public:
36
    MessagesModel *messages;
37
    ConversationTarget *target;
38 39 40
    //stores if the conversation has been delegated to another client and we are only observing the channel
    //and not handling it.
    bool delegated;
41
    bool valid;
42
    Tp::AccountPtr account;
43 44
};

Martin Klapetek's avatar
Martin Klapetek committed
45 46
Conversation::Conversation(const Tp::TextChannelPtr &channel,
                           const Tp::AccountPtr &account,
47
                           QObject *parent) :
48
        QObject(parent),
49
        d (new ConversationPrivate)
50
{
Lasath Fernando's avatar
Lasath Fernando committed
51 52
    kDebug();

53
    d->account = account;
54
    connect(d->account.data(), SIGNAL(connectionChanged(Tp::ConnectionPtr)), SLOT(onAccountConnectionChanged(Tp::ConnectionPtr)));
55

56
    d->messages = new MessagesModel(account, this);
57
    setTextChannel(channel);
58
    d->target = new ConversationTarget(account, KTp::ContactPtr::qObjectCast(channel->targetContact()), this);
59

60 61
    d->delegated = false;

Lasath Fernando's avatar
Lasath Fernando committed
62 63
}

64
Conversation::Conversation(QObject *parent) : QObject(parent)
Lasath Fernando's avatar
Lasath Fernando committed
65
{
66
    kError() << "Conversation should not be created directly. Use ConversationWatcher instead.";
67
    Q_ASSERT(false);
68 69
}

70 71
void Conversation::setTextChannel(const Tp::TextChannelPtr& channel)
{
72 73 74 75 76 77 78
    if (d->messages->textChannel() != channel) {
        d->messages->setTextChannel(channel);
        d->valid = channel->isValid();
        connect(channel.data(), SIGNAL(invalidated(Tp::DBusProxy*,QString,QString)),
                SLOT(onChannelInvalidated(Tp::DBusProxy*,QString,QString)));
        Q_EMIT validityChanged(d->valid);
    }
79 80 81 82 83 84 85
}

Tp::TextChannelPtr Conversation::textChannel() const
{
    return d->messages->textChannel();
}

86
MessagesModel* Conversation::messages() const
87
{
88
    return d->messages;
89 90
}

91
ConversationTarget* Conversation::target() const
92
{
93
    return d->target;
94 95
}

96 97 98 99 100
bool Conversation::isValid()
{
    return d->valid;
}

Martin Klapetek's avatar
Martin Klapetek committed
101
void Conversation::onChannelInvalidated(Tp::DBusProxy *proxy, const QString &errorName, const QString &errorMessage)
102 103 104 105 106 107 108 109
{
    kDebug() << proxy << errorName << ":" << errorMessage;

    d->valid = false;

    Q_EMIT validityChanged(d->valid);
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
void Conversation::onAccountConnectionChanged(const Tp::ConnectionPtr& connection)
{
    //if we have reconnected and we were handling the channel
    if (connection && ! d->delegated) {

        //general convention is to never use ensureAndHandle when we already have a client registrar
        //ensureAndHandle will implicity create a new temporary client registrar which is a waste
        //it's also more code to get the new channel

        //However, we cannot use use ensureChannel as normal because without being able to pass a preferredHandler
        //we need a preferredHandler so that this handler is the one that ends up with the channel if multi handlers are active
        //we do not know the name that this handler is currently registered with
        Tp::PendingChannel *pendingChannel = d->account->ensureAndHandleTextChat(textChannel()->targetId());
        connect(pendingChannel, SIGNAL(finished(Tp::PendingOperation*)), SLOT(onCreateChannelFinished(Tp::PendingOperation*)));
    }
}

void Conversation::onCreateChannelFinished(Tp::PendingOperation* op)
{
    Tp::PendingChannel *pendingChannelOp = qobject_cast<Tp::PendingChannel*>(op);
    Tp::TextChannelPtr textChannel = Tp::TextChannelPtr::dynamicCast(pendingChannelOp->channel());
    if (textChannel) {
        setTextChannel(textChannel);
    }
}

136 137 138
void Conversation::delegateToProperClient()
{
    ChannelDelegator::delegateChannel(d->account, d->messages->textChannel());
139
    d->delegated = true;
140
    Q_EMIT conversationCloseRequested();
141 142
}

143 144 145
void Conversation::requestClose()
{
    kDebug();
146 147 148

    //removing from the model will delete this object closing the channel
    Q_EMIT conversationCloseRequested();
149 150
}

151 152
Conversation::~Conversation()
{
Lasath Fernando's avatar
Lasath Fernando committed
153
    kDebug();
154 155 156 157
    //if we are not handling the channel do nothing.
    if (!d->delegated) {
        d->messages->textChannel()->requestClose();
    }
158
    delete d;
159
}