Commit 42a7a211 authored by Halla Rempt's avatar Halla 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()
......
/*
* 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.
*/
#include "KisResourceBundle.h"
#include "KisResourceBundleManifest.h"
#include <KoXmlReader.h>
#include <KoXmlWriter.h>
#include <KoStore.h>
#include <KoResourceServerProvider.h>
#include <KoResourcePaths.h>
#include <QScopedPointer>
#include <QProcessEnvironment>
#include <QDate>
#include <QDir>
#include <kis_debug.h>
#include <QBuffer>
#include <QCryptographicHash>
#include <QByteArray>
#include <QPainter>
#include <QStringList>
#include <QMessageBox>
#include <KoHashGeneratorProvider.h>
#include <KoHashGenerator.h>
#include <kis_resource_server_provider.h>
#include <kis_workspace_resource.h>
#include <kis_paintop_preset.h>
#include <kis_brush_server.h>
#include <kis_debug.h>
#include <CalligraVersionWrapper.h>
KisResourceBundle::KisResourceBundle(QString const& fileName)
: KoResource(fileName),
m_bundleVersion("1")
{
setName(QFileInfo(fileName).baseName());
m_metadata["generator"] = "Krita (" + CalligraVersionWrapper::versionString(true) + ")";
}
KisResourceBundle::~KisResourceBundle()
{
}
QString KisResourceBundle::defaultFileExtension() const
{
return QString(".bundle");
}
bool KisResourceBundle::load()
{
if (filename().isEmpty()) return false;
QScopedPointer<KoStore> resourceStore(KoStore::createStore(filename(), KoStore::Read, "application/x-krita-resourcebundle", KoStore::Zip));
if (!resourceStore || resourceStore->bad()) {
warnKrita << "Could not open store on bundle" << filename();
m_installed = false;
setValid(false);
return false;
} else {
m_metadata.clear();
bool toRecreate = false;
if (resourceStore->open("META-INF/manifest.xml")) {
if (!m_manifest.load(resourceStore->device())) {
warnKrita << "Could not open manifest for bundle" << filename();
return false;
}
resourceStore->close();
Q_FOREACH (KisResourceBundleManifest::ResourceReference ref, m_manifest.files()) {
if (!resourceStore->open(ref.resourcePath)) {
warnKrita << "Bundle is broken. File" << ref.resourcePath << "is missing";
toRecreate = true;
}
else {
resourceStore->close();
}
}
if(toRecreate) {
warnKrita << "Due to missing files and wrong entries in the manifest, " << filename() << " will be recreated.";
}
} else {
warnKrita << "Could not load META-INF/manifest.xml";
return false;
}
bool versionFound = false;
if (resourceStore->open("meta.xml")) {
KoXmlDocument doc;
if (!doc.setContent(resourceStore->device())) {
warnKrita << "Could not parse meta.xml for" << filename();
return false;
}
// First find the manifest:manifest node.
KoXmlNode n = doc.firstChild();
for (; !n.isNull(); n = n.nextSibling()) {
if (!n.isElement()) {
continue;
}
if (n.toElement().tagName() == "meta:meta") {
break;
}
}
if (n.isNull()) {
warnKrita << "Could not find manifest node for bundle" << filename();
return false;
}
const KoXmlElement metaElement = n.toElement();
for (n = metaElement.firstChild(); !n.isNull(); n = n.nextSibling()) {
if (n.isElement()) {
KoXmlElement e = n.toElement();
if (e.tagName() == "meta:generator") {
m_metadata.insert("generator", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:author") {
m_metadata.insert("author", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:title") {
m_metadata.insert("title", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:description") {
m_metadata.insert("description", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:initial-creator") {
m_metadata.insert("author", e.firstChild().toText().data());
}
else if (e.tagName() == "dc:creator") {
m_metadata.insert("author", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:creation-date") {
m_metadata.insert("created", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:dc-date") {
m_metadata.insert("updated", e.firstChild().toText().data());
}
else if (e.tagName() == "meta:meta-userdefined") {
if (e.attribute("meta:name") == "tag") {
m_bundletags << e.attribute("meta:value");
}
else {
m_metadata.insert(e.attribute("meta:name"), e.attribute("meta:value"));
}
}
else if(e.tagName() == "meta:bundle-version") {
m_metadata.insert("bundle-version", e.firstChild().toText().data());
versionFound = true;
}
}
}
resourceStore->close();
}
else {
warnKrita << "Could not load meta.xml";
return false;
}
if (resourceStore->open("preview.png")) {
// Workaround for some OS (Debian, Ubuntu), where loading directly from the QIODevice
// fails with "libpng error: IDAT: CRC error"
QByteArray data = resourceStore->device()->readAll();
QBuffer buffer(&data);
m_thumbnail.load(&buffer, "PNG");
resourceStore->close();
}
else {
warnKrita << "Could not open preview.png";
}
/*
* If no version is found it's an old bundle with md5 hashes to fix, or if some manifest resource entry
* doesn't not correspond to a file the bundle is "broken", in both cases we need to recreate the bundle.
*/
if(!versionFound) {
m_metadata.insert("bundle-version", "1");
warnKrita << filename() << " has an old version and possibly wrong resources md5, so it will be recreated.";
toRecreate = true;
}
if(toRecreate) {
recreateBundle(resourceStore);
}
m_installed = true;
setValid(true);
setImage(m_thumbnail);
}
return true;
}
bool KisResourceBundle::loadFromDevice(QIODevice *)
{
return false;
}
bool saveResourceToStore(KoResource *resource, KoStore *store, const QString &resType)
{
if (!resource) {
warnKrita << "No Resource";
return false;
}
if (!resource->valid()) {
warnKrita << "Resource is not valid";
return false;
}
if (!store || store->bad()) {
warnKrita << "No Store or Store is Bad";
return false;
}
QByteArray ba;
QBuffer buf;
QFileInfo fi(resource->filename());
if (fi.exists() && fi.isReadable()) {
QFile f(resource->filename());
if (!f.open(QFile::ReadOnly)) {
warnKrita << "Could not open resource" << resource->filename();
return false;
}
ba = f.readAll();
if (ba.size() == 0) {
warnKrita << "Resource is empty" << resource->filename();
return false;
}
f.close();
buf.setBuffer(&ba);
}
else {
warnKrita << "Could not find the resource " << resource->filename() << " or it isn't readable";
return false;
}
if (!buf.open(QBuffer::ReadOnly)) {
warnKrita << "Could not open buffer";