File indexing completed on 2025-01-05 04:14:56

0001 /* This file is part of the TikZKit project.
0002  *
0003  * Copyright (C) 2013-2014 Dominik Haumann <dhaumann@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU Library General Public License as published
0007  * by the Free Software Foundation, either version 2 of the License, or
0008  * (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013  * GNU Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, see
0017  * <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "EdgePath.h"
0021 #include "UndoSetEdgePos.h"
0022 #include "Node.h"
0023 #include "Document.h"
0024 
0025 namespace tikz {
0026 namespace core {
0027 
0028 class EdgePathPrivate
0029 {
0030     public:
0031         EdgePathPrivate(Document * doc)
0032             : start(doc)
0033             , end(doc)
0034         {}
0035 
0036         // the element type of this edge
0037         PathType type;
0038 
0039         // start meta node this edge points to
0040         MetaPos start;
0041 
0042         // target/end meta node this edge points to
0043         MetaPos end;
0044 };
0045 
0046 EdgePath::EdgePath(PathType type, const Uid & uid)
0047     : Path(uid)
0048     , d(new EdgePathPrivate(uid.document()))
0049 {
0050     d->type = type;
0051 
0052     connect(d->start.notificationObject(), SIGNAL(changed(tikz::core::MetaPos*)), this, SLOT(emitChangedIfNeeded()));
0053     connect(d->end.notificationObject(), SIGNAL(changed(tikz::core::MetaPos*)), this, SLOT(emitChangedIfNeeded()));
0054 }
0055 
0056 EdgePath::~EdgePath()
0057 {
0058     delete d;
0059 }
0060 
0061 const tikz::core::MetaPos & EdgePath::startMetaPos() const
0062 {
0063     return d->start;
0064 }
0065 
0066 const tikz::core::MetaPos & EdgePath::endMetaPos() const
0067 {
0068     return d->end;
0069 }
0070 
0071 void EdgePath::deconstruct()
0072 {
0073     // just set both the start and end pos to (0, 0).
0074     // undo (i.e., creating the node again), will then restore the initial
0075     // connections correctly.
0076     ConfigTransaction transaction(this);
0077     setStartPos(tikz::Pos());
0078     setEndPos(tikz::Pos());
0079 }
0080 
0081 void EdgePath::detachFromNode(Node * node)
0082 {
0083     Q_ASSERT(node != nullptr);
0084 
0085     // disconnect start from node, if currently attached
0086     if (d->start.node() == node) {
0087         auto newPos = startMetaPos();
0088         newPos.setNode(nullptr);
0089         setStartMetaPos(newPos);
0090     }
0091 
0092     // disconnect end from node, if currently attached
0093     if (d->end.node() == node) {
0094         auto newPos = endMetaPos();
0095         newPos.setNode(nullptr);
0096         setEndMetaPos(newPos);
0097     }
0098 
0099     Q_ASSERT(d->start.node() != node);
0100     Q_ASSERT(d->end.node() != node);
0101 }
0102 
0103 PathType EdgePath::type() const
0104 {
0105     return d->type;
0106 }
0107 
0108 void EdgePath::setStartNode(Node* node)
0109 {
0110     auto newPos = startMetaPos();
0111     newPos.setNode(node);
0112     setStartMetaPos(newPos);
0113 
0114     Q_ASSERT(d->start.node() == node);
0115 }
0116 
0117 void EdgePath::setEndNode(Node* node)
0118 {
0119     auto newPos = endMetaPos();
0120     newPos.setNode(node);
0121     setEndMetaPos(newPos);
0122 
0123     Q_ASSERT(d->end.node() == node);
0124 }
0125 
0126 Node* EdgePath::startNode() const
0127 {
0128     return d->start.node();
0129 }
0130 
0131 Node* EdgePath::endNode()
0132 {
0133     return d->end.node();
0134 }
0135 
0136 tikz::Pos EdgePath::startPos() const
0137 {
0138     return d->start.pos();
0139 }
0140 
0141 tikz::Pos EdgePath::endPos() const
0142 {
0143     return d->end.pos();
0144 }
0145 
0146 void EdgePath::setStartPos(const tikz::Pos & pos)
0147 {
0148     auto newPos = startMetaPos();
0149     newPos.setPos(pos);
0150     setStartMetaPos(newPos);
0151 
0152     Q_ASSERT(d->start.pos() == pos);
0153 }
0154 
0155 void EdgePath::setEndPos(const tikz::Pos & pos)
0156 {
0157     auto newPos = endMetaPos();
0158     newPos.setPos(pos);
0159     setEndMetaPos(newPos);
0160 
0161     Q_ASSERT(d->end.pos() == pos);
0162 }
0163 
0164 void EdgePath::setStartMetaPos(const tikz::core::MetaPos & pos)
0165 {
0166     if (d->start == pos) {
0167         return;
0168     }
0169 
0170     if (document()->undoActive()) {
0171         ConfigTransaction transaction(this);
0172         auto oldNode = startNode();
0173         d->start = pos;
0174         auto newNode = startNode();
0175         if (oldNode != newNode) {
0176             Q_EMIT startNodeChanged(newNode);
0177         }
0178     } else {
0179         document()->addUndoItem(
0180             new UndoSetEdgePos(this, pos, true, document()));
0181     }
0182 }
0183 
0184 void EdgePath::setEndMetaPos(const tikz::core::MetaPos & pos)
0185 {
0186     if (d->end == pos) {
0187         return;
0188     }
0189 
0190     if (document()->undoActive()) {
0191         ConfigTransaction transaction(this);
0192         auto oldNode = endNode();
0193         d->end = pos;
0194         auto newNode = endNode();
0195         if (oldNode != newNode) {
0196             Q_EMIT endNodeChanged(newNode);
0197         }
0198     } else {
0199         document()->addUndoItem(
0200             new UndoSetEdgePos(this, pos, false, document()));
0201     }
0202 }
0203 
0204 QString EdgePath::startAnchor() const
0205 {
0206     return d->start.anchor();
0207 }
0208 
0209 QString EdgePath::endAnchor() const
0210 {
0211     return d->end.anchor();
0212 }
0213 
0214 void EdgePath::setStartAnchor(const QString & anchor)
0215 {
0216     auto newPos = startMetaPos();
0217     newPos.setAnchor(anchor);
0218     setStartMetaPos(newPos);
0219 
0220     Q_ASSERT(d->start.anchor() == anchor);
0221 }
0222 
0223 void EdgePath::setEndAnchor(const QString & anchor)
0224 {
0225     auto newPos = endMetaPos();
0226     newPos.setAnchor(anchor);
0227     setEndMetaPos(newPos);
0228 
0229     Q_ASSERT(d->end.anchor() == anchor);
0230 }
0231 
0232 void EdgePath::loadData(const QJsonObject & json)
0233 {
0234     ConfigTransaction transaction(this);
0235     Path::loadData(json);
0236 
0237     if (json.contains("start")) {
0238         setStartMetaPos(MetaPos(json["start"].toString(), document()));
0239     }
0240 
0241     if (json.contains("end")) {
0242         setEndMetaPos(MetaPos(json["end"].toString(), document()));
0243     }
0244 
0245     if (json.contains("style")) {
0246         const Uid styleId(json["style"].toString(), document());
0247         setStyle(styleId);
0248     }
0249 }
0250 
0251 QJsonObject EdgePath::saveData() const
0252 {
0253     QJsonObject json = Path::saveData();
0254 
0255     json["start"] = d->start.toString();
0256     json["end"] = d->end.toString();
0257     json["style"] = styleUid().toString();
0258 
0259     return json;
0260 }
0261 
0262 
0263 }
0264 }
0265 
0266 // kate: indent-width 4; replace-tabs on;