File indexing completed on 2024-05-12 15:58:49

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