File indexing completed on 2024-12-22 04:12:32

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_shape_controller.h"
0008 
0009 
0010 #include <klocalizedstring.h>
0011 
0012 #include <KoShape.h>
0013 #include <KoShapeContainer.h>
0014 #include <KoShapeManager.h>
0015 #include <KoCanvasBase.h>
0016 #include <KoToolManager.h>
0017 #include <KisView.h>
0018 #include <KoSelection.h>
0019 #include <KoShapeLayer.h>
0020 #include <KoPathShape.h>
0021 #include <KoColorSpaceConstants.h>
0022 #include <KoCanvasController.h>
0023 
0024 #include "kis_node_manager.h"
0025 #include "kis_shape_selection.h"
0026 #include "kis_selection.h"
0027 #include "kis_selection_component.h"
0028 #include "kis_adjustment_layer.h"
0029 #include "kis_clone_layer.h"
0030 #include "canvas/kis_canvas2.h"
0031 #include "KisDocument.h"
0032 #include "kis_image.h"
0033 #include "kis_group_layer.h"
0034 #include "kis_node_shape.h"
0035 #include "kis_node_shapes_graph.h"
0036 #include "kis_name_server.h"
0037 #include "kis_mask.h"
0038 #include "kis_shape_layer.h"
0039 #include "KisViewManager.h"
0040 #include "kis_node.h"
0041 
0042 #include <KoDocumentResourceManager.h>
0043 #include <commands/kis_image_layer_add_command.h>
0044 #include <kis_undo_adapter.h>
0045 #include "KoSelectedShapesProxy.h"
0046 #include "kis_signal_auto_connection.h"
0047 
0048 #include "KoAddRemoveShapeCommands.h"
0049 
0050 
0051 struct KisShapeController::Private
0052 {
0053 public:
0054     KisNameServer *nameServer;
0055     KisSignalAutoConnectionsStore imageConnections;
0056 
0057     KisNodeShapesGraph shapesGraph;
0058 };
0059 
0060 KisShapeController::KisShapeController(KisNameServer *nameServer, KUndo2Stack *undoStack, QObject *parent)
0061     : KisDummiesFacadeBase(parent)
0062     , m_d(new Private())
0063 {
0064     m_d->nameServer = nameServer;
0065     resourceManager()->setUndoStack(undoStack);
0066 }
0067 
0068 
0069 KisShapeController::~KisShapeController()
0070 {
0071     KisNodeDummy *node = m_d->shapesGraph.rootDummy();
0072     if (node) {
0073         m_d->shapesGraph.removeNode(node->node());
0074     }
0075 
0076     delete m_d;
0077 }
0078 
0079 void KisShapeController::slotUpdateDocumentResolution()
0080 {
0081     KisImageSP image = this->image();
0082 
0083     if (image) {
0084         const qreal pixelsPerInch = image->xRes() * 72.0;
0085         resourceManager()->setResource(KoDocumentResourceManager::DocumentResolution, pixelsPerInch);
0086     }
0087 }
0088 
0089 void KisShapeController::slotUpdateDocumentSize()
0090 {
0091     KisImageSP image = this->image();
0092 
0093     if (image) {
0094         resourceManager()->setResource(KoDocumentResourceManager::DocumentRectInPixels, image->bounds());
0095     }
0096 }
0097 
0098 void KisShapeController::addNodeImpl(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis)
0099 {
0100     KisNodeShape *newShape =
0101         m_d->shapesGraph.addNode(node, parent, aboveThis);
0102     // XXX: what are we going to do with this shape?
0103     Q_UNUSED(newShape);
0104 
0105     KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node.data());
0106     if (shapeLayer) {
0107         /**
0108          * Forward signals for global shape manager
0109          * \see comment in the constructor of KisCanvas2
0110          */
0111         connect(shapeLayer, SIGNAL(selectionChanged()),
0112                 SIGNAL(selectionChanged()));
0113         connect(shapeLayer->shapeManager(), SIGNAL(selectionContentChanged()),
0114                 SIGNAL(selectionContentChanged()));
0115         connect(shapeLayer, SIGNAL(currentLayerChanged(const KoShapeLayer*)),
0116                 SIGNAL(currentLayerChanged(const KoShapeLayer*)));
0117     }
0118 }
0119 
0120 void KisShapeController::removeNodeImpl(KisNodeSP node)
0121 {
0122     KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node.data());
0123     if (shapeLayer) {
0124         shapeLayer->disconnect(this);
0125     }
0126 
0127     m_d->shapesGraph.removeNode(node);
0128 }
0129 
0130 bool KisShapeController::hasDummyForNode(KisNodeSP node) const
0131 {
0132     return m_d->shapesGraph.containsNode(node);
0133 }
0134 
0135 KisNodeDummy* KisShapeController::dummyForNode(KisNodeSP node) const
0136 {
0137     return m_d->shapesGraph.nodeToDummy(node);
0138 }
0139 
0140 KisNodeDummy* KisShapeController::rootDummy() const
0141 {
0142     return m_d->shapesGraph.rootDummy();
0143 }
0144 
0145 int KisShapeController::dummiesCount() const
0146 {
0147     return m_d->shapesGraph.shapesCount();
0148 }
0149 static inline bool belongsToShapeSelection(KoShape* shape) {
0150     return dynamic_cast<KisShapeSelectionMarker*>(shape->userData());
0151 }
0152 
0153 KoShapeContainer *KisShapeController::createParentForShapes(const QList<KoShape *> shapes, KUndo2Command *parentCommand)
0154 {
0155     KoShapeContainer *resultParent = 0;
0156     KisCommandUtils::CompositeCommand *resultCommand =
0157         new KisCommandUtils::CompositeCommand(parentCommand);
0158 
0159     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!shapes.isEmpty(), resultParent);
0160     Q_FOREACH (KoShape *shape, shapes) {
0161         KIS_SAFE_ASSERT_RECOVER_BREAK(!shape->parent());
0162     }
0163 
0164     KisCanvas2 *canvas = dynamic_cast<KisCanvas2*>(KoToolManager::instance()->activeCanvasController()->canvas());
0165     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas, resultParent);
0166 
0167     const bool baseBelongsToSelection = belongsToShapeSelection(shapes.first());
0168     bool allSameBelongsToShapeSelection = true;
0169 
0170     Q_FOREACH (KoShape *shape, shapes) {
0171         allSameBelongsToShapeSelection &= belongsToShapeSelection(shape) == baseBelongsToSelection;
0172     }
0173 
0174     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(!baseBelongsToSelection || allSameBelongsToShapeSelection, resultParent);
0175 
0176     if (baseBelongsToSelection && allSameBelongsToShapeSelection) {
0177         KisSelectionSP selection = canvas->viewManager()->selection();
0178         if (selection) {
0179             KisSelectionComponent* shapeSelectionComponent = selection->shapeSelection();
0180 
0181             if (!shapeSelectionComponent) {
0182                 shapeSelectionComponent = new KisShapeSelection(this, selection);
0183                 resultCommand->addCommand(selection->convertToVectorSelection(shapeSelectionComponent));
0184             }
0185 
0186             KisShapeSelection * shapeSelection = static_cast<KisShapeSelection*>(shapeSelectionComponent);
0187             resultParent = shapeSelection;
0188         }
0189     } else {
0190         KisShapeLayer *shapeLayer =
0191                 dynamic_cast<KisShapeLayer*>(
0192                     canvas->selectedShapesProxy()->selection()->activeLayer());
0193 
0194         if (!shapeLayer) {
0195             shapeLayer = new KisShapeLayer(this, image(),
0196                                            i18n("Vector Layer %1", m_d->nameServer->number()),
0197                                            OPACITY_OPAQUE_U8);
0198 
0199             resultCommand->addCommand(
0200                         new KisImageLayerAddCommand(image(),
0201                                                     shapeLayer,
0202                                                     image()->rootLayer(),
0203                                                     image()->rootLayer()->childCount()));
0204         }
0205 
0206         resultParent = shapeLayer;
0207     }
0208 
0209     return resultParent;
0210 }
0211 
0212 QRectF KisShapeController::documentRectInPixels() const
0213 {
0214     KisImageSP image = this->image();
0215     return image ? image->bounds() : QRect(0, 0, 666, 777);
0216 }
0217 
0218 qreal KisShapeController::pixelsPerInch() const
0219 {
0220     KisImageSP image = this->image();
0221     return image ? image->xRes() * 72.0 : 72.0;
0222 }
0223 
0224 void KisShapeController::setInitialShapeForCanvas(KisCanvas2 *canvas)
0225 {
0226     if (!image()) return;
0227 
0228     KisNodeSP rootNode = image()->root();
0229 
0230     if (m_d->shapesGraph.containsNode(rootNode)) {
0231         Q_ASSERT(canvas);
0232         Q_ASSERT(canvas->shapeManager());
0233         KoSelection *selection = canvas->shapeManager()->selection();
0234         if (selection && m_d->shapesGraph.nodeToShape(rootNode)) {
0235             selection->select(m_d->shapesGraph.nodeToShape(rootNode));
0236             KoToolManager::instance()->switchToolRequested(KoToolManager::instance()->preferredToolForSelection(selection->selectedShapes()));
0237         }
0238     }
0239 }
0240 
0241 void KisShapeController::setImage(KisImageWSP image)
0242 {
0243     m_d->imageConnections.clear();
0244 
0245     if (image) {
0246         m_d->imageConnections.addConnection(image, SIGNAL(sigResolutionChanged(double, double)), this, SLOT(slotUpdateDocumentResolution()));
0247         m_d->imageConnections.addConnection(image, SIGNAL(sigSizeChanged(QPointF, QPointF)), this, SLOT(slotUpdateDocumentSize()));
0248     }
0249 
0250     KisDummiesFacadeBase::setImage(image);
0251 
0252     slotUpdateDocumentResolution();
0253     slotUpdateDocumentSize();
0254 }
0255 
0256 KoShapeLayer* KisShapeController::shapeForNode(KisNodeSP node) const
0257 {
0258     if (node) {
0259         return m_d->shapesGraph.nodeToShape(node);
0260     }
0261     return 0;
0262 }
0263