diff --git a/libs/ui/KisDocument.cpp b/libs/ui/KisDocument.cpp
index 1c2db42cdd..0466ce7636 100644
--- a/libs/ui/KisDocument.cpp
+++ b/libs/ui/KisDocument.cpp
@@ -1,1709 +1,1709 @@
/* This file is part of the Krita project
*
* Copyright (C) 2014 Boudewijn Rempt
*
* 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 "KisMainWindow.h" // XXX: remove
#include // XXX: remove
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Krita Image
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// Local
#include "KisViewManager.h"
#include "kis_clipboard.h"
#include "widgets/kis_custom_image_widget.h"
#include "canvas/kis_canvas2.h"
#include "flake/kis_shape_controller.h"
#include "kis_statusbar.h"
#include "widgets/kis_progress_widget.h"
#include "kis_canvas_resource_provider.h"
#include "kis_resource_server_provider.h"
#include "kis_node_manager.h"
#include "KisPart.h"
#include "KisApplication.h"
#include "KisDocument.h"
#include "KisImportExportManager.h"
#include "KisPart.h"
#include "KisView.h"
#include "kis_grid_config.h"
#include "kis_guides_config.h"
#include "kis_image_barrier_lock_adapter.h"
#include
// Define the protocol used here for embedded documents' URL
// This used to "store" but QUrl didn't like it,
// so let's simply make it "tar" !
#define STORE_PROTOCOL "tar"
// The internal path is a hack to make QUrl happy and for document children
#define INTERNAL_PROTOCOL "intern"
#define INTERNAL_PREFIX "intern:/"
// Warning, keep it sync in koStore.cc
#include
using namespace std;
/**********************************************************
*
* KisDocument
*
**********************************************************/
namespace {
class DocumentProgressProxy : public KoProgressProxy {
public:
KisMainWindow *m_mainWindow;
DocumentProgressProxy(KisMainWindow *mainWindow)
: m_mainWindow(mainWindow)
{
}
~DocumentProgressProxy() override {
// signal that the job is done
setValue(-1);
}
int maximum() const override {
return 100;
}
void setValue(int value) override {
if (m_mainWindow) {
m_mainWindow->slotProgress(value);
}
}
void setRange(int /*minimum*/, int /*maximum*/) override {
}
void setFormat(const QString &/*format*/) override {
}
};
}
//static
QString KisDocument::newObjectName()
{
static int s_docIFNumber = 0;
QString name; name.setNum(s_docIFNumber++); name.prepend("document_");
return name;
}
class UndoStack : public KUndo2Stack
{
public:
UndoStack(KisDocument *doc)
: m_doc(doc)
{
}
void setIndex(int idx) override {
KisImageWSP image = this->image();
image->requestStrokeCancellation();
if(image->tryBarrierLock()) {
KUndo2Stack::setIndex(idx);
image->unlock();
}
}
void notifySetIndexChangedOneCommand() override {
KisImageWSP image = this->image();
image->unlock();
/**
* Some very weird commands may emit blocking signals to
* the GUI (e.g. KisGuiContextCommand). Here is the best thing
* we can do to avoid the deadlock
*/
while(!image->tryBarrierLock()) {
QApplication::processEvents();
}
}
void undo() override {
KisImageWSP image = this->image();
image->requestUndoDuringStroke();
if (image->tryUndoUnfinishedLod0Stroke() == UNDO_OK) {
return;
}
if(image->tryBarrierLock()) {
KUndo2Stack::undo();
image->unlock();
}
}
void redo() override {
KisImageWSP image = this->image();
if(image->tryBarrierLock()) {
KUndo2Stack::redo();
image->unlock();
}
}
private:
KisImageWSP image() {
KisImageWSP currentImage = m_doc->image();
Q_ASSERT(currentImage);
return currentImage;
}
private:
KisDocument *m_doc;
};
class Q_DECL_HIDDEN KisDocument::Private
{
public:
Private() :
docInfo(0),
progressUpdater(0),
progressProxy(0),
importExportManager(0),
isImporting(false),
isExporting(false),
password(QString()),
modifiedAfterAutosave(false),
isAutosaving(false),
backupFile(true),
doNotSaveExtDoc(false),
undoStack(0),
m_saveOk(false),
m_waitForSave(false),
m_duringSaveAs(false),
m_bAutoDetectedMime(false),
modified(false),
readwrite(true),
disregardAutosaveFailure(false),
nserver(0),
macroNestDepth(0),
imageIdleWatcher(2000 /*ms*/),
suppressProgress(false),
fileProgressProxy(0),
savingLock(&savingMutex)
{
if (QLocale().measurementSystem() == QLocale::ImperialSystem) {
unit = KoUnit::Inch;
} else {
unit = KoUnit::Centimeter;
}
}
~Private() {
// Don't delete m_d->shapeController because it's in a QObject hierarchy.
delete nserver;
}
KoDocumentInfo *docInfo;
KoProgressUpdater *progressUpdater;
KoProgressProxy *progressProxy;
KoUnit unit;
KisImportExportManager *importExportManager; // The filter-manager to use when loading/saving [for the options]
QByteArray mimeType; // The actual mimetype of the document
QByteArray outputMimeType; // The mimetype to use when saving
bool isImporting;
bool isExporting; // File --> Import/Export vs File --> Open/Save
QString password; // The password used to encrypt an encrypted document
QTimer autoSaveTimer;
QString lastErrorMessage; // see openFile()
int autoSaveDelay {300}; // in seconds, 0 to disable.
bool modifiedAfterAutosave;
bool isAutosaving;
bool backupFile;
bool doNotSaveExtDoc; // makes it possible to save only internally stored child documents
KUndo2Stack *undoStack;
KisGuidesConfig guidesConfig;
QUrl m_originalURL; // for saveAs
QString m_originalFilePath; // for saveAs
bool m_saveOk;
bool m_waitForSave;
bool m_duringSaveAs;
bool m_bAutoDetectedMime; // whether the mimetype in the arguments was detected by the part itself
QUrl m_url; // local url - the one displayed to the user.
QString m_file; // Local file - the only one the part implementation should deal with.
QEventLoop m_eventLoop;
QMutex savingMutex;
bool modified;
bool readwrite;
QDateTime firstMod;
QDateTime lastMod;
bool disregardAutosaveFailure;
KisNameServer *nserver;
qint32 macroNestDepth;
KisImageSP image;
KisImageSP savingImage;
KisNodeSP preActivatedNode;
KisShapeController* shapeController;
KoShapeController* koShapeController;
KisIdleWatcher imageIdleWatcher;
QScopedPointer imageIdleConnection;
bool suppressProgress;
KoProgressProxy* fileProgressProxy;
QList assistants;
KisGridConfig gridConfig;
StdLockableWrapper savingLock;
void setImageAndInitIdleWatcher(KisImageSP _image) {
image = _image;
imageIdleWatcher.setTrackedImage(image);
if (image) {
imageIdleConnection.reset(
new KisSignalAutoConnection(
&imageIdleWatcher, SIGNAL(startedIdleMode()),
image.data(), SLOT(explicitRegenerateLevelOfDetail())));
}
}
class SafeSavingLocker;
};
class KisDocument::Private::SafeSavingLocker {
public:
SafeSavingLocker(KisDocument::Private *_d, KisDocument *document)
: d(_d)
, m_document(document)
, m_locked(false)
, m_imageLock(d->image, true)
{
const int realAutoSaveInterval = KisConfig().autoSaveInterval();
const int emergencyAutoSaveInterval = 10; // sec
/**
* Initial try to lock both objects. Locking the image guards
* us from any image composition threads running in the
* background, while savingMutex guards us from entering the
* saving code twice by autosave and main threads.
*
* Since we are trying to lock multiple objects, so we should
* do it in a safe manner.
*/
m_locked = std::try_lock(m_imageLock, d->savingLock) < 0;
if (!m_locked) {
if (d->isAutosaving) {
d->disregardAutosaveFailure = true;
if (realAutoSaveInterval) {
m_document->setAutoSaveDelay(emergencyAutoSaveInterval);
}
} else {
d->image->requestStrokeEnd();
QApplication::processEvents();
// one more try...
m_locked = std::try_lock(m_imageLock, d->savingLock) < 0;
}
}
if (m_locked) {
d->disregardAutosaveFailure = false;
}
}
~SafeSavingLocker() {
if (m_locked) {
m_imageLock.unlock();
d->savingLock.unlock();
const int realAutoSaveInterval = KisConfig().autoSaveInterval();
m_document->setAutoSaveDelay(realAutoSaveInterval);
}
}
bool successfullyLocked() const {
return m_locked;
}
private:
KisDocument::Private *d;
KisDocument *m_document;
bool m_locked;
KisImageBarrierLockAdapter m_imageLock;
};
KisDocument::KisDocument()
: d(new Private())
{
d->undoStack = new UndoStack(this);
d->undoStack->setParent(this);
d->importExportManager = new KisImportExportManager(this);
d->importExportManager->setProgresUpdater(d->progressUpdater);
connect(&d->autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
KisConfig cfg;
setAutoSaveDelay(cfg.autoSaveInterval());
setObjectName(newObjectName());
d->docInfo = new KoDocumentInfo(this);
d->firstMod = QDateTime::currentDateTime();
d->lastMod = QDateTime::currentDateTime();
// preload the krita resources
KisResourceServerProvider::instance();
d->nserver = new KisNameServer(1);
d->shapeController = new KisShapeController(this, d->nserver);
d->koShapeController = new KoShapeController(0, d->shapeController);
undoStack()->setUndoLimit(KisConfig().undoStackLimit());
connect(d->undoStack, SIGNAL(indexChanged(int)), this, SLOT(slotUndoStackIndexChanged(int)));
setBackupFile(KisConfig().backupFile());
}
KisDocument::~KisDocument()
{
/**
* Push a timebomb, which will try to release the memory after
* the document has been deleted
*/
KisPaintDevice::createMemoryReleaseObject()->deleteLater();
d->autoSaveTimer.disconnect(this);
d->autoSaveTimer.stop();
delete d->importExportManager;
// Despite being QObject they needs to be deleted before the image
delete d->shapeController;
delete d->koShapeController;
if (d->image) {
d->image->notifyAboutToBeDeleted();
/**
* WARNING: We should wait for all the internal image jobs to
* finish before entering KisImage's destructor. The problem is,
* while execution of KisImage::~KisImage, all the weak shared
* pointers pointing to the image enter an inconsistent
* state(!). The shared counter is already zero and destruction
* has started, but the weak reference doesn't know about it,
* because KisShared::~KisShared hasn't been executed yet. So all
* the threads running in background and having weak pointers will
* enter the KisImage's destructor as well.
*/
d->image->requestStrokeCancellation();
d->image->waitForDone();
// clear undo commands that can still point to the image
d->undoStack->clear();
d->image->waitForDone();
KisImageWSP sanityCheckPointer = d->image;
Q_UNUSED(sanityCheckPointer);
// The following line trigger the deletion of the image
d->image.clear();
// check if the image has actually been deleted
KIS_SAFE_ASSERT_RECOVER_NOOP(!sanityCheckPointer.isValid());
}
delete d;
}
bool KisDocument::reload()
{
// XXX: reimplement!
return false;
}
bool KisDocument::exportDocument(const QUrl &_url, KisPropertiesConfigurationSP exportConfiguration)
{
//qDebug() << "exportDocument" << _url.toDisplayString() << "is autosaving" << d->isAutosaving;
bool ret;
d->isExporting = true;
//
// Preserve a lot of state here because we need to restore it in order to
// be able to fake a File --> Export. Can't do this in saveFile() because,
// for a start, KParts has already set url and m_file and because we need
// to restore the modified flag etc. and don't want to put a load on anyone
// reimplementing saveFile() (Note: importDocument() and exportDocument()
// will remain non-virtual).
//
QUrl oldURL = url();
QString oldFile = localFilePath();
//qDebug() << "\toldUrl" << oldURL << "oldFile" << oldFile << "export url" << _url;
bool wasModified = isModified();
// save...
ret = saveAs(_url, exportConfiguration);
//
// This is sooooo hacky :(
// Hopefully we will restore enough state.
//
dbgUI << "Restoring KisDocument state to before export";
// always restore url & m_file regardless of failure or success
//qDebug() << "\tafter saveAs: url" << url() << "local file path" << localFilePath();
setUrl(oldURL);
setLocalFilePath(oldFile);
//qDebug() << "\tafter restoring: url" << url() << "local file path" << localFilePath();
// on successful export we need to restore modified etc. too
// on failed export, mimetype/modified hasn't changed anyway
if (ret) {
setModified(wasModified);
}
d->isExporting = false;
return ret;
}
bool KisDocument::saveAs(const QUrl &url, KisPropertiesConfigurationSP exportConfiguration)
{
//qDebug() << "saveAs" << url;
if (!url.isValid() || !url.isLocalFile()) {
errKrita << "saveAs: Malformed URL " << url.url() << endl;
return false;
}
d->m_duringSaveAs = true;
d->m_originalURL = d->m_url;
d->m_originalFilePath = d->m_file;
d->m_url = url; // Store where to upload in saveToURL
d->m_file = d->m_url.toLocalFile();
bool result = save(exportConfiguration); // Save local file and upload local file
if (!result) {
d->m_url = d->m_originalURL;
d->m_file = d->m_originalFilePath;
d->m_duringSaveAs = false;
d->m_originalURL = QUrl();
d->m_originalFilePath.clear();
}
return result;
}
bool KisDocument::save(KisPropertiesConfigurationSP exportConfiguration)
{
//qDebug() << "save" << d->m_file << d->m_url << url() << localFilePath();
d->m_saveOk = false;
if (d->m_file.isEmpty()) { // document was created empty
d->m_file = d->m_url.toLocalFile();
}
updateEditingTime(true);
setFileProgressProxy();
setUrl(url());
bool ok = saveFile(localFilePath(), exportConfiguration);
clearFileProgressProxy();
if (ok) {
setModified( false );
emit completed();
d->m_saveOk = true;
d->m_duringSaveAs = false;
d->m_originalURL = QUrl();
d->m_originalFilePath.clear();
return true; // Nothing to do
}
else {
emit canceled(QString());
}
return false;
}
bool KisDocument::saveFile(const QString &filePath, KisPropertiesConfigurationSP exportConfiguration)
{
if (!prepareLocksForSaving()) {
return false;
}
// Unset the error message
setErrorMessage("");
// Save it to be able to restore it after a failed save
const bool wasModified = isModified();
// The output format is set by KisMainWindow, and by openFile
QByteArray outputMimeType = d->outputMimeType;
if (outputMimeType.isEmpty()) {
outputMimeType = d->outputMimeType = nativeFormatMimeType();
}
//qDebug() << "saveFile. Is Autosaving?" << isAutosaving() << "url" << filePath << d->outputMimeType;
if (d->backupFile) {
Q_ASSERT(url().isLocalFile());
KBackup::backupFile(url().toLocalFile());
}
qApp->processEvents();
bool ret = false;
bool suppressErrorDialog = false;
KisImportExportFilter::ConversionStatus status = KisImportExportFilter::OK;
setFileProgressUpdater(i18n("Saving Document"));
QFileInfo fi(filePath);
QString tempororaryFileName;
{
QTemporaryFile tf(QDir::tempPath() + "/XXXXXX" + fi.baseName() + "." + fi.completeSuffix());
tf.open();
tempororaryFileName = tf.fileName();
}
Q_ASSERT(!tempororaryFileName.isEmpty());
//qDebug() << "saving to tempory file" << tempororaryFileName;
- status = d->importExportManager->exportDocument(tempororaryFileName, outputMimeType, !d->isExporting , exportConfiguration);
+ status = d->importExportManager->exportDocument(tempororaryFileName, filePath, outputMimeType, !d->isExporting , exportConfiguration);
ret = (status == KisImportExportFilter::OK);
suppressErrorDialog = (isAutosaving() || status == KisImportExportFilter::UserCancelled || status == KisImportExportFilter::BadConversionGraph);
//qDebug() << "Export status was" << status;
if (ret) {
//qDebug() << "copying temporary file" << tempororaryFileName << "to" << filePath;
if (!d->isAutosaving && !d->suppressProgress) {
QPointer updater = d->progressUpdater->startSubtask(1, "clear undo stack");
updater->setProgress(0);
d->undoStack->setClean();
updater->setProgress(100);
} else {
d->undoStack->setClean();
}
QFile tempFile(tempororaryFileName);
QString s = filePath;
QFile dstFile(s);
while (QFileInfo(s).exists()) {
s.append("_");
}
bool r;
if (s != filePath) {
r = dstFile.rename(s);
if (!r) {
setErrorMessage(i18n("Could not rename original file to %1: %2", dstFile.fileName(), dstFile. errorString()));
ret = false;
}
}
if (tempFile.exists()) {
r = tempFile.copy(filePath);
if (!r) {
setErrorMessage(i18n("Copying the temporary file failed: %1 to %2: %3", tempFile.fileName(), dstFile.fileName(), tempFile.errorString()));
ret = false;
}
else {
r = tempFile.remove();
if (!r) {
setErrorMessage(i18n("Could not remove temporary file %1: %2", tempFile.fileName(), tempFile.errorString()));
ret = false;
}
else if (s != filePath) {
r = dstFile.remove();
if (!r) {
setErrorMessage(i18n("Could not remove saved original file: %1", dstFile.errorString()));
ret = false;
}
}
}
}
else {
setErrorMessage(i18n("The temporary file %1 is gone before we could copy it!", tempFile.fileName()));
ret = false;
}
if (errorMessage().isEmpty()) {
if (!isAutosaving()) {
removeAutoSaveFiles();
}
}
else {
ret = false;
qWarning() << "Error while saving:" << errorMessage();
}
// Restart the autosave timer
// (we don't want to autosave again 2 seconds after a real save)
if (!isAutosaving()) {
setAutoSaveDelay(d->autoSaveDelay);
}
d->mimeType = outputMimeType;
}
if (!ret) {
if (!suppressErrorDialog) {
if (errorMessage().isEmpty()) {
setErrorMessage(KisImportExportFilter::conversionStatusString(status));
}
if (errorMessage().isEmpty()) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save\n%1", filePath));
} else {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not save %1\nReason: %2", filePath, errorMessage()));
}
}
// couldn't save file so this new URL is invalid
// FIXME: we should restore the current document's true URL instead of
// setting it to nothing otherwise anything that depends on the URL
// being correct will not work (i.e. the document will be called
// "Untitled" which may not be true)
//
// Update: now the URL is restored in KisMainWindow but really, this
// should still be fixed in KisDocument/KParts (ditto for file).
// We still resetURL() here since we may or may not have been called
// by KisMainWindow - Clarence
resetURL();
// As we did not save, restore the "was modified" status
setModified(wasModified);
}
emit sigSavingFinished();
clearFileProgressUpdater();
unlockAfterSaving();
return ret;
}
QByteArray KisDocument::mimeType() const
{
return d->mimeType;
}
void KisDocument::setMimeType(const QByteArray & mimeType)
{
d->mimeType = mimeType;
}
void KisDocument::setOutputMimeType(const QByteArray & mimeType)
{
d->outputMimeType = mimeType;
}
QByteArray KisDocument::outputMimeType() const
{
return d->outputMimeType;
}
bool KisDocument::fileBatchMode() const
{
return d->importExportManager->batchMode();
}
void KisDocument::setFileBatchMode(const bool batchMode)
{
d->importExportManager->setBatchMode(batchMode);
}
bool KisDocument::isImporting() const
{
return d->isImporting;
}
bool KisDocument::isExporting() const
{
return d->isExporting;
}
void KisDocument::slotAutoSave()
{
//qDebug() << "slotAutoSave. Modified:" << d->modified << "modifiedAfterAutosave" << d->modified << "url" << url() << localFilePath();
if (!d->isAutosaving && d->modified && d->modifiedAfterAutosave) {
connect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int)));
emit statusBarMessage(i18n("Autosaving..."));
d->isAutosaving = true;
QString autoSaveFileName = generateAutoSaveFileName(localFilePath());
QByteArray mimetype = d->outputMimeType;
d->outputMimeType = nativeFormatMimeType();
bool ret = exportDocument(QUrl::fromLocalFile(autoSaveFileName));
d->outputMimeType = mimetype;
if (ret) {
d->modifiedAfterAutosave = false;
d->autoSaveTimer.stop(); // until the next change
}
d->isAutosaving = false;
emit clearStatusBarMessage();
disconnect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int)));
if (!ret && !d->disregardAutosaveFailure) {
emit statusBarMessage(i18n("Error during autosave! Partition full?"));
}
}
}
void KisDocument::setReadWrite(bool readwrite)
{
d->readwrite = readwrite;
setAutoSaveDelay(d->autoSaveDelay);
Q_FOREACH (KisMainWindow *mainWindow, KisPart::instance()->mainWindows()) {
mainWindow->setReadWrite(readwrite);
}
}
void KisDocument::setAutoSaveDelay(int delay)
{
//qDebug() << "setting autosave delay from" << d->autoSaveDelay << "to" << delay;
d->autoSaveDelay = delay;
if (isReadWrite() && d->autoSaveDelay > 0) {
d->autoSaveTimer.start(d->autoSaveDelay * 1000);
}
else {
d->autoSaveTimer.stop();
}
}
KoDocumentInfo *KisDocument::documentInfo() const
{
return d->docInfo;
}
bool KisDocument::isModified() const
{
return d->modified;
}
QPixmap KisDocument::generatePreview(const QSize& size)
{
if (d->image) {
QRect bounds = d->image->bounds();
QSize newSize = bounds.size();
newSize.scale(size, Qt::KeepAspectRatio);
QPixmap px = QPixmap::fromImage(d->image->convertToQImage(newSize, 0));
if (px.size() == QSize(0,0)) {
px = QPixmap(newSize);
QPainter gc(&px);
QBrush checkBrush = QBrush(KisCanvasWidgetBase::createCheckersImage(newSize.width() / 5));
gc.fillRect(px.rect(), checkBrush);
gc.end();
}
}
return QPixmap(size);
}
QString KisDocument::generateAutoSaveFileName(const QString & path) const
{
QString retval;
// Using the extension allows to avoid relying on the mime magic when opening
const QString extension (".kra");
if (path.isEmpty()) {
// Never saved?
#ifdef Q_OS_WIN
// On Windows, use the temp location (https://bugs.kde.org/show_bug.cgi?id=314921)
retval = QString("%1%2.%3-%4-%5-autosave%6").arg(QDir::tempPath()).arg(QDir::separator()).arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension);
#else
// On Linux, use a temp file in $HOME then. Mark it with the pid so two instances don't overwrite each other's autosave file
retval = QString("%1%2.%3-%4-%5-autosave%6").arg(QDir::homePath()).arg(QDir::separator()).arg("krita").arg(qApp->applicationPid()).arg(objectName()).arg(extension);
#endif
} else {
QFileInfo fi(path);
QString dir = fi.absolutePath();
QString filename = fi.fileName();
retval = QString("%1%2.%3-autosave%4").arg(dir).arg(QDir::separator()).arg(filename).arg(extension);
}
//qDebug() << "generateAutoSaveFileName() for path" << path << ":" << retval;
return retval;
}
bool KisDocument::importDocument(const QUrl &_url)
{
bool ret;
dbgUI << "url=" << _url.url();
d->isImporting = true;
// open...
ret = openUrl(_url);
// reset url & m_file (kindly? set by KisParts::openUrl()) to simulate a
// File --> Import
if (ret) {
dbgUI << "success, resetting url";
resetURL();
setTitleModified();
}
d->isImporting = false;
return ret;
}
bool KisDocument::openUrl(const QUrl &_url, KisDocument::OpenUrlFlags flags)
{
if (!_url.isLocalFile()) {
return false;
}
dbgUI << "url=" << _url.url();
d->lastErrorMessage.clear();
// Reimplemented, to add a check for autosave files and to improve error reporting
if (!_url.isValid()) {
d->lastErrorMessage = i18n("Malformed URL\n%1", _url.url()); // ## used anywhere ?
return false;
}
QUrl url(_url);
bool autosaveOpened = false;
if (url.isLocalFile() && !fileBatchMode()) {
QString file = url.toLocalFile();
QString asf = generateAutoSaveFileName(file);
if (QFile::exists(asf)) {
KisApplication *kisApp = static_cast(qApp);
kisApp->hideSplashScreen();
//dbgUI <<"asf=" << asf;
// ## TODO compare timestamps ?
int res = QMessageBox::warning(0,
i18nc("@title:window", "Krita"),
i18n("An autosaved file exists for this document.\nDo you want to open it instead?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
switch (res) {
case QMessageBox::Yes :
url.setPath(asf);
autosaveOpened = true;
break;
case QMessageBox::No :
QFile::remove(asf);
break;
default: // Cancel
return false;
}
}
}
bool ret = openUrlInternal(url);
if (autosaveOpened) {
resetURL(); // Force save to act like 'Save As'
setReadWrite(true); // enable save button
setModified(true);
}
else {
if( !(flags & OPEN_URL_FLAG_DO_NOT_ADD_TO_RECENT_FILES) ) {
KisPart::instance()->addRecentURLToAllMainWindows(_url);
}
if (ret) {
// Detect readonly local-files; remote files are assumed to be writable
QFileInfo fi(url.toLocalFile());
setReadWrite(fi.isWritable());
}
}
return ret;
}
bool KisDocument::openFile()
{
//dbgUI <<"for" << localFilePath();
if (!QFile::exists(localFilePath())) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("File %1 does not exist.", localFilePath()));
return false;
}
QString filename = localFilePath();
QString typeName = mimeType();
if (typeName.isEmpty()) {
typeName = KisMimeDatabase::mimeTypeForFile(filename);
}
//qDebug() << "mimetypes 4:" << typeName;
// Allow to open backup files, don't keep the mimetype application/x-trash.
if (typeName == "application/x-trash") {
QString path = filename;
while (path.length() > 0) {
path.chop(1);
typeName = KisMimeDatabase::mimeTypeForFile(path);
//qDebug() << "\t" << path << typeName;
if (!typeName.isEmpty()) {
break;
}
}
//qDebug() << "chopped" << filename << "to" << path << "Was trash, is" << typeName;
}
dbgUI << localFilePath() << "type:" << typeName;
setFileProgressUpdater(i18n("Opening Document"));
KisImportExportFilter::ConversionStatus status;
status = d->importExportManager->importDocument(localFilePath(), typeName);
if (status != KisImportExportFilter::OK) {
QString msg = KisImportExportFilter::conversionStatusString(status);
if (!msg.isEmpty()) {
QString errorMsg(i18n("Could not open %2.\nReason: %1.\n%3", msg, prettyPathOrUrl(), errorMessage()));
QMessageBox::critical(0, i18nc("@title:window", "Krita"), errorMsg);
}
clearFileProgressUpdater();
return false;
}
setMimeTypeAfterLoading(typeName);
emit sigLoadingFinished();
if (!d->suppressProgress && d->progressUpdater) {
QPointer updater = d->progressUpdater->startSubtask(1, "clear undo stack");
updater->setProgress(0);
undoStack()->clear();
updater->setProgress(100);
clearFileProgressUpdater();
} else {
undoStack()->clear();
}
return true;
}
KoProgressUpdater *KisDocument::progressUpdater() const
{
return d->progressUpdater;
}
void KisDocument::setProgressProxy(KoProgressProxy *progressProxy)
{
d->progressProxy = progressProxy;
}
KoProgressProxy* KisDocument::progressProxy() const
{
if (!d->progressProxy) {
KisMainWindow *mainWindow = 0;
if (KisPart::instance()->mainwindowCount() > 0) {
mainWindow = KisPart::instance()->mainWindows()[0];
}
d->progressProxy = new DocumentProgressProxy(mainWindow);
}
return d->progressProxy;
}
// shared between openFile and koMainWindow's "create new empty document" code
void KisDocument::setMimeTypeAfterLoading(const QString& mimeType)
{
d->mimeType = mimeType.toLatin1();
d->outputMimeType = d->mimeType;
}
bool KisDocument::loadNativeFormat(const QString & file_)
{
return openUrl(QUrl::fromLocalFile(file_));
}
void KisDocument::setModified()
{
d->modified = true;
}
void KisDocument::setModified(bool mod)
{
if (mod) {
updateEditingTime(false);
}
if (d->isAutosaving) // ignore setModified calls due to autosaving
return;
if ( !d->readwrite && d->modified ) {
errKrita << "Can't set a read-only document to 'modified' !" << endl;
return;
}
//dbgUI<<" url:" << url.path();
//dbgUI<<" mod="<docInfo->aboutInfo("editing-time").toInt() + d->firstMod.secsTo(d->lastMod)));
d->firstMod = now;
} else if (firstModDelta > 60 || forceStoreElapsed) {
d->docInfo->setAboutInfo("editing-time", QString::number(d->docInfo->aboutInfo("editing-time").toInt() + firstModDelta));
d->firstMod = now;
}
d->lastMod = now;
}
QString KisDocument::prettyPathOrUrl() const
{
QString _url(url().toDisplayString());
#ifdef Q_OS_WIN
if (url().isLocalFile()) {
_url = QDir::toNativeSeparators(_url);
}
#endif
return _url;
}
// Get caption from document info (title(), in about page)
QString KisDocument::caption() const
{
QString c;
if (documentInfo()) {
c = documentInfo()->aboutInfo("title");
}
const QString _url(url().fileName());
if (!c.isEmpty() && !_url.isEmpty()) {
c = QString("%1 - %2").arg(c).arg(_url);
}
else if (c.isEmpty()) {
c = _url; // Fall back to document URL
}
return c;
}
void KisDocument::setTitleModified()
{
emit titleModified(caption(), isModified());
}
QDomDocument KisDocument::createDomDocument(const QString& tagName, const QString& version) const
{
return createDomDocument("krita", tagName, version);
}
//static
QDomDocument KisDocument::createDomDocument(const QString& appName, const QString& tagName, const QString& version)
{
QDomImplementation impl;
QString url = QString("http://www.calligra.org/DTD/%1-%2.dtd").arg(appName).arg(version);
QDomDocumentType dtype = impl.createDocumentType(tagName,
QString("-//KDE//DTD %1 %2//EN").arg(appName).arg(version),
url);
// The namespace URN doesn't need to include the version number.
QString namespaceURN = QString("http://www.calligra.org/DTD/%1").arg(appName);
QDomDocument doc = impl.createDocument(namespaceURN, tagName, dtype);
doc.insertBefore(doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\""), doc.documentElement());
return doc;
}
bool KisDocument::isNativeFormat(const QByteArray& mimetype) const
{
if (mimetype == nativeFormatMimeType())
return true;
return extraNativeMimeTypes().contains(mimetype);
}
void KisDocument::setErrorMessage(const QString& errMsg)
{
d->lastErrorMessage = errMsg;
}
QString KisDocument::errorMessage() const
{
return d->lastErrorMessage;
}
void KisDocument::removeAutoSaveFiles()
{
//qDebug() << "removeAutoSaveFiles";
// Eliminate any auto-save file
QString asf = generateAutoSaveFileName(localFilePath()); // the one in the current dir
//qDebug() << "\tfilename:" << asf << "exists:" << QFile::exists(asf);
if (QFile::exists(asf)) {
//qDebug() << "\tremoving autosavefile" << asf;
QFile::remove(asf);
}
asf = generateAutoSaveFileName(QString()); // and the one in $HOME
//qDebug() << "Autsavefile in $home" << asf;
if (QFile::exists(asf)) {
//qDebug() << "\tremoving autsavefile 2" << asf;
QFile::remove(asf);
}
}
void KisDocument::setBackupFile(bool saveBackup)
{
d->backupFile = saveBackup;
}
KoUnit KisDocument::unit() const
{
return d->unit;
}
void KisDocument::setUnit(const KoUnit &unit)
{
if (d->unit != unit) {
d->unit = unit;
emit unitChanged(unit);
}
}
KUndo2Stack *KisDocument::undoStack()
{
return d->undoStack;
}
KisImportExportManager *KisDocument::importExportManager() const
{
return d->importExportManager;
}
void KisDocument::addCommand(KUndo2Command *command)
{
if (command)
d->undoStack->push(command);
}
void KisDocument::beginMacro(const KUndo2MagicString & text)
{
d->undoStack->beginMacro(text);
}
void KisDocument::endMacro()
{
d->undoStack->endMacro();
}
void KisDocument::slotUndoStackIndexChanged(int idx)
{
// even if the document was already modified, call setModified to re-start autosave timer
setModified(idx != d->undoStack->cleanIndex());
}
void KisDocument::clearUndoHistory()
{
d->undoStack->clear();
}
KisGridConfig KisDocument::gridConfig() const
{
return d->gridConfig;
}
void KisDocument::setGridConfig(const KisGridConfig &config)
{
d->gridConfig = config;
}
const KisGuidesConfig& KisDocument::guidesConfig() const
{
return d->guidesConfig;
}
void KisDocument::setGuidesConfig(const KisGuidesConfig &data)
{
if (d->guidesConfig == data) return;
d->guidesConfig = data;
emit sigGuidesConfigChanged(d->guidesConfig);
}
void KisDocument::resetURL() {
setUrl(QUrl());
setLocalFilePath(QString());
}
KoDocumentInfoDlg *KisDocument::createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const
{
return new KoDocumentInfoDlg(parent, docInfo);
}
bool KisDocument::isReadWrite() const
{
return d->readwrite;
}
QUrl KisDocument::url() const
{
return d->m_url;
}
bool KisDocument::closeUrl(bool promptToSave)
{
if (promptToSave) {
if ( isReadWrite() && isModified()) {
Q_FOREACH (KisView *view, KisPart::instance()->views()) {
if (view && view->document() == this) {
if (!view->queryClose()) {
return false;
}
}
}
}
}
// Not modified => ok and delete temp file.
d->mimeType = QByteArray();
// It always succeeds for a read-only part,
// but the return value exists for reimplementations
// (e.g. pressing cancel for a modified read-write part)
return true;
}
void KisDocument::setUrl(const QUrl &url)
{
d->m_url = url;
}
QString KisDocument::localFilePath() const
{
return d->m_file;
}
void KisDocument::setLocalFilePath( const QString &localFilePath )
{
d->m_file = localFilePath;
}
bool KisDocument::openUrlInternal(const QUrl &url)
{
if ( !url.isValid() )
return false;
if (d->m_bAutoDetectedMime) {
d->mimeType = QByteArray();
d->m_bAutoDetectedMime = false;
}
QByteArray mimetype = d->mimeType;
if ( !closeUrl() )
return false;
d->mimeType = mimetype;
setUrl(url);
d->m_file.clear();
if (d->m_url.isLocalFile()) {
d->m_file = d->m_url.toLocalFile();
bool ret;
// set the mimetype only if it was not already set (for example, by the host application)
if (d->mimeType.isEmpty()) {
// get the mimetype of the file
// using findByUrl() to avoid another string -> url conversion
QString mime = KisMimeDatabase::mimeTypeForFile(d->m_url.toLocalFile());
d->mimeType = mime.toLocal8Bit();
d->m_bAutoDetectedMime = true;
}
setFileProgressProxy();
setUrl(d->m_url);
ret = openFile();
clearFileProgressProxy();
if (ret) {
emit completed();
} else {
emit canceled(QString());
}
return ret;
}
return false;
}
bool KisDocument::newImage(const QString& name,
qint32 width, qint32 height,
const KoColorSpace* cs,
const KoColor &bgColor, bool backgroundAsLayer,
int numberOfLayers,
const QString &description, const double imageResolution)
{
Q_ASSERT(cs);
KisConfig cfg;
KisImageSP image;
KisPaintLayerSP layer;
if (!cs) return false;
QApplication::setOverrideCursor(Qt::BusyCursor);
image = new KisImage(createUndoStore(), width, height, cs, name);
Q_CHECK_PTR(image);
connect(image, SIGNAL(sigImageModified()), this, SLOT(setImageModified()), Qt::UniqueConnection);
image->setResolution(imageResolution, imageResolution);
image->assignImageProfile(cs->profile());
documentInfo()->setAboutInfo("title", name);
if (name != i18n("Unnamed") && !name.isEmpty()) {
setUrl(QUrl::fromLocalFile(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation) + '/' + name + ".kra"));
}
documentInfo()->setAboutInfo("abstract", description);
layer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, cs);
Q_CHECK_PTR(layer);
if (backgroundAsLayer) {
image->setDefaultProjectionColor(KoColor(cs));
if (bgColor.opacityU8() == OPACITY_OPAQUE_U8) {
layer->paintDevice()->setDefaultPixel(bgColor);
} else {
// Hack: with a semi-transparent background color, the projection isn't composited right if we just set the default pixel
KisFillPainter painter;
painter.begin(layer->paintDevice());
painter.fillRect(0, 0, width, height, bgColor, bgColor.opacityU8());
}
} else {
image->setDefaultProjectionColor(bgColor);
}
layer->setDirty(QRect(0, 0, width, height));
image->addNode(layer.data(), image->rootLayer().data());
setCurrentImage(image);
for(int i = 1; i < numberOfLayers; ++i) {
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), OPACITY_OPAQUE_U8, cs);
image->addNode(layer, image->root(), i);
layer->setDirty(QRect(0, 0, width, height));
}
cfg.defImageWidth(width);
cfg.defImageHeight(height);
cfg.defImageResolution(imageResolution);
cfg.defColorModel(image->colorSpace()->colorModelId().id());
cfg.setDefaultColorDepth(image->colorSpace()->colorDepthId().id());
cfg.defColorProfile(image->colorSpace()->profile()->name());
QApplication::restoreOverrideCursor();
return true;
}
KoShapeBasedDocumentBase *KisDocument::shapeController() const
{
return d->shapeController;
}
KoShapeLayer* KisDocument::shapeForNode(KisNodeSP layer) const
{
return d->shapeController->shapeForNode(layer);
}
vKisNodeSP KisDocument::activeNodes() const
{
vKisNodeSP nodes;
Q_FOREACH (KisView *v, KisPart::instance()->views()) {
if (v->document() == this && v->viewManager()) {
KisNodeSP activeNode = v->viewManager()->activeNode();
if (activeNode && !nodes.contains(activeNode)) {
if (activeNode->inherits("KisMask")) {
activeNode = activeNode->parent();
}
nodes.append(activeNode);
}
}
}
return nodes;
}
QList KisDocument::assistants() const
{
return d->assistants;
}
void KisDocument::setAssistants(const QList value)
{
d->assistants = value;
}
void KisDocument::setPreActivatedNode(KisNodeSP activatedNode)
{
d->preActivatedNode = activatedNode;
}
KisNodeSP KisDocument::preActivatedNode() const
{
return d->preActivatedNode;
}
void KisDocument::setFileProgressUpdater(const QString &text)
{
d->suppressProgress = d->importExportManager->batchMode();
if (!d->suppressProgress) {
d->progressUpdater = new KoProgressUpdater(d->progressProxy, KoProgressUpdater::Unthreaded);
d->progressUpdater->start(100, text);
d->importExportManager->setProgresUpdater(d->progressUpdater);
connect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int)));
connect(KisPart::instance()->currentMainwindow(), SIGNAL(sigProgressCanceled()), this, SIGNAL(sigProgressCanceled()));
}
}
void KisDocument::clearFileProgressUpdater()
{
if (!d->suppressProgress && d->progressUpdater) {
disconnect(KisPart::instance()->currentMainwindow(), SIGNAL(sigProgressCanceled()), this, SIGNAL(sigProgressCanceled()));
disconnect(this, SIGNAL(sigProgress(int)), KisPart::instance()->currentMainwindow(), SLOT(slotProgress(int)));
delete d->progressUpdater;
d->importExportManager->setProgresUpdater(0);
d->progressUpdater = 0;
}
}
void KisDocument::setFileProgressProxy()
{
if (!d->progressProxy && !d->importExportManager->batchMode()) {
d->fileProgressProxy = progressProxy();
} else {
d->fileProgressProxy = 0;
}
}
void KisDocument::clearFileProgressProxy()
{
if (d->fileProgressProxy) {
setProgressProxy(0);
delete d->fileProgressProxy;
d->fileProgressProxy = 0;
}
}
KisImageWSP KisDocument::image() const
{
return d->image;
}
KisImageSP KisDocument::savingImage() const
{
return d->savingImage;
}
void KisDocument::setCurrentImage(KisImageSP image)
{
if (d->image) {
// Disconnect existing sig/slot connections
d->image->disconnect(this);
d->shapeController->setImage(0);
d->image = 0;
}
if (!image) return;
d->setImageAndInitIdleWatcher(image);
d->shapeController->setImage(image);
setModified(false);
connect(d->image, SIGNAL(sigImageModified()), this, SLOT(setImageModified()), Qt::UniqueConnection);
d->image->initialRefreshGraph();
setAutoSaveDelay(KisConfig().autoSaveInterval());
}
void KisDocument::setImageModified()
{
setModified(true);
}
KisUndoStore* KisDocument::createUndoStore()
{
return new KisDocumentUndoStore(this);
}
bool KisDocument::isAutosaving() const
{
return d->isAutosaving;
}
bool KisDocument::prepareLocksForSaving()
{
KisImageSP copiedImage;
{
Private::SafeSavingLocker locker(d, this);
if (locker.successfullyLocked()) {
copiedImage = d->image->clone(true);
}
else if (!isAutosaving()) {
// even though it is a recovery operation, we should ensure we do not enter saving twice!
std::unique_lock> l(d->savingLock, std::try_to_lock);
if (l.owns_lock()) {
d->lastErrorMessage = i18n("The image was still busy while saving. Your saved image might be incomplete.");
d->image->lock();
copiedImage = d->image->clone(true);
d->image->unlock();
}
}
}
bool result = false;
// ensure we do not enter saving twice
if (copiedImage && d->savingMutex.tryLock()) {
d->savingImage = copiedImage;
result = true;
} else {
qWarning() << "Could not lock the document for saving!";
d->lastErrorMessage = i18n("Could not lock the image for saving.");
}
return result;
}
void KisDocument::unlockAfterSaving()
{
d->savingImage = 0;
d->savingMutex.unlock();
}
diff --git a/libs/ui/KisImportExportFilter.cpp b/libs/ui/KisImportExportFilter.cpp
index 5def976d74..dd4f62d995 100644
--- a/libs/ui/KisImportExportFilter.cpp
+++ b/libs/ui/KisImportExportFilter.cpp
@@ -1,268 +1,279 @@
/* This file is part of the KDE libraries
Copyright (C) 2001 Werner Trobin
2002 Werner Trobin
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 "KisImportExportFilter.h"
#include
#include
#include
#include "KisImportExportManager.h"
#include
#include
#include
#include
#include "KoUpdater.h"
#include
class Q_DECL_HIDDEN KisImportExportFilter::Private
{
public:
QPointer updater;
QByteArray mime;
QString filename;
+ QString realFilename;
bool batchmode;
QMap capabilities;
Private()
: updater(0)
, batchmode(false)
{}
~Private()
{
qDeleteAll(capabilities);
}
};
KisImportExportFilter::KisImportExportFilter(QObject *parent)
: QObject(parent)
, d(new Private)
{
}
KisImportExportFilter::~KisImportExportFilter()
{
Q_ASSERT(d->updater);
if (d->updater) {
d->updater->setProgress(100);
}
delete d;
}
-
QString KisImportExportFilter::filename() const
{
return d->filename;
}
+QString KisImportExportFilter::realFilename() const
+{
+ return d->realFilename;
+}
+
bool KisImportExportFilter::batchMode() const
{
return d->batchmode;
}
void KisImportExportFilter::setBatchMode(bool batchmode)
{
d->batchmode = batchmode;
}
void KisImportExportFilter::setFilename(const QString &filename)
{
d->filename = filename;
}
+void KisImportExportFilter::setRealFilename(const QString &filename)
+{
+ d->realFilename = filename;
+}
+
+
void KisImportExportFilter::setMimeType(const QString &mime)
{
d->mime = mime.toLatin1();
}
QByteArray KisImportExportFilter::mimeType() const
{
return d->mime;
}
QString KisImportExportFilter::conversionStatusString(ConversionStatus status)
{
QString msg;
switch (status) {
case OK: break;
case FilterCreationError:
msg = i18n("Could not create the filter plugin"); break;
case CreationError:
msg = i18n("Could not create the output document"); break;
case FileNotFound:
msg = i18n("File not found"); break;
case StorageCreationError:
msg = i18n("Cannot create storage"); break;
case BadMimeType:
msg = i18n("Bad MIME type"); break;
case WrongFormat:
msg = i18n("Format not recognized"); break;
case NotImplemented:
msg = i18n("Not implemented"); break;
case ParsingError:
msg = i18n("Parsing error"); break;
case InvalidFormat:
msg = i18n("Invalid file format"); break;
case InternalError:
case UsageError:
msg = i18n("Internal error"); break;
case ProgressCancelled:
msg = i18n("Cancelled by user"); break;
case BadConversionGraph:
msg = i18n("Unknown file type"); break;
case UnsupportedVersion:
msg = i18n("Unsupported file version"); break;
case UserCancelled:
// intentionally we do not prompt the error message here
break;
default: msg = i18n("Unknown error"); break;
}
return msg;
}
KisPropertiesConfigurationSP KisImportExportFilter::defaultConfiguration(const QByteArray &from, const QByteArray &to) const
{
Q_UNUSED(from);
Q_UNUSED(to);
return 0;
}
KisPropertiesConfigurationSP KisImportExportFilter::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const
{
return defaultConfiguration(from, to);
}
KisConfigWidget *KisImportExportFilter::createConfigurationWidget(QWidget *, const QByteArray &from, const QByteArray &to) const
{
Q_UNUSED(from);
Q_UNUSED(to);
return 0;
}
QMap KisImportExportFilter::exportChecks()
{
qDeleteAll(d->capabilities);
initializeCapabilities();
return d->capabilities;
}
void KisImportExportFilter::setUpdater(QPointer updater)
{
d->updater = updater;
}
void KisImportExportFilter::setProgress(int value)
{
if (d->updater) {
d->updater->setValue(value);
}
}
void KisImportExportFilter::initializeCapabilities()
{
// XXX: Initialize everything to fully supported?
}
void KisImportExportFilter::addCapability(KisExportCheckBase *capability)
{
d->capabilities[capability->id()] = capability;
}
void KisImportExportFilter::addSupportedColorModels(QList > supportedColorModels, const QString &name, KisExportCheckBase::Level level)
{
Q_ASSERT(level != KisExportCheckBase::SUPPORTED);
QString layerMessage;
QString imageMessage;
QList allColorModels = KoColorSpaceRegistry::instance()->colorModelsList(KoColorSpaceRegistry::AllColorSpaces);
Q_FOREACH(const KoID &colorModelID, allColorModels) {
QList allColorDepths = KoColorSpaceRegistry::instance()->colorDepthList(colorModelID.id(), KoColorSpaceRegistry::AllColorSpaces);
Q_FOREACH(const KoID &colorDepthID, allColorDepths) {
KisExportCheckFactory *colorModelCheckFactory =
KisExportCheckRegistry::instance()->get("ColorModelCheck/" + colorModelID.id() + "/" + colorDepthID.id());
KisExportCheckFactory *colorModelPerLayerCheckFactory =
KisExportCheckRegistry::instance()->get("ColorModelPerLayerCheck/" + colorModelID.id() + "/" + colorDepthID.id());
if(!colorModelCheckFactory || !colorModelPerLayerCheckFactory) {
qDebug() << "No factory for" << colorModelID << colorDepthID;
continue;
}
if (supportedColorModels.contains(QPair(colorModelID, colorDepthID))) {
addCapability(colorModelCheckFactory->create(KisExportCheckBase::SUPPORTED));
addCapability(colorModelPerLayerCheckFactory->create(KisExportCheckBase::SUPPORTED));
}
else {
if (level == KisExportCheckBase::PARTIALLY) {
imageMessage = i18nc("image conversion warning",
"%1 cannot save images with color model %2 and depth %3. The image will be converted."
,name, colorModelID.name(), colorDepthID.name());
layerMessage =
i18nc("image conversion warning",
"%1 cannot save layers with color model %2 and depth %3. The layers will be converted or skipped."
,name, colorModelID.name(), colorDepthID.name());
}
else {
imageMessage = i18nc("image conversion warning",
"%1 cannot save images with color model %2 and depth %3. The image will not be saved."
,name, colorModelID.name(), colorDepthID.name());
layerMessage =
i18nc("image conversion warning",
"%1 cannot save layers with color model %2 and depth %3. The layers will be skipped."
, name, colorModelID.name(), colorDepthID.name());
}
addCapability(colorModelCheckFactory->create(level, imageMessage));
addCapability(colorModelPerLayerCheckFactory->create(level, layerMessage));
}
}
}
}
diff --git a/libs/ui/KisImportExportFilter.h b/libs/ui/KisImportExportFilter.h
index 48c60dddaf..2cf439499c 100644
--- a/libs/ui/KisImportExportFilter.h
+++ b/libs/ui/KisImportExportFilter.h
@@ -1,174 +1,176 @@
/* This file is part of the Calligra libraries
Copyright (C) 2001 Werner Trobin
2002 Werner Trobin
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 KIS_IMPORT_EXPORT_FILTER_H
#define KIS_IMPORT_EXPORT_FILTER_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class KoUpdater;
class KisDocument;
class KisConfigWidget;
#include "kritaui_export.h"
/**
* @brief The base class for import and export filters.
*
* Derive your filter class from this base class and implement
* the @ref convert() method. Don't forget to specify the Q_OBJECT
* macro in your class even if you don't use signals or slots.
* This is needed as filters are created on the fly.
*
* @note Take care: The m_chain pointer is invalid while the constructor
* runs due to the implementation -- @em don't use it in the constructor.
* After the constructor, when running the @ref convert() method it's
* guaranteed to be valid, so no need to check against 0.
*
* @note If the code is compiled in debug mode, setting CALLIGRA_DEBUG_FILTERS
* environment variable to any value disables deletion of temporary files while
* importing/exporting. This is useful for testing purposes.
*
* @author Werner Trobin
* @todo the class has no constructor and therefore cannot initialize its private class
*/
class KRITAUI_EXPORT KisImportExportFilter : public QObject
{
Q_OBJECT
public:
/**
* This enum is used to signal the return state of your filter.
* Return OK in @ref convert() in case everything worked as expected.
* Feel free to add some more error conditions @em before the last item
* if it's needed.
*/
enum ConversionStatus { OK,
UsageError,
CreationError,
FileNotFound,
StorageCreationError,
BadMimeType,
BadConversionGraph,
WrongFormat,
NotImplemented,
ParsingError,
InternalError,
UserCancelled,
InvalidFormat,
FilterCreationError,
ProgressCancelled,
UnsupportedVersion,
JustInCaseSomeBrokenCompilerUsesLessThanAByte = 255
};
virtual ~KisImportExportFilter();
void setBatchMode(bool batchmode);
void setFilename(const QString &filename);
+ void setRealFilename(const QString &filename);
void setMimeType(const QString &mime);
void setUpdater(QPointer updater);
/**
* The filter chain calls this method to perform the actual conversion.
* The passed mimetypes should be a pair of those you specified in your
* .desktop file.
* You @em have to implement this method to make the filter work.
*
* @return The error status, see the @ref #ConversionStatus enum.
* KisImportExportFilter::OK means that everything is alright.
*/
virtual ConversionStatus convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0) = 0;
/**
* Get the text version of the status value
*/
static QString conversionStatusString(ConversionStatus status);
/**
* @brief defaultConfiguration defines the default settings for the given import export filter
* @param from The mimetype of the source file/document
* @param to The mimetype of the destination file/document
* @return a serializable KisPropertiesConfiguration object
*/
virtual KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const;
/**
* @brief lastSavedConfiguration return the last saved configuration for this filter
* @param from The mimetype of the source file/document
* @param to The mimetype of the destination file/document
* @return a serializable KisPropertiesConfiguration object
*/
virtual KisPropertiesConfigurationSP lastSavedConfiguration(const QByteArray &from = "", const QByteArray &to = "") const;
/**
* @brief createConfigurationWidget creates a widget that can be used to define the settings for a given import/export filter
* @param parent the ownder of the widget; the caller is responsible for deleting
* @param from The mimetype of the source file/document
* @param to The mimetype of the destination file/document
*
* @return the widget
*/
virtual KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const;
/**
* @brief generate and return the list of capabilities of this export filter. The list
* @return returns the list of capabilities of this export filter
*/
virtual QMap exportChecks();
protected:
/**
* This is the constructor your filter has to call, obviously.
*/
KisImportExportFilter(QObject *parent = 0);
QString filename() const;
+ QString realFilename() const;
bool batchMode() const;
QByteArray mimeType() const;
void setProgress(int value);
virtual void initializeCapabilities();
void addCapability(KisExportCheckBase *capability);
void addSupportedColorModels(QList > supportedColorModels, const QString &name, KisExportCheckBase::Level level = KisExportCheckBase::PARTIALLY);
private:
KisImportExportFilter(const KisImportExportFilter& rhs);
KisImportExportFilter& operator=(const KisImportExportFilter& rhs);
class Private;
Private *const d;
};
#endif
diff --git a/libs/ui/KisImportExportManager.cpp b/libs/ui/KisImportExportManager.cpp
index 0df753375a..36b6c2e278 100644
--- a/libs/ui/KisImportExportManager.cpp
+++ b/libs/ui/KisImportExportManager.cpp
@@ -1,433 +1,434 @@
/*
* Copyright (C) 2016 Boudewijn Rempt
*
* 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 "KisImportExportManager.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "kis_config.h"
#include "KisImportExportFilter.h"
#include "KisDocument.h"
#include
#include
#include "kis_guides_config.h"
#include "kis_grid_config.h"
#include "kis_popup_button.h"
#include
// static cache for import and export mimetypes
QStringList KisImportExportManager::m_importMimeTypes;
QStringList KisImportExportManager::m_exportMimeTypes;
class Q_DECL_HIDDEN KisImportExportManager::Private
{
public:
bool batchMode {false};
QPointer progressUpdater {0};
};
KisImportExportManager::KisImportExportManager(KisDocument* document)
: m_document(document)
, d(new Private)
{
}
KisImportExportManager::~KisImportExportManager()
{
delete d;
}
KisImportExportFilter::ConversionStatus KisImportExportManager::importDocument(const QString& location, const QString& mimeType)
{
- return convert(Import, location, mimeType, false, 0);
+ return convert(Import, location, location, mimeType, false, 0);
}
-KisImportExportFilter::ConversionStatus KisImportExportManager::exportDocument(const QString& location, QByteArray& mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
+KisImportExportFilter::ConversionStatus KisImportExportManager::exportDocument(const QString& location, const QString& realLocation, QByteArray& mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
- return convert(Export, location, mimeType, showWarnings, exportConfiguration);
+ return convert(Export, location, realLocation, mimeType, showWarnings, exportConfiguration);
}
// The static method to figure out to which parts of the
// graph this mimetype has a connection to.
QStringList KisImportExportManager::mimeFilter(Direction direction)
{
// Find the right mimetype by the extension
QSet mimeTypes;
// mimeTypes << KisDocument::nativeFormatMimeType() << "application/x-krita-paintoppreset" << "image/openraster";
if (direction == KisImportExportManager::Import) {
if (m_importMimeTypes.isEmpty()) {
KoJsonTrader trader;
QListlist = trader.query("Krita/FileFilter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
Q_FOREACH(const QString &mimetype, json.value("X-KDE-Import").toString().split(",", QString::SkipEmptyParts)) {
//qDebug() << "Adding import mimetype" << mimetype << KisMimeDatabase::descriptionForMimeType(mimetype) << "from plugin" << loader;
mimeTypes << mimetype;
}
}
qDeleteAll(list);
m_importMimeTypes = mimeTypes.toList();
}
return m_importMimeTypes;
}
else if (direction == KisImportExportManager::Export) {
if (m_exportMimeTypes.isEmpty()) {
KoJsonTrader trader;
QListlist = trader.query("Krita/FileFilter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
Q_FOREACH(const QString &mimetype, json.value("X-KDE-Export").toString().split(",", QString::SkipEmptyParts)) {
//qDebug() << "Adding export mimetype" << mimetype << KisMimeDatabase::descriptionForMimeType(mimetype) << "from plugin" << loader;
mimeTypes << mimetype;
}
}
qDeleteAll(list);
m_exportMimeTypes = mimeTypes.toList();
}
return m_exportMimeTypes;
}
return QStringList();
}
KisImportExportFilter *KisImportExportManager::filterForMimeType(const QString &mimetype, KisImportExportManager::Direction direction)
{
int weight = -1;
KisImportExportFilter *filter = 0;
KoJsonTrader trader;
QListlist = trader.query("Krita/FileFilter", "");
Q_FOREACH(QPluginLoader *loader, list) {
QJsonObject json = loader->metaData().value("MetaData").toObject();
QString directionKey = direction == Export ? "X-KDE-Export" : "X-KDE-Import";
if (json.value(directionKey).toString().split(",", QString::SkipEmptyParts).contains(mimetype)) {
KLibFactory *factory = qobject_cast(loader->instance());
if (!factory) {
warnUI << loader->errorString();
continue;
}
QObject* obj = factory->create(0);
if (!obj || !obj->inherits("KisImportExportFilter")) {
delete obj;
continue;
}
KisImportExportFilter *f = qobject_cast(obj);
if (!f) {
delete obj;
continue;
}
int w = json.value("X-KDE-Weight").toInt();
if (w > weight) {
delete filter;
filter = f;
f->setObjectName(loader->fileName());
weight = w;
}
}
}
qDeleteAll(list);
filter->setMimeType(mimetype);
return filter;
}
void KisImportExportManager::setBatchMode(const bool batch)
{
d->batchMode = batch;
}
bool KisImportExportManager::batchMode(void) const
{
return d->batchMode;
}
void KisImportExportManager::setProgresUpdater(KoProgressUpdater *updater)
{
d->progressUpdater = updater;
}
-KisImportExportFilter::ConversionStatus KisImportExportManager::convert(KisImportExportManager::Direction direction, const QString &location, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
+KisImportExportFilter::ConversionStatus KisImportExportManager::convert(KisImportExportManager::Direction direction, const QString &location, const QString& realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration)
{
QString typeName = mimeType;
if (typeName.isEmpty()) {
typeName = KisMimeDatabase::mimeTypeForFile(location);
}
QSharedPointer filter(filterForMimeType(typeName, direction));
if (!filter) {
return KisImportExportFilter::FilterCreationError;
}
filter->setFilename(location);
+ filter->setRealFilename(realLocation);
filter->setBatchMode(batchMode());
filter->setMimeType(typeName);
if (d->progressUpdater) {
filter->setUpdater(d->progressUpdater->startSubtask());
}
QByteArray from, to;
if (direction == Export) {
from = m_document->nativeFormatMimeType();
to = mimeType.toLatin1();
}
else {
from = mimeType.toLatin1();
to = m_document->nativeFormatMimeType();
}
if (!exportConfiguration) {
exportConfiguration = filter->lastSavedConfiguration(from, to);
if (exportConfiguration) {
// Fill with some meta information about the image
KisImageWSP image = m_document->image();
KisPaintDeviceSP pd = image->projection();
bool isThereAlpha = false;
KisSequentialConstIterator it(pd, image->bounds());
const KoColorSpace* cs = pd->colorSpace();
do {
if (cs->opacityU8(it.oldRawData()) != OPACITY_OPAQUE_U8) {
isThereAlpha = true;
break;
}
} while (it.nextPixel());
exportConfiguration->setProperty("ImageContainsTransparency", isThereAlpha);
exportConfiguration->setProperty("ColorModelID", cs->colorModelId().id());
exportConfiguration->setProperty("ColorDepthID", cs->colorDepthId().id());
bool sRGB = (cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive) && !cs->profile()->name().contains(QLatin1String("g10")));
exportConfiguration->setProperty("sRGB", sRGB);
}
}
KisPreExportChecker checker;
if (direction == Export) {
checker.check(m_document->image(), filter->exportChecks());
}
KisConfigWidget *wdg = filter->createConfigurationWidget(0, from, to);
bool alsoAsKra = false;
QStringList warnings = checker.warnings();
QStringList errors = checker.errors();
// Extra checks that cannot be done by the checker, because the checker only has access to the image.
if (!m_document->assistants().isEmpty() && typeName != m_document->nativeFormatMimeType()) {
warnings.append(i18nc("image conversion warning", "The image contains assistants. The assistants will not be saved."));
}
if (m_document->guidesConfig().hasGuides() && typeName != m_document->nativeFormatMimeType()) {
warnings.append(i18nc("image conversion warning", "The image contains guides. The guides will not be saved."));
}
if (!m_document->gridConfig().isDefault() && typeName != m_document->nativeFormatMimeType()) {
warnings.append(i18nc("image conversion warning", "The image contains a custom grid configuration. The configuration will not be saved."));
}
if (!batchMode() && !errors.isEmpty()) {
QString error = ""
+ i18n("Error: cannot save this image as a %1.", KisMimeDatabase::descriptionForMimeType(typeName))
+ " Reasons:
"
+ "";
Q_FOREACH(const QString &w, errors) {
error += "\n- " + w + "
";
}
error += "
";
QMessageBox::critical(KisPart::instance()->currentMainwindow(), i18nc("@title:window", "Krita: Export Error"), error);
return KisImportExportFilter::UserCancelled;
}
if (!batchMode() && (wdg || !warnings.isEmpty())) {
KoDialog dlg;
dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
dlg.setWindowTitle(KisMimeDatabase::descriptionForMimeType(mimeType));
QWidget *page = new QWidget(&dlg);
QVBoxLayout *layout = new QVBoxLayout(page);
if (!checker.warnings().isEmpty()) {
if (showWarnings) {
QHBoxLayout *hLayout = new QHBoxLayout();
QLabel *labelWarning = new QLabel();
labelWarning->setPixmap(KisIconUtils::loadIcon("dialog-warning").pixmap(32, 32));
hLayout->addWidget(labelWarning);
KisPopupButton *bn = new KisPopupButton(0);
bn->setText(i18nc("Keep the extra space at the end of the sentence, please", "Warning: saving as %1 will lose information from your image. ", KisMimeDatabase::descriptionForMimeType(mimeType)));
hLayout->addWidget(bn);
layout->addLayout(hLayout);
QTextBrowser *browser = new QTextBrowser();
browser->setMinimumWidth(bn->width());
bn->setPopupWidget(browser);
QString warning = ""
+ i18n("You will lose information when saving this image as a %1.", KisMimeDatabase::descriptionForMimeType(typeName));
if (warnings.size() == 1) {
warning += " Reason:
";
}
else {
warning += " Reasons:
";
}
warning += "";
Q_FOREACH(const QString &w, warnings) {
warning += "\n- " + w + "
";
}
warning += "
";
browser->setHtml(warning);
}
}
if (wdg) {
QGroupBox *box = new QGroupBox(i18n("Options"));
QVBoxLayout *boxLayout = new QVBoxLayout(box);
wdg->setConfiguration(exportConfiguration);
boxLayout->addWidget(wdg);
layout->addWidget(box);
}
QCheckBox *chkAlsoAsKra = 0;
if (showWarnings) {
if (!checker.warnings().isEmpty()) {
chkAlsoAsKra = new QCheckBox(i18n("Also save your image as a Krita file."));
chkAlsoAsKra->setChecked(KisConfig().readEntry("AlsoSaveAsKra", false));
layout->addWidget(chkAlsoAsKra);
}
}
dlg.setMainWidget(page);
dlg.resize(dlg.minimumSize());
if (showWarnings || wdg) {
if (!dlg.exec()) {
return KisImportExportFilter::UserCancelled;
}
}
if (chkAlsoAsKra) {
KisConfig().writeEntry("AlsoSaveAsKra", chkAlsoAsKra->isChecked());
alsoAsKra = chkAlsoAsKra->isChecked();
}
if (wdg) {
exportConfiguration = wdg->configuration();
}
}
QFile io(location);
if (direction == Import) {
if (!io.exists()) {
return KisImportExportFilter::FileNotFound;
}
if (!io.open(QFile::ReadOnly)) {
return KisImportExportFilter::FileNotFound;
}
}
else if (direction == Export) {
if (!io.open(QFile::WriteOnly)) {
return KisImportExportFilter::CreationError;
}
}
else {
return KisImportExportFilter::BadConversionGraph;
}
if (!batchMode()) {
QApplication::setOverrideCursor(Qt::WaitCursor);
}
KisImportExportFilter::ConversionStatus status = filter->convert(m_document, &io, exportConfiguration);
io.close();
if (exportConfiguration) {
KisConfig().setExportConfiguration(typeName, exportConfiguration);
}
if (alsoAsKra) {
QString l = location + ".kra";
QByteArray ba = m_document->nativeFormatMimeType();
KisImportExportFilter *filter = filterForMimeType(QString::fromLatin1(ba), Export);
QFile f(l);
f.open(QIODevice::WriteOnly);
if (filter) {
filter->setFilename(l);
filter->convert(m_document, &f);
}
f.close();
delete filter;
}
if (!batchMode()) {
QApplication::restoreOverrideCursor();
}
return status;
}
#include
diff --git a/libs/ui/KisImportExportManager.h b/libs/ui/KisImportExportManager.h
index 6a29700ea1..2535d29882 100644
--- a/libs/ui/KisImportExportManager.h
+++ b/libs/ui/KisImportExportManager.h
@@ -1,144 +1,144 @@
/*
* Copyright (C) 2016 Boudewijn Rempt
*
* 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 KIS_IMPORT_EXPORT_MANAGER_H
#define KIS_IMPORT_EXPORT_MANAGER_H
#include
#include
#include
#include
#include "KisImportExportFilter.h"
#include "kritaui_export.h"
class KisDocument;
class KoProgressUpdater;
/**
* @brief The class managing all the filters.
*
* This class manages all filters for a %Calligra application. Normally
* you will not have to use it, since KisMainWindow takes care of loading
* and saving documents.
*
* @ref KisFilter
*
* @author Kalle Dalheimer
* @author Torben Weis
* @author Werner Trobin
*/
class KRITAUI_EXPORT KisImportExportManager : public QObject
{
Q_OBJECT
public:
/**
* This enum is used to distinguish the import/export cases
*/
enum Direction { Import = 1, Export = 2 };
/**
* Create a filter manager for a document
*/
explicit KisImportExportManager(KisDocument *document);
public:
virtual ~KisImportExportManager();
/**
* Imports the specified document and returns the resultant filename
* (most likely some file in /tmp).
* @p path can be either a URL or a filename.
* @p documentMimeType gives importDocument a hint about what type
* the document may be. It can be left empty.
*
* @return status signals the success/error of the conversion.
* If the QString which is returned isEmpty() and the status is OK,
* then we imported the file directly into the document.
*/
KisImportExportFilter::ConversionStatus importDocument(const QString &location, const QString &mimeType);
/**
* @brief Exports the given file/document to the specified URL/mimetype.
*
* If @p mimeType is empty, then the closest matching Calligra part is searched
* and when the method returns @p mimeType contains this mimetype.
* Oh, well, export is a C++ keyword ;)
*/
- KisImportExportFilter::ConversionStatus exportDocument(const QString &location, QByteArray &mimeType, bool showWarnings = true, KisPropertiesConfigurationSP exportConfiguration = 0);
+ KisImportExportFilter::ConversionStatus exportDocument(const QString &location, const QString& realLocation, QByteArray &mimeType, bool showWarnings = true, KisPropertiesConfigurationSP exportConfiguration = 0);
///@name Static API
//@{
/**
* Suitable for passing to KoFileDialog::setMimeTypeFilters. The default mime
* gets set by the "users" of this method, as we do not have enough
* information here.
* Optionally, @p extraNativeMimeTypes are added after the native mimetype.
*/
static QStringList mimeFilter(Direction direction);
/**
* @brief filterForMimeType loads the relevant import/export plugin and returns it. The caller
* is responsible for deleting it!
* @param mimetype the mimetype we want to import/export. If there's more than one plugin, the one
* with the highest weight as defined in the json description will be taken
* @param direction import or export
* @return a pointer to the filter plugin or 0 if none could be found
*/
static KisImportExportFilter *filterForMimeType(const QString &mimetype, Direction direction);
/**
* Set the filter manager is batch mode (no dialog shown)
* instead of the interactive mode (dialog shown)
*/
void setBatchMode(const bool batch);
/**
* Get if the filter manager is batch mode (true)
* or in interactive mode (true)
*/
bool batchMode(void) const;
void setProgresUpdater(KoProgressUpdater *updater);
private Q_SLOTS:
private:
- KisImportExportFilter::ConversionStatus convert(Direction direction, const QString &location, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration);
+ KisImportExportFilter::ConversionStatus convert(Direction direction, const QString &location, const QString& realLocation, const QString &mimeType, bool showWarnings, KisPropertiesConfigurationSP exportConfiguration);
// Private API
KisImportExportManager(const KisImportExportManager& rhs);
KisImportExportManager &operator=(const KisImportExportManager& rhs);
KisDocument *m_document;
/// A static cache for the availability checks of filters
static QStringList m_importMimeTypes;
static QStringList m_exportMimeTypes;
class Private;
Private * const d;
};
#endif // __KO_FILTER_MANAGER_H__
diff --git a/plugins/impex/exr/tests/kis_exr_test.cpp b/plugins/impex/exr/tests/kis_exr_test.cpp
index 9b6d082dd5..b4dd11325a 100644
--- a/plugins/impex/exr/tests/kis_exr_test.cpp
+++ b/plugins/impex/exr/tests/kis_exr_test.cpp
@@ -1,95 +1,95 @@
/*
* Copyright (C) 2007 Cyrille Berger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_exr_test.h"
#include
#include
#include
#include
#include
#include "filestest.h"
#ifndef FILES_DATA_DIR
#error "FILES_DATA_DIR not set. A directory with the data used for testing the importing of files in krita"
#endif
void KisExrTest::testFiles()
{
TestUtil::testFiles(QString(FILES_DATA_DIR) + "/sources", QStringList(), QString(), 1);
}
void KisExrTest::testRoundTrip()
{
QString inputFileName(TestUtil::fetchDataFileLazy("CandleGlass.exr"));
KisDocument *doc1 = KisPart::instance()->createDocument();
KisImportExportManager manager(doc1);
manager.setBatchMode(true);
KisImportExportFilter::ConversionStatus status = manager.importDocument(inputFileName, QString());
QCOMPARE(status, KisImportExportFilter::OK);
QVERIFY(doc1->image());
QTemporaryFile savedFile(QDir::tempPath() + QLatin1String("/krita_XXXXXX") + QLatin1String(".exr"));
savedFile.setAutoRemove(false);
savedFile.open();
QString savedFileName(savedFile.fileName());
QString typeName = KisMimeDatabase::mimeTypeForFile(savedFileName);
QByteArray mimeType(typeName.toLatin1());
- status = manager.exportDocument(savedFileName, mimeType);
+ status = manager.exportDocument(savedFileName, savedFileName, mimeType);
QVERIFY(QFileInfo(savedFileName).exists());
{
KisDocument *doc2 = KisPart::instance()->createDocument();
KisImportExportManager manager(doc2);
manager.setBatchMode(true);
status = manager.importDocument(savedFileName, QString());
QCOMPARE(status, KisImportExportFilter::OK);
QVERIFY(doc2->image());
QVERIFY(TestUtil::comparePaintDevicesClever(
doc1->image()->root()->firstChild()->paintDevice(),
doc2->image()->root()->firstChild()->paintDevice(),
0.01 /* meaningless alpha */));
delete doc2;
}
savedFile.close();
delete doc1;
}
QTEST_MAIN(KisExrTest)
diff --git a/plugins/impex/qml/qml_converter.cc b/plugins/impex/qml/qml_converter.cc
index 99c18a89d8..f9085cfe46 100644
--- a/plugins/impex/qml/qml_converter.cc
+++ b/plugins/impex/qml/qml_converter.cc
@@ -1,92 +1,93 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* 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; version 2.1 of the License.
*
* 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 program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qml_converter.h"
#include
#include
#include
#include
#include
#define SPACE " "
QMLConverter::QMLConverter()
{
}
QMLConverter::~QMLConverter()
{
}
-KisImageBuilder_Result QMLConverter::buildFile(const QString &filename, QIODevice *io, KisImageSP image)
+KisImageBuilder_Result QMLConverter::buildFile(const QString &filename, const QString &realFilename, QIODevice *io, KisImageSP image)
{
QTextStream out(io);
out.setCodec("UTF-8");
out << "import QtQuick 1.1" << "\n\n";
out << "Rectangle {\n";
writeInt(out, 1, "width", image->width());
writeInt(out, 1, "height", image->height());
out << "\n";
QFileInfo info(filename);
+ QFileInfo infoRealFile(realFilename);
KisNodeSP node = image->rootLayer()->firstChild();
- QString imageDir = info.baseName() + "_images";
- QString imagePath = info.absolutePath() + '/' + imageDir;
+ QString imageDir = infoRealFile.baseName() + "_images";
+ QString imagePath = infoRealFile.absolutePath() + '/' + imageDir;
if (node) {
QDir dir;
dir.mkpath(imagePath);
}
dbgFile << "Saving images to " << imagePath;
while(node) {
KisPaintDeviceSP projection = node->projection();
QRect rect = projection->exactBounds();
QImage qmlImage = projection->convertToQImage(0, rect.x(), rect.y(), rect.width(), rect.height());
QString name = node->name().replace(' ', '_').toLower();
QString fileName = name + ".png";
qmlImage.save(imagePath +'/'+ fileName);
out << SPACE << "Image {\n";
writeString(out, 2, "id", name);
writeInt(out, 2, "x", rect.x());
writeInt(out, 2, "y", rect.y());
writeInt(out, 2, "width", rect.width());
writeInt(out, 2, "height", rect.height());
writeString(out, 2, "source", "\"" + imageDir + '/' + fileName + "\"" );
writeString(out, 2, "opacity", QString().setNum(node->opacity()/255.0));
out << SPACE << "}\n";
node = node->nextSibling();
}
out << "}\n";
return KisImageBuilder_RESULT_OK;
}
void QMLConverter::writeString(QTextStream& out, int spacing, const QString& setting, const QString& value) {
for (int space = 0; space < spacing; space++) {
out << SPACE;
}
out << setting << ": " << value << "\n";
}
void QMLConverter::writeInt(QTextStream& out, int spacing, const QString& setting, int value) {
writeString(out, spacing, setting, QString::number(value));
}
diff --git a/plugins/impex/qml/qml_converter.h b/plugins/impex/qml/qml_converter.h
index 9d20405d9f..32224a20aa 100644
--- a/plugins/impex/qml/qml_converter.h
+++ b/plugins/impex/qml/qml_converter.h
@@ -1,44 +1,44 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* 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; version 2.1 of the License.
*
* 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 program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _QML_CONVERTER_H_
#define _QML_CONVERTER_H_
#include
#include
#include
#include "kis_types.h"
#include
class QMLConverter : public QObject
{
Q_OBJECT
public:
QMLConverter();
virtual ~QMLConverter();
public:
- KisImageBuilder_Result buildFile(const QString &filename, QIODevice *io, KisImageSP image);
+ KisImageBuilder_Result buildFile(const QString &filename, const QString &realFilename, QIODevice *io, KisImageSP image);
private:
void writeString(QTextStream& out, int spacing, const QString& setting, const QString& value);
void writeInt(QTextStream& out, int spacing, const QString& setting, int value);
};
#endif
diff --git a/plugins/impex/qml/qml_export.cc b/plugins/impex/qml/qml_export.cc
index a09e8d8c1f..d70a3278bb 100644
--- a/plugins/impex/qml/qml_export.cc
+++ b/plugins/impex/qml/qml_export.cc
@@ -1,73 +1,73 @@
/*
* Copyright (c) 2013 Sven Langkamp
*
* 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; version 2.1 of the License.
*
* 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 program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "qml_export.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include "qml_converter.h"
#include
K_PLUGIN_FACTORY_WITH_JSON(ExportFactory, "krita_qml_export.json", registerPlugin();)
QMLExport::QMLExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent)
{
}
QMLExport::~QMLExport()
{
}
KisImportExportFilter::ConversionStatus QMLExport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/)
{
KisImageSP image = document->savingImage();
Q_CHECK_PTR(image);
QMLConverter converter;
- KisImageBuilder_Result result = converter.buildFile(filename(), io, image);
+ KisImageBuilder_Result result = converter.buildFile(filename(), realFilename(), io, image);
if (result == KisImageBuilder_RESULT_OK) {
dbgFile << "success !";
return KisImportExportFilter::OK;
}
dbgFile << " Result =" << result;
return KisImportExportFilter::InternalError;
}
void QMLExport::initializeCapabilities()
{
addCapability(KisExportCheckRegistry::instance()->get("MultiLayerCheck")->create(KisExportCheckBase::SUPPORTED));
QList > supportedColorModels;
supportedColorModels << QPair()
<< QPair(RGBAColorModelID, Integer8BitsColorDepthID)
<< QPair(GrayAColorModelID, Integer8BitsColorDepthID);
addSupportedColorModels(supportedColorModels, "QML");
}
#include