File indexing completed on 2024-05-12 16:01:33
0001 /* 0002 * SPDX-FileCopyrightText: 2011 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "kis_mimedata.h" 0008 #include "kis_config.h" 0009 #include "kis_node.h" 0010 #include "kis_paint_device.h" 0011 #include "kis_shared_ptr.h" 0012 #include "kis_image.h" 0013 #include "kis_layer.h" 0014 #include "kis_shape_layer.h" 0015 #include "kis_paint_layer.h" 0016 #include "kis_clone_layer.h" 0017 #include "KisDocument.h" 0018 #include "kis_shape_controller.h" 0019 #include "KisPart.h" 0020 #include "kis_layer_utils.h" 0021 #include "kis_generator_registry.h" 0022 #include "KisGlobalResourcesInterface.h" 0023 #include "kis_filter_configuration.h" 0024 #include "kis_generator_layer.h" 0025 #include "kis_selection.h" 0026 #include "kis_node_insertion_adapter.h" 0027 #include "kis_dummies_facade_base.h" 0028 #include "kis_node_dummies_graph.h" 0029 #include "KisImportExportManager.h" 0030 #include "KisImageBarrierLockerWithFeedback.h" 0031 0032 #include <KoProperties.h> 0033 #include <KoStore.h> 0034 #include <KoColorProfile.h> 0035 #include <KoColorSpaceRegistry.h> 0036 0037 #include <QApplication> 0038 #include <QImage> 0039 #include <QByteArray> 0040 #include <QBuffer> 0041 #include <QDomDocument> 0042 #include <QDomElement> 0043 #include <QDesktopWidget> 0044 #include <QDir> 0045 0046 namespace { 0047 KisNodeSP safeCopyNode(KisNodeSP node, bool detachClones = true) { 0048 KisCloneLayerSP cloneLayer = dynamic_cast<KisCloneLayer*>(node.data()); 0049 return cloneLayer && detachClones ? 0050 KisNodeSP(cloneLayer->reincarnateAsPaintLayer()) : node->clone(); 0051 } 0052 } 0053 0054 0055 KisMimeData::KisMimeData(QList<KisNodeSP> nodes, KisImageSP image, bool forceCopy) 0056 : QMimeData() 0057 , m_nodes(nodes) 0058 , m_forceCopy(forceCopy) 0059 , m_image(image) 0060 { 0061 Q_ASSERT(m_nodes.size() > 0); 0062 0063 KIS_SAFE_ASSERT_RECOVER_RETURN(image); 0064 0065 Q_FOREACH (KisNodeSP node, nodes) { 0066 m_copiedBounds |= KisLayerUtils::recursiveTightNodeVisibleBounds(node); 0067 } 0068 } 0069 0070 void KisMimeData::deepCopyNodes() 0071 { 0072 KisNodeList newNodes; 0073 0074 { 0075 KisImageBarrierLockerWithFeedbackAllowNull locker(m_image); 0076 Q_FOREACH (KisNodeSP node, m_nodes) { 0077 KisNodeSP newNode = safeCopyNode(node); 0078 newNode->setImage(nullptr); 0079 0080 newNodes << newNode; 0081 } 0082 } 0083 0084 m_nodes = newNodes; 0085 m_image = 0; 0086 } 0087 0088 QList<KisNodeSP> KisMimeData::nodes() const 0089 { 0090 return m_nodes; 0091 } 0092 0093 QStringList KisMimeData::formats () const 0094 { 0095 QStringList f = QMimeData::formats(); 0096 if (m_nodes.size() > 0) { 0097 f << "application/x-qt-image" 0098 << "application/zip" 0099 << "application/x-krita-node-internal-pointer"; 0100 } 0101 return f; 0102 } 0103 0104 KisDocument *createDocument(QList<KisNodeSP> nodes, KisImageSP srcImage, const QRect &copiedBounds) 0105 { 0106 KisDocument *doc = KisPart::instance()->createTemporaryDocument(); 0107 QRect rc = copiedBounds; 0108 0109 QRect offset(0, 0, rc.width(), rc.height()); 0110 rc |= offset; 0111 0112 if (rc.isEmpty() && srcImage) { 0113 rc = srcImage->bounds(); 0114 } 0115 0116 KisImageSP image = new KisImage(0, rc.width(), rc.height(), nodes.first()->colorSpace(), nodes.first()->name()); 0117 image->setAllowMasksOnRootNode(true); 0118 0119 if (srcImage) { 0120 image->setResolution(srcImage->xRes(), srcImage->yRes()); 0121 } 0122 0123 { 0124 KisImageBarrierLockerWithFeedbackAllowNull locker(srcImage); 0125 Q_FOREACH (KisNodeSP node, nodes) { 0126 KisNodeSP clonedNode = safeCopyNode(node); 0127 /// HACK ALERT: here we just initilize parent image link 0128 /// and skip initilizing shapeController! 0129 /// Ideally, we should call initializeExternalNode() 0130 /// instead. 0131 image->addNode(clonedNode); 0132 KIS_SAFE_ASSERT_RECOVER(clonedNode->image() == KisImageWSP(image)) { 0133 clonedNode->setImage(image); 0134 } 0135 } 0136 } 0137 0138 doc->setCurrentImage(image); 0139 0140 return doc; 0141 } 0142 0143 QByteArray serializeToByteArray(QList<KisNodeSP> nodes, KisImageSP srcImage, const QRect &copiedBounds) 0144 { 0145 QScopedPointer<KisDocument> doc(createDocument(nodes, srcImage, copiedBounds)); 0146 QByteArray result = doc->serializeToNativeByteArray(); 0147 0148 // avoid a sanity check failure caused by the fact that the image outlives 0149 // the document (and it does) 0150 doc->setCurrentImage(0); 0151 0152 return result; 0153 } 0154 0155 QVariant KisMimeData::retrieveData(const QString &mimetype, QVariant::Type preferredType) const 0156 { 0157 /** 0158 * HACK ALERT: 0159 * 0160 * Sometimes Qt requests the data *after* destruction of Krita, 0161 * we cannot load the nodes in that case, because we need signals 0162 * and timers. So we just skip serializing. 0163 */ 0164 if (!QApplication::instance()) return QVariant(); 0165 0166 0167 Q_ASSERT(m_nodes.size() > 0); 0168 0169 if (mimetype == "application/x-qt-image") { 0170 KisConfig cfg(true); 0171 0172 QScopedPointer<KisDocument> doc(createDocument(m_nodes, m_image, m_copiedBounds)); 0173 0174 return doc->image()->projection()->convertToQImage(cfg.displayProfile(QApplication::desktop()->screenNumber(qApp->activeWindow())), 0175 KoColorConversionTransformation::internalRenderingIntent(), 0176 KoColorConversionTransformation::internalConversionFlags()); 0177 } 0178 else if (mimetype == "application/zip") { 0179 0180 QByteArray ba = serializeToByteArray(m_nodes, m_image, m_copiedBounds); 0181 return ba; 0182 0183 } 0184 else if (mimetype == "application/x-krita-node-internal-pointer") { 0185 0186 QDomDocument doc("krita_internal_node_pointer"); 0187 QDomElement root = doc.createElement("pointer"); 0188 root.setAttribute("application_pid", (qint64)QApplication::applicationPid()); 0189 root.setAttribute("force_copy", m_forceCopy); 0190 root.setAttribute("image_pointer_value", (qint64)m_image.data()); 0191 doc.appendChild(root); 0192 0193 Q_FOREACH (KisNodeSP node, m_nodes) { 0194 QDomElement element = doc.createElement("node"); 0195 element.setAttribute("pointer_value", (qint64)node.data()); 0196 root.appendChild(element); 0197 } 0198 0199 return doc.toByteArray(); 0200 0201 } 0202 else { 0203 return QMimeData::retrieveData(mimetype, preferredType); 0204 } 0205 } 0206 0207 void KisMimeData::initializeExternalNode(KisNodeSP *node, 0208 KisImageSP srcImage, 0209 KisImageSP dstImage, 0210 KisShapeController *shapeController) 0211 { 0212 KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node->data()); 0213 if (shapeLayer) { 0214 // attach the layer to a new shape controller 0215 KisShapeLayer *shapeLayer2 = new KisShapeLayer(*shapeLayer, shapeController); 0216 0217 if (srcImage 0218 && (!qFuzzyCompare(dstImage->xRes(), srcImage->xRes()) 0219 || !qFuzzyCompare(dstImage->yRes(), srcImage->yRes()))) { 0220 0221 const QTransform t = QTransform::fromScale(srcImage->xRes() / dstImage->xRes(), 0222 srcImage->yRes() / dstImage->yRes()); 0223 0224 shapeLayer2->setTransformation(shapeLayer2->transformation() * t); 0225 } 0226 0227 *node = shapeLayer2; 0228 } 0229 } 0230 0231 QList<KisNodeSP> KisMimeData::tryLoadInternalNodes(const QMimeData *data, 0232 KisImageSP image, 0233 KisShapeController *shapeController, 0234 bool /* IN-OUT */ ©Node) 0235 { 0236 QList<KisNodeSP> nodes; 0237 bool forceCopy = false; 0238 KisImageSP sourceImage; 0239 0240 // Qt 4.7 and Qt 5.5 way 0241 const KisMimeData *mimedata = qobject_cast<const KisMimeData*>(data); 0242 if (mimedata) { 0243 nodes = mimedata->nodes(); 0244 forceCopy = mimedata->m_forceCopy; 0245 sourceImage = mimedata->m_image; 0246 } 0247 0248 // Qt 4.8 way 0249 if (nodes.isEmpty() && data->hasFormat("application/x-krita-node-internal-pointer")) { 0250 QByteArray nodeXml = data->data("application/x-krita-node-internal-pointer"); 0251 0252 QDomDocument doc; 0253 doc.setContent(nodeXml); 0254 0255 QDomElement element = doc.documentElement(); 0256 qint64 pid = element.attribute("application_pid").toLongLong(); 0257 forceCopy = element.attribute("force_copy").toInt(); 0258 qint64 imagePointerValue = element.attribute("image_pointer_value").toLongLong(); 0259 sourceImage = reinterpret_cast<KisImage*>(imagePointerValue); 0260 0261 if (pid == QApplication::applicationPid()) { 0262 0263 QDomNode n = element.firstChild(); 0264 while (!n.isNull()) { 0265 QDomElement e = n.toElement(); 0266 if (!e.isNull()) { 0267 qint64 pointerValue = e.attribute("pointer_value").toLongLong(); 0268 if (pointerValue) { 0269 nodes << reinterpret_cast<KisNode*>(pointerValue); 0270 } 0271 } 0272 n = n.nextSibling(); 0273 } 0274 } 0275 } 0276 0277 if (!nodes.isEmpty() && (forceCopy || copyNode || sourceImage != image)) { 0278 KisImageBarrierLockerWithFeedbackAllowNull locker(sourceImage); 0279 0280 QList<KisNodeSP> clones; 0281 Q_FOREACH (KisNodeSP node, nodes) { 0282 node = safeCopyNode(node, sourceImage != image); 0283 if ((forceCopy || copyNode) && sourceImage == image) { 0284 KisLayerUtils::addCopyOfNameTag(node); 0285 } 0286 initializeExternalNode(&node, sourceImage, image, shapeController); 0287 clones << node; 0288 } 0289 nodes = clones; 0290 copyNode = true; 0291 } 0292 return nodes; 0293 } 0294 0295 QList<KisNodeSP> KisMimeData::loadNonNativeNodes(const QMimeData *data, 0296 KisImageWSP image, 0297 KisShapeController *shapeController) 0298 { 0299 bool doRecenter = false; 0300 QList<KisNodeSP> nodes; 0301 0302 if (nodes.isEmpty() && (data->hasFormat("application/x-color") || data->hasFormat("krita/x-colorsetentry"))) { 0303 QColor color = data->hasColor() ? qvariant_cast<QColor>(data->colorData()) : QColor(255, 0, 255); 0304 if (!data->hasColor() && data->hasFormat("krita/x-colorsetentry")) { 0305 QByteArray byteData = data->data("krita/x-colorsetentry"); 0306 KisSwatch s = KisSwatch::fromByteArray(byteData); 0307 color = s.color().toQColor(); 0308 } 0309 KisGeneratorSP generator = KisGeneratorRegistry::instance()->value("color"); 0310 KisFilterConfigurationSP defaultConfig = generator->factoryConfiguration(KisGlobalResourcesInterface::instance()); 0311 defaultConfig->setProperty("color", color); 0312 defaultConfig->createLocalResourcesSnapshot(KisGlobalResourcesInterface::instance()); 0313 0314 if (image) { 0315 KisGeneratorLayerSP fillLayer = new KisGeneratorLayer(image, image->nextLayerName(i18n("Fill Layer")), 0316 defaultConfig, image->globalSelection()); 0317 nodes << fillLayer; 0318 } 0319 } 0320 0321 if (nodes.isEmpty() && data->hasImage()) { 0322 QImage qimage = qvariant_cast<QImage>(data->imageData()); 0323 0324 KisPaintDeviceSP device = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8()); 0325 device->convertFromQImage(qimage, 0); 0326 0327 if (image) { 0328 nodes << new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, device); 0329 } 0330 0331 doRecenter = true; 0332 } 0333 0334 if (!nodes.isEmpty() && doRecenter) { 0335 const QRect imageBounds = image->bounds(); 0336 0337 Q_FOREACH (KisNodeSP node, nodes) { 0338 const QRect layerBounds = node->projection()->exactBounds(); 0339 if (doRecenter) { 0340 QPoint pt = imageBounds.center() - layerBounds.center(); 0341 node->setX(pt.x()); 0342 node->setY(pt.y()); 0343 } 0344 } 0345 } 0346 0347 return nodes; 0348 } 0349 0350 QMimeData* KisMimeData::mimeForLayers(const KisNodeList &nodes, KisImageSP image, bool forceCopy) 0351 { 0352 KisNodeList inputNodes = nodes; 0353 KisNodeList sortedNodes; 0354 KisLayerUtils::sortMergableNodes(image->root(), inputNodes, sortedNodes); 0355 if (sortedNodes.isEmpty()) return 0; 0356 0357 KisMimeData* data = new KisMimeData(sortedNodes, image, forceCopy); 0358 return data; 0359 } 0360 0361 QMimeData* KisMimeData::mimeForLayersDeepCopy(const KisNodeList &nodes, KisImageSP image, bool forceCopy) 0362 { 0363 KisNodeList inputNodes = nodes; 0364 KisNodeList sortedNodes; 0365 KisLayerUtils::sortMergableNodes(image->root(), inputNodes, sortedNodes); 0366 if (sortedNodes.isEmpty()) return 0; 0367 0368 KisMimeData* data = new KisMimeData(sortedNodes, image, forceCopy); 0369 data->deepCopyNodes(); 0370 return data; 0371 } 0372 0373 bool nodeAllowsAsChild(KisNodeSP parent, KisNodeList nodes) 0374 { 0375 bool result = true; 0376 Q_FOREACH (KisNodeSP node, nodes) { 0377 if (!parent->allowAsChild(node) || !parent->isEditable(false)) { 0378 result = false; 0379 break; 0380 } 0381 } 0382 return result; 0383 } 0384 0385 bool correctNewNodeLocation(KisNodeList nodes, 0386 KisNodeDummy* &parentDummy, 0387 KisNodeDummy* &aboveThisDummy) 0388 { 0389 KisNodeSP parentNode = parentDummy->node(); 0390 bool result = true; 0391 0392 if(!nodeAllowsAsChild(parentDummy->node(), nodes) || 0393 (parentDummy->node()->inherits("KisGroupLayer") && parentDummy->node()->collapsed())) { 0394 aboveThisDummy = parentDummy; 0395 parentDummy = parentDummy->parent(); 0396 0397 result = (!parentDummy) ? false : 0398 correctNewNodeLocation(nodes, parentDummy, aboveThisDummy); 0399 } 0400 0401 return result; 0402 } 0403 0404 KisNodeList KisMimeData::loadNodesFast( 0405 const QMimeData *data, 0406 KisImageSP image, 0407 KisShapeController *shapeController, 0408 bool ©Node) 0409 { 0410 QList<KisNodeSP> nodes = 0411 KisMimeData::tryLoadInternalNodes(data, 0412 image, 0413 shapeController, 0414 copyNode /* IN-OUT */); 0415 0416 if (nodes.isEmpty()) { 0417 nodes = KisMimeData::loadNonNativeNodes(data, image, shapeController); 0418 /** 0419 * Don't try to move a node originating from another image, 0420 * just copy it. 0421 */ 0422 copyNode = true; 0423 } 0424 0425 return nodes; 0426 } 0427 0428 KisNodeList KisMimeData::loadNodesFastAndRecenter(const QPoint &preferredCenter, const QMimeData *data, KisImageSP image, KisShapeController *shapeController, bool ©Node) 0429 { 0430 KisNodeList nodes = loadNodesFast(data, image, shapeController, copyNode); 0431 0432 Q_FOREACH (KisNodeSP node, nodes) { 0433 const QRect layerBounds = node->exactBounds(); 0434 const QPoint offset = preferredCenter - layerBounds.center(); 0435 0436 node->setX(node->x() + offset.x()); 0437 node->setY(node->y() + offset.y()); 0438 } 0439 0440 return nodes; 0441 } 0442 0443 bool KisMimeData::insertMimeLayers(const QMimeData *data, 0444 KisImageSP image, 0445 KisShapeController *shapeController, 0446 KisNodeDummy *parentDummy, 0447 KisNodeDummy *aboveThisDummy, 0448 bool copyNode, 0449 KisNodeInsertionAdapter *nodeInsertionAdapter, 0450 bool changeOffset, 0451 QPointF offset) 0452 { 0453 QList<KisNodeSP> nodes = loadNodesFast(data, image, shapeController, copyNode /* IN-OUT */); 0454 0455 if (changeOffset) { 0456 Q_FOREACH (KisNodeSP node, nodes) { 0457 KisLayerUtils::recursiveApplyNodes(node, [offset] (KisNodeSP node){ 0458 if (node->hasEditablePaintDevice()) { 0459 KisPaintDeviceSP dev = node->paintDevice(); 0460 dev->moveTo(offset.x(), offset.y()); 0461 } 0462 }); 0463 } 0464 } 0465 0466 if (nodes.isEmpty()) return false; 0467 0468 bool result = true; 0469 0470 if (!correctNewNodeLocation(nodes, parentDummy, aboveThisDummy)) { 0471 return false; 0472 } 0473 0474 KIS_ASSERT_RECOVER(nodeInsertionAdapter) { return false; } 0475 0476 Q_ASSERT(parentDummy); 0477 KisNodeSP aboveThisNode = aboveThisDummy ? aboveThisDummy->node() : 0; 0478 if (copyNode) { 0479 nodeInsertionAdapter->addNodes(nodes, parentDummy->node(), aboveThisNode); 0480 } 0481 else { 0482 Q_ASSERT(nodes.first()->graphListener() == image.data()); 0483 nodeInsertionAdapter->moveNodes(nodes, parentDummy->node(), aboveThisNode); 0484 } 0485 0486 const bool hasDelayedNodes = 0487 std::find_if(nodes.begin(), nodes.end(), 0488 [] (KisNodeSP node) { 0489 return bool(dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data())); 0490 }) != nodes.end(); 0491 0492 if (hasDelayedNodes) { 0493 /** 0494 * We have the node juggler running, so it will delay the update of the 0495 * generator layers that might be included into the paste. To avoid 0496 * that we should forcefully to make it stop 0497 */ 0498 image->requestStrokeEnd(); 0499 } 0500 0501 return result; 0502 }