Commit 6a507fdc authored by Jan Hambrecht's avatar Jan Hambrecht

Connection points are no longer referenced by index but by their id.

This was required as ODF specifies 4 standard connection points with
reserved ids from 0-3 and custom connection points with ids > 3 .
When loading connection points they may have ids that do not relate
to their index, so things would go wrong when trying to create connections
saved to files.
A rather basic support for loading connection points was added along
with some supporting functions to check if a connection point exists or
to get a specific connection point position.
parent a72551d1
......@@ -81,6 +81,15 @@ namespace KoFlake
Foreground ///< the foreground / border style is active
};
/// Default connection point ids
enum ConnectionPointId {
TopConnectionPoint = 0,
RightConnectionPoint = 1,
BottomConnectionPoint = 2,
LeftConnectionPoint = 3,
FirstCustomConnectionPoint = 4
};
/// clones the given gradient
FLAKE_EXPORT QGradient *cloneGradient(const QGradient *gradient);
......
......@@ -105,10 +105,10 @@ KoShapePrivate::KoShapePrivate(KoShape *shape)
textRunAroundSide(KoShape::BiggestRunAroundSide),
textRunAroundDistance(1.0)
{
connectors.append(QPointF(0.5, 0.0));
connectors.append(QPointF(1.0, 0.5));
connectors.append(QPointF(0.5, 1.0));
connectors.append(QPointF(0.0, 0.5));
connectors[KoFlake::TopConnectionPoint] = defaultConnectionPoint(KoFlake::TopConnectionPoint);
connectors[KoFlake::RightConnectionPoint] = defaultConnectionPoint(KoFlake::RightConnectionPoint);
connectors[KoFlake::BottomConnectionPoint] = defaultConnectionPoint(KoFlake::BottomConnectionPoint);
connectors[KoFlake::LeftConnectionPoint] = defaultConnectionPoint(KoFlake::LeftConnectionPoint);
}
KoShapePrivate::~KoShapePrivate()
......@@ -203,7 +203,22 @@ void KoShapePrivate::removeShapeCache()
}
}
QPointF KoShapePrivate::defaultConnectionPoint(KoFlake::ConnectionPointId connectionPointId)
{
switch(connectionPointId)
{
case KoFlake::TopConnectionPoint:
return QPointF(0.5, 0.0);
case KoFlake::RightConnectionPoint:
return QPointF(1.0, 0.5);
case KoFlake::BottomConnectionPoint:
return QPointF(0.5, 1.0);
case KoFlake::LeftConnectionPoint:
return QPointF(0.0, 0.5);
default:
return QPointF();
}
}
// static
QString KoShapePrivate::getStyleProperty(const char *property, KoShapeLoadingContext &context)
{
......@@ -728,12 +743,46 @@ QPointF KoShape::position() const
return d->localMatrix.map(center) - center;
}
void KoShape::addConnectionPoint(const QPointF &point)
int KoShape::addConnectionPoint(const QPointF &point)
{
Q_D(KoShape);
QSizeF s = size();
// convert glue point from shape coordinates to factors of size
d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height()));
QPointF connectionPoint(point.x() / s.width(), point.y() / s.height());
// get next glue point id
int nextConnectionPointId = KoFlake::FirstCustomConnectionPoint;
if(d->connectors.size())
nextConnectionPointId = qMax(nextConnectionPointId, (--d->connectors.end()).key()+1);
// allow adding default connection point
if(connectionPoint == d->defaultConnectionPoint(KoFlake::TopConnectionPoint))
nextConnectionPointId = KoFlake::TopConnectionPoint;
else if(connectionPoint == d->defaultConnectionPoint(KoFlake::RightConnectionPoint))
nextConnectionPointId = KoFlake::RightConnectionPoint;
else if(connectionPoint == d->defaultConnectionPoint(KoFlake::BottomConnectionPoint))
nextConnectionPointId = KoFlake::BottomConnectionPoint;
else if(connectionPoint == d->defaultConnectionPoint(KoFlake::LeftConnectionPoint))
nextConnectionPointId = KoFlake::LeftConnectionPoint;
d->connectors[nextConnectionPointId] = connectionPoint;
return nextConnectionPointId;
}
bool KoShape::hasConnectionPoint(int connectionPointId) const
{
Q_D(const KoShape);
return d->connectors.contains(connectionPointId);
}
QPointF KoShape::connectionPoint(int connectionPointId) const
{
Q_D(const KoShape);
QSizeF s = size();
QPointF p = d->connectors.value(connectionPointId, QPointF());
p.rx() *= s.width();
p.ry() *= s.height();
return p;
}
QList<QPointF> KoShape::connectionPoints() const
......@@ -748,6 +797,18 @@ QList<QPointF> KoShape::connectionPoints() const
return points;
}
void KoShape::removeConnectionPoint(int connectionPointId)
{
Q_D(KoShape);
d->connectors.remove(connectionPointId);
}
void KoShape::clearConnectionPoints()
{
Q_D(KoShape);
d->connectors.clear();
}
void KoShape::addEventAction(KoEventAction *action)
{
Q_D(KoShape);
......@@ -1012,13 +1073,6 @@ QTransform KoShape::transform() const
return d->localMatrix;
}
void KoShape::removeConnectionPoint(int index)
{
Q_D(KoShape);
if (index < d->connectors.count())
d->connectors.remove(index);
}
QString KoShape::name() const
{
Q_D(const KoShape);
......@@ -1282,6 +1336,47 @@ bool KoShape::loadOdfAttributes(const KoXmlElement &element, KoShapeLoadingConte
d->eventActions = KoEventActionRegistry::instance()->createEventActionsFromOdf(eventActionsElement, context);
}
// load glue points (connection points)
KoXmlElement child;
forEachElement(child, element) {
if (child.namespaceURI() != KoXmlNS::draw)
continue;
if (child.localName() == "glue-point") {
const QString id = child.attributeNS(KoXmlNS::draw, "id", QString());
const int index = id.toInt();
if(id.isEmpty() || index < 4) {
kWarning(30006) << "glue-point with no or invalid id";
continue;
}
QString xStr = child.attributeNS(KoXmlNS::svg, "x", QString()).simplified();
QString yStr = child.attributeNS(KoXmlNS::svg, "y", QString()).simplified();
if(xStr.isEmpty() || yStr.isEmpty()) {
kWarning(30006) << "glue-point with invald position";
continue;
}
QPointF connectorPos;
const QRectF bbox = boundingRect();
if(child.hasAttributeNS(KoXmlNS::draw, "align")) {
// absolute distances to the edge specified by align
connectorPos.setX(KoUnit::parseValue(xStr));
connectorPos.setY(KoUnit::parseValue(yStr));
// TODO: convert position to percentage values taking align attribute into account
} else {
// x and y are relative to drawing object center
if(xStr.endsWith('%'))
connectorPos.setX(xStr.remove('%').toDouble()/100.0);
else
connectorPos.setX(KoUnit::parseValue(xStr) / bbox.width());
if(yStr.endsWith('%'))
connectorPos.setY(yStr.remove('%').toDouble()/100.0);
else
connectorPos.setY(KoUnit::parseValue(yStr) / bbox.height());
// convert position to be relative to top-left corner
connectorPos += QPointF(0.5, 0.5);
}
d->connectors[index] = connectorPos;
kDebug(30006) << "loaded glue-point" << index << "at position" << connectorPos;
}
}
}
return true;
......
......@@ -318,8 +318,15 @@ public:
* are based around the zero-pos which is the top-left of the shape
* The point does not have to be inside the boundings rectangle. The point is in pt,
* just like the rest of the KoShape class uses.
* @return the id of the new connection point
*/
void addConnectionPoint(const QPointF &point);
int addConnectionPoint(const QPointF &point);
/// Checks if a connection point with the specified id exists
bool hasConnectionPoint(int connectionPointId) const;
/// Returns connection point with specified connection point id
QPointF connectionPoint(int connectionPointId) const;
/**
* Return a list of the connection points that have been added to this shape.
......@@ -328,6 +335,12 @@ public:
*/
QList<QPointF> connectionPoints() const;
/// Removes connection point with specified id
void removeConnectionPoint(int connectionPointId);
/// Removes all connection points
void clearConnectionPoints();
/**
* Add a event action
*/
......@@ -819,9 +832,6 @@ public:
/// checks recursively if the shape or one of its parents is not visible or locked
bool isEditable() const;
/// Removes connection point with given index
void removeConnectionPoint(int index);
/**
* Adds a shape which depends on this shape.
* Making a shape dependent on this one means it will get shapeChanged() called
......
......@@ -89,7 +89,7 @@ public:
QTransform localMatrix; ///< the shapes local transformation matrix
QVector<QPointF> connectors; ///< glue points in percent of size [0..1]
QMap<int, QPointF> connectors; ///< glue point id and position in percent of size [0..1]
KoShapeContainer *parent;
QSet<KoShapeManager *> shapeManagers;
......@@ -142,6 +142,9 @@ public:
*/
void removeShapeCache();
/// Returns the specified default connection point
QPointF defaultConnectionPoint(KoFlake::ConnectionPointId connectionPointId);
Q_DECLARE_PUBLIC(KoShape)
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment