1 /* 2 Copyright (C) 2016 Martin Klapetek <mklapetek@kde.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 #ifndef MAINLOGMODEL_H 20 #define MAINLOGMODEL_H 21 22 #include <QObject> 23 #include <QAbstractListModel> 24 #include <QSqlQuery> 25 26 #include <TelepathyQt/AbstractClientObserver> 27 #include <TelepathyQt/AbstractClientHandler> 28 #include <TelepathyQt/ChannelDispatchOperation> 29 30 #include <KTp/persistent-contact.h> 31 #include <KTp/types.h> 32 33 class Conversation; 34 class MainLogModel; // Cause of ObserverProxy 35 36 class LogItem { 37 public: 38 QDateTime messageDateTime; 39 QString message; 40 QString accountObjectPath; 41 QString targetContact; 42 Conversation *conversation; 43 }; 44 45 /** 46 * The reason for this class is that an Observer and a Handler cannot 47 * be registered under the same client name if the Observer is not to 48 * be autostarted and only monitor things once the app is executed. 49 * 50 * So this is a tiny proxy class that gets registered as SpaceBarObserverProxy 51 * and forwards all observerChannels calls to the model which then merges 52 * them with the existing conversations 53 */ 54 class ObserverProxy : public QObject, public Tp::AbstractClientObserver 55 { 56 Q_OBJECT 57 58 public: 59 ObserverProxy(MainLogModel *model); 60 61 void observeChannels(const Tp::MethodInvocationContextPtr<> &context, 62 const Tp::AccountPtr &account, 63 const Tp::ConnectionPtr &connection, 64 const QList<Tp::ChannelPtr> &channels, 65 const Tp::ChannelDispatchOperationPtr &dispatchOperation, 66 const QList<Tp::ChannelRequestPtr> &requestsSatisfied, 67 const Tp::AbstractClientObserver::ObserverInfo &observerInfo) override; 68 69 private: 70 MainLogModel *m_model; 71 }; 72 73 //----------------------------------------------------------------------------- 74 75 class MainLogModel : public QAbstractListModel, public Tp::AbstractClientHandler 76 { 77 Q_OBJECT 78 79 public: 80 enum Role { 81 ContactDisplayNameRole = Qt::DisplayRole, 82 ChatPictureRole = Qt::DecorationRole, 83 ContactIdRole = Qt::UserRole, 84 PersonUriRole, 85 AccountIdRole, 86 LastMessageDateRole, 87 LastMessageTextRole, 88 ConversationRole, 89 HasUnreadMessagesRole, 90 UnreadMessagesCountRole, 91 92 UserRole = Qt::UserRole + 0x1000 ///< in case it's needed to extend, use this one to start from 93 }; 94 Q_ENUMS(Role) 95 96 MainLogModel(QObject *parent = nullptr); 97 ~MainLogModel() override; 98 99 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 100 int rowCount(const QModelIndex &parent = QModelIndex()) const override; 101 QHash<int, QByteArray> roleNames() const override; 102 103 Q_INVOKABLE bool canChat(const QString &accountId) const; 104 Q_INVOKABLE void setAccountManager(const Tp::AccountManagerPtr &accountManager); 105 Q_INVOKABLE QVariant data(int index, QByteArray role) const; 106 Q_INVOKABLE QObject* observerProxy() const; 107 108 void handleChannels(const Tp::MethodInvocationContextPtr<> &context, 109 const Tp::AccountPtr &account, 110 const Tp::ConnectionPtr &connection, 111 const QList<Tp::ChannelPtr> &channels, 112 const QList<Tp::ChannelRequestPtr> &channelRequests, 113 const QDateTime &userActionTime, 114 const HandlerInfo &handlerInfo) override; 115 116 bool bypassApproval() const override; 117 118 Q_SIGNALS: 119 void newRequestedChannel(const QModelIndex &index); 120 121 public Q_SLOTS: 122 void startChat(const QString &personUri); 123 void startChat(const QString &accountId, const QString &contactId); 124 125 private Q_SLOTS: 126 void handleChannel(const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel); 127 void onConversationChanged(); 128 void onAccountManagerReady(); 129 130 private: 131 void setupSignals(Conversation *conversation) const; 132 void processQueryResults(QSqlQuery query); 133 134 QHash<QString, Conversation*> m_conversations; // This is a hash with keys "accountId + contactId" 135 QList<LogItem> m_logItems; 136 QSqlQuery m_query; 137 QSqlDatabase m_db; 138 Tp::AccountManagerPtr m_accountManager; 139 ObserverProxy *m_observerProxy; 140 141 // This is true when mission control autostarted the app 142 // on an incoming channel; the model will emit newRequestedChannel() 143 // for the first incoming channel even though it was not requested 144 // This is useful to switch the application directly to the new 145 // message 146 bool m_openIncomingChannel; 147 148 friend class ObserverProxy; 149 }; 150 151 Q_DECLARE_METATYPE(Tp::ChannelDispatchOperationPtr) 152 153 #endif 154