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