File indexing completed on 2024-05-19 04:28:54
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(QApplication::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 KisClipboard::clip(const QRect &imageBounds, bool showPopup, int overridePasteBehaviour, KisTimeSpan *clipRange) const 0183 { 0184 const QMimeData *cbData = d->clipboard->mimeData(); 0185 0186 if (!cbData) { 0187 return nullptr; 0188 } 0189 0190 dbgUI << Q_FUNC_INFO; 0191 dbgUI << "\tFormats: " << cbData->formats(); 0192 dbgUI << "\tUrls: " << cbData->urls(); 0193 dbgUI << "\tHas images: " << cbData->hasImage(); 0194 0195 return clipFromMimeData(cbData, imageBounds, showPopup, overridePasteBehaviour, clipRange, true); 0196 } 0197 0198 KisPaintDeviceSP KisClipboard::clipFromMimeData(const QMimeData *cbData, 0199 const QRect &imageBounds, 0200 bool showPopup, 0201 int overridePasteBehaviour, 0202 KisTimeSpan *clipRange, 0203 bool useClipboardFallback) const 0204 { 0205 if (clipRange) { 0206 *clipRange = KisTimeSpan(); 0207 } 0208 0209 KisPaintDeviceSP clip = clipFromKritaSelection(cbData, imageBounds, clipRange); 0210 0211 if (!clip) { 0212 clip = clipFromBoardContents(cbData, imageBounds, showPopup, overridePasteBehaviour, useClipboardFallback); 0213 } 0214 0215 return clip; 0216 } 0217 0218 KisPaintDeviceSP KisClipboard::clipFromKritaSelection(const QMimeData *cbData, const QRect &imageBounds, KisTimeSpan *clipRange) const 0219 { 0220 const QByteArray mimeType = QByteArrayLiteral("application/x-krita-selection"); 0221 0222 KisPaintDeviceSP clip; 0223 0224 if (!cbData) { 0225 return nullptr; 0226 } 0227 0228 if (cbData->hasFormat(mimeType)) { 0229 QByteArray encodedData = cbData->data(mimeType); 0230 QBuffer buffer(&encodedData); 0231 QScopedPointer<KoStore> store(KoStore::createStore(&buffer, KoStore::Read, mimeType)); 0232 0233 const KoColorProfile *profile = 0; 0234 0235 QString csDepth, csModel; 0236 0237 // ColorSpace id of layer data 0238 if (store->hasFile("colormodel")) { 0239 store->open("colormodel"); 0240 csModel = QString(store->read(store->size())); 0241 store->close(); 0242 } 0243 0244 if (store->hasFile("colordepth")) { 0245 store->open("colordepth"); 0246 csDepth = QString(store->read(store->size())); 0247 store->close(); 0248 } 0249 0250 if (store->hasFile("profile.icc")) { 0251 QByteArray data; 0252 store->open("profile.icc"); 0253 data = store->read(store->size()); 0254 store->close(); 0255 profile = KoColorSpaceRegistry::instance()->createColorProfile(csModel, csDepth, data); 0256 } 0257 0258 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(csModel, csDepth, profile); 0259 if (cs) { 0260 clip = new KisPaintDevice(cs); 0261 0262 if (store->hasFile("layerdata")) { 0263 store->open("layerdata"); 0264 if (!clip->read(store->device())) { 0265 clip = 0; 0266 } 0267 store->close(); 0268 } 0269 0270 if (clip && !imageBounds.isEmpty()) { 0271 // load topLeft 0272 if (store->hasFile("topLeft")) { 0273 store->open("topLeft"); 0274 QString str = store->read(store->size()); 0275 store->close(); 0276 QStringList list = str.split(' '); 0277 if (list.size() == 2) { 0278 QPoint topLeft(list[0].toInt(), list[1].toInt()); 0279 clip->setX(topLeft.x()); 0280 clip->setY(topLeft.y()); 0281 } 0282 } 0283 0284 QRect clipBounds = clip->exactBounds(); 0285 0286 if (!imageBounds.contains(clipBounds) && !imageBounds.intersects(clipBounds)) { 0287 QPoint diff = imageBounds.center() - clipBounds.center(); 0288 clip->setX(clip->x() + diff.x()); 0289 clip->setY(clip->y() + diff.y()); 0290 } 0291 0292 if (store->hasFile("timeRange") && clipRange) { 0293 store->open("timeRange"); 0294 QString str = store->read(store->size()); 0295 store->close(); 0296 QStringList list = str.split(' '); 0297 if (list.size() == 2) { 0298 KisTimeSpan range = KisTimeSpan::fromTimeToTime(list[0].toInt(), list[1].toInt()); 0299 *clipRange = range; 0300 dbgUI << "Pasted time range" << range; 0301 } 0302 } 0303 } 0304 } 0305 } 0306 0307 return clip; 0308 } 0309 0310 KisPaintDeviceSP KisClipboard::clipFromKritaLayers(const QRect &imageBounds, 0311 const KoColorSpace *cs) const 0312 { 0313 const QMimeData *data = KisClipboard::instance()->layersMimeData(); 0314 0315 if (!data) { 0316 return nullptr; 0317 } 0318 0319 const auto *mimedata = qobject_cast<const KisMimeData *>(data); 0320 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(mimedata, nullptr); 0321 0322 KisNodeList nodes = mimedata->nodes(); 0323 0324 if (nodes.size() > 1) { 0325 KisImageSP tempImage = new KisImage(nullptr, 0326 imageBounds.width(), 0327 imageBounds.height(), 0328 cs, 0329 "ClipImage"); 0330 for (KisNodeSP node : nodes) { 0331 tempImage->addNode(node, tempImage->root()); 0332 } 0333 tempImage->refreshGraphAsync(); 0334 tempImage->waitForDone(); 0335 0336 return tempImage->projection(); 0337 } else if (!nodes.isEmpty()) { 0338 return nodes.first()->projection(); 0339 } 0340 0341 return nullptr; 0342 } 0343 0344 QPair<bool, KisClipboard::PasteFormatBehaviour> 0345 KisClipboard::askUserForSource(const QMimeData *cbData, 0346 bool useClipboardFallback) const 0347 { 0348 if (!cbData) { 0349 return {false, PASTE_FORMAT_ASK}; 0350 } 0351 0352 KisConfig cfg(true); 0353 0354 bool saveSourceSetting = false; 0355 0356 auto choice = (PasteFormatBehaviour)cfg.pasteFormat(false); 0357 0358 const QImage qimage = [&]() { 0359 QImage qimage = getImageFromMimeData(cbData); 0360 0361 if (qimage.isNull() && useClipboardFallback) { 0362 qimage = d->clipboard->image(); 0363 } 0364 0365 return qimage; 0366 }(); 0367 0368 if (!qimage.isNull() || cbData->hasUrls()) { 0369 const auto &urls = cbData->urls(); 0370 0371 bool local = false; 0372 bool remote = false; 0373 bool isURI = false; 0374 0375 std::for_each(urls.constBegin(), urls.constEnd(), [&](const QUrl &url) { 0376 local |= url.isLocalFile(); 0377 remote |= !url.isLocalFile(); 0378 isURI |= url.scheme() == "data"; 0379 }); 0380 0381 const bool hasMultipleFormatsAvailable = (remote && local) 0382 || (remote && !qimage.isNull()) || (local && !qimage.isNull()); 0383 0384 const bool defaultOptionUnavailable = 0385 (!remote && choice == PASTE_FORMAT_DOWNLOAD) 0386 || (!local && choice == PASTE_FORMAT_LOCAL) 0387 || (qimage.isNull() && choice == PASTE_FORMAT_CLIP); 0388 0389 dbgUI << "Incoming paste event:"; 0390 dbgUI << "\tHas attached bitmap:" << cbData->hasImage(); 0391 dbgUI << "\tHas local images:" << local; 0392 dbgUI << "\tHas remote images:" << remote; 0393 dbgUI << "\tHas multiple formats:" << hasMultipleFormatsAvailable; 0394 dbgUI << "\tDefault source preference" << choice; 0395 dbgUI << "\tDefault source available:" << !defaultOptionUnavailable; 0396 dbgUI << "\tIs data URI:" << isURI; 0397 0398 if (hasMultipleFormatsAvailable && choice == PASTE_FORMAT_ASK && !isURI) { 0399 KisDlgPasteFormat dlg(qApp->activeWindow()); 0400 0401 dlg.setSourceAvailable(PASTE_FORMAT_DOWNLOAD, remote); 0402 dlg.setSourceAvailable(PASTE_FORMAT_LOCAL, local); 0403 dlg.setSourceAvailable(PASTE_FORMAT_CLIP, !qimage.isNull()); 0404 0405 if (dlg.exec() != KoDialog::Accepted) { 0406 return {false, PASTE_FORMAT_ASK}; 0407 }; 0408 0409 choice = dlg.source(); 0410 0411 saveSourceSetting = dlg.remember(); 0412 } else if (defaultOptionUnavailable || choice == PASTE_FORMAT_ASK) { 0413 if (remote) { 0414 choice = PASTE_FORMAT_DOWNLOAD; 0415 } else if (local) { 0416 choice = PASTE_FORMAT_LOCAL; 0417 } else if (!qimage.isNull()) { 0418 choice = PASTE_FORMAT_CLIP; 0419 } else { 0420 return {false, PASTE_FORMAT_ASK}; 0421 } 0422 } else if (isURI) { 0423 choice = PASTE_FORMAT_DOWNLOAD; 0424 } 0425 } 0426 0427 if (saveSourceSetting) { 0428 cfg.setPasteFormat(choice); 0429 } 0430 0431 dbgUI << "Selected source for the paste:" << choice; 0432 0433 return {true, choice}; 0434 } 0435 0436 KisPaintDeviceSP KisClipboard::clipFromBoardContents(const QMimeData *cbData, 0437 const QRect &imageBounds, 0438 bool showPopup, 0439 int pasteBehaviourOverride, 0440 bool useClipboardFallback, 0441 QPair<bool, PasteFormatBehaviour> source) const 0442 { 0443 if (!cbData) { 0444 return nullptr; 0445 } 0446 0447 KisPaintDeviceSP clip; 0448 0449 PasteFormatBehaviour choice = PASTE_FORMAT_ASK; 0450 0451 if (!source.first) { 0452 choice = askUserForSource(cbData).second; 0453 } else { 0454 choice = source.second; 0455 } 0456 0457 if (choice == PASTE_FORMAT_CLIP) { 0458 const QImage qimage = [&]() { 0459 QImage qimage = getImageFromMimeData(cbData); 0460 0461 if (qimage.isNull() && useClipboardFallback) { 0462 qimage = d->clipboard->image(); 0463 } 0464 0465 return qimage; 0466 }(); 0467 0468 KIS_SAFE_ASSERT_RECOVER(!qimage.isNull()) 0469 { 0470 warnKrita << "Clipboard was cleared before loading image"; 0471 return nullptr; 0472 } 0473 0474 int behaviour = pasteBehaviourOverride; 0475 bool saveColorSetting = false; 0476 0477 KisConfig cfg(true); 0478 0479 if (pasteBehaviourOverride == -1) { 0480 behaviour = cfg.pasteBehaviour(); 0481 } 0482 0483 if (behaviour == PASTE_ASK && showPopup) { 0484 // Ask user each time. 0485 KisDlgMissingColorProfile dlg(qApp->activeWindow()); 0486 0487 if (dlg.exec() != QDialog::Accepted) { 0488 return nullptr; 0489 } 0490 0491 behaviour = dlg.source(); 0492 0493 saveColorSetting = dlg.remember(); // should we save this option to the config for next time? 0494 } 0495 0496 const KoColorSpace *cs = nullptr; 0497 const KoColorProfile *profile = nullptr; 0498 if (!profile && behaviour == PASTE_ASSUME_MONITOR) 0499 profile = cfg.displayProfile(QApplication::desktop()->screenNumber(QApplication::activeWindow())); 0500 0501 cs = KoColorSpaceRegistry::instance()->rgb8(profile); 0502 if (!cs) { 0503 cs = KoColorSpaceRegistry::instance()->rgb8(); 0504 profile = cs->profile(); 0505 } 0506 0507 clip = new KisPaintDevice(cs); 0508 Q_CHECK_PTR(clip); 0509 clip->convertFromQImage(qimage, profile); 0510 0511 // save the user's selection to the configuration if the option is checked 0512 if (saveColorSetting) { 0513 cfg.setPasteBehaviour(behaviour); 0514 } 0515 } else { 0516 const auto &urls = cbData->urls(); 0517 const auto url = std::find_if(urls.constBegin(), urls.constEnd(), [&](const QUrl &url) { 0518 if (choice == PASTE_FORMAT_DOWNLOAD) { 0519 return !url.isLocalFile(); 0520 } else if (choice == PASTE_FORMAT_LOCAL) { 0521 return url.isLocalFile(); 0522 } else { 0523 return false; 0524 } 0525 }); 0526 0527 if (url != urls.constEnd()) { 0528 clip = fetchImageByURL(*url); 0529 } 0530 } 0531 0532 if (clip && !imageBounds.isEmpty()) { 0533 QRect clipBounds = clip->exactBounds(); 0534 QPoint diff = imageBounds.center() - clipBounds.center(); 0535 clip->setX(diff.x()); 0536 clip->setY(diff.y()); 0537 } 0538 0539 return clip; 0540 } 0541 0542 void KisClipboard::clipboardDataChanged() 0543 { 0544 if (!d->pushedClipboard) { 0545 const QMimeData *cbData = d->clipboard->mimeData(); 0546 d->hasClip = d->clipboard->mimeData()->hasImage() 0547 || (cbData && cbData->hasFormat("application/x-krita-selection")); 0548 } 0549 d->pushedClipboard = false; 0550 emit clipChanged(); 0551 } 0552 0553 bool KisClipboard::hasClip() const 0554 { 0555 return d->hasClip; 0556 } 0557 0558 QSize KisClipboard::clipSize() const 0559 { 0560 const auto mimeType = QByteArrayLiteral("application/x-krita-selection"); 0561 const QMimeData *cbData = d->clipboard->mimeData(); 0562 0563 KisPaintDeviceSP clip; 0564 0565 if (cbData && cbData->hasFormat(mimeType)) { 0566 QByteArray encodedData = cbData->data(mimeType); 0567 QBuffer buffer(&encodedData); 0568 QScopedPointer<KoStore> store(KoStore::createStore(&buffer, KoStore::Read, mimeType)); 0569 const KoColorProfile *profile = 0; 0570 QString csDepth, csModel; 0571 0572 // ColorSpace id of layer data 0573 if (store->hasFile("colormodel")) { 0574 store->open("colormodel"); 0575 csModel = QString(store->read(store->size())); 0576 store->close(); 0577 } 0578 0579 if (store->hasFile("colordepth")) { 0580 store->open("colordepth"); 0581 csDepth = QString(store->read(store->size())); 0582 store->close(); 0583 } 0584 0585 if (store->hasFile("profile.icc")) { 0586 QByteArray data; 0587 store->open("profile.icc"); 0588 data = store->read(store->size()); 0589 store->close(); 0590 profile = KoColorSpaceRegistry::instance()->createColorProfile(csModel, csDepth, data); 0591 } 0592 0593 const KoColorSpace *cs = KoColorSpaceRegistry::instance()->colorSpace(csModel, csDepth, profile); 0594 if (!cs) { 0595 cs = KoColorSpaceRegistry::instance()->rgb8(); 0596 } 0597 clip = new KisPaintDevice(cs); 0598 0599 if (store->hasFile("layerdata")) { 0600 store->open("layerdata"); 0601 clip->read(store->device()); 0602 store->close(); 0603 } 0604 0605 return clip->exactBounds().size(); 0606 } else { 0607 if (d->clipboard->mimeData()->hasImage()) { 0608 QImage qimage = d->clipboard->image(); 0609 return qimage.size(); 0610 } 0611 } 0612 return QSize(); 0613 } 0614 0615 void KisClipboard::setLayers(KisNodeList nodes, KisImageSP image, bool forceCopy) 0616 { 0617 /** 0618 * See a comment in KisMimeData::deepCopyNodes() 0619 */ 0620 QMimeData *data = KisMimeData::mimeForLayersDeepCopy(nodes, image, forceCopy); 0621 if (!data) 0622 return; 0623 0624 d->clipboard->setMimeData(data); 0625 } 0626 0627 bool KisClipboard::hasLayers() const 0628 { 0629 const QByteArray mimeType = QByteArrayLiteral("application/x-krita-node-internal-pointer"); 0630 return d->clipboard->mimeData()->hasFormat(mimeType); 0631 } 0632 0633 bool KisClipboard::hasLayerStyles() const 0634 { 0635 // NOTE: please don't disable the paste action based on the 0636 // result of this function, because we allow pasting 0637 // of the layer styles as 'text/plain' 0638 0639 return d->clipboard->mimeData()->hasFormat("application/x-krita-layer-style"); 0640 } 0641 0642 const QMimeData *KisClipboard::layersMimeData() const 0643 { 0644 const QMimeData *cbData = d->clipboard->mimeData(); 0645 return cbData->hasFormat("application/x-krita-node-internal-pointer") ? cbData : 0; 0646 } 0647 0648 bool KisClipboard::hasUrls() const 0649 { 0650 return d->clipboard->mimeData()->hasUrls(); 0651 } 0652 0653 QImage KisClipboard::getImageFromMimeData(const QMimeData *cbData) const 0654 { 0655 static const QList<ClipboardImageFormat> supportedFormats = { 0656 {{"image/png"}, "PNG"}, 0657 {{"image/tiff"}, "TIFF"}, 0658 {{"image/bmp", "image/x-bmp", "image/x-MS-bmp", "image/x-win-bitmap"}, "BMP"}}; 0659 0660 QImage image; 0661 QSet<QString> clipboardMimeTypes; 0662 0663 Q_FOREACH (const QString &format, cbData->formats()) { 0664 clipboardMimeTypes << format; 0665 } 0666 0667 Q_FOREACH (const ClipboardImageFormat &item, supportedFormats) { 0668 const QSet<QString> &intersection = item.mimeTypes & clipboardMimeTypes; 0669 if (intersection.isEmpty()) { 0670 continue; 0671 } 0672 0673 const QString &format = *intersection.constBegin(); 0674 const QByteArray &imageData = cbData->data(format); 0675 if (imageData.isEmpty()) { 0676 continue; 0677 } 0678 0679 if (image.loadFromData(imageData, item.format.toLatin1())) { 0680 break; 0681 } 0682 } 0683 0684 if (image.isNull() && cbData->hasImage()) { 0685 image = qvariant_cast<QImage>(cbData->imageData()); 0686 } 0687 0688 return image; 0689 } 0690 0691 KisPaintDeviceSP KisClipboard::fetchImageByURL(const QUrl &originalUrl) const 0692 { 0693 KisPaintDeviceSP result; 0694 QUrl url(originalUrl); 0695 QScopedPointer<QTemporaryFile> tmp; 0696 0697 if (!originalUrl.isLocalFile()) { 0698 tmp.reset(new QTemporaryFile()); 0699 tmp->setAutoRemove(true); 0700 0701 // download the file and substitute the url 0702 KisRemoteFileFetcher fetcher; 0703 0704 if (!fetcher.fetchFile(originalUrl, tmp.data())) { 0705 qWarning() << "Fetching" << originalUrl << "failed"; 0706 return result; 0707 } 0708 url = QUrl::fromLocalFile(tmp->fileName()); 0709 } 0710 0711 if (url.isLocalFile()) { 0712 QFileInfo fileInfo(url.toLocalFile()); 0713 0714 QString type = KisMimeDatabase::mimeTypeForFile(url.toLocalFile()); 0715 QStringList mimes = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Import); 0716 0717 if (!mimes.contains(type)) { 0718 QString msg = KisImportExportErrorCode(ImportExportCodes::FileFormatNotSupported).errorMessage(); 0719 QMessageBox::warning(KisPart::instance()->currentMainwindow(), 0720 i18nc("@title:window", "Krita"), 0721 i18n("Could not open %2.\nReason: %1.", msg, url.toDisplayString())); 0722 return result; 0723 } 0724 0725 QScopedPointer<KisDocument> doc(KisPart::instance()->createDocument()); 0726 0727 if (doc->openPath(url.toLocalFile(), KisDocument::DontAddToRecent)) { 0728 // Wait for required updates, if any. BUG: 448256 0729 KisLayerUtils::forceAllDelayedNodesUpdate(doc->image()->root()); 0730 doc->image()->waitForDone(); 0731 result = new KisPaintDevice(*doc->image()->projection()); 0732 } else { 0733 qWarning() << "Failed to import file" << url.toLocalFile(); 0734 } 0735 } 0736 0737 return result; 0738 }