File indexing completed on 2024-05-12 16:01:28
0001 /* 0002 * SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2021 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "kis_clipboard.h" 0009 0010 #include <QApplication> 0011 #include <QBuffer> 0012 #include <QClipboard> 0013 #include <QDesktopWidget> 0014 #include <QFileInfo> 0015 #include <QMessageBox> 0016 #include <QMimeData> 0017 #include <QScopedPointer> 0018 #include <QTemporaryFile> 0019 0020 // kritaglobal 0021 #include <algorithm> 0022 #include <kis_assert.h> 0023 #include <kis_debug.h> 0024 0025 // kritastore 0026 #include <KoStore.h> 0027 0028 // kritaimage 0029 #include <kis_annotation.h> 0030 #include <kis_layer_utils.h> 0031 #include <kis_paint_device.h> 0032 #include <kis_time_span.h> 0033 0034 // local 0035 #include "KisDocument.h" 0036 #include "KisImportExportManager.h" 0037 #include "KisMainWindow.h" 0038 #include "KisMimeDatabase.h" 0039 #include "KisPart.h" 0040 #include "KisRemoteFileFetcher.h" 0041 #include "dialogs/kis_dlg_missing_color_profile.h" 0042 #include "dialogs/kis_dlg_paste_format.h" 0043 #include "kis_mimedata.h" 0044 #include "kis_store_paintdevice_writer.h" 0045 0046 Q_GLOBAL_STATIC(KisClipboard, s_instance) 0047 0048 struct ClipboardImageFormat { 0049 QSet<QString> mimeTypes; 0050 QString format; 0051 }; 0052 0053 class Q_DECL_HIDDEN KisClipboardPrivate 0054 { 0055 public: 0056 KisClipboardPrivate() 0057 : clipboard(QApplication::clipboard()) 0058 { 0059 } 0060 0061 bool hasClip{}; 0062 bool pushedClipboard{}; 0063 QClipboard *clipboard; 0064 }; 0065 0066 KisClipboard::KisClipboard() 0067 : d(new KisClipboardPrivate) 0068 { 0069 // Check that we don't already have a clip ready 0070 clipboardDataChanged(); 0071 0072 // Make sure we are notified when clipboard changes 0073 connect(d->clipboard, &QClipboard::dataChanged, this, &KisClipboard::clipboardDataChanged, Qt::UniqueConnection); 0074 } 0075 0076 KisClipboard::~KisClipboard() 0077 { 0078 dbgRegistry << "deleting KisClipBoard"; 0079 delete d; 0080 } 0081 0082 KisClipboard *KisClipboard::instance() 0083 { 0084 return s_instance; 0085 } 0086 0087 void KisClipboard::setClip(KisPaintDeviceSP dev, const QPoint &topLeft, const KisTimeSpan &range) 0088 { 0089 if (!dev) 0090 return; 0091 0092 d->hasClip = true; 0093 0094 // We'll create a store (ZIP format) in memory 0095 QBuffer buffer; 0096 const auto mimeType = QByteArrayLiteral("application/x-krita-selection"); 0097 QScopedPointer<KoStore> store(KoStore::createStore(&buffer, KoStore::Write, mimeType)); 0098 KisStorePaintDeviceWriter writer(store.data()); 0099 Q_ASSERT(store); 0100 Q_ASSERT(!store->bad()); 0101 0102 // Layer data 0103 if (store->open("layerdata")) { 0104 if (!dev->write(writer)) { 0105 dev->disconnect(); 0106 store->close(); 0107 return; 0108 } 0109 store->close(); 0110 } 0111 0112 // copied frame time limits 0113 if (range.isValid() && store->open("timeRange")) { 0114 store->write(QString("%1 %2").arg(range.start()).arg(range.end()).toLatin1()); 0115 store->close(); 0116 } 0117 0118 // Coordinates 0119 if (store->open("topLeft")) { 0120 store->write(QString("%1 %2").arg(topLeft.x()).arg(topLeft.y()).toLatin1()); 0121 store->close(); 0122 } 0123 // ColorSpace id of layer data 0124 if (store->open("colormodel")) { 0125 QString csName = dev->colorSpace()->colorModelId().id(); 0126 store->write(csName.toLatin1()); 0127 store->close(); 0128 } 0129 if (store->open("colordepth")) { 0130 QString csName = dev->colorSpace()->colorDepthId().id(); 0131 store->write(csName.toLatin1()); 0132 store->close(); 0133 } 0134 0135 if (dev->colorSpace()->profile()) { 0136 const KoColorProfile *profile = dev->colorSpace()->profile(); 0137 KisAnnotationSP annotation; 0138 0139 if (profile && profile->type() == "icc" && !profile->rawData().isEmpty()) { 0140 annotation = new KisAnnotation("icc", profile->name(), profile->rawData()); 0141 0142 if (annotation) { 0143 // save layer profile 0144 if (store->open("profile.icc")) { 0145 store->write(annotation->annotation()); 0146 store->close(); 0147 } 0148 } 0149 } 0150 } 0151 0152 QMimeData *mimeData = new QMimeData; 0153 Q_CHECK_PTR(mimeData); 0154 0155 if (mimeData) { 0156 mimeData->setData(mimeType, buffer.buffer()); 0157 } 0158 0159 // We also create a QImage so we can interchange with other applications 0160 QImage qimage; 0161 KisConfig cfg(true); 0162 const KoColorProfile *monitorProfile = 0163 cfg.displayProfile(QApplication::desktop()->screenNumber(qApp->activeWindow())); 0164 qimage = dev->convertToQImage(monitorProfile, 0165 KoColorConversionTransformation::internalRenderingIntent(), 0166 KoColorConversionTransformation::internalConversionFlags()); 0167 if (!qimage.isNull() && mimeData) { 0168 mimeData->setImageData(qimage); 0169 } 0170 0171 if (mimeData) { 0172 d->pushedClipboard = true; 0173 d->clipboard->setMimeData(mimeData); 0174 } 0175 } 0176 0177 void KisClipboard::setClip(KisPaintDeviceSP dev, const QPoint &topLeft) 0178 { 0179 setClip(dev, topLeft, KisTimeSpan()); 0180 } 0181 0182 KisPaintDeviceSP 0183 KisClipboard::clip(const QRect &imageBounds, bool showPopup, int overridePasteBehaviour, KisTimeSpan *clipRange) const 0184 { 0185 const QMimeData *cbData = d->clipboard->mimeData(); 0186 0187 if (!cbData) { 0188 return nullptr; 0189 } 0190 0191 dbgUI << Q_FUNC_INFO; 0192 dbgUI << "\tFormats: " << cbData->formats(); 0193 dbgUI << "\tUrls: " << cbData->urls(); 0194 dbgUI << "\tHas images: " << cbData->hasImage(); 0195 0196 return clipFromMimeData(cbData, imageBounds, showPopup, overridePasteBehaviour, clipRange, true); 0197 } 0198 0199 KisPaintDeviceSP KisClipboard::clipFromMimeData(const QMimeData *cbData, 0200 const QRect &imageBounds, 0201 bool showPopup, 0202 int overridePasteBehaviour, 0203 KisTimeSpan *clipRange, 0204 bool useClipboardFallback) const 0205 { 0206 if (clipRange) { 0207 *clipRange = KisTimeSpan(); 0208 } 0209 0210 KisPaintDeviceSP clip = clipFromKritaSelection(cbData, imageBounds, clipRange); 0211 0212 if (!clip) { 0213 clip = clipFromBoardContents(cbData, imageBounds, showPopup, overridePasteBehaviour, useClipboardFallback); 0214 } 0215 0216 return clip; 0217 } 0218 0219 KisPaintDeviceSP 0220 KisClipboard::clipFromKritaSelection(const QMimeData *cbData, const QRect &imageBounds, KisTimeSpan *clipRange) const 0221 { 0222 const QByteArray mimeType = QByteArrayLiteral("application/x-krita-selection"); 0223 0224 KisPaintDeviceSP clip; 0225 0226 if (!cbData) { 0227 return nullptr; 0228 } 0229 0230 if (cbData->hasFormat(mimeType)) { 0231 QByteArray encodedData = cbData->data(mimeType); 0232 QBuffer buffer(&encodedData); 0233 QScopedPointer<KoStore> store(KoStore::createStore(&buffer, KoStore::Read, mimeType)); 0234 0235 const KoColorProfile *profile = 0; 0236 0237 QString csDepth, csModel; 0238 0239 // ColorSpace id of layer data 0240 if (store->hasFile("colormodel")) { 0241 store->open("colormodel"); 0242 csModel = QString(store->read(store->size())); 0243 store->close(); 0244 } 0245 0246 if (store->hasFile("colordepth")) { 0247 store->open("colordepth"); 0248 csDepth = QString(store->read(store->size())); 0249 store->close(); 0250 } 0251 0252 if (store->hasFile("profile.icc")) { 0253 QByteArray data; 0254 store->open("profile.icc"); 0255 data = store->read(store->size()); 0256 store->close(); 0257 profile = KoColorSpaceRegistry::instance()->createColorProfile(csModel, csDepth, data); 0258 } 0259 0260 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(csModel, csDepth, profile); 0261 if (cs) { 0262 clip = new KisPaintDevice(cs); 0263 0264 if (store->hasFile("layerdata")) { 0265 store->open("layerdata"); 0266 if (!clip->read(store->device())) { 0267 clip = 0; 0268 } 0269 store->close(); 0270 } 0271 0272 if (clip && !imageBounds.isEmpty()) { 0273 // load topLeft 0274 if (store->hasFile("topLeft")) { 0275 store->open("topLeft"); 0276 QString str = store->read(store->size()); 0277 store->close(); 0278 QStringList list = str.split(' '); 0279 if (list.size() == 2) { 0280 QPoint topLeft(list[0].toInt(), list[1].toInt()); 0281 clip->setX(topLeft.x()); 0282 clip->setY(topLeft.y()); 0283 } 0284 } 0285 0286 QRect clipBounds = clip->exactBounds(); 0287 0288 if (!imageBounds.contains(clipBounds) && !imageBounds.intersects(clipBounds)) { 0289 QPoint diff = imageBounds.center() - clipBounds.center(); 0290 clip->setX(clip->x() + diff.x()); 0291 clip->setY(clip->y() + diff.y()); 0292 } 0293 0294 if (store->hasFile("timeRange") && clipRange) { 0295 store->open("timeRange"); 0296 QString str = store->read(store->size()); 0297 store->close(); 0298 QStringList list = str.split(' '); 0299 if (list.size() == 2) { 0300 KisTimeSpan range = KisTimeSpan::fromTimeToTime(list[0].toInt(), list[1].toInt()); 0301 *clipRange = range; 0302 dbgUI << "Pasted time range" << range; 0303 } 0304 } 0305 } 0306 } 0307 } 0308 0309 return clip; 0310 } 0311 0312 KisPaintDeviceSP KisClipboard::clipFromKritaLayers(const QRect &imageBounds, 0313 const KoColorSpace *cs) const 0314 { 0315 const QMimeData *data = KisClipboard::instance()->layersMimeData(); 0316 0317 if (!data) { 0318 return nullptr; 0319 } 0320 0321 const auto *mimedata = qobject_cast<const KisMimeData *>(data); 0322 KIS_ASSERT_RECOVER_RETURN_VALUE(mimedata, nullptr); 0323 0324 KisNodeList nodes = mimedata->nodes(); 0325 0326 KisImageSP tempImage = new KisImage(nullptr, 0327 imageBounds.width(), 0328 imageBounds.height(), 0329 cs, 0330 "ClipImage"); 0331 for (KisNodeSP node : nodes) { 0332 tempImage->addNode(node, tempImage->root()); 0333 } 0334 tempImage->refreshGraphAsync(); 0335 tempImage->waitForDone(); 0336 0337 return tempImage->projection(); 0338 } 0339 0340 QPair<bool, KisClipboard::PasteFormatBehaviour> 0341 KisClipboard::askUserForSource(const QMimeData *cbData, 0342 bool useClipboardFallback) const 0343 { 0344 if (!cbData) { 0345 return {false, PASTE_FORMAT_ASK}; 0346 } 0347 0348 KisConfig cfg(true); 0349 0350 bool saveSourceSetting = false; 0351 0352 auto choice = (PasteFormatBehaviour)cfg.pasteFormat(false); 0353 0354 const QImage qimage = [&]() { 0355 QImage qimage = getImageFromMimeData(cbData); 0356 0357 if (qimage.isNull() && useClipboardFallback) { 0358 qimage = d->clipboard->image(); 0359 } 0360 0361 return qimage; 0362 }(); 0363 0364 if (!qimage.isNull() || cbData->hasUrls()) { 0365 const auto &urls = cbData->urls(); 0366 0367 bool local = false; 0368 bool remote = false; 0369 0370 std::for_each(urls.constBegin(), urls.constEnd(), [&](const QUrl &url) { 0371 local |= url.isLocalFile(); 0372 remote |= !url.isLocalFile(); 0373 }); 0374 0375 const bool hasMultipleFormatsAvailable = (remote && local) 0376 || (remote && !qimage.isNull()) || (local && !qimage.isNull()); 0377 0378 const bool defaultOptionUnavailable = 0379 (!remote && choice == PASTE_FORMAT_DOWNLOAD) 0380 || (!local && choice == PASTE_FORMAT_LOCAL) 0381 || (qimage.isNull() && choice == PASTE_FORMAT_CLIP); 0382 0383 dbgUI << "Incoming paste event:"; 0384 dbgUI << "\tHas attached bitmap:" << cbData->hasImage(); 0385 dbgUI << "\tHas local images:" << local; 0386 dbgUI << "\tHas remote images:" << remote; 0387 dbgUI << "\tHas multiple formats:" << hasMultipleFormatsAvailable; 0388 dbgUI << "\tDefault source preference" << choice; 0389 dbgUI << "\tDefault source available:" << !defaultOptionUnavailable; 0390 0391 if (hasMultipleFormatsAvailable && choice == PASTE_FORMAT_ASK) { 0392 KisDlgPasteFormat dlg(qApp->activeWindow()); 0393 0394 dlg.setSourceAvailable(PASTE_FORMAT_DOWNLOAD, remote); 0395 dlg.setSourceAvailable(PASTE_FORMAT_LOCAL, local); 0396 dlg.setSourceAvailable(PASTE_FORMAT_CLIP, !qimage.isNull()); 0397 0398 if (dlg.exec() != KoDialog::Accepted) { 0399 return {false, PASTE_FORMAT_ASK}; 0400 }; 0401 0402 choice = dlg.source(); 0403 0404 saveSourceSetting = dlg.remember(); 0405 } else if (defaultOptionUnavailable || choice == PASTE_FORMAT_ASK) { 0406 if (remote) { 0407 choice = PASTE_FORMAT_DOWNLOAD; 0408 } else if (local) { 0409 choice = PASTE_FORMAT_LOCAL; 0410 } else if (!qimage.isNull()) { 0411 choice = PASTE_FORMAT_CLIP; 0412 } else { 0413 return {false, PASTE_FORMAT_ASK}; 0414 } 0415 } 0416 } 0417 0418 if (saveSourceSetting) { 0419 cfg.setPasteFormat(choice); 0420 } 0421 0422 dbgUI << "Selected source for the paste:" << choice; 0423 0424 return {true, choice}; 0425 } 0426 0427 KisPaintDeviceSP KisClipboard::clipFromBoardContents( 0428 const QMimeData *cbData, 0429 const QRect &imageBounds, 0430 bool showPopup, 0431 int pasteBehaviourOverride, 0432 bool useClipboardFallback, 0433 QPair<bool, PasteFormatBehaviour> source) const 0434 { 0435 if (!cbData) { 0436 return nullptr; 0437 } 0438 0439 KisPaintDeviceSP clip; 0440 0441 PasteFormatBehaviour choice = PASTE_FORMAT_ASK; 0442 0443 if (!source.first) { 0444 choice = askUserForSource(cbData).second; 0445 } else { 0446 choice = source.second; 0447 } 0448 0449 if (choice == PASTE_FORMAT_CLIP) { 0450 const QImage qimage = [&]() { 0451 QImage qimage = getImageFromMimeData(cbData); 0452 0453 if (qimage.isNull() && useClipboardFallback) { 0454 qimage = d->clipboard->image(); 0455 } 0456 0457 return qimage; 0458 }(); 0459 0460 KIS_SAFE_ASSERT_RECOVER(!qimage.isNull()) 0461 { 0462 warnKrita << "Clipboard was cleared before loading image"; 0463 return nullptr; 0464 } 0465 0466 int behaviour = pasteBehaviourOverride; 0467 bool saveColorSetting = false; 0468 0469 KisConfig cfg(true); 0470 0471 if (pasteBehaviourOverride == -1) { 0472 behaviour = cfg.pasteBehaviour(); 0473 } 0474 0475 if (behaviour == PASTE_ASK && showPopup) { 0476 // Ask user each time. 0477 KisDlgMissingColorProfile dlg(qApp->activeWindow()); 0478 0479 if (dlg.exec() != QDialog::Accepted) { 0480 return nullptr; 0481 } 0482 0483 behaviour = dlg.source(); 0484 0485 saveColorSetting = dlg.remember(); // should we save this option to the config for next time? 0486 } 0487 0488 const KoColorSpace *cs = nullptr; 0489 const KoColorProfile *profile = nullptr; 0490 if (!profile && behaviour == PASTE_ASSUME_MONITOR) 0491 profile = cfg.displayProfile(QApplication::desktop()->screenNumber(qApp->activeWindow())); 0492 0493 cs = KoColorSpaceRegistry::instance()->rgb8(profile); 0494 if (!cs) { 0495 cs = KoColorSpaceRegistry::instance()->rgb8(); 0496 profile = cs->profile(); 0497 } 0498 0499 clip = new KisPaintDevice(cs); 0500 Q_CHECK_PTR(clip); 0501 clip->convertFromQImage(qimage, profile); 0502 0503 // save the persion's selection to the configuration if the option is checked 0504 if (saveColorSetting) { 0505 cfg.setPasteBehaviour(behaviour); 0506 } 0507 } else { 0508 const auto &urls = cbData->urls(); 0509 const auto url = std::find_if(urls.constBegin(), urls.constEnd(), [&](const QUrl &url) { 0510 if (choice == PASTE_FORMAT_DOWNLOAD) { 0511 return !url.isLocalFile(); 0512 } else if (choice == PASTE_FORMAT_LOCAL) { 0513 return url.isLocalFile(); 0514 } else { 0515 return false; 0516 } 0517 }); 0518 0519 if (url != urls.constEnd()) { 0520 clip = fetchImageByURL(*url); 0521 } 0522 } 0523 0524 if (clip && !imageBounds.isEmpty()) { 0525 QRect clipBounds = clip->exactBounds(); 0526 QPoint diff = imageBounds.center() - clipBounds.center(); 0527 clip->setX(diff.x()); 0528 clip->setY(diff.y()); 0529 } 0530 0531 return clip; 0532 } 0533 0534 void KisClipboard::clipboardDataChanged() 0535 { 0536 if (!d->pushedClipboard) { 0537 const QMimeData *cbData = d->clipboard->mimeData(); 0538 d->hasClip = (d->clipboard->mimeData()->hasImage() || cbData && cbData->hasFormat("application/x-krita-selection")); 0539 } 0540 d->pushedClipboard = false; 0541 emit clipChanged(); 0542 } 0543 0544 bool KisClipboard::hasClip() const 0545 { 0546 return d->hasClip; 0547 } 0548 0549 QSize KisClipboard::clipSize() const 0550 { 0551 const auto mimeType = QByteArrayLiteral("application/x-krita-selection"); 0552 const QMimeData *cbData = d->clipboard->mimeData(); 0553 0554 KisPaintDeviceSP clip; 0555 0556 if (cbData && cbData->hasFormat(mimeType)) { 0557 QByteArray encodedData = cbData->data(mimeType); 0558 QBuffer buffer(&encodedData); 0559 QScopedPointer<KoStore> store(KoStore::createStore(&buffer, KoStore::Read, mimeType)); 0560 const KoColorProfile *profile = 0; 0561 QString csDepth, csModel; 0562 0563 // ColorSpace id of layer data 0564 if (store->hasFile("colormodel")) { 0565 store->open("colormodel"); 0566 csModel = QString(store->read(store->size())); 0567 store->close(); 0568 } 0569 0570 if (store->hasFile("colordepth")) { 0571 store->open("colordepth"); 0572 csDepth = QString(store->read(store->size())); 0573 store->close(); 0574 } 0575 0576 if (store->hasFile("profile.icc")) { 0577 QByteArray data; 0578 store->open("profile.icc"); 0579 data = store->read(store->size()); 0580 store->close(); 0581 profile = KoColorSpaceRegistry::instance()->createColorProfile(csModel, csDepth, data); 0582 } 0583 0584 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(csModel, csDepth, profile); 0585 if (!cs) { 0586 cs = KoColorSpaceRegistry::instance()->rgb8(); 0587 } 0588 clip = new KisPaintDevice(cs); 0589 0590 if (store->hasFile("layerdata")) { 0591 store->open("layerdata"); 0592 clip->read(store->device()); 0593 store->close(); 0594 } 0595 0596 return clip->exactBounds().size(); 0597 } else { 0598 if (d->clipboard->mimeData()->hasImage()) { 0599 QImage qimage = d->clipboard->image(); 0600 return qimage.size(); 0601 } 0602 } 0603 return QSize(); 0604 } 0605 0606 void KisClipboard::setLayers(KisNodeList nodes, KisImageSP image, bool forceCopy) 0607 { 0608 /** 0609 * See a comment in KisMimeData::deepCopyNodes() 0610 */ 0611 QMimeData *data = KisMimeData::mimeForLayersDeepCopy(nodes, image, forceCopy); 0612 if (!data) 0613 return; 0614 0615 d->clipboard->setMimeData(data); 0616 } 0617 0618 bool KisClipboard::hasLayers() const 0619 { 0620 const QByteArray mimeType = QByteArrayLiteral("application/x-krita-node-internal-pointer"); 0621 return d->clipboard->mimeData()->hasFormat(mimeType); 0622 } 0623 0624 bool KisClipboard::hasLayerStyles() const 0625 { 0626 // NOTE: please don't disable the pacte action based on the 0627 // result of this function, because we allow pasting 0628 // of the layer styles as 'text/plain' 0629 0630 return d->clipboard->mimeData()->hasFormat("application/x-krita-layer-style"); 0631 } 0632 0633 const QMimeData *KisClipboard::layersMimeData() const 0634 { 0635 const QMimeData *cbData = d->clipboard->mimeData(); 0636 return cbData->hasFormat("application/x-krita-node-internal-pointer") ? cbData : 0; 0637 } 0638 0639 bool KisClipboard::hasUrls() const 0640 { 0641 return d->clipboard->mimeData()->hasUrls(); 0642 } 0643 0644 QImage KisClipboard::getImageFromMimeData(const QMimeData *cbData) const 0645 { 0646 static const QList<ClipboardImageFormat> supportedFormats = { 0647 {{"image/png"}, "PNG"}, 0648 {{"image/tiff"}, "TIFF"}, 0649 {{"image/bmp", "image/x-bmp", "image/x-MS-bmp", "image/x-win-bitmap"}, "BMP"}}; 0650 0651 QImage image; 0652 QSet<QString> clipboardMimeTypes; 0653 0654 Q_FOREACH (const QString &format, cbData->formats()) { 0655 clipboardMimeTypes << format; 0656 } 0657 0658 Q_FOREACH (const ClipboardImageFormat &item, supportedFormats) { 0659 const QSet<QString> &intersection = item.mimeTypes & clipboardMimeTypes; 0660 if (intersection.isEmpty()) { 0661 continue; 0662 } 0663 0664 const QString &format = *intersection.constBegin(); 0665 const QByteArray &imageData = cbData->data(format); 0666 if (imageData.isEmpty()) { 0667 continue; 0668 } 0669 0670 if (image.loadFromData(imageData, item.format.toLatin1())) { 0671 break; 0672 } 0673 } 0674 0675 if (image.isNull() && cbData->hasImage()) { 0676 image = qvariant_cast<QImage>(cbData->imageData()); 0677 } 0678 0679 return image; 0680 } 0681 0682 KisPaintDeviceSP KisClipboard::fetchImageByURL(const QUrl &originalUrl) const 0683 { 0684 KisPaintDeviceSP result; 0685 QUrl url(originalUrl); 0686 QScopedPointer<QTemporaryFile> tmp; 0687 0688 if (!originalUrl.isLocalFile()) { 0689 tmp.reset(new QTemporaryFile()); 0690 tmp->setAutoRemove(true); 0691 0692 // download the file and substitute the url 0693 KisRemoteFileFetcher fetcher; 0694 0695 if (!fetcher.fetchFile(originalUrl, tmp.data())) { 0696 qWarning() << "Fetching" << originalUrl << "failed"; 0697 return result; 0698 } 0699 url = QUrl::fromLocalFile(tmp->fileName()); 0700 } 0701 0702 if (url.isLocalFile()) { 0703 QFileInfo fileInfo(url.toLocalFile()); 0704 0705 QString type = KisMimeDatabase::mimeTypeForFile(url.toLocalFile()); 0706 QStringList mimes = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import); 0707 0708 if (!mimes.contains(type)) { 0709 QString msg = KisImportExportErrorCode(ImportExportCodes::FileFormatNotSupported).errorMessage(); 0710 QMessageBox::warning(KisPart::instance()->currentMainwindow(), 0711 i18nc("@title:window", "Krita"), 0712 i18n("Could not open %2.\nReason: %1.", msg, url.toDisplayString())); 0713 return result; 0714 } 0715 0716 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument()); 0717 0718 if (doc->openPath(url.toLocalFile(), KisDocument::DontAddToRecent)) { 0719 // Wait for required updates, if any. BUG: 448256 0720 KisLayerUtils::forceAllDelayedNodesUpdate(doc->image()->root()); 0721 doc->image()->waitForDone(); 0722 result = new KisPaintDevice(*doc->image()->projection()); 0723 } else { 0724 qWarning() << "Failed to import file" << url.toLocalFile(); 0725 } 0726 } 0727 0728 return result; 0729 }