File indexing completed on 2025-03-09 04:45:05
0001 /* 0002 SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org> 0003 SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com> 0004 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net> 0005 SPDX-FileContributor: Kevin Krammer <krake@kdab.com> 0006 0007 Marcus Bains line. 0008 SPDX-FileCopyrightText: 2001 Ali Rahimi <ali@mit.edu> 0009 0010 SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0 0011 */ 0012 #pragma once 0013 0014 #include "agendaitem.h" 0015 #include "eventviews_export.h" 0016 #include "viewcalendar.h" 0017 0018 #include <Akonadi/Item> 0019 0020 #include <KCalendarCore/Todo> 0021 0022 #include <QFrame> 0023 #include <QScrollArea> 0024 0025 #include <memory> 0026 0027 namespace Akonadi 0028 { 0029 class IncidenceChanger; 0030 } 0031 0032 namespace EventViews 0033 { 0034 class Agenda; 0035 class AgendaItem; 0036 class AgendaView; 0037 0038 class MarcusBainsPrivate; 0039 0040 class MarcusBains : public QFrame 0041 { 0042 Q_OBJECT 0043 public: 0044 explicit MarcusBains(EventView *eventView, Agenda *agenda = nullptr); 0045 void updateLocationRecalc(bool recalculate = false); 0046 ~MarcusBains() override; 0047 0048 public Q_SLOTS: 0049 void updateLocation(); 0050 0051 private: 0052 std::unique_ptr<MarcusBainsPrivate> const d; 0053 }; 0054 0055 class AgendaPrivate; 0056 0057 class EVENTVIEWS_EXPORT Agenda : public QWidget 0058 { 0059 Q_OBJECT 0060 public: 0061 Agenda(AgendaView *agendaView, QScrollArea *scrollArea, int columns, int rows, int rowSize, bool isInteractive); 0062 0063 Agenda(AgendaView *agendaView, QScrollArea *scrollArea, int columns, bool isInteractive); 0064 0065 ~Agenda() override; 0066 0067 [[nodiscard]] KCalendarCore::Incidence::Ptr selectedIncidence() const; 0068 [[nodiscard]] QDate selectedIncidenceDate() const; 0069 QSize sizeHint() const override; 0070 QSize minimumSizeHint() const override; 0071 QSize minimumSize() const; 0072 int minimumHeight() const; 0073 // QSizePolicy sizePolicy() const; 0074 [[nodiscard]] int contentsY() const 0075 { 0076 return -y(); 0077 } 0078 0079 [[nodiscard]] int contentsX() const 0080 { 0081 return x(); 0082 } 0083 0084 QScrollBar *verticalScrollBar() const; 0085 0086 QScrollArea *scrollArea() const; 0087 0088 [[nodiscard]] AgendaItem::List agendaItems(const QString &uid) const; 0089 0090 /** 0091 Returns the uid of the last incidence that was selected. This 0092 persists across reloads and clear, so that if the same uid 0093 reappears, it can be reselected. 0094 */ 0095 [[nodiscard]] QString lastSelectedItemUid() const; 0096 0097 bool eventFilter(QObject *, QEvent *) override; 0098 0099 void paintEvent(QPaintEvent *) override; 0100 0101 [[nodiscard]] QPoint contentsToGrid(QPoint pos) const; 0102 [[nodiscard]] QPoint gridToContents(QPoint gpos) const; 0103 0104 [[nodiscard]] int timeToY(QTime time) const; 0105 [[nodiscard]] QTime gyToTime(int y) const; 0106 0107 [[nodiscard]] QList<int> minContentsY() const; 0108 [[nodiscard]] QList<int> maxContentsY() const; 0109 0110 [[nodiscard]] int visibleContentsYMin() const; 0111 [[nodiscard]] int visibleContentsYMax() const; 0112 0113 void setStartTime(QTime startHour); 0114 0115 AgendaItem::QPtr insertItem(const KCalendarCore::Incidence::Ptr &incidence, 0116 const QDateTime &recurrenceId, 0117 int X, 0118 int YTop, 0119 int YBottom, 0120 int itemPos, 0121 int itemCount, 0122 bool isSelected); 0123 0124 AgendaItem::QPtr insertAllDayItem(const KCalendarCore::Incidence::Ptr &event, const QDateTime &recurrenceId, int XBegin, int XEnd, bool isSelected); 0125 0126 void 0127 insertMultiItem(const KCalendarCore::Incidence::Ptr &event, const QDateTime &recurrenceId, int XBegin, int XEnd, int YTop, int YBottom, bool isSelected); 0128 0129 /** 0130 Removes an event and all its multi-items from the agenda. This function 0131 removes the items from the view, but doesn't delete them immediately. 0132 Instead, they are queued in mItemsToDelete and later deleted by the 0133 slot deleteItemsToDelete() (called by QTimer::singleShot ). 0134 @param incidence The pointer to the incidence that should be removed. 0135 */ 0136 void removeIncidence(const KCalendarCore::Incidence::Ptr &incidence); 0137 0138 void changeColumns(int columns); 0139 0140 [[nodiscard]] int columns() const; 0141 [[nodiscard]] int rows() const; 0142 0143 [[nodiscard]] double gridSpacingX() const; 0144 [[nodiscard]] double gridSpacingY() const; 0145 0146 void clear(); 0147 0148 /** Update configuration from preference settings */ 0149 void updateConfig(); 0150 0151 void checkScrollBoundaries(); 0152 0153 void setHolidayMask(QList<bool> *); 0154 0155 void setDateList(const KCalendarCore::DateList &selectedDates); 0156 [[nodiscard]] KCalendarCore::DateList dateList() const; 0157 0158 void setCalendar(const EventViews::MultiViewCalendar::Ptr &cal); 0159 0160 void setIncidenceChanger(Akonadi::IncidenceChanger *changer); 0161 0162 public Q_SLOTS: 0163 void scrollUp(); 0164 void scrollDown(); 0165 0166 void checkScrollBoundaries(int); 0167 0168 /** Deselect selected items. This function does not Q_EMIT any signals. */ 0169 void deselectItem(); 0170 0171 void clearSelection(); 0172 0173 /** 0174 Select item. If the argument is 0, the currently selected item gets 0175 deselected. This function emits the itemSelected(bool) signal to inform 0176 about selection/deselection of events. 0177 */ 0178 void selectItem(const AgendaItem::QPtr &); 0179 0180 /** 0181 Selects the item associated with a given Akonadi Item id. 0182 Linear search, use carefully. 0183 @param id the item id of the item that should be selected. If no such 0184 item exists, the selection is not changed. 0185 */ 0186 void selectIncidenceByUid(const QString &id); 0187 void selectItem(const Akonadi::Item &item); 0188 0189 bool removeAgendaItem(const AgendaItem::QPtr &item); 0190 void showAgendaItem(const AgendaItem::QPtr &item); 0191 0192 Q_SIGNALS: 0193 void newEventSignal(); 0194 void newTimeSpanSignal(const QPoint &, const QPoint &); 0195 void newStartSelectSignal(); 0196 0197 void showIncidenceSignal(const KCalendarCore::Incidence::Ptr &); 0198 void editIncidenceSignal(const KCalendarCore::Incidence::Ptr &); 0199 void deleteIncidenceSignal(const KCalendarCore::Incidence::Ptr &); 0200 void showIncidencePopupSignal(const KCalendarCore::Incidence::Ptr &, const QDate &); 0201 0202 void showNewEventPopupSignal(); 0203 0204 void incidenceSelected(const KCalendarCore::Incidence::Ptr &, const QDate &); 0205 0206 void lowerYChanged(int); 0207 void upperYChanged(int); 0208 0209 void startDragSignal(const KCalendarCore::Incidence::Ptr &); 0210 void droppedIncidences(const KCalendarCore::Incidence::List &, const QPoint &gpos, bool allDay); 0211 void droppedIncidences(const QList<QUrl> &, const QPoint &gpos, bool allDay); 0212 0213 void enableAgendaUpdate(bool enable); 0214 void zoomView(const int delta, const QPoint &pos, const Qt::Orientation); 0215 0216 void mousePosSignal(const QPoint &pos); 0217 void enterAgenda(); 0218 void leaveAgenda(); 0219 0220 void gridSpacingYChanged(double); 0221 0222 private: 0223 enum MouseActionType { NOP, MOVE, SELECT, RESIZETOP, RESIZEBOTTOM, RESIZELEFT, RESIZERIGHT }; 0224 0225 AgendaItem::QPtr 0226 createAgendaItem(const KCalendarCore::Incidence::Ptr &incidence, int itemPos, int itemCount, const QDateTime &recurrentId, bool isSelected); 0227 0228 protected: 0229 /** 0230 Draw the background grid of the agenda. 0231 @p cw grid width 0232 @p ch grid height 0233 */ 0234 void drawContents(QPainter *p, int cx, int cy, int cw, int ch); 0235 0236 int columnWidth(int column) const; 0237 void resizeEvent(QResizeEvent *) override; 0238 0239 /** Handles mouse events. Called from eventFilter */ 0240 virtual bool eventFilter_mouse(QObject *, QMouseEvent *); 0241 #ifndef QT_NO_WHEELEVENT 0242 /** Handles mousewheel events. Called from eventFilter */ 0243 virtual bool eventFilter_wheel(QObject *, QWheelEvent *); 0244 #endif 0245 /** Handles key events. Called from eventFilter */ 0246 virtual bool eventFilter_key(QObject *, QKeyEvent *); 0247 0248 /** Handles drag and drop events. Called from eventFilter */ 0249 virtual bool eventFilter_drag(QObject *, QDropEvent *); 0250 0251 /** returns RESIZELEFT if pos is near the lower edge of the action item, 0252 RESIZERIGHT if pos is near the higher edge, and MOVE otherwise. 0253 If --reverse is used, RESIZELEFT still means resizing the beginning of 0254 the event, although that means moving to the right! 0255 horizontal is the same as mAllDayAgenda. 0256 @param horizontal Whether horizontal resizing is possible 0257 @param pos The current mouse position 0258 @param item The affected item 0259 */ 0260 MouseActionType isInResizeArea(bool horizontal, QPoint pos, const AgendaItem::QPtr &item); 0261 /** Return whether the cell specified by the grid point belongs to the current select 0262 */ 0263 bool ptInSelection(QPoint gpos) const; 0264 0265 /** Start selecting time span. */ 0266 void startSelectAction(QPoint viewportPos); 0267 0268 /** Select time span. */ 0269 void performSelectAction(QPoint viewportPos); 0270 0271 /** Emd selecting time span. */ 0272 void endSelectAction(const QPoint &viewportPos); 0273 0274 /** Start moving/resizing agenda item */ 0275 void startItemAction(const QPoint &viewportPos); 0276 0277 /** Move/resize agenda item */ 0278 void performItemAction(QPoint viewportPos); 0279 0280 /** End moving/resizing agenda item */ 0281 void endItemAction(); 0282 0283 /** Set cursor, when no item action is in progress */ 0284 void setNoActionCursor(const AgendaItem::QPtr &moveItem, QPoint viewportPos); 0285 /** Sets the cursor according to the given action type. 0286 @param actionType The type of action for which the cursor should be set. 0287 @param acting If true, the corresponding action is running (e.g. the 0288 item is currently being moved by the user). If false the 0289 cursor should just indicate that the corresponding 0290 action is possible */ 0291 void setActionCursor(int actionType, bool acting = false); 0292 0293 /** calculate the width of the column subcells of the given item */ 0294 double calcSubCellWidth(const AgendaItem::QPtr &item); 0295 /** Move and resize the given item to the correct position */ 0296 void placeAgendaItem(const AgendaItem::QPtr &item, double subCellWidth); 0297 /** Place agenda item in agenda and adjust other cells if necessary */ 0298 void placeSubCells(const AgendaItem::QPtr &placeItem); 0299 /** Place the agenda item at the correct position (ignoring conflicting items) */ 0300 void adjustItemPosition(const AgendaItem::QPtr &item); 0301 0302 /** Process the keyevent, including the ignored keyevents of eventwidgets. 0303 * Implements pgup/pgdn and cursor key navigation in the view. 0304 */ 0305 void keyPressEvent(QKeyEvent *) override; 0306 0307 void calculateWorkingHours(); 0308 0309 virtual void contentsMousePressEvent(QMouseEvent *); 0310 0311 protected Q_SLOTS: 0312 /** delete the items that are queued for deletion */ 0313 void deleteItemsToDelete(); 0314 /** Resizes all the child elements after the size of the agenda 0315 changed. This is needed because Qt seems to have a bug when 0316 the resizeEvent of one of the widgets in a splitter takes a 0317 lot of time / does a lot of resizes.... see bug 80114 */ 0318 void resizeAllContents(); 0319 0320 private: 0321 EVENTVIEWS_NO_EXPORT void init(); 0322 EVENTVIEWS_NO_EXPORT void marcus_bains(); 0323 0324 private: 0325 friend class AgendaPrivate; 0326 std::unique_ptr<AgendaPrivate> const d; 0327 }; 0328 0329 class AgendaScrollArea : public QScrollArea 0330 { 0331 Q_OBJECT 0332 public: 0333 AgendaScrollArea(bool allDay, AgendaView *agendaView, bool isInteractive, QWidget *parent); 0334 ~AgendaScrollArea() override; 0335 0336 Agenda *agenda() const; 0337 0338 private: 0339 Agenda *mAgenda = nullptr; 0340 }; 0341 }