Commit 7699443c authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement KoShape::cloneShape()

This is a mandatory function to be able to load shapes from SVG,
because the same shape may be instantiated from different places.
We still need to discuss whether we need to really "share" the
shape template, but for now I just deep-copy them (which is the
easiest because of shape normalization problem we have).

There are the following drawbacks/hacks in this patch:

1) Not all the shapes have KoShape::cloneShape() implemented! Basically,
   it is defined only for group shape and all the descendants of a path
   shape (which are the only shapes used in SVG). Other shapes use the
   default implementation which simply returns null.

   Ideally, there should be no default implementation and all the shapes
   should define it. But, given that we are going to deprecate quite a lot
   of stuff, I'll keep them just unimplemented for now.

2) The following shape properties are not yet copied during cloning:

   * toolDelegates
   * dependees
   * shadow
   * border
   * filterEffectStack

   All the properties, except of tool delegates will probably be
   deprecated soon. And for the tool delegates we need to invent
   something ingenious to handle the pointers to recover pointers
   to the *cloned* shapes.

3) I cannot guarantee TextShape's work anymore. I just blindly
   refactored it to use QScopedPointer to QTextDocument instead of
   the previous raw pointers trickery and never tested it. Hope it
   still works...
parent bc68cda4
...@@ -57,7 +57,7 @@ void KoCreatePathTool::paint(QPainter &painter, const KoViewConverter &converter ...@@ -57,7 +57,7 @@ void KoCreatePathTool::paint(QPainter &painter, const KoViewConverter &converter
if (pathStarted()) { if (pathStarted()) {
KoShapeStroke *stroke(createStroke()); KoShapeStrokeSP stroke(createStroke());
if (stroke) { if (stroke) {
d->shape->setStroke(stroke); d->shape->setStroke(stroke);
...@@ -199,7 +199,7 @@ void KoCreatePathTool::mousePressEvent(KoPointerEvent *event) ...@@ -199,7 +199,7 @@ void KoCreatePathTool::mousePressEvent(KoPointerEvent *event)
d->shape = pathShape; d->shape = pathShape;
pathShape->setShapeId(KoPathShapeId); pathShape->setShapeId(KoPathShapeId);
KoShapeStroke *stroke = new KoShapeStroke(canvas()->resourceManager()->activeStroke()); KoShapeStrokeSP stroke(new KoShapeStroke(canvas()->resourceManager()->activeStroke()));
stroke->setColor(canvas()->resourceManager()->foregroundColor().toQColor()); stroke->setColor(canvas()->resourceManager()->foregroundColor().toQColor());
pathShape->setStroke(stroke); pathShape->setStroke(stroke);
...@@ -518,11 +518,11 @@ QList<QPointer<QWidget> > KoCreatePathTool::createOptionWidgets() ...@@ -518,11 +518,11 @@ QList<QPointer<QWidget> > KoCreatePathTool::createOptionWidgets()
return list; return list;
} }
KoShapeStroke *KoCreatePathTool::createStroke() KoShapeStrokeSP KoCreatePathTool::createStroke()
{ {
Q_D(KoCreatePathTool); Q_D(KoCreatePathTool);
KoShapeStroke *stroke = 0; KoShapeStrokeSP stroke;
if (d->strokeWidget) { if (d->strokeWidget) {
stroke = d->strokeWidget->createShapeStroke(); stroke = d->strokeWidget->createShapeStroke();
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "kritabasicflakes_export.h" #include "kritabasicflakes_export.h"
#include <KoFlakeTypes.h>
#include <KoToolBase.h> #include <KoToolBase.h>
#include <QList> #include <QList>
...@@ -101,7 +102,7 @@ protected: ...@@ -101,7 +102,7 @@ protected:
virtual QList<QPointer<QWidget> > createOptionWidgets(); virtual QList<QPointer<QWidget> > createOptionWidgets();
private: private:
KoShapeStroke *createStroke(); KoShapeStrokeSP createStroke();
Q_DECLARE_PRIVATE(KoCreatePathTool) Q_DECLARE_PRIVATE(KoCreatePathTool)
Q_PRIVATE_SLOT(d_func(), void angleDeltaChanged(int)) Q_PRIVATE_SLOT(d_func(), void angleDeltaChanged(int))
......
...@@ -417,9 +417,9 @@ void KoPencilTool::setDelta(double delta) ...@@ -417,9 +417,9 @@ void KoPencilTool::setDelta(double delta)
m_combineAngle = delta; m_combineAngle = delta;
} }
KoShapeStroke* KoPencilTool::createStroke() KoShapeStrokeSP KoPencilTool::createStroke()
{ {
KoShapeStroke *stroke = 0; KoShapeStrokeSP stroke;
if (m_strokeWidget) { if (m_strokeWidget) {
stroke = m_strokeWidget->createShapeStroke(); stroke = m_strokeWidget->createShapeStroke();
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#ifndef _KOPENCILTOOL_H_ #ifndef _KOPENCILTOOL_H_
#define _KOPENCILTOOL_H_ #define _KOPENCILTOOL_H_
#include "KoFlakeTypes.h"
#include "KoToolBase.h" #include "KoToolBase.h"
class KoPathShape; class KoPathShape;
...@@ -57,7 +58,7 @@ protected: ...@@ -57,7 +58,7 @@ protected:
*/ */
virtual void addPathShape(KoPathShape* path, bool closePath); virtual void addPathShape(KoPathShape* path, bool closePath);
KoShapeStroke* createStroke(); KoShapeStrokeSP createStroke();
void setFittingError(qreal fittingError); void setFittingError(qreal fittingError);
qreal getFittingError(); qreal getFittingError();
......
...@@ -35,7 +35,6 @@ set(kritaflake_SRCS ...@@ -35,7 +35,6 @@ set(kritaflake_SRCS
KoShapeApplicationData.cpp KoShapeApplicationData.cpp
KoShapeContainer.cpp KoShapeContainer.cpp
KoShapeContainerModel.cpp KoShapeContainerModel.cpp
KoShapeContainerDefaultModel.cpp
KoShapeGroup.cpp KoShapeGroup.cpp
KoShapeManagerPaintingStrategy.cpp KoShapeManagerPaintingStrategy.cpp
KoShapeManager.cpp KoShapeManager.cpp
......
...@@ -28,6 +28,26 @@ ...@@ -28,6 +28,26 @@
#include <KoShapePainter.h> #include <KoShapePainter.h>
struct Q_DECL_HIDDEN KoClipMask::Private { struct Q_DECL_HIDDEN KoClipMask::Private {
Private() {}
Private(const Private &rhs)
: coordinates(rhs.coordinates),
contentCoordinates(rhs.contentCoordinates),
maskRect(rhs.maskRect),
extraShapeTransform(rhs.extraShapeTransform)
{
Q_FOREACH (KoShape *shape, rhs.shapes) {
KoShape *clonedShape = shape->cloneShape();
KIS_ASSERT_RECOVER(clonedShape) { continue; }
shapes << clonedShape;
}
}
~Private() {
qDeleteAll(shapes);
shapes.clear();
}
CoordinateSystem coordinates = ObjectBoundingBox; CoordinateSystem coordinates = ObjectBoundingBox;
CoordinateSystem contentCoordinates = UserSpaceOnUse; CoordinateSystem contentCoordinates = UserSpaceOnUse;
...@@ -46,13 +66,11 @@ KoClipMask::KoClipMask() ...@@ -46,13 +66,11 @@ KoClipMask::KoClipMask()
KoClipMask::~KoClipMask() KoClipMask::~KoClipMask()
{ {
// TODO: yes, yes, shapes are leaked!
} }
KoClipMask::KoClipMask(const KoClipMask &rhs) KoClipMask::KoClipMask(const KoClipMask &rhs)
: m_d(new Private(*rhs.m_d)) : m_d(new Private(*rhs.m_d))
{ {
// TODO: yes, we leak shapes at the moment!
} }
KoClipMask *KoClipMask::clone() const KoClipMask *KoClipMask::clone() const
...@@ -146,4 +164,3 @@ void KoClipMask::drawMask(QPainter *painter, KoShape *shape) ...@@ -146,4 +164,3 @@ void KoClipMask::drawMask(QPainter *painter, KoShape *shape)
painter->restore(); painter->restore();
} }
...@@ -53,12 +53,14 @@ public: ...@@ -53,12 +53,14 @@ public:
~Private() ~Private()
{ {
if (deleteClipShapes) if (deleteClipShapes) {
qDeleteAll(clipPathShapes); qDeleteAll(clipPathShapes);
clipPathShapes.clear();
}
} }
QList<KoShape*> clipPathShapes; QList<KoShape*> clipPathShapes;
bool deleteClipShapes; bool deleteClipShapes; // TODO: deprecate this option!
}; };
KoClipData::KoClipData(KoPathShape *clipPathShape) KoClipData::KoClipData(KoPathShape *clipPathShape)
...@@ -85,6 +87,19 @@ KoClipData::KoClipData(const QList<KoShape*> &clipPathShapes) ...@@ -85,6 +87,19 @@ KoClipData::KoClipData(const QList<KoShape*> &clipPathShapes)
d->clipPathShapes = clipPathShapes; d->clipPathShapes = clipPathShapes;
} }
KoClipData::KoClipData(const KoClipData &rhs)
: d(new Private())
{
Q_FOREACH (KoShape *shape, rhs.d->clipPathShapes) {
KoShape *clonedShape = shape->cloneShape();
KIS_ASSERT_RECOVER(clonedShape) { continue; }
d->clipPathShapes << clonedShape;
}
d->deleteClipShapes = rhs.d->deleteClipShapes;
}
KoClipData::~KoClipData() KoClipData::~KoClipData()
{ {
delete d; delete d;
...@@ -107,6 +122,16 @@ public: ...@@ -107,6 +122,16 @@ public:
: clipData(data) : clipData(data)
{} {}
Private(const Private &rhs)
: clipData(new KoClipData(*rhs.clipData)),
clipPath(rhs.clipPath),
clipRule(rhs.clipRule),
coordinates(rhs.coordinates),
initialTransformToShape(rhs.initialTransformToShape),
initialShapeSize(rhs.initialShapeSize)
{
}
~Private() ~Private()
{ {
} }
...@@ -189,11 +214,21 @@ KoClipPath::KoClipPath(KoShape *clippedShape, KoClipData *clipData) ...@@ -189,11 +214,21 @@ KoClipPath::KoClipPath(KoShape *clippedShape, KoClipData *clipData)
d->compileClipPath(clippedShape); d->compileClipPath(clippedShape);
} }
KoClipPath::KoClipPath(const KoClipPath &rhs)
: d(new Private(*rhs.d))
{
}
KoClipPath::~KoClipPath() KoClipPath::~KoClipPath()
{ {
delete d; delete d;
} }
KoClipPath *KoClipPath::clone() const
{
return new KoClipPath(*this);
}
void KoClipPath::setClipRule(Qt::FillRule clipRule) void KoClipPath::setClipRule(Qt::FillRule clipRule)
{ {
d->clipRule = clipRule; d->clipRule = clipRule;
......
...@@ -45,6 +45,8 @@ public: ...@@ -45,6 +45,8 @@ public:
explicit KoClipData(const QList<KoShape*> &clipPathShapes); explicit KoClipData(const QList<KoShape*> &clipPathShapes);
explicit KoClipData(const KoClipData &rhs);
/// Destroys the clip path data /// Destroys the clip path data
~KoClipData(); ~KoClipData();
...@@ -87,6 +89,8 @@ public: ...@@ -87,6 +89,8 @@ public:
~KoClipPath(); ~KoClipPath();
KoClipPath *clone() const;
CoordinateSystem coordinates() const; CoordinateSystem coordinates() const;
/// Sets the clip rule to be used for the clip path /// Sets the clip rule to be used for the clip path
...@@ -116,6 +120,9 @@ public: ...@@ -116,6 +120,9 @@ public:
/// Applies the clipping to the given painter /// Applies the clipping to the given painter
static void applyClipping(KoShape *clippedShape, QPainter &painter, const KoViewConverter &converter); static void applyClipping(KoShape *clippedShape, QPainter &painter, const KoViewConverter &converter);
private:
KoClipPath(const KoClipPath &rhs);
private: private:
class Private; class Private;
Private * const d; Private * const d;
......
...@@ -49,6 +49,20 @@ KoConnectionShapePrivate::KoConnectionShapePrivate(KoConnectionShape *q) ...@@ -49,6 +49,20 @@ KoConnectionShapePrivate::KoConnectionShapePrivate(KoConnectionShape *q)
{ {
} }
KoConnectionShapePrivate::KoConnectionShapePrivate(const KoConnectionShapePrivate &rhs, KoConnectionShape *q)
: KoParameterShapePrivate(rhs, q),
path(rhs.path),
shape1(0), // FIXME: it should point to the new shapes!!!
shape2(0), // FIXME: it should point to the new shapes!!!
connectionPointId1(rhs.connectionPointId1),
connectionPointId2(rhs.connectionPointId2),
connectionType(rhs.connectionType),
forceUpdate(rhs.forceUpdate),
hasCustomPath(rhs.hasCustomPath)
{
}
QPointF KoConnectionShapePrivate::escapeDirection(int handleId) const QPointF KoConnectionShapePrivate::escapeDirection(int handleId) const
{ {
Q_Q(const KoConnectionShape); Q_Q(const KoConnectionShape);
...@@ -299,7 +313,7 @@ void KoConnectionShape::updateConnections() ...@@ -299,7 +313,7 @@ void KoConnectionShape::updateConnections()
} }
KoConnectionShape::KoConnectionShape() KoConnectionShape::KoConnectionShape()
: KoParameterShape(*(new KoConnectionShapePrivate(this))) : KoParameterShape(new KoConnectionShapePrivate(this))
{ {
Q_D(KoConnectionShape); Q_D(KoConnectionShape);
d->handles.push_back(QPointF(0, 0)); d->handles.push_back(QPointF(0, 0));
...@@ -313,6 +327,12 @@ KoConnectionShape::KoConnectionShape() ...@@ -313,6 +327,12 @@ KoConnectionShape::KoConnectionShape()
clearConnectionPoints(); clearConnectionPoints();
} }
KoConnectionShape::KoConnectionShape(const KoConnectionShape &rhs)
: KoParameterShape(new KoConnectionShapePrivate(*rhs.d_func(), this))
{
}
KoConnectionShape::~KoConnectionShape() KoConnectionShape::~KoConnectionShape()
{ {
Q_D(KoConnectionShape); Q_D(KoConnectionShape);
...@@ -322,6 +342,11 @@ KoConnectionShape::~KoConnectionShape() ...@@ -322,6 +342,11 @@ KoConnectionShape::~KoConnectionShape()
d->shape2->removeDependee(this); d->shape2->removeDependee(this);
} }
KoShape *KoConnectionShape::cloneShape() const
{
return new KoConnectionShape(*this);
}
void KoConnectionShape::saveOdf(KoShapeSavingContext & context) const void KoConnectionShape::saveOdf(KoShapeSavingContext & context) const
{ {
Q_D(const KoConnectionShape); Q_D(const KoConnectionShape);
...@@ -445,7 +470,7 @@ bool KoConnectionShape::loadOdf(const KoXmlElement & element, KoShapeLoadingCont ...@@ -445,7 +470,7 @@ bool KoConnectionShape::loadOdf(const KoXmlElement & element, KoShapeLoadingCont
if (d->hasCustomPath) { if (d->hasCustomPath) {
KoPathShapeLoader loader(this); KoPathShapeLoader loader(this);
loader.parseSvg(element.attributeNS(KoXmlNS::svg, "d"), true); loader.parseSvg(element.attributeNS(KoXmlNS::svg, "d"), true);
if (m_subpaths.size() > 0) { if (d->subpaths.size() > 0) {
QRectF viewBox = loadOdfViewbox(element); QRectF viewBox = loadOdfViewbox(element);
if (viewBox.isEmpty()) { if (viewBox.isEmpty()) {
// there should be a viewBox to transform the path data // there should be a viewBox to transform the path data
...@@ -503,8 +528,8 @@ void KoConnectionShape::finishLoadingConnection() ...@@ -503,8 +528,8 @@ void KoConnectionShape::finishLoadingConnection()
p2 = d->handles[EndHandle]; p2 = d->handles[EndHandle];
} }
QPointF relativeBegin = m_subpaths.first()->first()->point(); QPointF relativeBegin = d->subpaths.first()->first()->point();
QPointF relativeEnd = m_subpaths.last()->last()->point(); QPointF relativeEnd = d->subpaths.last()->last()->point();
QPointF diffRelative(relativeBegin - relativeEnd); QPointF diffRelative(relativeBegin - relativeEnd);
QPointF diffAbsolute(p1 - p2); QPointF diffAbsolute(p1 - p2);
......
...@@ -54,6 +54,8 @@ public: ...@@ -54,6 +54,8 @@ public:
KoConnectionShape(); KoConnectionShape();
virtual ~KoConnectionShape(); virtual ~KoConnectionShape();
KoShape* cloneShape() const override;
// reimplemented // reimplemented
virtual void saveOdf(KoShapeSavingContext &context) const; virtual void saveOdf(KoShapeSavingContext &context) const;
...@@ -124,6 +126,9 @@ public: ...@@ -124,6 +126,9 @@ public:
void updateConnections(); void updateConnections();
protected: protected:
KoConnectionShape(const KoConnectionShape &rhs);
/// reimplemented /// reimplemented
void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier); void moveHandleAction(int handleId, const QPointF &point, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include <KoShapeStroke.h> #include <KoShapeStroke.h>
#include <KoShapeLoadingContext.h> #include <KoShapeLoadingContext.h>
#include "kis_global.h"
KoConnectionShapeFactory::KoConnectionShapeFactory() KoConnectionShapeFactory::KoConnectionShapeFactory()
: KoShapeFactoryBase(KOCONNECTIONSHAPEID, i18n("Tie")) : KoShapeFactoryBase(KOCONNECTIONSHAPEID, i18n("Tie"))
{ {
...@@ -44,7 +46,7 @@ KoConnectionShapeFactory::KoConnectionShapeFactory() ...@@ -44,7 +46,7 @@ KoConnectionShapeFactory::KoConnectionShapeFactory()
KoShape* KoConnectionShapeFactory::createDefaultShape(KoDocumentResourceManager *) const KoShape* KoConnectionShapeFactory::createDefaultShape(KoDocumentResourceManager *) const
{ {
KoConnectionShape * shape = new KoConnectionShape(); KoConnectionShape * shape = new KoConnectionShape();
shape->setStroke(new KoShapeStroke()); shape->setStroke(toQShared(new KoShapeStroke()));
shape->setShapeId(KoPathShapeId); shape->setShapeId(KoPathShapeId);
return shape; return shape;
} }
......
...@@ -25,6 +25,7 @@ class KoConnectionShapePrivate : public KoParameterShapePrivate ...@@ -25,6 +25,7 @@ class KoConnectionShapePrivate : public KoParameterShapePrivate
{ {
public: public:
explicit KoConnectionShapePrivate(KoConnectionShape *q); explicit KoConnectionShapePrivate(KoConnectionShape *q);
explicit KoConnectionShapePrivate(const KoConnectionShapePrivate &rhs, KoConnectionShape *q);
/// Returns escape direction of given handle /// Returns escape direction of given handle
QPointF escapeDirection(int handleId) const; QPointF escapeDirection(int handleId) const;
......
/*
* Copyright (c) 2016 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef KOFLAKETYPES_H
#define KOFLAKETYPES_H
class KoShapeStroke;
class KoShapeStrokeModel;
template<class T> class QSharedPointer;
typedef QSharedPointer<KoShapeStrokeModel> KoShapeStrokeModelSP;
typedef QSharedPointer<KoShapeStroke> KoShapeStrokeSP;
#endif // KOFLAKETYPES_H
...@@ -350,6 +350,11 @@ KoImageData &KoImageData::operator=(const KoImageData &other) ...@@ -350,6 +350,11 @@ KoImageData &KoImageData::operator=(const KoImageData &other)
return *this; return *this;
} }
KoShapeUserData *KoImageData::clone() const
{
return new KoImageData(*this);
}
qint64 KoImageData::key() const qint64 KoImageData::key() const
{ {
return d->key; return d->key;
......
...@@ -68,6 +68,8 @@ public: ...@@ -68,6 +68,8 @@ public:
inline bool operator!=(const KoImageData &other) const { return !operator==(other); } inline bool operator!=(const KoImageData &other) const { return !operator==(other); }
bool operator==(const KoImageData &other) const; bool operator==(const KoImageData &other) const;
KoShapeUserData* clone() const override;
void setImage(const QString &location, KoStore *store, KoImageCollection *collection = 0); void setImage(const QString &location, KoStore *store, KoImageCollection *collection = 0);
/** /**
......
...@@ -24,12 +24,24 @@ ...@@ -24,12 +24,24 @@
#include <QPainter> #include <QPainter>
#include <FlakeDebug.h> #include <FlakeDebug.h>
KoParameterShapePrivate::KoParameterShapePrivate(KoParameterShape *shape)
: KoPathShapePrivate(shape),
parametric(true)
{
}
KoParameterShapePrivate::KoParameterShapePrivate(const KoParameterShapePrivate &rhs, KoParameterShape *q)
: KoPathShapePrivate(rhs, q),
handles(rhs.handles)
{
}
KoParameterShape::KoParameterShape() KoParameterShape::KoParameterShape()
: KoPathShape(*(new KoParameterShapePrivate(this))) : KoPathShape(new KoParameterShapePrivate(this))
{ {
} }
KoParameterShape::KoParameterShape(KoParameterShapePrivate &dd) KoParameterShape::KoParameterShape(KoParameterShapePrivate *dd)
: KoPathShape(dd) : KoPathShape(dd)
{ {