1 /******************************************************************************
2  * Copyright (C) 2018 Kitsune Ral <kitsune-ral@users.sf.net>
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 #pragma once
20 
21 #include "events/stateevent.h"
22 
23 #include <utility>
24 
25 namespace Quotient {
26 class StateEventBase;
27 
28 class EventStatus {
29     Q_GADGET
30 public:
31     /** Special marks an event can assume
32      *
33      * This is used to hint at a special status of some events in UI.
34      * All values except Redacted and Hidden are mutually exclusive.
35      */
36     enum Code {
37         Normal = 0x0, //< No special designation
38         Submitted = 0x01, //< The event has just been submitted for sending
39         FileUploaded = 0x02, //< The file attached to the event has been
40                              // uploaded to the server
41         Departed = 0x03, //< The event has left the client
42         ReachedServer = 0x04, //< The server has received the event
43         SendingFailed = 0x05, //< The server could not receive the event
44         Redacted = 0x08, //< The event has been redacted
45         Replaced = 0x10, //< The event has been replaced
46         Hidden = 0x100, //< The event should not be shown in the timeline
47     };
48     Q_DECLARE_FLAGS(Status, Code)
49     Q_FLAG(Status)
50 };
51 
52 class EventItemBase {
53 public:
EventItemBase(RoomEventPtr && e)54     explicit EventItemBase(RoomEventPtr&& e) : evt(std::move(e))
55     {
56         Q_ASSERT(evt);
57     }
58 
event()59     const RoomEvent* event() const { return rawPtr(evt); }
get()60     const RoomEvent* get() const { return event(); }
61     template <typename EventT>
viewAs()62     const EventT* viewAs() const
63     {
64         return eventCast<const EventT>(evt);
65     }
66     const RoomEventPtr& operator->() const { return evt; }
67     const RoomEvent& operator*() const { return *evt; }
68 
69     // Used for event redaction
replaceEvent(RoomEventPtr && other)70     RoomEventPtr replaceEvent(RoomEventPtr&& other)
71     {
72         return std::exchange(evt, move(other));
73     }
74 
75 protected:
76     template <typename EventT>
getAs()77     EventT* getAs()
78     {
79         return eventCast<EventT>(evt);
80     }
81 
82 private:
83     RoomEventPtr evt;
84 };
85 
86 class TimelineItem : public EventItemBase {
87 public:
88     // For compatibility with Qt containers, even though we use
89     // a std:: container now for the room timeline
90     using index_t = int;
91 
TimelineItem(RoomEventPtr && e,index_t number)92     TimelineItem(RoomEventPtr&& e, index_t number)
93         : EventItemBase(std::move(e)), idx(number)
94     {}
95 
index()96     index_t index() const { return idx; }
97 
98 private:
99     index_t idx;
100 };
101 
102 template <>
103 inline const StateEventBase* EventItemBase::viewAs<StateEventBase>() const
104 {
105     return evt->isStateEvent() ? weakPtrCast<const StateEventBase>(evt)
106                                : nullptr;
107 }
108 
109 template <>
110 inline const CallEventBase* EventItemBase::viewAs<CallEventBase>() const
111 {
112     return evt->isCallEvent() ? weakPtrCast<const CallEventBase>(evt) : nullptr;
113 }
114 
115 class PendingEventItem : public EventItemBase {
116     Q_GADGET
117 public:
118     using EventItemBase::EventItemBase;
119 
deliveryStatus()120     EventStatus::Code deliveryStatus() const { return _status; }
lastUpdated()121     QDateTime lastUpdated() const { return _lastUpdated; }
annotation()122     QString annotation() const { return _annotation; }
123 
setDeparted()124     void setDeparted() { setStatus(EventStatus::Departed); }
125     void setFileUploaded(const QUrl& remoteUrl);
setReachedServer(const QString & eventId)126     void setReachedServer(const QString& eventId)
127     {
128         setStatus(EventStatus::ReachedServer);
129         (*this)->addId(eventId);
130     }
setSendingFailed(QString errorText)131     void setSendingFailed(QString errorText)
132     {
133         setStatus(EventStatus::SendingFailed);
134         _annotation = std::move(errorText);
135     }
resetStatus()136     void resetStatus() { setStatus(EventStatus::Submitted); }
137 
138 private:
139     EventStatus::Code _status = EventStatus::Submitted;
140     QDateTime _lastUpdated = QDateTime::currentDateTimeUtc();
141     QString _annotation;
142 
setStatus(EventStatus::Code status)143     void setStatus(EventStatus::Code status)
144     {
145         _status = status;
146         _lastUpdated = QDateTime::currentDateTimeUtc();
147         _annotation.clear();
148     }
149 };
150 
151 inline QDebug& operator<<(QDebug& d, const TimelineItem& ti)
152 {
153     QDebugStateSaver dss(d);
154     d.nospace() << "(" << ti.index() << "|" << ti->id() << ")";
155     return d;
156 }
157 } // namespace Quotient
158 Q_DECLARE_METATYPE(Quotient::EventStatus)
159