1 /*
2   SPDX-FileCopyrightText: 2000, 2001, 2003 Cornelius Schumacher <schumacher@kde.org>
3   SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
4 
5   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
6 */
7 #pragma once
8 
9 #include "viewcalendar.h"
10 
11 #include <CalendarSupport/CellItem>
12 
13 #include <Akonadi/Calendar/ETMCalendar>
14 #include <Akonadi/Item>
15 
16 #include <QDateTime>
17 #include <QPointer>
18 #include <QWidget>
19 
20 namespace EventViews
21 {
22 class AgendaItem;
23 class EventView;
24 
25 struct MultiItemInfo {
26     int mStartCellXLeft, mStartCellXRight;
27     int mStartCellYTop, mStartCellYBottom;
28     QPointer<AgendaItem> mFirstMultiItem;
29     QPointer<AgendaItem> mPrevMultiItem;
30     QPointer<AgendaItem> mNextMultiItem;
31     QPointer<AgendaItem> mLastMultiItem;
32 };
33 
34 /**
35   @class AgendaItem
36 
37   @brief This class describes the widgets that represent the various calendar
38          items in the agenda view
39 
40   The AgendaItem has to make sure that it receives all mouse events, which
41   are to be used for dragging and resizing. That means it has to be installed
42   as event filter for its children, if it has children, and it has to pass
43   mouse events from the children to itself. See eventFilter().
44 
45   Some comments on the movement of multi-day items:
46   Basically, the agenda items are arranged in two implicit double-linked lists.
47   The mMultiItemInfo works like before to describe the currently viewed
48   multi-item.
49   When moving, new events might need to be added to the beginning or the end of
50   the multi-item sequence, or events might need to be hidden. I cannot just
51   delete this items, since I have to restore/show them if the move is reset
52   (i.e. if a drag started). So internally, I keep another doubly-linked list
53   which is longer than the one defined by mMultiItemInfo, but includes the
54   multi-item sequence, too.
55 
56   The mStartMoveInfo stores the first and last item of the multi-item sequence
57   when the move started. The prev and next members of mStartMoveInfo are used
58   for that longer sequence including all (shown and hidden) items.
59 */
60 
61 class AgendaItem : public QWidget, public CalendarSupport::CellItem
62 {
63     Q_OBJECT
64 public:
65     using QPtr = QPointer<AgendaItem>;
66     using List = QList<QPtr>;
67 
68     AgendaItem(EventView *eventView,
69                const MultiViewCalendar::Ptr &calendar,
70                const KCalendarCore::Incidence::Ptr &incidence,
71                int itemPos,
72                int itemCount,
73                const QDateTime &qd,
74                bool isSelected,
75                QWidget *parent);
76     ~AgendaItem() override;
77 
cellXLeft()78     Q_REQUIRED_RESULT int cellXLeft() const
79     {
80         return mCellXLeft;
81     }
82 
cellXRight()83     Q_REQUIRED_RESULT int cellXRight() const
84     {
85         return mCellXRight;
86     }
87 
cellYTop()88     Q_REQUIRED_RESULT int cellYTop() const
89     {
90         return mCellYTop;
91     }
92 
cellYBottom()93     Q_REQUIRED_RESULT int cellYBottom() const
94     {
95         return mCellYBottom;
96     }
97 
98     Q_REQUIRED_RESULT int cellHeight() const;
99     Q_REQUIRED_RESULT int cellWidth() const;
100 
itemPos()101     Q_REQUIRED_RESULT int itemPos() const
102     {
103         return mItemPos;
104     }
105 
itemCount()106     Q_REQUIRED_RESULT int itemCount() const
107     {
108         return mItemCount;
109     }
110 
111     void setCellXY(int X, int YTop, int YBottom);
112     void setCellY(int YTop, int YBottom);
113     void setCellX(int XLeft, int XRight);
114     void setCellXRight(int XRight);
115 
116     /** Start movement */
117     void startMove();
118 
119     /** Reset to original values */
120     void resetMove();
121 
122     /** End the movement (i.e. clean up) */
123     void endMove();
124 
125     void moveRelative(int dx, int dy);
126 
127     /**
128      * Expands the item's top.
129      *
130      * @param dy             delta y, number of units to be added to mCellYTop
131      * @param allowOverLimit If false, the new mCellYTop can't be bigger than
132      *                       mCellYBottom, instead, it gets mCellYBottom's value.
133      *                       If true, @p dy is always added, regardless if mCellYTop
134      *                       becomes bigger than mCellYBottom, this is useful when
135      *                       moving items because it guarantees expandTop and the
136      *                       following expandBottom call add the same value.
137      */
138     void expandTop(int dy, const bool allowOverLimit = false);
139     void expandBottom(int dy);
140     void expandLeft(int dx);
141     void expandRight(int dx);
142 
143     Q_REQUIRED_RESULT bool isMultiItem() const;
144 
prevMoveItem()145     AgendaItem::QPtr prevMoveItem() const
146     {
147         return (mStartMoveInfo) ? (mStartMoveInfo->mPrevMultiItem) : nullptr;
148     }
149 
nextMoveItem()150     AgendaItem::QPtr nextMoveItem() const
151     {
152         return (mStartMoveInfo) ? (mStartMoveInfo->mNextMultiItem) : nullptr;
153     }
154 
moveInfo()155     MultiItemInfo *moveInfo() const
156     {
157         return mStartMoveInfo;
158     }
159 
160     void setMultiItem(const AgendaItem::QPtr &first, const AgendaItem::QPtr &prev, const AgendaItem::QPtr &next, const AgendaItem::QPtr &last);
161 
162     AgendaItem::QPtr prependMoveItem(const AgendaItem::QPtr &);
163 
164     AgendaItem::QPtr appendMoveItem(const AgendaItem::QPtr &);
165 
166     AgendaItem::QPtr removeMoveItem(const AgendaItem::QPtr &);
167 
firstMultiItem()168     AgendaItem::QPtr firstMultiItem() const
169     {
170         return (mMultiItemInfo) ? (mMultiItemInfo->mFirstMultiItem) : nullptr;
171     }
172 
prevMultiItem()173     AgendaItem::QPtr prevMultiItem() const
174     {
175         return (mMultiItemInfo) ? (mMultiItemInfo->mPrevMultiItem) : nullptr;
176     }
177 
nextMultiItem()178     AgendaItem::QPtr nextMultiItem() const
179     {
180         return (mMultiItemInfo) ? (mMultiItemInfo->mNextMultiItem) : nullptr;
181     }
182 
lastMultiItem()183     AgendaItem::QPtr lastMultiItem() const
184     {
185         return (mMultiItemInfo) ? (mMultiItemInfo->mLastMultiItem) : nullptr;
186     }
187 
188     Q_REQUIRED_RESULT bool dissociateFromMultiItem();
189 
190     void setIncidence(const KCalendarCore::Incidence::Ptr &incidence);
191 
incidence()192     const KCalendarCore::Incidence::Ptr &incidence() const
193     {
194         return mIncidence;
195     }
196 
occurrenceDateTime()197     Q_REQUIRED_RESULT QDateTime occurrenceDateTime() const
198     {
199         return mOccurrenceDateTime;
200     }
201 
202     Q_REQUIRED_RESULT QDate occurrenceDate() const;
203 
204     // /** Update the date of this item's occurrence (not in the event) */
205     void setOccurrenceDateTime(const QDateTime &qd);
206 
setText(const QString & text)207     void setText(const QString &text)
208     {
209         mLabelText = text;
210     }
211 
text()212     Q_REQUIRED_RESULT QString text() const
213     {
214         return mLabelText;
215     }
216 
217     QList<AgendaItem::QPtr> &conflictItems();
218     void setConflictItems(const QList<AgendaItem::QPtr> &);
219     void addConflictItem(const AgendaItem::QPtr &ci);
220 
221     QString label() const override;
222 
223     /** Tells whether this item overlaps item @p o */
224     bool overlaps(CellItem *o) const override;
225 
setResourceColor(const QColor & color)226     void setResourceColor(const QColor &color)
227     {
228         mResourceColor = color;
229     }
230 
resourceColor()231     Q_REQUIRED_RESULT QColor resourceColor() const
232     {
233         return mResourceColor;
234     }
235 
236 Q_SIGNALS:
237     void removeAgendaItem(const AgendaItem::QPtr &);
238     void showAgendaItem(const AgendaItem::QPtr &);
239 
240 public Q_SLOTS:
241     void updateIcons();
242     void select(bool selected = true);
243     void addAttendee(const QString &);
244 
245 protected:
246     bool eventFilter(QObject *obj, QEvent *event) override;
247     bool event(QEvent *event) override;
248     void dragEnterEvent(QDragEnterEvent *e) override;
249     void dropEvent(QDropEvent *e) override;
250     void paintEvent(QPaintEvent *e) override;
251 
252     /** private movement functions. startMove needs to be called of only one of
253      *  the multitems. it will then loop through the whole series using
254      *  startMovePrivate. Same for resetMove and endMove */
255     void startMovePrivate();
256     void resetMovePrivate();
257     void endMovePrivate();
258 
259     // Variables to remember start position
260     MultiItemInfo *mStartMoveInfo = nullptr;
261     // Color of the resource
262     QColor mResourceColor;
263 
264 private:
265     void paintIcon(QPainter *p, int &x, int y, int ft);
266 
267     // paint all visible icons
268     void paintIcons(QPainter *p, int &x, int y, int ft);
269 
270     void drawRoundedRect(QPainter *p, QRect rect, bool selected, const QColor &bgColor, const QColor &frameColor, bool frame, int ft, bool roundTop, bool roundBottom);
271 
272     Q_REQUIRED_RESULT QColor getCategoryColor() const;
273     Q_REQUIRED_RESULT QColor getFrameColor(const QColor &resourceColor, const QColor &categoryColor) const;
274     Q_REQUIRED_RESULT QColor getBackgroundColor(const QColor &resourceColor, const QColor &categoryColor) const;
275 
276     int mCellXLeft, mCellXRight;
277     int mCellYTop, mCellYBottom;
278 
279     EventView *const mEventView;
280     MultiViewCalendar::Ptr mCalendar;
281     KCalendarCore::Incidence::Ptr mIncidence;
282     QDateTime mOccurrenceDateTime;
283     bool mValid = true;
284     bool mCloned = false;
285     QString mLabelText;
286     bool mSelected;
287     bool mIconAlarm;
288     bool mIconRecur;
289     bool mIconReadonly;
290     bool mIconReply;
291     bool mIconGroup;
292     bool mIconGroupTent;
293     bool mIconOrganizer;
294     bool mSpecialEvent;
295 
296     // For incidences that expand through more than 1 day
297     // Will be 1 for single day incidences
298     int mItemPos;
299     int mItemCount;
300 
301     // Multi item pointers
302     MultiItemInfo *mMultiItemInfo = nullptr;
303 
304     QList<AgendaItem::QPtr> mConflictItems;
305 
306     static QPixmap *alarmPxmp;
307     static QPixmap *recurPxmp;
308     static QPixmap *readonlyPxmp;
309     static QPixmap *replyPxmp;
310     static QPixmap *groupPxmp;
311     static QPixmap *groupPxmpTent;
312     static QPixmap *organizerPxmp;
313     static QPixmap *eventPxmp;
314     static QPixmap *todoPxmp;
315     static QPixmap *completedPxmp;
316 };
317 }
318 
319