File indexing completed on 2024-05-19 04:26:41

0001 /*
0002  * SPDX-FileCopyrightText: 2018 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "KisAslStorage.h"
0008 #include <KisResourceStorage.h>
0009 #include <kis_psd_layer_style.h>
0010 
0011 #include <QFileInfo>
0012 #include <KisStaticInitializer.h>
0013 
0014 KIS_DECLARE_STATIC_INITIALIZER {
0015     KisStoragePluginRegistry::instance()->addStoragePluginFactory(KisResourceStorage::StorageType::AdobeStyleLibrary, new KisStoragePluginFactory<KisAslStorage>());
0016 }
0017 
0018 
0019 class AslTagIterator : public KisResourceStorage::TagIterator
0020 {
0021 public:
0022 
0023     AslTagIterator(const QString &location, const QString &resourceType)
0024         : m_location(location)
0025         , m_resourceType(resourceType)
0026     {}
0027 
0028     bool hasNext() const override {return false;}
0029     void next() override {}
0030 
0031     KisTagSP tag() const override { return nullptr; }
0032 
0033 private:
0034 
0035     QString m_location;
0036     QString m_resourceType;
0037 
0038 };
0039 
0040 class AslIterator : public KisResourceStorage::ResourceIterator
0041 {
0042 
0043 private:
0044 
0045     QString m_filename;
0046     QSharedPointer<KisAslLayerStyleSerializer> m_aslSerializer;
0047     bool m_isLoaded;
0048     QHash<QString, KoPatternSP> m_patterns;
0049     QVector<KisPSDLayerStyleSP> m_styles;
0050     QScopedPointer<QHashIterator<QString, KoPatternSP>> m_patternsIterator;
0051     QScopedPointer<QVectorIterator<KisPSDLayerStyleSP>> m_stylesIterator;
0052     QString m_currentType;
0053     KoResourceSP m_currentResource;
0054     QString m_currentUuid;
0055     QString m_resourceType;
0056 
0057 public:
0058 
0059     AslIterator(QSharedPointer<KisAslLayerStyleSerializer> aslSerializer, const QString& filename, const QString& resourceType)
0060         : m_filename(filename)
0061         , m_aslSerializer(aslSerializer)
0062         , m_isLoaded(false)
0063         , m_resourceType(resourceType)
0064     {
0065     }
0066 
0067     bool hasNext() const override
0068     {
0069         if (!m_isLoaded && (m_resourceType == ResourceType::Patterns || m_resourceType == ResourceType::LayerStyles)) {
0070             if (!m_aslSerializer->isInitialized()) {
0071                 m_aslSerializer->readFromFile(m_filename);
0072             }
0073 
0074             const_cast<AslIterator*>(this)->m_isLoaded = true;
0075             const_cast<AslIterator*>(this)->m_patterns = m_aslSerializer->patterns();
0076             const_cast<AslIterator*>(this)->m_styles = m_aslSerializer->styles();
0077 
0078             const_cast<AslIterator*>(this)->m_patternsIterator.reset(new QHashIterator<QString, KoPatternSP>(m_patterns));
0079             const_cast<AslIterator*>(this)->m_stylesIterator.reset(new QVectorIterator<KisPSDLayerStyleSP>(m_styles));
0080         }
0081         if (!m_aslSerializer->isValid()) {
0082             return false;
0083         }
0084 
0085         if (m_resourceType == ResourceType::Patterns) {
0086             return m_patternsIterator->hasNext();
0087         } else if (m_resourceType == ResourceType::LayerStyles) {
0088             return m_stylesIterator->hasNext();
0089         }
0090         return false;
0091     }
0092     void next() override
0093     {
0094         if (m_resourceType == ResourceType::Patterns) {
0095             if (m_patternsIterator->hasNext()) {
0096                 m_currentType = ResourceType::Patterns;
0097                 m_patternsIterator->next();
0098                 KoPatternSP currentPattern = m_patternsIterator->value();
0099                 m_currentResource = currentPattern;
0100                 KIS_ASSERT(currentPattern);
0101                 m_currentUuid = currentPattern->filename();
0102             }
0103         } else if (m_resourceType == ResourceType::LayerStyles) {
0104             if (m_stylesIterator->hasNext()) {
0105                 m_currentType = ResourceType::LayerStyles;
0106                 KisPSDLayerStyleSP currentLayerStyle = m_stylesIterator->next();
0107                 m_currentResource = currentLayerStyle;
0108                 KIS_ASSERT(currentLayerStyle);
0109                 m_currentUuid = currentLayerStyle->filename();
0110             }
0111         }
0112     }
0113 
0114     QString url() const override
0115     {
0116         if (m_currentResource.isNull()) {
0117             return QString();
0118         }
0119         return m_currentUuid;
0120     }
0121 
0122     QString type() const override
0123     {
0124         return m_currentResource.isNull() ? QString() : m_currentType;
0125     }
0126 
0127     QDateTime lastModified() const override {
0128         QFileInfo fi(m_filename);
0129         return fi.lastModified();
0130     }
0131 
0132 
0133     /// This only loads the resource when called (but not in case of asl...)
0134     KoResourceSP resourceImpl() const override
0135     {
0136         return m_currentResource;
0137     }
0138 };
0139 
0140 KisAslStorage::KisAslStorage(const QString &location)
0141     : KisStoragePlugin(location)
0142     , m_aslSerializer(new KisAslLayerStyleSerializer())
0143 {
0144 }
0145 
0146 KisAslStorage::~KisAslStorage()
0147 {
0148 
0149 }
0150 
0151 KisResourceStorage::ResourceItem KisAslStorage::resourceItem(const QString &url)
0152 {
0153     KisResourceStorage::ResourceItem item;
0154     item.url = url;
0155     item.folder = location();
0156     item.resourceType = url.contains("pattern") ? ResourceType::Patterns : ResourceType::LayerStyles;
0157     item.lastModified = QFileInfo(location()).lastModified();
0158     return item;
0159 }
0160 
0161 KoResourceSP KisAslStorage::resource(const QString &url)
0162 {
0163     if (!m_aslSerializer->isInitialized()) {
0164         m_aslSerializer->readFromFile(location());
0165     }
0166     int indexOfUnderscore = url.lastIndexOf("_");
0167     QString realUuid = url;
0168     if (indexOfUnderscore >= 0) {
0169         realUuid.remove(indexOfUnderscore, url.length() - indexOfUnderscore); // remove _pattern or _style added in iterator
0170     }
0171     // TODO: RESOURCES: Since we do get a resource type at the beginning of the path now
0172     //  maybe we could skip adding the _[resourcetype] at the end of the path as well?
0173     realUuid = QFileInfo(realUuid).baseName(); // remove patterns/ at the beginning, if there are any
0174 
0175     if (url.contains("pattern") || url.contains(".pat")) {
0176         QHash<QString, KoPatternSP> patterns = m_aslSerializer->patterns();
0177 
0178         if (patterns.contains(realUuid)) {
0179             return patterns[realUuid];
0180         }
0181     }
0182     else {
0183         QHash<QString, KisPSDLayerStyleSP> styles = m_aslSerializer->stylesHash();
0184         if (styles.contains(realUuid)) {
0185             return styles[realUuid];
0186         } else {
0187             // can be {realUuid} or {realUuid}
0188             if (realUuid.startsWith("{")) {
0189                 realUuid = realUuid.right(realUuid.length() - 1);
0190             }
0191             if (realUuid.endsWith("}")) {
0192                 realUuid = realUuid.left(realUuid.length() - 1);
0193             }
0194 
0195             if (styles.contains(realUuid)) {
0196                 return styles[realUuid];
0197             } else {
0198                 Q_FOREACH(QString ke, styles.keys()) {
0199                 }
0200             }
0201 
0202         }
0203     }
0204     return 0;
0205 }
0206 
0207 bool KisAslStorage::loadVersionedResource(KoResourceSP /*resource*/)
0208 {
0209     return false;
0210 }
0211 
0212 bool KisAslStorage::supportsVersioning() const
0213 {
0214     return false;
0215 }
0216 
0217 QSharedPointer<KisResourceStorage::ResourceIterator> KisAslStorage::resources(const QString &resourceType)
0218 {
0219     return QSharedPointer<KisResourceStorage::ResourceIterator>(new AslIterator(m_aslSerializer, location(), resourceType));
0220 }
0221 
0222 QSharedPointer<KisResourceStorage::TagIterator> KisAslStorage::tags(const QString &resourceType)
0223 {
0224     return QSharedPointer<KisResourceStorage::TagIterator>(new AslTagIterator(location(), resourceType));
0225 }
0226 
0227 bool KisAslStorage::saveAsNewVersion(const QString &/*resourceType*/, KoResourceSP /*resource*/)
0228 {
0229     // not implemented yet
0230     warnKrita << "KisAslStorage::saveAsNewVersion is not implemented yet";
0231     return false;
0232 }
0233 
0234 bool KisAslStorage::addResource(const QString &/*resourceType*/, KoResourceSP resource)
0235 {
0236     if (!resource) {
0237         warnKrita << "Trying to add a null resource to KisAslStorage";
0238         return false;
0239     }
0240     KisPSDLayerStyleSP layerStyle = resource.dynamicCast<KisPSDLayerStyle>();
0241     if (!layerStyle) {
0242         warnKrita << "Trying to add a resource that is not a layer style to KisAslStorage";
0243         return false;
0244     }
0245 
0246     QVector<KisPSDLayerStyleSP> styles = m_aslSerializer->styles();
0247     styles << layerStyle;
0248     m_aslSerializer->setStyles(styles);
0249     return m_aslSerializer->saveToFile(location());
0250 }
0251 
0252 bool KisAslStorage::isValid() const
0253 {
0254     if (!m_aslSerializer->isInitialized()) {
0255         m_aslSerializer->readFromFile(location());
0256     }
0257     return m_aslSerializer->isValid();
0258 }