Commit 42a7a211 authored by Boudewijn Rempt's avatar Boudewijn Rempt

BUG:352149 Sanitize the order of resource and tag loading

This now loads the bundles at the end of loading all resources.
parent 6c02b9dd
add_subdirectory( tests )
set(kritaresourcemanager_SOURCES
resourcemanager.cpp
resourcebundle_manifest.cpp
resourcebundle.cpp
dlg_create_bundle.cpp
dlg_bundle_manager.cpp
)
......
......@@ -31,6 +31,7 @@
#include <kis_icon.h>
#include "kis_action.h"
#include <kis_resource_server_provider.h>
#define ICON_SIZE 48
......@@ -82,14 +83,14 @@ DlgBundleManager::DlgBundleManager(KisActionManager* actionMgr, QWidget *parent)
void DlgBundleManager::refreshListData()
{
KoResourceServer<ResourceBundle> *bundleServer = ResourceBundleServerProvider::instance()->resourceBundleServer();
KoResourceServer<KisResourceBundle> *bundleServer = KisResourceServerProvider::instance()->resourceBundleServer();
m_ui->listInactive->clear();
m_ui->listActive->clear();
Q_FOREACH (const QString &f, bundleServer->blackListedFiles()) {
ResourceBundle *bundle = new ResourceBundle(f);
KisResourceBundle *bundle = new KisResourceBundle(f);
bundle->load();
if (bundle->valid()) {
bundle->setInstalled(false);
......@@ -98,7 +99,7 @@ void DlgBundleManager::refreshListData()
}
fillListWidget(m_blacklistedBundles.values(), m_ui->listInactive);
Q_FOREACH (ResourceBundle *bundle, bundleServer->resources()) {
Q_FOREACH (KisResourceBundle *bundle, bundleServer->resources()) {
if (bundle->valid()) {
m_activeBundles[bundle->filename()] = bundle;
}
......@@ -108,19 +109,19 @@ void DlgBundleManager::refreshListData()
void DlgBundleManager::accept()
{
KoResourceServer<ResourceBundle> *bundleServer = ResourceBundleServerProvider::instance()->resourceBundleServer();
KoResourceServer<KisResourceBundle> *bundleServer = KisResourceServerProvider::instance()->resourceBundleServer();
for (int i = 0; i < m_ui->listActive->count(); ++i) {
QListWidgetItem *item = m_ui->listActive->item(i);
QByteArray ba = item->data(Qt::UserRole).toByteArray();
ResourceBundle *bundle = bundleServer->resourceByMD5(ba);
KisResourceBundle *bundle = bundleServer->resourceByMD5(ba);
QMessageBox bundleFeedback;
bundleFeedback.setIcon(QMessageBox::Warning);
QString feedback = "bundlefeedback";
if (!bundle) {
// Get it from the blacklisted bundles
Q_FOREACH (ResourceBundle *b2, m_blacklistedBundles.values()) {
Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) {
if (b2->md5() == ba) {
bundle = b2;
break;
......@@ -160,7 +161,7 @@ void DlgBundleManager::accept()
for (int i = 0; i < m_ui->listInactive->count(); ++i) {
QListWidgetItem *item = m_ui->listInactive->item(i);
QByteArray ba = item->data(Qt::UserRole).toByteArray();
ResourceBundle *bundle = bundleServer->resourceByMD5(ba);
KisResourceBundle *bundle = bundleServer->resourceByMD5(ba);
if (bundle && bundle->isInstalled()) {
bundle->uninstall();
......@@ -207,12 +208,12 @@ void DlgBundleManager::itemSelected(QListWidgetItem *current, QListWidgetItem *)
else {
QByteArray ba = current->data(Qt::UserRole).toByteArray();
KoResourceServer<ResourceBundle> *bundleServer = ResourceBundleServerProvider::instance()->resourceBundleServer();
ResourceBundle *bundle = bundleServer->resourceByMD5(ba);
KoResourceServer<KisResourceBundle> *bundleServer = KisResourceServerProvider::instance()->resourceBundleServer();
KisResourceBundle *bundle = bundleServer->resourceByMD5(ba);
if (!bundle) {
// Get it from the blacklisted bundles
Q_FOREACH (ResourceBundle *b2, m_blacklistedBundles.values()) {
Q_FOREACH (KisResourceBundle *b2, m_blacklistedBundles.values()) {
if (b2->md5() == ba) {
bundle = b2;
break;
......@@ -291,12 +292,12 @@ void DlgBundleManager::editBundle()
}
}
void DlgBundleManager::fillListWidget(QList<ResourceBundle *> bundles, QListWidget *w)
void DlgBundleManager::fillListWidget(QList<KisResourceBundle *> bundles, QListWidget *w)
{
w->setIconSize(QSize(ICON_SIZE, ICON_SIZE));
w->setSelectionMode(QAbstractItemView::MultiSelection);
Q_FOREACH (ResourceBundle *bundle, bundles) {
Q_FOREACH (KisResourceBundle *bundle, bundles) {
QPixmap pixmap(ICON_SIZE, ICON_SIZE);
if (!bundle->image().isNull()) {
QImage scaled = bundle->image().scaled(ICON_SIZE, ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation);
......
......@@ -24,7 +24,7 @@
#include <KoDialog.h>
#include "kis_action_manager.h"
class ResourceBundle;
class KisResourceBundle;
class QListWidget;
class QListWidgetItem;
......@@ -57,13 +57,13 @@ private:
QWidget *m_page;
Ui::WdgDlgBundleManager *m_ui;
void fillListWidget(QList<ResourceBundle*> bundles, QListWidget *w);
void fillListWidget(QList<KisResourceBundle*> bundles, QListWidget *w);
void refreshListData();
QMap<QString, ResourceBundle*> m_blacklistedBundles;
QMap<QString, ResourceBundle*> m_activeBundles;
QMap<QString, KisResourceBundle*> m_blacklistedBundles;
QMap<QString, KisResourceBundle*> m_activeBundles;
ResourceBundle *m_currentBundle;
KisResourceBundle *m_currentBundle;
KisActionManager* m_actionManager;
};
......
......@@ -43,11 +43,11 @@
#include <kis_config.h>
#include "resourcebundle.h"
#include "KisResourceBundle.h"
#define ICON_SIZE 48
DlgCreateBundle::DlgCreateBundle(ResourceBundle *bundle, QWidget *parent)
DlgCreateBundle::DlgCreateBundle(KisResourceBundle *bundle, QWidget *parent)
: KoDialog(parent)
, m_ui(new Ui::WdgDlgCreateBundle)
, m_bundle(bundle)
......
......@@ -21,7 +21,7 @@
#include <KoDialog.h>
class ResourceBundle;
class KisResourceBundle;
namespace Ui
{
......@@ -33,7 +33,7 @@ class DlgCreateBundle : public KoDialog
Q_OBJECT
public:
explicit DlgCreateBundle(ResourceBundle *bundle = 0, QWidget *parent = 0);
explicit DlgCreateBundle(KisResourceBundle *bundle = 0, QWidget *parent = 0);
~DlgCreateBundle();
QString bundleName() const;
......@@ -74,7 +74,7 @@ private:
QString m_previewImage;
ResourceBundle *m_bundle;
KisResourceBundle *m_bundle;
};
#endif // KOBUNDLECREATIONWIDGET_H
......@@ -48,40 +48,11 @@
#include "dlg_bundle_manager.h"
#include "dlg_create_bundle.h"
Q_GLOBAL_STATIC(ResourceBundleServerProvider, s_instance)
ResourceBundleServerProvider::ResourceBundleServerProvider()
{
// user-local
m_resourceBundleServer = new KoResourceServerSimpleConstruction<ResourceBundle>("kis_resourcebundles", "*.bundle");
if (!QFileInfo(m_resourceBundleServer->saveLocation()).exists()) {
QDir().mkpath(m_resourceBundleServer->saveLocation());
}
}
ResourceBundleServerProvider *ResourceBundleServerProvider::instance()
{
return s_instance;
}
ResourceBundleServerProvider::~ResourceBundleServerProvider()
{
delete m_resourceBundleServer;
}
KoResourceServer<ResourceBundle> *ResourceBundleServerProvider::resourceBundleServer()
{
return m_resourceBundleServer;
}
class ResourceManager::Private {
public:
Private()
: loader(0)
{
brushServer = KisBrushServer::instance()->brushServer(false);
paintopServer = KisResourceServerProvider::instance()->paintOpPresetServer(false);
......@@ -98,8 +69,6 @@ public:
KoResourceServer<KoColorSet>* paletteServer;
KoResourceServer<KisWorkspaceResource>* workspaceServer;
QThread *loader;
};
K_PLUGIN_FACTORY_WITH_JSON(ResourceManagerFactory, "kritaresourcemanager.json", registerPlugin<ResourceManager>();)
......@@ -184,7 +153,7 @@ void ResourceManager::slotImport()
}
else if (resourceType == "bundles") {
Q_FOREACH (const QString &res, resources) {
ResourceBundle *bundle = ResourceBundleServerProvider::instance()->resourceBundleServer()->createResource(res);
KisResourceBundle *bundle = KisResourceServerProvider::instance()->resourceBundleServer()->createResource(res);
bundle->load();
if (bundle->valid()) {
if (!bundle->install()) {
......@@ -196,17 +165,17 @@ void ResourceManager::slotImport()
}
QFileInfo fi(res);
QString newFilename = ResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + bundle->defaultFileExtension();
QString newFilename = KisResourceServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + bundle->defaultFileExtension();
QFileInfo fileInfo(newFilename);
int i = 1;
while (fileInfo.exists()) {
fileInfo.setFile(ResourceBundleServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + QString("%1").arg(i) + bundle->defaultFileExtension());
fileInfo.setFile(KisResourceServerProvider::instance()->resourceBundleServer()->saveLocation() + fi.baseName() + QString("%1").arg(i) + bundle->defaultFileExtension());
i++;
}
bundle->setFilename(fileInfo.filePath());
QFile::copy(res, newFilename);
ResourceBundleServerProvider::instance()->resourceBundleServer()->addResource(bundle, false);
KisResourceServerProvider::instance()->resourceBundleServer()->addResource(bundle, false);
}
}
else if (resourceType == "patterns") {
......@@ -238,7 +207,7 @@ void ResourceManager::slotCreateBundle()
}
QString bundlePath = dlgCreateBundle.saveLocation() + "/" + dlgCreateBundle.bundleName() + ".bundle";
ResourceBundle* newBundle = new ResourceBundle(bundlePath);
KisResourceBundle* newBundle = new KisResourceBundle(bundlePath);
newBundle->addMeta("name", dlgCreateBundle.bundleName());
newBundle->addMeta("author", dlgCreateBundle.authorName());
......@@ -307,26 +276,5 @@ void ResourceManager::slotManageBundles()
}
void ResourceManager::loadBundles()
{
d->loader = new KoResourceLoaderThread(ResourceBundleServerProvider::instance()->resourceBundleServer());
connect(d->loader, SIGNAL(finished()), this, SLOT(bundlesLoaded()));
d->loader->start();
}
void ResourceManager::bundlesLoaded()
{
delete d->loader;
d->loader = 0;
Q_FOREACH (ResourceBundle *bundle, ResourceBundleServerProvider::instance()->resourceBundleServer()->resources()) {
if (!bundle->install()) {
warnKrita << "Could not install resources for bundle" << bundle->name();
}
}
}
#include "resourcemanager.moc"
......@@ -22,26 +22,10 @@
#include <QVariant>
#include <KoResourceServer.h>
#
#include <kis_view_plugin.h>
#include "resourcebundle.h"
class ResourceBundleServerProvider {
public:
static ResourceBundleServerProvider *instance();
ResourceBundleServerProvider();
~ResourceBundleServerProvider();
KoResourceServer<ResourceBundle> *resourceBundleServer();
private:
KoResourceServer<ResourceBundle> *m_resourceBundleServer;
Q_DISABLE_COPY(ResourceBundleServerProvider)
};
#include "KisResourceBundle.h"
class ResourceManager : public KisViewPlugin
{
......@@ -54,8 +38,7 @@ private Q_SLOTS:
void slotImport();
void slotCreateBundle();
void slotManageBundles();
void loadBundles();
void bundlesLoaded();
private:
class Private;
Private *const d;
......
......@@ -331,6 +331,8 @@ set(kritaui_LIB_SRCS
qtsingleapplication/qtlocalpeer.cpp
qtsingleapplication/qtsingleapplication.cpp
KisResourceBundle.cpp
KisResourceBundleManifest.cpp
kis_md5_generator.cpp
KisApplicationArguments.cpp
......
......@@ -290,6 +290,7 @@ void loadResources()
KisBrushServer::instance()->brushServer(true);
// load paintop presets
KisResourceServerProvider::instance()->paintOpPresetServer(true);
KisResourceServerProvider::instance()->resourceBundleServer();
}
void loadPlugins()
......
This diff is collapsed.
/*
* Copyright (c) 2014 Victor Lafon metabolic.ewilan@hotmail.fr
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KORESOURCEBUNDLE_H
#define KORESOURCEBUNDLE_H
#include <QSet>
#include <QList>
#include <KoXmlWriter.h>
#include "KoResource.h"
#include "KisResourceBundleManifest.h"
#include "kritaui_export.h"
class KoStore;
/**
* @brief The ResourceBundle class
* @details Describe the resource bundles as KoResources
*/
class KRITAUI_EXPORT KisResourceBundle : public KoResource
{
public:
/**
* @brief ResourceBundle : Ctor * @param bundlePath the path of the bundle
*/
KisResourceBundle(QString const& fileName);
/**
* @brief ~ResourceBundle : Dtor
*/
virtual ~KisResourceBundle();
/**
* @brief defaultFileExtension
* @return the default file extension which should be when saving the resource
*/
QString defaultFileExtension() const;
/**
* @brief load : Load this resource.
* @return true if succeed, false otherwise.
*/
bool load();
virtual bool loadFromDevice(QIODevice *dev);
/**
* @brief save : Save this resource.
* @return true if succeed, false otherwise.
*/
bool save();
virtual bool saveToDevice(QIODevice* dev) const;
/**
* @brief install : Install the contents of the resource bundle.
*/
bool install();
/**
* @brief uninstall : Uninstall the resource bundle.
*/
bool uninstall();
/**
* @brief addMeta : Add a Metadata to the resource
* @param type type of the metadata
* @param value value of the metadata
*/
void addMeta(const QString &type, const QString &value);
const QString getMeta(const QString &type, const QString &defaultValue = QString()) const;
/**
* @brief addFile : Add a file to the bundle
* @param fileType type of the resource file
* @param filePath path of the resource file
*/
void addResource(QString fileType, QString filePath, QStringList fileTagList, const QByteArray md5sum);
QList<QString> getTagsList();
/**
* @brief isInstalled
* @return true if the bundle is installed, false otherwise.
*/
bool isInstalled();
/**
* @brief setInstalled
* This allows you to set installed or uninstalled upon loading. This is used with blacklists.
*/
void setInstalled(bool install);
void setThumbnail(QString);
/**
* @brief saveMetadata: saves bundle metadata
* @param store bundle where to save the metadata
*/
void saveMetadata(QScopedPointer<KoStore> &store);
/**
* @brief saveManifest: saves bundle manifest
* @param store bundle where to save the manifest
*/
void saveManifest(QScopedPointer<KoStore> &store);
/**
* @brief recreateBundle
* It recreates the bundle by copying the old bundle information to a new store
* and recalculating the md5 of each resource.
* @param oldStore the old store to be recreated.
*/
void recreateBundle(QScopedPointer<KoStore> &oldStore);
QStringList resourceTypes();
QList<KoResource*> resources(const QString &resType);
private:
void writeMeta(const char *metaTag, const QString &metaKey, KoXmlWriter *writer);
void writeUserDefinedMeta(const QString &metaKey, KoXmlWriter *writer);
private:
QImage m_thumbnail;
KisResourceBundleManifest m_manifest;
QMap<QString, QString> m_metadata;
QSet<QString> m_bundletags;
bool m_installed;
QList<QByteArray> m_gradientsMd5Installed;
QList<QByteArray> m_patternsMd5Installed;
QList<QByteArray> m_brushesMd5Installed;
QList<QByteArray> m_palettesMd5Installed;
QList<QByteArray> m_workspacesMd5Installed;
QList<QByteArray> m_presetsMd5Installed;
QString m_bundleVersion;
};
#endif // KORESOURCEBUNDLE_H
/* This file is part of the KDE project
Copyright (C) 2014, Victor Lafon <metabolic.ewilan@hotmail.fr>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "KisResourceBundleManifest.h"
#include <QList>
#include <QString>
#include <QDomDocument>
#include <QDomElement>
#include <QDomNode>
#include <QDomNodeList>
#include <QForeachContainer>
#include <KoXmlNS.h>
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include "KoPattern.h"
#include "KoAbstractGradient.h"
#include "kis_brush_server.h"
#include "kis_resource_server_provider.h"
#include "kis_paintop_preset.h"
#include "kis_workspace_resource.h"
QString resourceTypeToManifestType(const QString &type) {
if (type.startsWith("ko_")) {
return type.mid(3);
}
else if (type.startsWith("kis_")) {
return type.mid(4);
}
else {
return type;
}
}
QString manifestTypeToResourceType(const QString &type) {
if (type == "patterns" || type == "gradients" || type == "palettes") {
return "ko_" + type;
}
else {
return "kis_" + type;
}
}
KisResourceBundleManifest::KisResourceBundleManifest()
{
}
KisResourceBundleManifest::~KisResourceBundleManifest()
{
}
bool KisResourceBundleManifest::load(QIODevice *device)
{
m_resources.clear();
if (!device->isOpen()) {
if (!device->open(QIODevice::ReadOnly)) {
return false;
}
}
KoXmlDocument manifestDocument;
QString errorMessage;
int errorLine;
int errorColumn;
if (!manifestDocument.setContent(device, true, &errorMessage, &errorLine, &errorColumn)) {
return false;
}
if (!errorMessage.isEmpty()) {
warnKrita << "Error parsing manifest" << errorMessage << "line" << errorLine << "column" << errorColumn;
return false;
}
// First find the manifest:manifest node.
KoXmlNode n = manifestDocument.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
if (!n.isElement()) {
continue;
}
if (n.toElement().localName() == "manifest" && n.toElement().namespaceURI() == KoXmlNS::manifest) {
break;
}
}
if (n.isNull()) {
// "Could not find manifest:manifest";
return false;
}
// Now loop through the children of the manifest:manifest and
// store all the manifest:file-entry elements.
const KoXmlElement manifestElement = n.toElement();
for (n = manifestElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
if (!n.isElement())
continue;
KoXmlElement el = n.toElement();
if (!(el.localName() == "file-entry" && el.namespaceURI() == KoXmlNS::manifest))
continue;
QString fullPath = el.attributeNS(KoXmlNS::manifest, "full-path", QString());
QString mediaType = el.attributeNS(KoXmlNS::manifest, "media-type", QString(""));
QString md5sum = el.attributeNS(KoXmlNS::manifest, "md5sum", QString(""));
QString version = el.attributeNS(KoXmlNS::manifest, "version", QString());
QStringList tagList;
KoXmlNode tagNode = n.firstChildElement().firstChildElement();
while (!tagNode.isNull()) {
if (tagNode.firstChild().isText()) {
tagList.append(tagNode.firstChild().toText().data());
}
tagNode = tagNode.nextSibling();
}
// Only if fullPath is valid, should we store this entry.
// If not, we don't bother to find out exactly what is wrong, we just skip it.
if (!fullPath.isNull() && !mediaType.isEmpty() && !md5sum.isEmpty()) {
addResource(mediaType, fullPath, tagList, QByteArray::fromHex(md5sum.toLatin1()));
}
}
return true;
}
bool KisResourceBundleManifest::save(QIODevice *device)
{
if (!device->isOpen()) {
if (!device->open(QIODevice::WriteOnly)) {
return false;
}
}
KoXmlWriter manifestWriter(device);
manifestWriter.startDocument("manifest:manifest");
manifestWriter.startElement("manifest:manifest");
manifestWriter.addAttribute("xmlns:manifest", KoXmlNS::manifest);
manifestWriter.addAttribute("manifest:version", "1.2");
manifestWriter.addManifestEntry("/", "application/x-krita-resourcebundle");
Q_FOREACH (QString resourceType, m_resources.uniqueKeys()) {
Q_FOREACH (const ResourceReference &resource, m_resources[resourceType].values()) {
manifestWriter.startElement("manifest:file-entry");
manifestWriter.addAttribute("manifest:media-type", resourceTypeToManifestType(resourceType));
manifestWriter.addAttribute("manifest:full-path", resourceTypeToManifestType(resourceType) + "/" + QFileInfo(resource.resourcePath).fileName());
manifestWriter.addAttribute("manifest:md5sum", QString(resource.md5sum.toHex()));
if (!resource.tagList.isEmpty()) {
manifestWriter.startElement("manifest:tags");
Q_FOREACH (const QString tag, resource.tagList) {
manifestWriter.startElement("manifest:tag");
manifestWriter.addTextNode(tag);
manifestWriter.endElement();
}
manifestWriter.endElement();
}
manifestWriter.endElement();
}
}
manifestWriter.endElement();
manifestWriter.endDocument();
return true;
}
void KisResourceBundleManifest::addResource(const QString &fileTypeName, const QString &fileName, const QStringList &fileTagList, const QByteArray &md5)
{
ResourceReference ref(fileName, fileTagList, fileTypeName, md5);
if (!m_resources.contains(fileTypeName)) {
m_resources[fileTypeName] = QMap<QString, ResourceReference>();
}
m_resources[fileTypeName].insert(fileName, ref);
}
QStringList KisResourceBundleManifest::types() const
{
return m_resources.keys();
}
QStringList KisResourceBundleManifest::tags() const