8fdb3915a67b463698d220295673926b65f717ea
[quassel.git] / src / core / corebuffersyncer.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2020 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
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.                                           *
9  *                                                                         *
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.                          *
14  *                                                                         *
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  ***************************************************************************/
20
21 #include "corebuffersyncer.h"
22
23 #include <algorithm>
24 #include <iterator>
25 #include <set>
26
27 #include "core.h"
28 #include "corenetwork.h"
29 #include "coresession.h"
30 #include "ircchannel.h"
31 #include "util.h"
32
33 class PurgeEvent : public QEvent
34 {
35 public:
36     PurgeEvent()
37         : QEvent(QEvent::User)
38     {}
39 };
40
41 CoreBufferSyncer::CoreBufferSyncer(CoreSession* parent)
42     : BufferSyncer(Core::bufferLastSeenMsgIds(parent->user()),
43                    Core::bufferMarkerLineMsgIds(parent->user()),
44                    Core::bufferActivities(parent->user()),
45                    Core::highlightCounts(parent->user()),
46                    parent)
47     , _coreSession(parent)
48     , _purgeBuffers(false)
49 {
50     connect(parent, &CoreSession::displayMsg, this, &CoreBufferSyncer::addBufferActivity);
51     connect(parent, &CoreSession::displayMsg, this, &CoreBufferSyncer::addCoreHighlight);
52 }
53
54 void CoreBufferSyncer::requestSetLastSeenMsg(BufferId buffer, const MsgId& msgId)
55 {
56     if (setLastSeenMsg(buffer, msgId)) {
57         int activity = Core::bufferActivity(buffer, msgId);
58         int highlightCount = Core::highlightCount(buffer, msgId);
59
60         setBufferActivity(buffer, activity);
61         setHighlightCount(buffer, highlightCount);
62
63         dirtyLastSeenBuffers << buffer;
64     }
65 }
66
67 void CoreBufferSyncer::requestSetMarkerLine(BufferId buffer, const MsgId& msgId)
68 {
69     if (setMarkerLine(buffer, msgId))
70         dirtyMarkerLineBuffers << buffer;
71 }
72
73 void CoreBufferSyncer::storeDirtyIds()
74 {
75     UserId userId = _coreSession->user();
76     MsgId msgId;
77     foreach (BufferId bufferId, dirtyLastSeenBuffers) {
78         msgId = lastSeenMsg(bufferId);
79         if (msgId.isValid())
80             Core::setBufferLastSeenMsg(userId, bufferId, msgId);
81     }
82
83     foreach (BufferId bufferId, dirtyMarkerLineBuffers) {
84         msgId = markerLine(bufferId);
85         if (msgId.isValid())
86             Core::setBufferMarkerLineMsg(userId, bufferId, msgId);
87     }
88
89     foreach (BufferId bufferId, dirtyActivities) {
90         Core::setBufferActivity(userId, bufferId, activity(bufferId));
91     }
92
93     foreach (BufferId bufferId, dirtyHighlights) {
94         Core::setHighlightCount(userId, bufferId, highlightCount(bufferId));
95     }
96
97     dirtyLastSeenBuffers.clear();
98     dirtyMarkerLineBuffers.clear();
99     dirtyActivities.clear();
100     dirtyHighlights.clear();
101 }
102
103 void CoreBufferSyncer::removeBuffer(BufferId bufferId)
104 {
105     BufferInfo bufferInfo = Core::getBufferInfo(_coreSession->user(), bufferId);
106     if (!bufferInfo.isValid()) {
107         qWarning() << "CoreBufferSyncer::removeBuffer(): invalid BufferId:" << bufferId << "for User:" << _coreSession->user();
108         return;
109     }
110
111     if (bufferInfo.type() == BufferInfo::StatusBuffer) {
112         qWarning() << "CoreBufferSyncer::removeBuffer(): Status Buffers cannot be removed!";
113         return;
114     }
115
116     if (bufferInfo.type() == BufferInfo::ChannelBuffer) {
117         CoreNetwork* net = _coreSession->network(bufferInfo.networkId());
118         if (!net) {
119             qWarning() << "CoreBufferSyncer::removeBuffer(): Received BufferInfo with unknown networkId!";
120             return;
121         }
122         IrcChannel* chan = net->ircChannel(bufferInfo.bufferName());
123         if (chan) {
124             qWarning() << "CoreBufferSyncer::removeBuffer(): Unable to remove Buffer for joined Channel:" << bufferInfo.bufferName();
125             return;
126         }
127     }
128     if (Core::removeBuffer(_coreSession->user(), bufferId))
129         BufferSyncer::removeBuffer(bufferId);
130 }
131
132 void CoreBufferSyncer::renameBuffer(BufferId bufferId, QString newName)
133 {
134     BufferInfo bufferInfo = Core::getBufferInfo(_coreSession->user(), bufferId);
135     if (!bufferInfo.isValid()) {
136         qWarning() << "CoreBufferSyncer::renameBuffer(): invalid BufferId:" << bufferId << "for User:" << _coreSession->user();
137         return;
138     }
139
140     if (bufferInfo.type() != BufferInfo::QueryBuffer) {
141         qWarning() << "CoreBufferSyncer::renameBuffer(): only QueryBuffers can be renamed" << bufferId;
142         return;
143     }
144
145     if (Core::renameBuffer(_coreSession->user(), bufferId, newName))
146         BufferSyncer::renameBuffer(bufferId, newName);
147 }
148
149 void CoreBufferSyncer::mergeBuffersPermanently(BufferId bufferId1, BufferId bufferId2)
150 {
151     BufferInfo bufferInfo1 = Core::getBufferInfo(_coreSession->user(), bufferId1);
152     BufferInfo bufferInfo2 = Core::getBufferInfo(_coreSession->user(), bufferId2);
153     if (!bufferInfo1.isValid() || !bufferInfo2.isValid()) {
154         qWarning() << "CoreBufferSyncer::mergeBuffersPermanently(): invalid BufferIds:" << bufferId1 << bufferId2
155                    << "for User:" << _coreSession->user();
156         return;
157     }
158
159     if ((bufferInfo1.type() != BufferInfo::QueryBuffer && bufferInfo1.type() != BufferInfo::ChannelBuffer)
160         || (bufferInfo2.type() != BufferInfo::QueryBuffer && bufferInfo2.type() != BufferInfo::ChannelBuffer)) {
161         qWarning() << "CoreBufferSyncer::mergeBuffersPermanently(): only QueryBuffers and/or ChannelBuffers can be merged!" << bufferId1
162                    << bufferId2;
163         return;
164     }
165
166     if (Core::mergeBuffersPermanently(_coreSession->user(), bufferId1, bufferId2)) {
167         BufferSyncer::mergeBuffersPermanently(bufferId1, bufferId2);
168     }
169 }
170
171 void CoreBufferSyncer::customEvent(QEvent* event)
172 {
173     if (event->type() != QEvent::User)
174         return;
175
176     purgeBufferIds();
177     event->accept();
178 }
179
180 void CoreBufferSyncer::requestPurgeBufferIds()
181 {
182     if (_purgeBuffers)
183         return;
184
185     _purgeBuffers = true;
186     QCoreApplication::postEvent(this, new PurgeEvent());
187 }
188
189 void CoreBufferSyncer::purgeBufferIds()
190 {
191     _purgeBuffers = false;
192     auto bufferInfos = Core::requestBuffers(_coreSession->user());
193     std::set<BufferId> actualBuffers;
194     std::transform(bufferInfos.cbegin(), bufferInfos.cend(), std::inserter(actualBuffers, actualBuffers.end()),
195                    [](auto&& bufferInfo) { return bufferInfo.bufferId(); });
196
197     QSet<BufferId> storedIds = toQSet(lastSeenBufferIds()) + toQSet(markerLineBufferIds());
198     foreach (BufferId bufferId, storedIds) {
199         if (actualBuffers.find(bufferId) == actualBuffers.end()) {
200             BufferSyncer::removeBuffer(bufferId);
201         }
202     }
203 }
204
205 void CoreBufferSyncer::setBufferActivity(BufferId buffer, int activity)
206 {
207     BufferSyncer::setBufferActivity(buffer, activity);
208     dirtyActivities << buffer;
209 }
210
211 void CoreBufferSyncer::setHighlightCount(BufferId buffer, int highlightCount)
212 {
213     BufferSyncer::setHighlightCount(buffer, highlightCount);
214     dirtyHighlights << buffer;
215 }