1 /***************************************************************************
2 * Copyright (C) 2005-2022 by the Quassel Project *
3 * devel@quassel-irc.org *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) version 3. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
23 #include "client-export.h"
25 #include "bufferinfo.h"
26 #include "clientsettings.h"
29 #include "treemodel.h"
32 class StatusBufferItem;
34 /*****************************************
36 *****************************************/
37 class NetworkItem : public PropertyMapItem
40 Q_PROPERTY(QString networkName READ networkName)
41 Q_PROPERTY(QString currentServer READ currentServer)
42 Q_PROPERTY(int nickCount READ nickCount)
45 NetworkItem(const NetworkId& netid, AbstractTreeItem* parent = nullptr);
47 QStringList propertyOrder() const override;
49 QVariant data(int column, int row) const override;
52 * Escapes a string as HTML, ready for Qt markup.
54 * Implementation depends on Qt version - Qt4 uses Qt::escape, while Qt5 uses .toHtmlEscaped().
56 * @param[in] string QString to escape
57 * @param[in] useNonbreakingSpaces
59 * If true, replace spaces with non-breaking spaces (i.e. ' '), otherwise only HTML escape.
62 static QString escapeHTML(const QString& string, bool useNonbreakingSpaces = false);
64 inline bool isActive() const { return (bool)_network ? _network->isConnected() : false; }
66 inline const NetworkId& networkId() const { return _networkId; }
67 inline QString networkName() const { return (bool)_network ? _network->networkName() : QString(); }
68 inline QString currentServer() const { return (bool)_network ? _network->currentServer() : QString(); }
69 inline int nickCount() const { return (bool)_network ? _network->ircUsers().count() : 0; }
71 QString toolTip(int column) const override;
73 BufferItem* findBufferItem(BufferId bufferId);
74 inline BufferItem* findBufferItem(const BufferInfo& bufferInfo) { return findBufferItem(bufferInfo.bufferId()); }
75 BufferItem* bufferItem(const BufferInfo& bufferInfo);
76 inline StatusBufferItem* statusBufferItem() const { return _statusBufferItem; }
79 void setNetworkName(const QString& networkName);
80 void setCurrentServer(const QString& serverName);
82 void attachNetwork(Network* network);
83 void attachIrcChannel(IrcChannel* channel);
84 void attachIrcUser(IrcUser* ircUser);
87 void networkDataChanged(int column = -1);
90 void onBeginRemoveChilds(int start, int end);
91 void onNetworkDestroyed();
95 StatusBufferItem* _statusBufferItem;
97 QPointer<Network> _network;
100 /*****************************************
102 *****************************************/
103 class BufferItem : public PropertyMapItem
106 Q_PROPERTY(QString bufferName READ bufferName WRITE setBufferName)
107 Q_PROPERTY(QString topic READ topic)
108 Q_PROPERTY(int nickCount READ nickCount)
111 BufferItem(BufferInfo bufferInfo, AbstractTreeItem* parent = nullptr);
113 QStringList propertyOrder() const override;
115 inline const BufferInfo& bufferInfo() const { return _bufferInfo; }
116 QVariant data(int column, int role) const override;
117 bool setData(int column, const QVariant& value, int role) override;
119 inline BufferId bufferId() const { return _bufferInfo.bufferId(); }
120 inline BufferInfo::Type bufferType() const { return _bufferInfo.type(); }
122 virtual void setBufferName(const QString& name);
123 virtual inline QString bufferName() const { return _bufferInfo.bufferName(); }
124 virtual inline QString topic() const { return QString(); }
125 virtual inline int nickCount() const { return 0; }
127 virtual inline bool isActive() const { return qobject_cast<NetworkItem*>(parent())->isActive(); }
129 inline MsgId lastSeenMsgId() const { return _lastSeenMsgId; }
130 inline MsgId markerLineMsgId() const { return _markerLineMsgId; }
131 void setLastSeenMsgId(MsgId msgId);
132 void setMarkerLineMsgId(MsgId msgId);
134 inline BufferInfo::ActivityLevel activityLevel() const { return _activity; }
135 void setActivityLevel(BufferInfo::ActivityLevel level);
136 void clearActivityLevel();
137 void updateActivityLevel(const Message& msg);
138 void setActivity(Message::Types msg, bool highlight);
139 bool addActivity(Message::Types msg, bool highlight);
141 inline const MsgId& firstUnreadMsgId() const { return _firstUnreadMsgId; }
143 bool isCurrentBuffer() const;
144 QString toolTip(int column) const override;
147 virtual inline void setTopic(const QString&) { emit dataChanged(1); }
148 virtual inline void setEncrypted(bool) { emit dataChanged(); }
151 BufferInfo _bufferInfo;
152 BufferInfo::ActivityLevel _activity;
153 MsgId _lastSeenMsgId;
154 MsgId _markerLineMsgId;
155 MsgId _firstUnreadMsgId;
158 /*****************************************
160 *****************************************/
161 class StatusBufferItem : public BufferItem
166 StatusBufferItem(const BufferInfo& bufferInfo, NetworkItem* parent);
168 QString toolTip(int column) const override;
169 inline QString bufferName() const override { return tr("Status Buffer"); }
172 /*****************************************
174 *****************************************/
175 class QueryBufferItem : public BufferItem
180 QueryBufferItem(const BufferInfo& bufferInfo, NetworkItem* parent);
182 QVariant data(int column, int role) const override;
183 bool setData(int column, const QVariant& value, int role) override;
185 inline bool isActive() const override { return (bool)_ircUser; }
186 QString toolTip(int column) const override;
188 void setBufferName(const QString& name) override;
191 void setIrcUser(IrcUser* ircUser);
192 void removeIrcUser();
198 /*****************************************
200 *****************************************/
201 class UserCategoryItem;
203 class ChannelBufferItem : public BufferItem
208 ChannelBufferItem(const BufferInfo& bufferInfo, AbstractTreeItem* parent);
210 QVariant data(int column, int role) const override;
211 inline bool isActive() const override { return (bool)_ircChannel; }
212 QString toolTip(int column) const override;
214 inline QString topic() const override { return (bool)_ircChannel ? _ircChannel->topic() : QString(); }
215 inline int nickCount() const override { return (bool)_ircChannel ? _ircChannel->ircUsers().count() : 0; }
217 void attachIrcChannel(IrcChannel* ircChannel);
220 * Gets the list of channel modes for a given nick.
222 * @param[in] nick IrcUser nickname to check
223 * @returns Channel modes as a string if any, otherwise empty string
225 QString nickChannelModes(const QString& nick) const;
228 void join(const QList<IrcUser*>& ircUsers);
229 void part(IrcUser* ircUser);
231 UserCategoryItem* findCategoryItem(int categoryId);
232 void addUserToCategory(IrcUser* ircUser);
233 void addUsersToCategory(const QList<IrcUser*>& ircUser);
234 void removeUserFromCategory(IrcUser* ircUser);
235 void userModeChanged(IrcUser* ircUser);
238 void ircChannelParted();
239 void ircChannelDestroyed();
242 IrcChannel* _ircChannel;
245 /*****************************************
246 * User Category Items (like @vh etc.)
247 *****************************************/
250 class CLIENT_EXPORT UserCategoryItem : public PropertyMapItem
253 Q_PROPERTY(QString categoryName READ categoryName)
256 UserCategoryItem(int category, AbstractTreeItem* parent);
258 QStringList propertyOrder() const override;
260 QString categoryName() const;
261 inline int categoryId() const { return _category; }
262 QVariant data(int column, int role) const override;
264 IrcUserItem* findIrcUser(IrcUser* ircUser);
265 void addUsers(const QList<IrcUser*>& ircUser);
266 bool removeUser(IrcUser* ircUser);
268 static int categoryFromModes(const QString& modes);
273 static const QList<QChar> categories;
276 /*****************************************
278 *****************************************/
279 class IrcUserItem : public PropertyMapItem
282 Q_PROPERTY(QString nickName READ nickName)
285 IrcUserItem(IrcUser* ircUser, AbstractTreeItem* parent);
287 QStringList propertyOrder() const override;
289 inline QString nickName() const { return _ircUser ? _ircUser->nick() : QString(); }
290 inline bool isActive() const { return _ircUser ? !_ircUser->isAway() : false; }
292 inline IrcUser* ircUser() { return _ircUser; }
293 QVariant data(int column, int role) const override;
294 QString toolTip(int column) const override;
297 * Gets the list of channel modes for this nick if parented to channel.
299 * @returns Channel modes as a string if any, otherwise empty string
301 QString channelModes() const;
304 inline void ircUserQuited() { parent()->removeChild(this); }
307 QPointer<IrcUser> _ircUser;
310 /*****************************************
312 *****************************************/
313 class CLIENT_EXPORT NetworkModel : public TreeModel
320 BufferTypeRole = TreeModel::UserRole,
330 BufferFirstUnreadMsgIdRole,
336 NetworkItemType = 0x01,
337 BufferItemType = 0x02,
338 UserCategoryItemType = 0x04,
339 IrcUserItemType = 0x08
341 Q_DECLARE_FLAGS(ItemTypes, ItemType)
343 NetworkModel(QObject* parent = nullptr);
344 static QList<QVariant> defaultHeader();
346 static bool mimeContainsBufferList(const QMimeData* mimeData);
347 static QList<QPair<NetworkId, BufferId>> mimeDataToBufferList(const QMimeData* mimeData);
349 QStringList mimeTypes() const override;
350 QMimeData* mimeData(const QModelIndexList&) const override;
352 void attachNetwork(Network* network);
354 bool isBufferIndex(const QModelIndex&) const;
355 // Buffer *getBufferByIndex(const QModelIndex &) const;
356 QModelIndex networkIndex(NetworkId networkId);
357 QModelIndex bufferIndex(BufferId bufferId);
359 const Network* networkByIndex(const QModelIndex& index) const;
361 BufferInfo::ActivityLevel bufferActivity(const BufferInfo& buffer) const;
363 //! Finds a buffer with a given name in a given network
364 /** This performs a linear search through all BufferItems, hence it is expensive.
365 * @param networkId The network which we search in
366 * @param bufferName The bufferName we look for
367 * @return The id of the buffer if found, an invalid one else
369 BufferId bufferId(NetworkId networkId, const QString& bufferName, Qt::CaseSensitivity cs = Qt::CaseInsensitive) const;
371 QString bufferName(BufferId bufferId) const;
372 BufferInfo::Type bufferType(BufferId bufferId) const;
373 BufferInfo bufferInfo(BufferId bufferId) const;
374 MsgId lastSeenMsgId(BufferId bufferId) const;
375 MsgId markerLineMsgId(BufferId bufferId) const;
376 NetworkId networkId(BufferId bufferId) const;
377 QString networkName(BufferId bufferId) const;
379 inline QList<BufferId> allBufferIds() const { return _bufferItemCache.keys(); }
380 QList<BufferId> allBufferIdsSorted() const;
381 void sortBufferIds(QList<BufferId>& bufferIds) const;
384 void bufferUpdated(BufferInfo bufferInfo);
385 void removeBuffer(BufferId bufferId);
386 MsgId lastSeenMsgId(const BufferId& bufferId);
387 void setLastSeenMsgId(const BufferId& bufferId, const MsgId& msgId);
388 void setMarkerLineMsgId(const BufferId& bufferId, const MsgId& msgId);
389 void setBufferActivity(const BufferId& bufferId, BufferInfo::ActivityLevel activity);
390 void clearBufferActivity(const BufferId& bufferId);
391 void updateBufferActivity(Message& msg);
392 void networkRemoved(const NetworkId& networkId);
393 void bufferActivityChanged(BufferId, Message::Types);
394 void highlightCountChanged(BufferId, int);
397 void requestSetLastSeenMsg(BufferId buffer, MsgId msg);
398 void lastSeenMsgSet(BufferId buffer, MsgId msg);
399 void markerLineSet(BufferId buffer, MsgId msg);
402 void checkForRemovedBuffers(const QModelIndex& parent, int start, int end);
403 void checkForNewBuffers(const QModelIndex& parent, int start, int end);
404 void messageRedirectionSettingsChanged();
407 int networkRow(NetworkId networkId) const;
408 NetworkItem* findNetworkItem(NetworkId networkId) const;
409 NetworkItem* networkItem(NetworkId networkId);
410 inline BufferItem* findBufferItem(const BufferInfo& bufferInfo) const { return findBufferItem(bufferInfo.bufferId()); }
411 BufferItem* findBufferItem(BufferId bufferId) const;
412 BufferItem* bufferItem(const BufferInfo& bufferInfo);
414 void updateBufferActivity(BufferItem* bufferItem, const Message& msg);
416 static bool bufferItemLessThan(const BufferItem* left, const BufferItem* right);
418 QHash<BufferId, BufferItem*> _bufferItemCache;
420 int _userNoticesTarget;
421 int _serverNoticesTarget;
422 int _errorMsgsTarget;
425 Q_DECLARE_OPERATORS_FOR_FLAGS(NetworkModel::ItemTypes)