Commit 91bbbd5f authored by Halla Rempt's avatar Halla Rempt
Browse files

Fix loading legacy brush masks

If there are two resources in two storages that have the same
md5sum (square_rough.png and texture_3.png), we need to make
sure that the one with the filename stored in the preset can
be found, so now resources(md5, filename, name) returns all
matching resources.

BUG:441350
BUG:441347
parent ee885708
Pipeline #78138 skipped with stage
......@@ -6,6 +6,8 @@
#include "kis_predefined_brush_factory.h"
#include <QApplication>
#include <QThread>
#include <QDomDocument>
#include <QFileInfo>
#include "kis_gbr_brush.h"
......@@ -26,18 +28,27 @@ QString KisPredefinedBrushFactory::id() const
KisBrushSP KisPredefinedBrushFactory::createBrush(const QDomElement& brushDefinition, KisResourcesInterfaceSP resourcesInterface)
{
auto resourceSourceAdapter = resourcesInterface->source<KisBrush>(ResourceType::Brushes);
const QString brushFileName = brushDefinition.attribute("filename", "");
const QString brushMD5Sum = brushDefinition.attribute("md5sum", "");
KisBrushSP brush = resourceSourceAdapter.resource(brushMD5Sum, brushFileName, "");
if (!brush) {
QVector<KisBrushSP> brushes = resourceSourceAdapter.resources(brushMD5Sum, brushFileName, "");
if (brushes.isEmpty()) {
return nullptr;
}
// we always return a copy of the brush!
brush = brush->clone().dynamicCast<KisBrush>();
KisBrushSP brush = brushes.first()->clone().dynamicCast<KisBrush>();
if (!brushFileName.isEmpty()) {
Q_FOREACH(KisBrushSP b, brushes) {
if (b->filename() == brushFileName) {
if (brushMD5Sum.isEmpty() || b->md5Sum() == brushMD5Sum) {
brush = b->clone().dynamicCast<KisBrush>();;
break;
}
}
}
}
double spacing = KisDomUtils::toDouble(brushDefinition.attribute("spacing", "0.25"));
brush->setSpacing(spacing);
......
......@@ -30,6 +30,7 @@
#include <KisResourceModel.h>
#include "KisPaintopSettingsIds.h"
#include <KisResourceTypes.h>
#include <KisResourceModelProvider.h>
#include <KoStore.h>
......@@ -161,7 +162,6 @@ bool KisPaintOpPreset::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP re
QString version = reader.text("version");
QString preset = reader.text("preset");
int resourceCount = reader.text("embedded_resources").toInt();
dbgImage << version;
if (!(version == "2.2" || "5.0")) {
return false;
......@@ -182,6 +182,7 @@ bool KisPaintOpPreset::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP re
if (!doc.setContent(preset)) {
return false;
}
if (version == "5.0" && resourceCount > 0) {
// Load the embedded resources
QDomNode n = doc.firstChild();
......@@ -196,10 +197,9 @@ bool KisPaintOpPreset::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP re
QString resourceType = e2.attribute("type");
QString md5sum = e2.attribute("md5sum");
QString name = e2.attribute("name");
QString filename = e2.attribute("filename");
KisResourceModel model(resourceType);
QVector<KoResourceSP> existingResources = model.resourcesForMD5(md5sum);
QVector<KoResourceSP> existingResources = resourcesInterface->source(resourceType).resources(md5sum, filename, name);
if (existingResources.isEmpty()) {
QByteArray ba = QByteArray::fromBase64(e2.text().toLatin1());
......@@ -209,6 +209,7 @@ bool KisPaintOpPreset::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP re
buf.open(QBuffer::ReadOnly);
KoResourceSP res = loader->load(name, buf, resourcesInterface);
if (res) {
KisResourceModel model(resourceType);
model.addResource(res, "memory");
}
}
......@@ -221,7 +222,6 @@ bool KisPaintOpPreset::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP re
}
}
fromXML(doc.documentElement(), resourcesInterface);
if (!d->settings) {
......@@ -230,27 +230,28 @@ bool KisPaintOpPreset::loadFromDevice(QIODevice *dev, KisResourcesInterfaceSP re
setValid(d->settings->isValid());
QSet<QString> requiredBrushes;
Q_FOREACH(const QString str, d->settings->getStringList(KisPaintOpUtils::RequiredBrushFilesListTag)) {
if (!str.isEmpty()) {
requiredBrushes << str;
if (version == "2.2") {
QSet<QString> requiredBrushes;
Q_FOREACH(const QString str, d->settings->getStringList(KisPaintOpUtils::RequiredBrushFilesListTag)) {
if (!str.isEmpty()) {
requiredBrushes << str;
}
}
}
QString requiredBrush = d->settings->getString(KisPaintOpUtils::RequiredBrushFileTag);
if (!requiredBrush.isEmpty()) {
requiredBrushes << requiredBrush;
}
if (!requiredBrushes.isEmpty()) {
QString requiredBrush = d->settings->getString(KisPaintOpUtils::RequiredBrushFileTag);
if (!requiredBrush.isEmpty()) {
requiredBrushes << requiredBrush;
}
if (!requiredBrushes.isEmpty()) {
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
QStringList resources(requiredBrushes.constBegin(), requiredBrushes.constEnd());
QStringList resourceFileNames(requiredBrushes.constBegin(), requiredBrushes.constEnd());
#else
QStringList resources = requiredBrushes.toList();
QStringList resourceFileNames = requiredBrushes.toList();
#endif
addMetaData("dependent_resources_filenames", resources);
addMetaData("dependent_resources_filenames", resourceFileNames);
}
}
setImage(img);
return true;
......@@ -284,6 +285,7 @@ void KisPaintOpPreset::toXML(QDomDocument& doc, QDomElement& elt) const
e.setAttribute("type", resource->resourceType().first);
e.setAttribute("md5sum", resource->md5Sum());
e.setAttribute("name", resource->name());
e.setAttribute("filename", resource->filename());
e.appendChild(text);
resourcesElement.appendChild(e);
......@@ -335,6 +337,7 @@ void KisPaintOpPreset::fromXML(const QDomElement& presetElt, KisResourcesInterfa
}
settings->fromXML(presetElt);
// sanitize the settings
bool hasTexture = settings->getBool("Texture/Pattern/Enabled");
if (!hasTexture) {
......@@ -344,8 +347,6 @@ void KisPaintOpPreset::fromXML(const QDomElement& presetElt, KisResourcesInterfa
}
}
}
setSettings(settings);
}
......@@ -491,6 +492,7 @@ QList<KoResourceSP> KisPaintOpPreset::linkedResources(KisResourcesInterfaceSP gl
resources << f->prepareLinkedResources(maskingPreset->settings(), globalResourcesInterface);
}
return resources;
}
......@@ -512,6 +514,7 @@ QList<KoResourceSP> KisPaintOpPreset::embeddedResources(KisResourcesInterfaceSP
resources << f->prepareEmbeddedResources(maskingPreset->settings(), globalResourcesInterface);
}
return resources;
}
......
......@@ -161,6 +161,9 @@ KisPaintOpSettingsSP KisPaintOpSettings::createMaskingSettings() const
const KoID pixelBrushId(KisPaintOpUtils::MaskingBrushPaintOpId, QString());
KisPaintOpSettingsSP maskingSettings = KisPaintOpRegistry::instance()->createSettings(pixelBrushId, resourcesInterface());
maskingSettings->dump();
this->getPrefixedProperties(KisPaintOpUtils::MaskingBrushPresetPrefix, maskingSettings);
const bool useMasterSize = this->getBool(KisPaintOpUtils::MaskingBrushUseMasterSizeTag, true);
......
......@@ -105,7 +105,7 @@ void KisPropertiesConfiguration::toXML(QDomDocument& doc, QDomElement& root) con
{
QMap<QString, QVariant>::ConstIterator it;
for (it = d->properties.constBegin(); it != d->properties.constEnd(); ++it) {
if(d->notSavedProperties.contains(it.key())) {
if (d->notSavedProperties.contains(it.key())) {
continue;
}
......
......@@ -353,7 +353,7 @@ public:
KoAbstractGradientSP gradient(KisResourcesInterfaceSP resourcesInterface) const
{
return m_gradientWrapper.isValid() ? m_gradientWrapper.resource(resourcesInterface) : KoAbstractGradientSP();
return m_gradientWrapper.isValid() ? m_gradientWrapper.resources(resourcesInterface).first() : KoAbstractGradientSP();
}
public:
......@@ -865,7 +865,7 @@ struct psd_layer_effects_bevel_emboss : public psd_layer_effects_shadow_base {
KoPatternSP texturePattern(KisResourcesInterfaceSP interface) const
{
return m_texturePatternLink.isValid() ? m_texturePatternLink.resource(interface) : KoPatternSP();
return m_texturePatternLink.isValid() ? m_texturePatternLink.resources(interface).first() : KoPatternSP();
}
void setTexturePattern(KoPatternSP value)
......@@ -1038,7 +1038,7 @@ struct psd_layer_effects_overlay_base : public psd_layer_effects_shadow_base {
KoPatternSP pattern(KisResourcesInterfaceSP resourcesInterface) const
{
return m_patternLink.isValid() ? m_patternLink.resource(resourcesInterface) : KoPatternSP();
return m_patternLink.isValid() ? m_patternLink.resources(resourcesInterface).first() : KoPatternSP();
}
int horizontalPhase() const
......
......@@ -26,18 +26,19 @@ public:
{
}
protected:
KoResourceSP resourceForFilename(const QString &filename) const override {
KoResourceSP res = m_model->resourceForFilename(filename);
QVector<KoResourceSP> resourcesForFilename(const QString &filename) const override {
QVector<KoResourceSP> res = m_model->resourcesForFilename(filename);
return res;
}
KoResourceSP resourceForName(const QString &name) const override {
KoResourceSP res = m_model->resourceForName(name);
QVector<KoResourceSP> resourcesForName(const QString &name) const override {
QVector<KoResourceSP> res = m_model->resourcesForName(name);
return res;
}
KoResourceSP resourceForMD5(const QString &md5) const override {
return m_model->resourceForMD5(md5);
QVector<KoResourceSP> resourcesForMD5(const QString &md5) const override {
QVector<KoResourceSP> res = m_model->resourcesForMD5(md5);
return res;
}
public:
KoResourceSP fallbackResource() const override {
......
......@@ -38,15 +38,14 @@ public:
{
}
ResourceTypeSP resource(KisResourcesInterfaceSP resourcesInterface) const
QVector<ResourceTypeSP> resources(KisResourcesInterfaceSP resourcesInterface) const
{
ResourceTypeSP result;
QVector<ResourceTypeSP> result;
KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!m_type.isEmpty(), result);
auto source = resourcesInterface->source<ResourceType>(m_type);
return source.resource(m_md5, m_filename, m_name);
return source.resources(m_md5, m_filename, m_name);
}
bool isValid() const {
......
......@@ -8,46 +8,47 @@
#include <QFileInfo>
#include "kis_assert.h"
#include "kis_debug.h"
namespace {
class LocalResourcesSource : public KisResourcesInterface::ResourceSourceAdapter
{
public:
LocalResourcesSource(const QString &resourceType, const QList<KoResourceSP> &cachedResources)
: m_resourceType(resourceType),
m_cachedResources(cachedResources)
LocalResourcesSource(const KisLocalStrokeResources *parent, const QString &resourceType, const QList<KoResourceSP> &cachedResources)
: m_resourceType(resourceType)
, m_cachedResources(cachedResources)
, m_parent(const_cast<KisLocalStrokeResources*>(parent))
{
}
protected:
KoResourceSP resourceForFilename(const QString &filename) const override {
auto it = std::find_if(m_cachedResources.begin(),
m_cachedResources.end(),
[this, filename] (KoResourceSP res) {
return res->resourceType().first == this->m_resourceType &&
(res->filename() == filename ||
QFileInfo(res->filename()).fileName() == filename);
});
return it != m_cachedResources.end() ? *it : KoResourceSP();
QVector<KoResourceSP> resourcesForFilename(const QString &filename) const override {
QVector<KoResourceSP> resources;
Q_FOREACH(KoResourceSP res, m_cachedResources) {
if (res->filename() == filename && res->resourceType().first == m_resourceType) {
resources << res;
}
}
return resources;
}
KoResourceSP resourceForName(const QString &name) const override {
auto it = std::find_if(m_cachedResources.begin(),
m_cachedResources.end(),
[this, name] (KoResourceSP res) {
return res->resourceType().first == this->m_resourceType &&
res->name() == name;
});
return it != m_cachedResources.end() ? *it : KoResourceSP();
QVector<KoResourceSP> resourcesForName(const QString &name) const override {
QVector<KoResourceSP> resources;
Q_FOREACH(KoResourceSP res, m_cachedResources) {
if (res->name() == name && res->resourceType().first == m_resourceType) {
resources << res;
}
}
return resources;
}
KoResourceSP resourceForMD5(const QString &md5) const override {
auto it = std::find_if(m_cachedResources.begin(),
m_cachedResources.end(),
[this, md5] (KoResourceSP res) {
return res->resourceType().first == this->m_resourceType &&
res->md5Sum() == md5;
});
return it != m_cachedResources.end() ? *it : KoResourceSP();
QVector<KoResourceSP> resourcesForMD5(const QString &md5) const override {
QVector<KoResourceSP> resources;
Q_FOREACH(KoResourceSP res, m_cachedResources) {
if (res->md5Sum() == md5 && res->resourceType().first == m_resourceType) {
resources << res;
}
}
return resources;
}
public:
......@@ -56,14 +57,15 @@ public:
auto it = std::find_if(m_cachedResources.begin(),
m_cachedResources.end(),
[this] (KoResourceSP res) {
return res->resourceType().first == this->m_resourceType;
});
return res->resourceType().first == this->m_resourceType;
});
return it != m_cachedResources.end() ? *it : KoResourceSP();
}
private:
const QString m_resourceType;
const QList<KoResourceSP> &m_cachedResources;
KisLocalStrokeResources *m_parent;
};
}
......@@ -73,12 +75,14 @@ public:
KisLocalStrokeResourcesPrivate(const QList<KoResourceSP> &_localResources)
: localResources(_localResources)
{
// sanity check that we don't have any null resources
KIS_SAFE_ASSERT_RECOVER(!localResources.contains(KoResourceSP())) {
localResources.removeAll(KoResourceSP());
}
}
}
QList<KoResourceSP> localResources;
};
......@@ -97,5 +101,5 @@ void KisLocalStrokeResources::addResource(KoResourceSP resource)
KisResourcesInterface::ResourceSourceAdapter *KisLocalStrokeResources::createSourceImpl(const QString &type) const
{
Q_D(const KisLocalStrokeResources);
return new LocalResourcesSource(type, d->localResources);
return new LocalResourcesSource(this, type, d->localResources);
}
......@@ -53,6 +53,7 @@ void createLocalResourcesSnapshot(T *object, KisResourcesInterfaceSP globalResou
object->requiredResources(globalResourcesInterface ?
globalResourcesInterface :
object->resourcesInterface());
object->setResourcesInterface(detail::createLocalResourcesStorage(resources));
}
......
......@@ -260,8 +260,12 @@ bool KisAllResourcesModel::resourceExists(const QString &md5, const QString &fil
return false;
}
KoResourceSP KisAllResourcesModel::resourceForFilename(QString filename, bool checkDependentResources) const
QVector<KoResourceSP> KisAllResourcesModel::resourcesForFilename(QString filename, bool checkDependentResources) const
{
QVector<KoResourceSP> resources;
if (filename.isEmpty()) return resources;
QSqlQuery q;
bool r = q.prepare("SELECT resources.id AS id\n"
"FROM resources\n"
......@@ -280,12 +284,16 @@ KoResourceSP KisAllResourcesModel::resourceForFilename(QString filename, bool ch
qWarning() << "Could not select" << d->resourceType << "resources by filename" << q.lastError() << q.boundValues();
}
if (q.first()) {
while (q.next()) {
int id = q.value("id").toInt();
return KisResourceLocator::instance()->resourceForId(id);
KoResourceSP resource = KisResourceLocator::instance()->resourceForId(id);
if (resource) {
resources << resource;
}
}
else if (checkDependentResources) {
if (resources.isEmpty() && checkDependentResources) {
// Check whether the requested resource was embedded in another resource, which has not been loaded so the embedded resource is not available.
r = q.prepare("SELECT value"
", foreign_id\n"
......@@ -312,19 +320,21 @@ KoResourceSP KisAllResourcesModel::resourceForFilename(QString filename, bool ch
Q_FOREACH(KoResourceSP embeddedRes, res->embeddedResources(KisGlobalResourcesInterface::instance())) {
// This is the best we can do because Krita4 only checked filename and resource type, too.
if (embeddedRes->filename() == filename && embeddedRes->resourceType().first == d->resourceType) {
return embeddedRes;
resources << embeddedRes;
}
}
}
}
}
}
return nullptr;
return resources;
}
KoResourceSP KisAllResourcesModel::resourceForName(const QString &name) const
QVector<KoResourceSP> KisAllResourcesModel::resourcesForName(const QString &name) const
{
if (name.isEmpty()) return 0;
QVector<KoResourceSP> resources;
if (name.isEmpty()) return resources;
KoResourceSP resource = 0;
......@@ -347,17 +357,24 @@ KoResourceSP KisAllResourcesModel::resourceForName(const QString &name) const
qWarning() << "Could not select" << d->resourceType << "resources by name" << q.lastError() << q.boundValues();
}
if (q.first()) {
while (q.next()) {
int id = q.value("id").toInt();
resource = KisResourceLocator::instance()->resourceForId(id);
if (resource) {
resources << resource;
}
}
return resource;
return resources;
}
KoResourceSP KisAllResourcesModel::resourceForMD5(const QString &md5sum) const
QVector<KoResourceSP> KisAllResourcesModel::resourcesForMD5(const QString &md5sum) const
{
QVector<KoResourceSP> resources;
if (md5sum.isEmpty()) return resources;
KoResourceSP resource = 0;
QSqlQuery q;
......@@ -374,11 +391,14 @@ KoResourceSP KisAllResourcesModel::resourceForMD5(const QString &md5sum) const
qWarning() << "Could not select" << d->resourceType << "resources by md5" << q.lastError() << q.boundValues();
}
if (q.first()) {
while (q.next()) {
int id = q.value("id").toInt();
resource = KisResourceLocator::instance()->resourceForId(id);
if (resource) {
resources << resource;
}
}
return resource;
return resources;
}
QModelIndex KisAllResourcesModel::indexForResource(KoResourceSP resource) const
......
......@@ -208,7 +208,7 @@ public:
* in a resource that's not been loaded yet in the metadata table.
* @return a resource if one is found, or 0 if none are found
*/
KoResourceSP resourceForFilename(QString fileName, bool checkDependentResources = false) const;
QVector<KoResourceSP> resourcesForFilename(QString fileName, bool checkDependentResources = false) const;
/**
* resourceForName returns the first resource with the given name that
......@@ -218,8 +218,8 @@ public:
*
* @return a resource if one is found, or 0 if none are found
*/
KoResourceSP resourceForName(const QString &name) const;
KoResourceSP resourceForMD5(const QString &md5sum) const;
QVector<KoResourceSP> resourcesForName(const QString &name) const;
QVector<KoResourceSP> resourcesForMD5(const QString &md5sum) const;
QVector<KisTagSP> tagsForResource(int resourceId) const;
private:
......
......@@ -47,9 +47,9 @@ public:
virtual ~ResourceSourceAdapter();
//protected:
friend class KisResourcesInterface;
virtual KoResourceSP resourceForFilename(const QString& filename) const = 0;
virtual KoResourceSP resourceForName(const QString& name) const = 0;
virtual KoResourceSP resourceForMD5(const QString& md5) const = 0;
virtual QVector<KoResourceSP> resourcesForFilename(const QString& filename) const = 0;
virtual QVector<KoResourceSP> resourcesForName(const QString& name) const = 0;
virtual QVector<KoResourceSP> resourcesForMD5(const QString& md5) const = 0;
public:
/**
* @brief resource retrieves a resource, prefarably by md5, but with filename and name
......@@ -57,21 +57,44 @@ public:
* not found by md5 if the md5 isn't empty, we do NOT then look by filename.
* @return a resource, or 0 of the resource doesn't exist.
*/
KoResourceSP resource(const QString md5, const QString filename, const QString name) {
QVector<KoResourceSP> resources(const QString md5, const QString filename, const QString name) {
QVector<KoResourceSP> resourceSet;
if (!md5.isEmpty()) {
return resourceForMD5(md5);
resourceSet += resourcesForMD5(md5);
}
if (!filename.isEmpty()) {
return resourceForFilename(filename);
if (md5.isEmpty()) {
resourceSet += resourcesForFilename(filename);
}
else {
Q_FOREACH(KoResourceSP resource, resourcesForFilename(filename)) {
if (resource->md5Sum() == md5) {
resourceSet << resource;
}
}
}
}
if (!name.isEmpty()) {
return resourceForName(name);
if (md5.isEmpty()) {
resourceSet += resourcesForName(name);
}
else {
Q_FOREACH(KoResourceSP resource, resourcesForName(name)) {
if (resource->md5Sum() == md5) {
resourceSet << resource;
}
}
}
}
return nullptr;
std::sort(resourceSet.begin(), resourceSet.end());
resourceSet.erase(std::unique(resourceSet.begin(), resourceSet.end()), resourceSet.end());
return resourceSet;
}
virtual KoResourceSP fallbackResource() const = 0;
......@@ -88,42 +111,59 @@ public:
{
}
private:
QSharedPointer<T> resourceForFilename(const QString& filename) const
QVector<QSharedPointer<T>> resourcesForFilename(const QString& filename) const
{
return m_source->resourceForFilename(filename).dynamicCast<T>();
QVector<QSharedPointer<T>> r;
Q_FOREACH(KoResourceSP resource, m_source->resourcesForFilename(filename)) {
r << resource.dynamicCast<T>();