File indexing completed on 2024-04-28 05:11:31

0001 /*
0002   SPDX-FileCopyrightText: 2000, 2001, 2004 Cornelius Schumacher <schumacher@kde.org>
0003   SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
0004   SPDX-FileCopyrightText: 2010 Andras Mantia <andras@kdab.com>
0005   SPDX-FileCopyrightText: 2010 Casey Link <casey@kdab.com>
0006 
0007   SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #pragma once
0011 
0012 #include "incidenceeditor_export.h"
0013 #include <CalendarSupport/FreeBusyItem>
0014 
0015 #include <QBitArray>
0016 #include <QSet>
0017 #include <QTimer>
0018 
0019 namespace CalendarSupport
0020 {
0021 class FreeBusyItemModel;
0022 }
0023 
0024 namespace IncidenceEditorNG
0025 {
0026 /**
0027  * Takes a list of attendees and event info (e.g., min time start, max time end)
0028  * fetches their freebusy information, then identifies conflicts and periods of non-conflict.
0029  *
0030  * It exposes these periods so another class can display them to the user and allow
0031  * them to choose a correct time.
0032  * @author Casey Link
0033  */
0034 class INCIDENCEEDITOR_EXPORT ConflictResolver : public QObject
0035 {
0036     Q_OBJECT
0037 public:
0038     /**
0039      * @param parentWidget is passed to Akonadi when fetching free/busy data.
0040      */
0041     explicit ConflictResolver(QWidget *parentWidget, QObject *parent = nullptr);
0042 
0043     /**
0044      *  Add an attendee
0045      * The attendees free busy info will be fetched
0046      * and integrated into the resolver.
0047      */
0048     void insertAttendee(const KCalendarCore::Attendee &attendee);
0049 
0050     void insertAttendee(const CalendarSupport::FreeBusyItem::Ptr &freebusy);
0051     /**
0052      * Removes an attendee
0053      * The attendee will no longer be considered when
0054      * resolving conflicts
0055      */
0056 
0057     void removeAttendee(const KCalendarCore::Attendee &attendee);
0058 
0059     /**
0060      * Clear all attendees
0061      */
0062     void clearAttendees();
0063 
0064     /**
0065      * Returns whether the resolver contains the attendee
0066      */
0067     [[nodiscard]] bool containsAttendee(const KCalendarCore::Attendee &attendee);
0068 
0069     /**
0070      * Constrain the free time slot search to the weekdays
0071      * identified by their KCalendarSystem integer representation
0072      * Default is Monday - Friday
0073      * @param weekdays a 7 bit array indicating the allowed days (bit 0=Monday, value 1=allowed).
0074      * @see KCalendarSystem
0075      */
0076     void setAllowedWeekdays(const QBitArray &weekdays);
0077 
0078     /**
0079      * Constrain the free time slot search to the set participant roles.
0080      * Mandatory roles are considered the minimum required to attend
0081      * the meeting, so only those attendees with the mandatory roles will
0082      * be considered  in the search.
0083      * Default is all roles are mandatory.
0084      * @param roles the set of mandatory participant roles
0085      */
0086     void setMandatoryRoles(const QSet<KCalendarCore::Attendee::Role> &roles);
0087 
0088     /**
0089      * Returns a list of date time ranges that conform to the
0090      * search constraints.
0091      * @see setMandatoryRoles
0092      * @see setAllowedWeekdays
0093      */
0094     [[nodiscard]] KCalendarCore::Period::List availableSlots() const;
0095 
0096     /**
0097       Finds a free slot in the future which has at least the same size as
0098       the initial slot.
0099     */
0100     [[nodiscard]] bool findFreeSlot(const KCalendarCore::Period &dateTimeRange);
0101 
0102     CalendarSupport::FreeBusyItemModel *model() const;
0103 
0104 Q_SIGNALS:
0105     /**
0106      * Emitted when the user changes the start and end dateTimes
0107      * for the incidence.
0108      */
0109     void dateTimesChanged(const QDateTime &newStart, const QDateTime &newEnd);
0110 
0111     /**
0112      * Emitted when there are conflicts
0113      * @param number the number of conflicts
0114      */
0115     void conflictsDetected(int number);
0116 
0117     /**
0118      * Emitted when the resolver locates new free slots.
0119      */
0120     void freeSlotsAvailable(const KCalendarCore::Period::List &);
0121 
0122 public Q_SLOTS:
0123     /**
0124      * Set the timeframe constraints
0125      *
0126      * These control the timeframe for which conflicts are to be resolved.
0127      */
0128     void setEarliestDate(QDate newDate);
0129     void setEarliestTime(QTime newTime);
0130     void setLatestDate(QDate newDate);
0131     void setLatestTime(QTime newTime);
0132 
0133     void setEarliestDateTime(const QDateTime &newDateTime);
0134     void setLatestDateTime(const QDateTime &newDateTime);
0135 
0136     void freebusyDataChanged();
0137 
0138     void findAllFreeSlots();
0139 
0140     void setResolution(int seconds);
0141 
0142 private:
0143     /**
0144       Checks whether the slot specified by (tryFrom, tryTo) matches the
0145       search constraints. If yes, return true. The return value is the
0146       number of conflicts that were detected, and (tryFrom, tryTo) contain the next free slot for
0147       that participant. In other words, the returned slot does not have to
0148       be free for everybody else.
0149     */
0150     INCIDENCEEDITOR_NO_EXPORT int tryDate(QDateTime &tryFrom, QDateTime &tryTo);
0151 
0152     /**
0153       Checks whether the slot specified by (tryFrom, tryTo) is available
0154       for the participant with specified fb. If yes, return true. If
0155       not, return false and change (tryFrom, tryTo) to contain the next
0156       possible slot for this participant (not necessarily a slot that is
0157       available for all participants).
0158     */
0159     INCIDENCEEDITOR_NO_EXPORT bool tryDate(const KCalendarCore::FreeBusy::Ptr &fb, QDateTime &tryFrom, QDateTime &tryTo);
0160 
0161     /**
0162      * Checks whether the supplied attendee passes the
0163      * current mandatory role constraint.
0164      * @return true if the attendee is of one of the mandatory roles, false if not
0165      */
0166     INCIDENCEEDITOR_NO_EXPORT bool matchesRoleConstraint(const KCalendarCore::Attendee &attendee);
0167 
0168     INCIDENCEEDITOR_NO_EXPORT void calculateConflicts();
0169 
0170     KCalendarCore::Period mTimeframeConstraint; //!< the datetime range for outside of which
0171     // free slots won't be searched.
0172     KCalendarCore::Period::List mAvailableSlots;
0173 
0174     QTimer mCalculateTimer; //!< A timer is used control the calculation of conflicts
0175     // to prevent the process from being repeated many times
0176     // after a series of quick parameter changes.
0177 
0178     CalendarSupport::FreeBusyItemModel *const mFBModel;
0179     QWidget *mParentWidget = nullptr;
0180 
0181     QSet<KCalendarCore::Attendee::Role> mMandatoryRoles;
0182     QBitArray mWeekdays; //!< a 7 bit array indicating the allowed days
0183     //(bit 0 = Monday, value 1 = allowed).
0184 
0185     int mSlotResolutionSeconds;
0186 };
0187 }