File indexing completed on 2024-05-12 04:35:06
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 "MetaPos.h" 0021 #include "MetaPos_p.h" 0022 0023 #include "Document.h" 0024 #include "Node.h" 0025 0026 #include <QDebug> 0027 0028 namespace tikz { 0029 namespace core { 0030 0031 MetaPos::MetaPos(Document * doc) 0032 : d(new MetaPosPrivate(this)) 0033 { 0034 Q_ASSERT(doc != nullptr); 0035 d->doc = doc; 0036 0037 Q_ASSERT(! d->nodeId.isValid()); 0038 Q_ASSERT(d->anchor.isEmpty()); 0039 } 0040 0041 MetaPos::MetaPos(const MetaPos & pos) 0042 : d(new MetaPosPrivate(this)) 0043 { 0044 d->doc = pos.d->doc; 0045 0046 // now copy object 0047 *this = pos; 0048 } 0049 0050 MetaPos::MetaPos(const QString & str, Document * document) 0051 : MetaPos(document) 0052 { 0053 fromString(str); 0054 } 0055 0056 MetaPos::~MetaPos() 0057 { 0058 delete d; 0059 } 0060 0061 Document * MetaPos::document() const 0062 { 0063 return d->doc; 0064 } 0065 0066 QString MetaPos::toString() const 0067 { 0068 if (node()) { 0069 return QString("(%1%2)") 0070 .arg(d->nodeId.toString()) 0071 .arg(d->anchor.isEmpty() ? QString() : (QLatin1Char('.') + d->anchor)); 0072 } else { 0073 return d->pos.toString(); 0074 } 0075 } 0076 0077 void MetaPos::fromString(const QString & str) 0078 { 0079 if (str.contains(QLatin1Char(','))) { 0080 setPos(tikz::Pos::fromString(str)); 0081 } else { 0082 const int openIndex = str.indexOf(QLatin1Char('(')); 0083 const int dotIndex = str.indexOf(QLatin1Char('.')); 0084 const int closeIndex = str.indexOf(QLatin1Char(')')); 0085 0086 Q_ASSERT(openIndex >= 0); 0087 Q_ASSERT(closeIndex >= openIndex); 0088 0089 d->beginChange(); 0090 const int endIndex = (dotIndex > 0) ? dotIndex : closeIndex; 0091 bool ok; 0092 d->nodeId = Uid(str.mid(openIndex + 1, endIndex - (openIndex + 1)).toLongLong(&ok), d->doc); 0093 Q_ASSERT(ok); 0094 0095 // read the anchor 0096 if (dotIndex > 0) { 0097 d->anchor = str.mid(dotIndex + 1, closeIndex - (dotIndex + 1)); 0098 } else { 0099 d->anchor.clear(); 0100 } 0101 d->endChange(); 0102 } 0103 } 0104 0105 MetaPos & MetaPos::operator=(const MetaPos & other) 0106 { 0107 if (*this == other) { 0108 return *this; 0109 } 0110 0111 // for now, only same Document is supported 0112 Q_ASSERT(d->doc == other.d->doc); 0113 0114 // start copying private data 0115 d->beginChange(); 0116 0117 // call setNode() to properly set up signals & slots 0118 setNode(other.node()); 0119 0120 // now copy rest 0121 d->doc = other.d->doc; 0122 d->pos = other.d->pos; 0123 d->anchor = other.d->anchor; 0124 0125 // calls changed 0126 d->endChange(); 0127 0128 return *this; 0129 } 0130 0131 bool MetaPos::operator==(const MetaPos & other) const 0132 { 0133 if (&other == this) { 0134 return true; 0135 } 0136 0137 if (d->doc != other.d->doc) { 0138 Q_ASSERT(d->doc == other.d->doc); 0139 return false; 0140 } 0141 0142 if (d->nodeId.isValid() || other.d->nodeId.isValid()) { 0143 return d->nodeId == other.d->nodeId 0144 && d->anchor == other.d->anchor; 0145 } 0146 0147 return d->pos == other.d->pos; 0148 } 0149 0150 bool MetaPos::operator!=(const MetaPos & other) const 0151 { 0152 return ! (*this == other); 0153 } 0154 0155 tikz::Pos MetaPos::pos() const 0156 { 0157 if (! d->nodeId.isValid()) { 0158 Q_ASSERT(node() == nullptr); 0159 return d->pos; 0160 } 0161 0162 Q_ASSERT(node() != nullptr); 0163 return document()->scenePos(*this); 0164 } 0165 0166 void MetaPos::setPos(const tikz::Pos & pos) 0167 { 0168 bool change = false; 0169 0170 // detach from node, if required 0171 Node * oldNode = node(); 0172 if (oldNode) { 0173 // disconnect changed() signal 0174 QObject::disconnect(oldNode, nullptr, d, nullptr); 0175 d->nodeId = Uid(); 0176 0177 change = true; 0178 } 0179 0180 if (d->pos != pos) { 0181 // update pos 0182 d->pos = pos; 0183 0184 change = true; 0185 } 0186 0187 // notify about change 0188 if (change) { 0189 d->changeRequest(); 0190 } 0191 } 0192 0193 bool MetaPos::setNode(Node* newNode) 0194 { 0195 Node * curNode = node(); 0196 0197 // if equal, stop 0198 if (curNode == newNode) { 0199 return false; 0200 } 0201 0202 // start changing this MetaPos 0203 d->beginChange(); 0204 0205 // detach from old node 0206 if (curNode) { 0207 // disconnect changed() signal 0208 QObject::disconnect(curNode, nullptr, d, nullptr); 0209 0210 // update pos in case the newNode is 0 0211 d->pos = pos(); 0212 } 0213 0214 // set new node and forward change() signal if applicable 0215 d->nodeId = newNode ? newNode->uid() : Uid(); 0216 curNode = node(); 0217 0218 // attach to newNode 0219 if (curNode) { 0220 // connect changed() signal to helper object 0221 QObject::connect(curNode, SIGNAL(changed()), d, SLOT(changeRequest())); 0222 } 0223 0224 // reset anchor 0225 d->anchor.clear(); 0226 0227 // notify about change 0228 d->endChange(); 0229 0230 // node was changed 0231 return true; 0232 } 0233 0234 Node* MetaPos::node() const 0235 { 0236 return d->nodeId.entity<Node>(); 0237 } 0238 0239 void MetaPos::setAnchor(const QString & anchor) 0240 { 0241 // setting an anchor only makes sense with a node 0242 Q_ASSERT(d->nodeId.isValid()); 0243 0244 if (d->anchor != anchor) { 0245 d->beginChange(); 0246 d->anchor = anchor; 0247 d->endChange(); 0248 } 0249 } 0250 0251 QString MetaPos::anchor() const 0252 { 0253 return (d->nodeId.isValid()) ? d->anchor : QString(); 0254 } 0255 0256 QObject * MetaPos::notificationObject() 0257 { 0258 return d; 0259 } 0260 0261 } 0262 } 0263 0264 namespace QTest { 0265 // Value: template specialization for QTest::toString() 0266 template<> 0267 char *toString(const tikz::core::MetaPos & metaPos) 0268 { 0269 // FIXME: Maybe not QCOMPARE fails due to different units, this may need a fix 0270 const QString str = "MetaPos[" + metaPos.toString() + "]"; 0271 const QByteArray ba = str.toLatin1(); 0272 return qstrdup(ba.data()); 0273 } 0274 } 0275 0276 // kate: indent-width 4; replace-tabs on;