File indexing completed on 2024-05-12 15:59:51
0001 /* 0002 * SPDX-FileCopyrightText: 2020 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #ifndef KISRESOURCESINTERFACE_H 0007 #define KISRESOURCESINTERFACE_H 0008 0009 #include "kritaresources_export.h" 0010 0011 #include <QScopedPointer> 0012 #include <KoResource.h> 0013 #include <QHash> 0014 #include <KoResourceLoadResult.h> 0015 0016 class QString; 0017 class QByteArray; 0018 class KisResourcesInterfacePrivate; 0019 0020 /** 0021 * @brief a provider-like interface class for accessing resource sources in Krita. 0022 * 0023 * Main differences to KoResourceServer and KisResourceModel: 0024 * 0025 * 1) It is a polymorphic class. Therefore, we are not obliged to pass 0026 a pointer to the global gui-only resource storage everywhere. Instead, 0027 we can create temporary storages and pass them to the strokes, when needed. 0028 0029 2) The class doesn't depend on any specific resource types. Its baseline 0030 implementation of resourceInterface->source(type) returns a source 0031 working with KoResourceSP only. But when needed, the caller may request 0032 a typed version via resourcesInterface->source<KisBrush>(type). It 0033 will instantiate a templated wrapper **in the caller's** object file, 0034 not in kritaresources library. It solves linking problem: 0035 we have a source for KisBrush objects in kritaresources library, 0036 even though this library doesn't link kritabrush. 0037 0038 3) Since strokes may have local storages for the resources, we operate 0039 with resources sources using shared pointers, not raw pointers. 0040 */ 0041 class KRITARESOURCES_EXPORT KisResourcesInterface 0042 { 0043 public: 0044 class KRITARESOURCES_EXPORT ResourceSourceAdapter 0045 { 0046 public: 0047 ResourceSourceAdapter(const QString &type); 0048 virtual ~ResourceSourceAdapter(); 0049 //protected: 0050 friend class KisResourcesInterface; 0051 virtual QVector<KoResourceSP> resourcesForFilename(const QString& filename) const = 0; 0052 virtual QVector<KoResourceSP> resourcesForName(const QString& name) const = 0; 0053 virtual QVector<KoResourceSP> resourcesForMD5(const QString& md5) const = 0; 0054 public: 0055 /** 0056 * @brief bestMatch retrieves a resource, prefarably by md5, but with filename and name 0057 * as fallback for older files that do not store the md5sum. If the resource is 0058 * not found by md5 and the md5 isn't empty, then it will try to fallback to searching 0059 * by filename, but will show a warning in case sanity checks are enabled. 0060 * 0061 * If multiple resources with the same md5 exist, then it prefers the one 0062 * with the same filename and name. 0063 * 0064 * @return a resource, or 0 of the resource doesn't exist. 0065 */ 0066 0067 KoResourceSP bestMatch(const QString md5, const QString filename, const QString name); 0068 0069 /** 0070 * Same as bestMatch(), but returns KoResourceLoadResult. In case the 0071 * resource is not found in the backend storage, the load-result 0072 * will be set in FailedLink state 0073 * 0074 */ 0075 KoResourceLoadResult bestMatchLoadResult(const QString md5, const QString filename, const QString name); 0076 0077 virtual KoResourceSP fallbackResource() const = 0; 0078 0079 private: 0080 Q_DISABLE_COPY(ResourceSourceAdapter); 0081 const QString m_type; 0082 }; 0083 0084 template <typename T> 0085 class TypedResourceSourceAdapter 0086 { 0087 public: 0088 TypedResourceSourceAdapter(ResourceSourceAdapter *adapter) 0089 : m_source(adapter) 0090 { 0091 } 0092 private: 0093 QVector<QSharedPointer<T>> resourcesForFilename(const QString& filename) const 0094 { 0095 QVector<QSharedPointer<T>> r; 0096 Q_FOREACH(KoResourceSP resource, m_source->resourcesForFilename(filename)) { 0097 r << resource.dynamicCast<T>(); 0098 } 0099 return r; 0100 } 0101 0102 QVector<QSharedPointer<T>> resourcesForName(const QString& name) const 0103 { 0104 QVector<QSharedPointer<T>> r; 0105 Q_FOREACH(KoResourceSP resource, m_source->resourcesForName(name)) { 0106 r << resource.dynamicCast<T>(); 0107 } 0108 return r; 0109 } 0110 0111 QVector<QSharedPointer<T>> resourcesForMD5(const QString& md5) const 0112 { 0113 QVector<QSharedPointer<T>> r; 0114 Q_FOREACH(KoResourceSP resource, m_source->resourcesForMD5(md5)) { 0115 r << resource.dynamicCast<T>(); 0116 } 0117 return r; 0118 } 0119 public: 0120 /** 0121 * @brief resource retrieves a resource, prefarably by md5, but with filename and name 0122 * as fallback for older files that do not store the md5sum. Note that if the resource is 0123 * not found by md5 if the md5 isn't empty, we do NOT then look by filename. 0124 * 0125 * If multiple resources with the same md5 exist, then it prefers the one 0126 * with the same filename and name. 0127 * 0128 * @return a resource, or 0 of the resource doesn't exist. 0129 */ 0130 0131 QSharedPointer<T> bestMatch(const QString md5, const QString filename, const QString name) { 0132 return m_source->bestMatch(md5, filename, name).dynamicCast<T>(); 0133 } 0134 0135 /** 0136 * Same as bestMatch(), but returns KoResourceLoadResult. In case the 0137 * resource is not found in the backend storage, the load-result 0138 * will be set in FailedLink state 0139 * 0140 */ 0141 KoResourceLoadResult bestMatchLoadResult(const QString md5, const QString filename, const QString name) { 0142 return m_source->bestMatchLoadResult(md5, filename, name); 0143 } 0144 0145 QSharedPointer<T> fallbackResource() const 0146 { 0147 return m_source->fallbackResource().dynamicCast<T>(); 0148 } 0149 0150 protected: 0151 ResourceSourceAdapter *m_source; 0152 }; 0153 0154 public: 0155 KisResourcesInterface(); 0156 virtual ~KisResourcesInterface(); 0157 0158 /** 0159 * A basic implementation that returns a source for a specific type 0160 * of the resource. Please take into account that this source object will 0161 * return un-casted resources of type KoResourceSP. If you want to have a 0162 * proper resource (in most of the cases), use a `server<T>(type)` instead. 0163 */ 0164 ResourceSourceAdapter& source(const QString &type) const; 0165 0166 /** 0167 * The main fetcher of resource source for resources of a specific type. 0168 * 0169 * Usage: 0170 * 0171 * \code{.cpp} 0172 * 0173 * auto source = resourceInterface->source<KisBrush>(ResourceType::Brushes); 0174 * KisBrushSP brush = source.resourceByMd5(md5) 0175 * 0176 * \endcode 0177 * 0178 */ 0179 template<typename T> 0180 TypedResourceSourceAdapter<T> source(const QString &type) const { 0181 return TypedResourceSourceAdapter<T>(&this->source(type)); 0182 } 0183 0184 protected: 0185 KisResourcesInterface(KisResourcesInterfacePrivate *dd); 0186 virtual ResourceSourceAdapter* createSourceImpl(const QString &type) const = 0; 0187 0188 protected: 0189 QScopedPointer<KisResourcesInterfacePrivate> d_ptr; 0190 0191 private: 0192 Q_DECLARE_PRIVATE(KisResourcesInterface) 0193 }; 0194 0195 using KisResourcesInterfaceSP = QSharedPointer<KisResourcesInterface>; 0196 0197 #endif // KISRESOURCESINTERFACE_H