File indexing completed on 2024-06-02 05:19:23

0001 /*
0002  *  resources.h  -  container for all ResourceType instances
0003  *  Program:  kalarm
0004  *  SPDX-FileCopyrightText: 2019-2021 David Jarvie <djarvie@kde.org>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #pragma once
0010 
0011 #include "datamodel.h"
0012 #include "resource.h"
0013 #include "resourcemodel.h"
0014 
0015 #include <QObject>
0016 
0017 using namespace KAlarmCal;
0018 
0019 /** Class to contain all ResourceType instances.
0020  *  It provides connection to signals from all ResourceType instances.
0021  */
0022 class Resources : public QObject
0023 {
0024     Q_OBJECT
0025 public:
0026     /** Creates the unique Resources instance.
0027      *  Note that this merely creates a container for individual resources,
0028      *  and doesn't create or initialise any ResourceType instances.
0029      */
0030     static Resources* instance();
0031 
0032     ~Resources() override;
0033     Resources(const Resources&) = delete;
0034     Resources& operator=(const Resources&) const = delete;
0035 
0036     /** Return a copy of the resource with a given ID.
0037      *  @return  The resource, or invalid if the ID doesn't already exist or is invalid.
0038      */
0039     static Resource resource(ResourceId);
0040 
0041     /** Return a copy of the resource with a given display ID.
0042      *  @return  The resource, or invalid if the ID doesn't already exist or is invalid
0043      *           or if more than one resource has the same display ID.
0044      */
0045     static Resource resourceFromDisplayId(ResourceId);
0046 
0047     /** Remove a resource. The calendar file is not removed.
0048      *  @return true if the resource has been removed or a removal job has been scheduled.
0049      */
0050     static bool removeResource(Resource&);
0051 
0052     /** Sorting criteria for allResources(Type, Sorting). May be OR'ed together. */
0053     enum Sorts
0054     {
0055         NoSort       = 0,
0056         DisplayName  = 0x01,   // sort by display name
0057         DefaultFirst = 0x02    // default resource is first in list. Requires a CalEvent::Type to be specified.
0058     };
0059     Q_DECLARE_FLAGS(Sorting, Sorts)
0060     /** Return all resources of a kind which contain a specified alarm type.
0061      *  @tparam RType      Resource type to fetch, default = all types.
0062      *  @param  alarmType  Alarm type to check for, or CalEvent::EMPTY for any type.
0063      *  @param  sorting    Sorting criteria to use.
0064      */
0065     template <class RType = ResourceType>
0066     static QList<Resource> allResources(CalEvent::Type alarmType = CalEvent::EMPTY, Sorting sorting = NoSort);
0067 
0068     /** Return the enabled resources which contain a specified alarm type.
0069      *  @param type      Alarm type to check for, or CalEvent::EMPTY for any type.
0070      *  @param writable  If true, only writable resources are included.
0071      */
0072     static QList<Resource> enabledResources(CalEvent::Type type = CalEvent::EMPTY, bool writable = false);
0073 
0074     /** Return the standard resource for an alarm type. This is the resource
0075      *  which can be set as the default to add new alarms to.
0076      *  Only enabled and writable resources can be standard.
0077      *  In the case of archived alarm resources, if no resource is specified
0078      *  as standard and there is exactly one writable archived alarm resource,
0079      *  that resource will be automatically set as standard.
0080      *
0081      *  @param type             Alarm type.
0082      *  @param useOnlyResource  If there is only one resource for the alarm type,
0083      *                          set it as standard.
0084      *  @return standard resource, or null if none.
0085      */
0086     static Resource getStandard(CalEvent::Type type, bool useOnlyResource = false);
0087 
0088     /** Return whether a resource is the standard resource for a specified alarm
0089      *  type. Only enabled and writable resources can be standard.
0090      *  In the case of archived alarms, if no resource is specified as standard
0091      *  and the resource is the only writable archived alarm resource, it will
0092      *  be automatically set as standard.
0093      */
0094     static bool isStandard(const Resource& resource, CalEvent::Type);
0095 
0096     /** Return the alarm type(s) for which a resource is the standard resource.
0097      *  Only enabled and writable resources can be standard.
0098      *  @param useDefault false to return the defined standard types, if any;
0099      *                    true to return the types for which it is the standard
0100      *                    or only resource.
0101      */
0102     static CalEvent::Types standardTypes(const Resource& resource, bool useDefault = false);
0103 
0104     /** Set or clear a resource as the standard resource for a specified alarm
0105      *  type. This does not affect its status for other alarm types.
0106      *  The resource must be writable and enabled for the type, to set
0107      *  standard = true.
0108      *  If the resource is being set as standard, the standard status for the
0109      *  alarm type is cleared for any other resources.
0110      */
0111     static void setStandard(Resource& resource, CalEvent::Type, bool standard);
0112 
0113     /** Set which alarm types a resource is the standard resource for.
0114      *  Its standard status is cleared for other alarm types.
0115      *  The resource must be writable and enabled for the type, to set
0116      *  standard = true.
0117      *  If the resource is being set as standard for any alarm types, the
0118      *  standard status is cleared for those alarm types for any other resources.
0119      */
0120     static void setStandard(Resource& resource, CalEvent::Types);
0121 
0122     /** Options for destination(). May be OR'ed together. */
0123     enum DestOption
0124     {
0125         NoDestOption     = 0,
0126         NoResourcePrompt = 0x01,   //!< Don't prompt the user even if the standard resource is not valid.
0127         UseOnlyResource  = 0x02    //!< If there is only one enabled resource, set it as standard.
0128     };
0129     Q_DECLARE_FLAGS(DestOptions, DestOption)
0130 
0131     /** Find the resource to be used to store an event of a given type.
0132      *  This will be the standard resource for the type, but if this is not valid,
0133      *  the user will be prompted to select a resource.
0134      *  @param type         The event type
0135      *  @param promptParent The parent widget for the prompt
0136      *  @param options      Options to use
0137      *  @param cancelled    If non-null: set to true if the user cancelled the
0138      *                      prompt dialogue; set to false if any other error
0139      */
0140     static Resource destination(CalEvent::Type type, QWidget* promptParent = nullptr, DestOptions options = NoDestOption, bool* cancelled = nullptr);
0141 
0142     /** Return whether all configured and migrated resources have been created. */
0143     static bool allCreated();
0144 
0145     /** Return whether all configured and migrated resources have been loaded
0146      *  at least once. */
0147     static bool allPopulated();
0148 
0149     /** Return the resource which an event belongs to, provided that the event's
0150      *  alarm type is enabled. */
0151     static Resource resourceForEvent(const QString& eventId);
0152 
0153     /** Return the resource which an event belongs to, and the event, provided
0154      *  that the event's alarm type is enabled. */
0155     static Resource resourceForEvent(const QString& eventId, KAEvent& event);
0156 
0157     /** Return the resource which has a given configuration identifier. */
0158     static Resource resourceForConfigName(const QString& configName);
0159 
0160     /** To be called when the start-of-day time has changed, to adjust the start
0161      *  times of all date-only alarms' recurrences, in all resources.
0162      */
0163     static void adjustStartOfDay();
0164 
0165     /** Called to notify that a new resource has completed its initialisation,
0166      *  in order to emit the resourceAdded() signal. */
0167     static void notifyNewResourceInitialised(Resource&);
0168 
0169     /** Called to notify that all configured and migrated resources have now
0170      *  been created. */
0171     static void notifyResourcesCreated();
0172 
0173     /** Called by a resource to notify that loading of events has successfully completed,
0174      *  or that loading has failed. */
0175     static void notifyResourcePopulated(const ResourceType*);
0176 
0177     /** Called to notify that a resource is about to be removed. */
0178     static void notifyResourceToBeRemoved(ResourceType*);
0179 
0180     /** Called by a resource to notify that its settings have changed.
0181      *  This will cause the settingsChanged() signal to be emitted.
0182      */
0183     static void notifySettingsChanged(ResourceType*, ResourceType::Changes, CalEvent::Types oldEnabled);
0184 
0185     /** Called by a resource when a user message should be displayed.
0186      *  This will cause the resourceMessage() signal to be emitted.
0187      *  @param message  Must include the resource's display name in order to
0188      *                  identify the resource to the user.
0189      */
0190     static void notifyResourceMessage(ResourceType*, ResourceType::MessageType, const QString& message, const QString& details);
0191 
0192     /** Called when a user message should be displayed for a resource.
0193      *  This will cause the resourceMessage() signal to be emitted.
0194      *  @param message  Must include the resource's display name in order to
0195      *                  identify the resource to the user.
0196      */
0197     static void notifyResourceMessage(ResourceId, ResourceType::MessageType, const QString& message, const QString& details);
0198 
0199     /** Called by a resource to notify that it has added events. */
0200     static void notifyEventsAdded(ResourceType*, const QList<KAEvent>&);
0201 
0202     /** Called by a resource to notify that it has changed an event.
0203      *  The event's UID must be unchanged.
0204      */
0205     static void notifyEventUpdated(ResourceType*, const KAEvent& event);
0206 
0207     /** Called by a resource to notify that it is about to delete events. */
0208     static void notifyEventsToBeRemoved(ResourceType*, const QList<KAEvent>&);
0209 
0210     /** Called by a resource to notify that it has deleted events. */
0211     static void notifyEventsRemoved(ResourceType*, const QList<KAEvent>&);
0212 
0213     /** Called by a resource settings instance to notify that it is about to be destructed. */
0214     static void notifySettingsDestroyed(ResourceId);
0215 
0216 Q_SIGNALS:
0217     /** Emitted when a resource's settings have changed. */
0218     void settingsChanged(Resource&, ResourceType::Changes);
0219 
0220     /** Emitted when all configured resource have been created (but not
0221      *  necessarily populated), and any necessary resource migration and
0222      *  the creation of default resources has been performed.
0223      */
0224     void resourcesCreated();
0225 
0226     /** Emitted when all configured and migrated resources have been loaded for
0227      *  the first time, or cannot currently be loaded.
0228      *  This is always emitted after resourcesCreated().
0229      */
0230     void resourcesPopulated();
0231 
0232     /** Emitted when a new resource has been created.
0233      *  The resource may or may not have loaded its events before the signal is
0234      *  emitted.
0235      */
0236     void resourceAdded(Resource&);
0237 
0238     /** Emitted when a resource's events have been successfully loaded.
0239      *
0240      *  This signal is not emitted if the resource's events have already been
0241      *  loaded before its resourceAdded() signal is emitted.
0242      *
0243      *  @see Resource::isPopulated() can be called at any time to check whether
0244      *  the resource's events have been loaded.
0245      */
0246     void resourcePopulated(Resource&);
0247 
0248     /** Emitted when a resource's config and settings are about to be removed. */
0249     void resourceToBeRemoved(Resource&);
0250 
0251     /** Emitted when a resource's config and settings have been removed. */
0252     void resourceRemoved(KAlarmCal::ResourceId);
0253 
0254     /** Emitted when a resource message should be displayed to the user.
0255      *  @note  Connections to this signal should use Qt::QueuedConnection type
0256      *         to allow processing to continue while the user message is displayed.
0257      */
0258     void resourceMessage(ResourceType::MessageType, const QString& message, const QString& details);
0259 
0260     /** Emitted when events have been added to a resource.
0261      *  Events are only notified whose alarm type is enabled.
0262      *
0263      *  This signal is not emitted when events are added to the resource before
0264      *  its resourceAdded() signal is emitted.
0265      */
0266     void eventsAdded(Resource&, const QList<KAEvent>&);
0267 
0268     /** Emitted when an event has been updated in a resource.
0269      *  Events are only notified whose alarm type is enabled.
0270      *  The event's UID is unchanged.
0271      */
0272     void eventUpdated(Resource&, const KAEvent&);
0273 
0274     /** Emitted when events are about to be deleted from a resource.
0275      *  Events are only notified whose alarm type is enabled.
0276      */
0277     void eventsToBeRemoved(Resource&, const QList<KAEvent>&);
0278 
0279     /** Emitted when events have been deleted from a resource.
0280      *  Events are only notified whose alarm type is enabled.
0281      */
0282     void eventsRemoved(Resource&, const QList<KAEvent>&);
0283 
0284 private:
0285     Resources();
0286 
0287     /** Add a new ResourceType instance, with a Resource owner.
0288      *  Once the resource has completed its initialisation, call
0289      *  notifyNewResourceInitialised() to emit the resourceAdded() signal.
0290      *  is require
0291      *  @param type      Newly constructed ResourceType instance, which will belong to
0292      *                   'resource' if successful. On error, it will be deleted.
0293      *  @param resource  If type is invalid, updated to an invalid resource;
0294      *                   If type ID already exists, updated to the existing resource with that ID;
0295      *                   If type ID doesn't exist, updated to the new resource containing res.
0296      *  @return true if a new resource has been created, false if invalid or already exists.
0297      */
0298     static bool addResource(ResourceType* type, Resource& resource);
0299 
0300     /** Remove the resource with a given ID.
0301      *  @note  The ResourceType instance will only be deleted once all Resource
0302      *         instances which refer to this ID go out of scope.
0303      */
0304     static void removeResource(ResourceId);
0305 
0306     static void checkResourcesPopulated();
0307 
0308     static Resources*                  mInstance;    // the unique instance
0309     static QHash<ResourceId, Resource> mResources;   // contains all ResourceType instances with an ID
0310     static bool                        mCreated;     // all resources have been created
0311     static bool                        mPopulated;   // all resources have been loaded once
0312 
0313     friend class ResourceType;
0314 };
0315 
0316 Q_DECLARE_OPERATORS_FOR_FLAGS(Resources::Sorting)
0317 Q_DECLARE_OPERATORS_FOR_FLAGS(Resources::DestOptions)
0318 
0319 
0320 /*=============================================================================
0321 * Template definitions.
0322 *============================================================================*/
0323 
0324 template <class RType>
0325 QList<Resource> Resources::allResources(CalEvent::Type type, Sorting sorting)
0326 {
0327     const CalEvent::Types types = (type == CalEvent::EMPTY)
0328                                 ? CalEvent::ACTIVE | CalEvent::ARCHIVED | CalEvent::TEMPLATE
0329                                 : type;
0330 
0331     QList<Resource> result;
0332     Resource std;
0333     if ((sorting & DefaultFirst)  &&  type != CalEvent::EMPTY)
0334     {
0335         std = getStandard(type, (type == CalEvent::ARCHIVED));
0336         if (std.isValid()  &&  std.is<RType>())
0337             result += std;
0338     }
0339     const int start = result.size();
0340 
0341     for (auto it = mResources.constBegin();  it != mResources.constEnd();  ++it)
0342     {
0343         const Resource& res = it.value();
0344         if (res != std  &&  res.is<RType>()  &&  (res.alarmTypes() & types))
0345             result += res;
0346     }
0347 
0348     if (sorting & DisplayName)
0349         std::sort(result.begin() + start, result.end(), [](const Resource& a, const Resource& b) { return a.displayName().compare(b.displayName(), Qt::CaseInsensitive) < 0; });
0350 
0351     return result;
0352 }
0353 
0354 // vim: et sw=4: