File indexing completed on 2024-05-12 15:59:14

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2012 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "DocumentManager.h"
0008 #include "ProgressProxy.h"
0009 #include "Settings.h"
0010 #include "RecentFileManager.h"
0011 #include <KoColor.h>
0012 #include <KisPart.h>
0013 
0014 
0015 #include <KoColorSpaceRegistry.h>
0016 
0017 #include <KisDocument.h>
0018 #include <kis_image.h>
0019 #include <KisMimeDatabase.h>
0020 #include <QCoreApplication>
0021 #include <QTimer>
0022 
0023 class DocumentManager::Private
0024 {
0025 public:
0026     Private()
0027         : proxy(0)
0028         , document(0)
0029         , settingsManager(0)
0030         , recentFileManager(0)
0031         , newDocWidth(0)
0032         , newDocHeight(0)
0033         , newDocResolution(0)
0034         , importingDocument(false)
0035         , temporaryFile(false)
0036     { }
0037 
0038     ProgressProxy* proxy;
0039     QPointer<KisDocument> document;
0040     Settings* settingsManager;
0041     RecentFileManager* recentFileManager;
0042 
0043     QString saveAsFilename;
0044     QString openDocumentFilename;
0045     int newDocWidth, newDocHeight; float newDocResolution;
0046     bool importingDocument;
0047     QVariantMap newDocOptions;
0048     bool temporaryFile;
0049 };
0050 
0051 DocumentManager *DocumentManager::sm_instance = 0;
0052 
0053 KisDocument* DocumentManager::document() const
0054 {
0055     return d->document;
0056 }
0057 
0058 ProgressProxy* DocumentManager::progressProxy() const
0059 {
0060     return d->proxy;
0061 }
0062 
0063 Settings* DocumentManager::settingsManager() const
0064 {
0065     return d->settingsManager;
0066 }
0067 
0068 void DocumentManager::setSettingsManager(Settings* newManager)
0069 {
0070     d->settingsManager = newManager;
0071 }
0072 
0073 RecentFileManager* DocumentManager::recentFileManager() const
0074 {
0075     return d->recentFileManager;
0076 }
0077 
0078 bool DocumentManager::isTemporaryFile() const
0079 {
0080     return d->temporaryFile;
0081 }
0082 
0083 void DocumentManager::newDocument(int width, int height, float resolution)
0084 {
0085     closeDocument();
0086 
0087     d->newDocWidth = width;
0088     d->newDocHeight = height;
0089     d->newDocResolution = resolution;
0090     QTimer::singleShot(300, this, SLOT(delayedNewDocument()));
0091 }
0092 
0093 void DocumentManager::newDocument(const QVariantMap& options)
0094 {
0095     closeDocument();
0096 
0097     d->newDocOptions = options;
0098     QTimer::singleShot(300, this, SLOT(delayedNewDocument()));
0099 }
0100 
0101 void DocumentManager::delayedNewDocument()
0102 {
0103     d->document = KisPart::instance()->createDocument();
0104 
0105     if (qAppName().contains("sketch")) {
0106         d->document->setFileBatchMode(true);
0107     }
0108 
0109     if (d->newDocOptions.isEmpty())
0110     {
0111         const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(0);
0112         QColor qc(Qt::white);
0113         qc.setAlpha(0);
0114         KoColor bgColor(qc, cs);
0115 
0116         d->document->newImage("New Image", d->newDocWidth, d->newDocHeight, KoColorSpaceRegistry::instance()->rgb8(), bgColor, KisConfig::RASTER_LAYER, 2, "", d->newDocResolution);
0117         d->document->resetPath();
0118     }
0119     else if (d->newDocOptions.contains("template")) {
0120         QUrl url(d->newDocOptions.value("template").toString().remove("template://"));
0121         bool ok = d->document->loadNativeFormat(url.toLocalFile());
0122         d->document->setModified(false);
0123         d->document->undoStack()->clear();
0124 
0125         if (ok) {
0126 
0127             QString mimeType = KisMimeDatabase::mimeTypeForFile(url.toLocalFile());
0128             // in case this is a open document template remove the -template from the end
0129             mimeType.remove( QRegExp( "-template$" ) );
0130             d->document->setMimeTypeAfterLoading(mimeType);
0131             d->document->resetPath();
0132         }
0133     }
0134     else
0135     {
0136         QString name = d->newDocOptions.value("name", "New Image").toString();
0137         int width = d->newDocOptions.value("width").toInt();
0138         int height = d->newDocOptions.value("height").toInt();
0139         // internal resolution is pixels per point, not ppi
0140         float res = d->newDocOptions.value("resolution", 72.0f).toFloat() / 72.0f;
0141 
0142         QString colorModelId = d->newDocOptions.value("colorModelId").toString();
0143         QString colorDepthId = d->newDocOptions.value("colorDepthId").toString();
0144         QString colorProfileId = d->newDocOptions.value("colorProfileId").toString();
0145 
0146         const KoColorSpace* cs;
0147         if(colorModelId.isEmpty() || colorDepthId.isEmpty() || colorProfileId.isEmpty()) {
0148             cs = KoColorSpaceRegistry::instance()->rgb8();
0149         }
0150         else
0151         {
0152             cs = KoColorSpaceRegistry::instance()->colorSpace(colorModelId, colorDepthId, colorProfileId);
0153         }
0154 
0155         QColor background = d->newDocOptions.value("backgroundColor", QColor("white")).value<QColor>();
0156         background.setAlphaF(d->newDocOptions.value("backgroundOpacity", 1.0f).toFloat());
0157         KoColor bg(background, cs);
0158 
0159         d->document->newImage(name, width, height, cs, bg, KisConfig::RASTER_LAYER, 1, "", res);
0160         d->document->resetPath();
0161     }
0162 
0163     KisPart::instance()->addDocument(d->document);
0164 
0165     d->temporaryFile = true;
0166 
0167     emit documentChanged();
0168 }
0169 
0170 void DocumentManager::openDocument(const QString& document, bool import)
0171 {
0172     closeDocument();
0173     d->openDocumentFilename = document;
0174     d->importingDocument = import;
0175     QTimer::singleShot(300, this, SLOT(delayedOpenDocument()));
0176 }
0177 
0178 void DocumentManager::delayedOpenDocument()
0179 {
0180     d->document = KisPart::instance()->createDocument();
0181     if (qAppName().contains("sketch")) {
0182         d->document->setFileBatchMode(true);
0183     }
0184 
0185     connect(d->document, SIGNAL(completed()), this, SLOT(onLoadCompleted()));
0186     connect(d->document, SIGNAL(canceled(QString)), this, SLOT(onLoadCanceled(QString)));
0187 
0188     // TODO: still needed?
0189     d->document->setModified(false);
0190     if (d->importingDocument)
0191         d->document->importDocument(d->openDocumentFilename);
0192     else
0193         d->document->openPath(d->openDocumentFilename);
0194     // TODO: handle fail of open/import
0195     d->recentFileManager->addRecent(d->openDocumentFilename);
0196 
0197     KisPart::instance()->addDocument(d->document);
0198 
0199     d->temporaryFile = false;
0200 }
0201 
0202 // Separate from openDocument to handle async loading (remote URLs)
0203 void DocumentManager::onLoadCompleted()
0204 {
0205     KisDocument *newdoc = qobject_cast<KisDocument*>(sender());
0206 
0207     disconnect(newdoc, SIGNAL(completed()), this, SLOT(onLoadCompleted()));
0208     disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(onLoadCanceled(QString)));
0209 
0210     emit documentChanged();
0211 }
0212 
0213 void DocumentManager::onLoadCanceled(const QString &/*errMsg*/)
0214 {
0215 //     if (!errMsg.isEmpty())   // empty when canceled by user
0216 //         QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg);
0217     // ... can't delete the document, it's the one who emitted the signal...
0218 
0219     KisDocument* newdoc = qobject_cast<KisDocument*>(sender());
0220     Q_ASSERT(newdoc);
0221     disconnect(newdoc, SIGNAL(completed()), this, SLOT(onLoadCompleted()));
0222     disconnect(newdoc, SIGNAL(canceled(QString)), this, SLOT(onLoadCanceled(QString)));
0223 }
0224 
0225 void DocumentManager::closeDocument()
0226 {
0227     if (d->document) {
0228         emit aboutToDeleteDocument();
0229         d->document->closePath(false);
0230         //d->document->deleteLater();
0231         d->document = 0;
0232     }
0233 }
0234 
0235 bool DocumentManager::save()
0236 {
0237 //    if (d->document->save())
0238 //    {
0239 //        d->recentFileManager->addRecent(d->document->url().toLocalFile());
0240 //        d->settingsManager->setCurrentFile(d->document->url().toLocalFile());
0241 //        emit documentSaved();
0242 //        return true;
0243 //    }
0244     return false;
0245 }
0246 
0247 void DocumentManager::saveAs(const QString &filename, const QString &mimetype)
0248 {
0249     d->document->setMimeType(mimetype.toLatin1());
0250     d->saveAsFilename = filename;
0251     // Yes. This is a massive hack. Basically, we need to wait a little while, to ensure
0252     // the save call happens late enough for a variety of UI things to happen first.
0253     // A second seems like a long time, but well, we do have file system interaction here,
0254     // so for now, we can get away with it.
0255     QTimer::singleShot(300, this, SLOT(delayedSaveAs()));
0256 }
0257 
0258 void DocumentManager::delayedSaveAs()
0259 {
0260     //d->document->saveAs(d->saveAsFilename);
0261     d->settingsManager->setCurrentFile(d->saveAsFilename);
0262     d->recentFileManager->addRecent(d->saveAsFilename);
0263     emit documentSaved();
0264 }
0265 
0266 void DocumentManager::reload()
0267 {
0268     QString path = d->document->path();
0269     closeDocument();
0270     d->openDocumentFilename = path;
0271     QTimer::singleShot(0, this, SLOT(delayedOpenDocument()));
0272 }
0273 
0274 void DocumentManager::setTemporaryFile(bool temp)
0275 {
0276     d->temporaryFile = temp;
0277     emit documentSaved();
0278 }
0279 
0280 DocumentManager* DocumentManager::instance()
0281 {
0282     if (!sm_instance) {
0283         sm_instance = new DocumentManager(QCoreApplication::instance());
0284     }
0285 
0286     return sm_instance;
0287 }
0288 
0289 DocumentManager::DocumentManager(QObject* parent)
0290     : QObject(parent), d(new Private)
0291 {
0292     d->proxy = new ProgressProxy(this);
0293     d->recentFileManager = new RecentFileManager(this);
0294 }
0295 
0296 DocumentManager::~DocumentManager()
0297 {
0298     delete d;
0299 }
0300