• Skip to content
  • Skip to link menu
  • KDE API Reference
  • KDE Home
  • Contact Us
 

Nepomuk-Core

  • KTp
  • Declarative
messages-model.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 Lasath Fernando <kde@lasath.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 
20 #include "messages-model.h"
21 
22 #include <KDebug>
23 #include <KLocalizedString>
24 
25 #include <TelepathyQt/ReceivedMessage>
26 #include <TelepathyQt/TextChannel>
27 #include <TelepathyQt/Account>
28 
29 #include "KTp/message-processor.h"
30 
31 class MessagesModel::MessagesModelPrivate
32 {
33  public:
34  Tp::TextChannelPtr textChannel;
35  Tp::AccountPtr account;
36  QList<KTp::Message> messages;
37  bool visible;
38 };
39 
40 MessagesModel::MessagesModel(const Tp::AccountPtr &account, QObject *parent) :
41  QAbstractListModel(parent),
42  d(new MessagesModelPrivate)
43 {
44  kDebug();
45 
46  QHash<int, QByteArray> roles;
47  roles[UserRole] = "user";
48  roles[TextRole] = "text";
49  roles[TimeRole] = "time";
50  roles[TypeRole] = "type";
51  setRoleNames(roles);
52 
53  d->account = account;
54  d->visible = false;
55 }
56 
57 Tp::TextChannelPtr MessagesModel::textChannel() const
58 {
59  return d->textChannel;
60 }
61 
62 bool MessagesModel::verifyPendingOperation(Tp::PendingOperation *op)
63 {
64  bool operationSucceeded = true;
65 
66  if (op->isError()) {
67  kWarning() << op->errorName() << "+" << op->errorMessage();
68  operationSucceeded = false;
69  }
70 
71  return operationSucceeded;
72 }
73 
74 void MessagesModel::setupChannelSignals(const Tp::TextChannelPtr &channel)
75 {
76  connect(channel.data(),
77  SIGNAL(messageReceived(Tp::ReceivedMessage)),
78  SLOT(onMessageReceived(Tp::ReceivedMessage)));
79  connect(channel.data(),
80  SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
81  SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
82  connect(channel.data(),
83  SIGNAL(pendingMessageRemoved(Tp::ReceivedMessage)),
84  SLOT(onPendingMessageRemoved()));
85 }
86 
87 void MessagesModel::setTextChannel(Tp::TextChannelPtr channel)
88 {
89  kDebug();
90  setupChannelSignals(channel);
91 
92  if (d->textChannel) {
93  removeChannelSignals(d->textChannel);
94  }
95 
96  d->textChannel = channel;
97 
98  QList<Tp::ReceivedMessage> messageQueue = channel->messageQueue();
99  Q_FOREACH(const Tp::ReceivedMessage &message, messageQueue) {
100  bool messageAlreadyInModel = false;
101  Q_FOREACH(const KTp::Message &current, d->messages) {
102  //FIXME: docs say messageToken can return an empty string. What to do if that happens?
103  //Tp::Message has an == operator. maybe I can use that?
104  if (current.token() == message.messageToken()) {
105  messageAlreadyInModel = true;
106  break;
107  }
108  }
109  if (!messageAlreadyInModel) {
110  onMessageReceived(message);
111  }
112  }
113 }
114 
115 void MessagesModel::onMessageReceived(const Tp::ReceivedMessage &message)
116 {
117  int unreadCount = d->textChannel->messageQueue().size();
118  kDebug() << "unreadMessagesCount =" << unreadCount;
119  kDebug() << "text =" << message.text();
120  kDebug() << "messageToken =" << message.messageToken();
121 
122  if (message.messageType() == Tp::ChannelTextMessageTypeNormal ||
123  message.messageType() == Tp::ChannelTextMessageTypeAction) {
124 
125  int length = rowCount();
126  beginInsertRows(QModelIndex(), length, length);
127 
128 
129  d->messages.append(KTp::MessageProcessor::instance()->processIncomingMessage(
130  message, d->account, d->textChannel));
131 
132  endInsertRows();
133 
134  if (d->visible) {
135  acknowledgeAllMessages();
136  } else {
137  enqueueSelf();
138  Q_EMIT unreadCountChanged(unreadCount);
139  }
140  }
141 
142 }
143 
144 void MessagesModel::onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &messageToken)
145 {
146  Q_UNUSED(flags);
147  Q_UNUSED(messageToken);
148 
149  int length = rowCount();
150  beginInsertRows(QModelIndex(), length, length);
151  kDebug() << "text =" << message.text();
152 
153  d->messages.append(KTp::MessageProcessor::instance()->processIncomingMessage(
154  message, d->account, d->textChannel));
155 
156  endInsertRows();
157 }
158 
159 void MessagesModel::onPendingMessageRemoved()
160 {
161  Q_EMIT unreadCountChanged(unreadCount());
162 }
163 
164 QVariant MessagesModel::data(const QModelIndex &index, int role) const
165 {
166  QVariant result;
167 
168  if (index.isValid()) {
169  KTp::Message requestedData = d->messages[index.row()];
170 
171  switch (role) {
172  case UserRole:
173  result = requestedData.senderAlias();
174  break;
175  case TextRole:
176  result = requestedData.finalizedMessage();
177  break;
178  case TypeRole:
179  if (requestedData.type() == Tp::ChannelTextMessageTypeAction) {
180  result = MessageTypeAction;
181  } else {
182  if (requestedData.direction() == KTp::Message::LocalToRemote) {
183  result = MessageTypeOutgoing;
184  } else {
185  result = MessageTypeIncoming;
186  }
187  }
188  break;
189  case TimeRole:
190  result = requestedData.time();
191  break;
192  };
193  } else {
194  kError() << "Attempting to access data at invalid index (" << index << ")";
195  }
196 
197  return result;
198 }
199 
200 int MessagesModel::rowCount(const QModelIndex &parent) const
201 {
202  Q_UNUSED(parent);
203  return d->messages.size();
204 }
205 
206 void MessagesModel::sendNewMessage(const QString &message)
207 {
208  if (message.isEmpty()) {
209  kWarning() << "Attempting to send empty string";
210  } else {
211  Tp::PendingOperation *op;
212  QString modifiedMessage = message;
213  if (d->textChannel->supportsMessageType(Tp::ChannelTextMessageTypeAction)
214  && modifiedMessage.startsWith(QLatin1String("/me "))) {
215  //remove "/me " from the start of the message
216  modifiedMessage.remove(0,4);
217  op = d->textChannel->send(modifiedMessage, Tp::ChannelTextMessageTypeAction);
218  } else {
219  op = d->textChannel->send(modifiedMessage);
220  }
221  connect(op,
222  SIGNAL(finished(Tp::PendingOperation*)),
223  SLOT(verifyPendingOperation(Tp::PendingOperation*)));
224  }
225 }
226 
227 void MessagesModel::removeChannelSignals(const Tp::TextChannelPtr &channel)
228 {
229  QObject::disconnect(channel.data(),
230  SIGNAL(messageReceived(Tp::ReceivedMessage)),
231  this,
232  SLOT(onMessageReceived(Tp::ReceivedMessage))
233  );
234  QObject::disconnect(channel.data(),
235  SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
236  this,
237  SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString))
238  );
239 }
240 
241 int MessagesModel::unreadCount() const
242 {
243  return d->textChannel->messageQueue().size();
244 }
245 
246 void MessagesModel::acknowledgeAllMessages()
247 {
248  QList<Tp::ReceivedMessage> queue
249  = d->textChannel->messageQueue();
250 
251  kDebug() << "Conversation Visible, Acknowledging " << queue.size() << " messages.";
252 
253  d->textChannel->acknowledge(queue);
254  removeSelfFromQueue();
255  Q_EMIT unreadCountChanged(queue.size());
256 }
257 
258 void MessagesModel::selfDequeued()
259 {
260  Q_EMIT popoutRequested();
261 }
262 
263 void MessagesModel::setVisibleToUser(bool visible)
264 {
265  kDebug() << visible;
266 
267  if (d->visible != visible) {
268  d->visible = visible;
269  Q_EMIT visibleToUserChanged(d->visible);
270  }
271 
272  if (visible) {
273  acknowledgeAllMessages();
274  }
275 }
276 
277 bool MessagesModel::isVisibleToUser() const
278 {
279  return d->visible;
280 }
281 
282 MessagesModel::~MessagesModel()
283 {
284  kDebug();
285  delete d;
286 }
287 
288 bool MessagesModel::shouldStartOpened() const
289 {
290  return d->textChannel->isRequested();
291 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Fri Mar 22 2013 10:58:52 by doxygen 1.8.1.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

ktp-common-internals API Reference

Skip menu "ktp-common-internals API Reference"
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal