Warning, file /office/calligra/libs/textlayout/KoTextShapeContainerModel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2007,2009,2010 Thomas Zander <zander@kde.org> 0003 * Copyright (C) 2010 C. Boemann <cbo@kogmbh.com> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (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 GNU 0013 * 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, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KoTextShapeContainerModel.h" 0022 0023 #include "KoAnchorInlineObject.h" 0024 #include "KoTextShapeData.h" 0025 #include "KoShapeContainer.h" 0026 0027 #include <QTextBlock> 0028 #include <QTextLayout> 0029 #include <QTextLine> 0030 #include <QTextDocument> 0031 0032 #include <TextLayoutDebug.h> 0033 0034 struct Relation 0035 { 0036 Relation(KoShape *shape = 0) 0037 : child(shape), 0038 anchor(0), 0039 nested(false), 0040 inheritsTransform(false) 0041 { 0042 } 0043 KoShape *child; 0044 KoShapeAnchor *anchor; 0045 uint nested : 1; 0046 uint inheritsTransform :1; 0047 }; 0048 0049 class Q_DECL_HIDDEN KoTextShapeContainerModel::Private 0050 { 0051 public: 0052 QHash<const KoShape*, Relation> children; 0053 QList<KoShapeAnchor *> shapeRemovedAnchors; 0054 }; 0055 0056 KoTextShapeContainerModel::KoTextShapeContainerModel() 0057 : d(new Private()) 0058 { 0059 } 0060 0061 KoTextShapeContainerModel::~KoTextShapeContainerModel() 0062 { 0063 delete d; 0064 } 0065 0066 void KoTextShapeContainerModel::add(KoShape *child) 0067 { 0068 if (d->children.contains(child)) 0069 return; 0070 Relation relation(child); 0071 d->children.insert(child, relation); 0072 0073 KoShapeAnchor *toBeAddedAnchor = 0; 0074 foreach (KoShapeAnchor *anchor, d->shapeRemovedAnchors) { 0075 if (child == anchor->shape()) { 0076 toBeAddedAnchor = anchor; 0077 break; 0078 } 0079 } 0080 0081 if (toBeAddedAnchor) { 0082 addAnchor(toBeAddedAnchor); 0083 d->shapeRemovedAnchors.removeAll(toBeAddedAnchor); 0084 } 0085 } 0086 0087 void KoTextShapeContainerModel::remove(KoShape *child) 0088 { 0089 Relation relation = d->children.value(child); 0090 d->children.remove(child); 0091 if (relation.anchor) { 0092 relation.anchor->placementStrategy()->detachFromModel(); 0093 d->shapeRemovedAnchors.append(relation.anchor); 0094 } 0095 } 0096 0097 void KoTextShapeContainerModel::setClipped(const KoShape *child, bool clipping) 0098 { 0099 Q_ASSERT(d->children.contains(child)); 0100 d->children[child].nested = clipping; 0101 } 0102 0103 bool KoTextShapeContainerModel::isClipped(const KoShape *child) const 0104 { 0105 Q_ASSERT(d->children.contains(child)); 0106 return d->children[child].nested; 0107 } 0108 0109 void KoTextShapeContainerModel::setInheritsTransform(const KoShape *shape, bool inherit) 0110 { 0111 Q_ASSERT(d->children.contains(shape)); 0112 d->children[shape].inheritsTransform = inherit; 0113 } 0114 0115 bool KoTextShapeContainerModel::inheritsTransform(const KoShape *shape) const 0116 { 0117 Q_ASSERT(d->children.contains(shape)); 0118 return d->children[shape].inheritsTransform; 0119 } 0120 0121 0122 int KoTextShapeContainerModel::count() const 0123 { 0124 return d->children.count(); 0125 } 0126 0127 QList<KoShape*> KoTextShapeContainerModel::shapes() const 0128 { 0129 QList<KoShape*> answer; 0130 answer.reserve(d->children.count()); 0131 foreach (const Relation &relation, d->children) { 0132 answer << relation.child; 0133 } 0134 return answer; 0135 } 0136 0137 void KoTextShapeContainerModel::containerChanged(KoShapeContainer *container, KoShape::ChangeType type) 0138 { 0139 Q_UNUSED(container); 0140 Q_UNUSED(type); 0141 } 0142 0143 void KoTextShapeContainerModel::childChanged(KoShape *child, KoShape::ChangeType type) 0144 { 0145 if (((type == KoShape::RotationChanged || 0146 type == KoShape::ScaleChanged || 0147 type == KoShape::ShearChanged || 0148 type == KoShape::ClipPathChanged || 0149 type == KoShape::PositionChanged || 0150 type == KoShape::SizeChanged) && child->textRunAroundSide() != KoShape::RunThrough) || 0151 type == KoShape::TextRunAroundChanged) { 0152 0153 relayoutInlineObject(child); 0154 } 0155 KoShapeContainerModel::childChanged( child, type ); 0156 } 0157 0158 void KoTextShapeContainerModel::addAnchor(KoShapeAnchor *anchor) 0159 { 0160 Q_ASSERT(anchor); 0161 Q_ASSERT(anchor->shape()); 0162 Q_ASSERT(d->children.contains(anchor->shape())); 0163 d->children[anchor->shape()].anchor = anchor; 0164 } 0165 0166 void KoTextShapeContainerModel::removeAnchor(KoShapeAnchor *anchor) 0167 { 0168 if (d->children.contains(anchor->shape())) { 0169 d->children[anchor->shape()].anchor = 0; 0170 d->shapeRemovedAnchors.removeAll(anchor); 0171 } 0172 } 0173 0174 void KoTextShapeContainerModel::proposeMove(KoShape *child, QPointF &move) 0175 { 0176 if (!d->children.contains(child)) 0177 return; 0178 Relation relation = d->children.value(child); 0179 if (relation.anchor == 0) 0180 return; 0181 0182 QPointF newPosition = child->position() + move/* + relation.anchor->offset()*/; 0183 //warnTextLayout <<"proposeMove:" /*<< move <<" |"*/ << newPosition <<" |" << parentShapeRect; 0184 0185 QTextLayout *layout = 0; 0186 int anchorPosInParag = -1; 0187 0188 if (relation.anchor->anchorType() == KoShapeAnchor::AnchorAsCharacter) { 0189 int posInDocument = relation.anchor->textLocation()->position(); 0190 const QTextDocument *document = relation.anchor->textLocation()->document(); 0191 QTextBlock block = document->findBlock(posInDocument); 0192 layout = block.layout(); 0193 anchorPosInParag = posInDocument - block.position(); 0194 if (layout) { 0195 QTextLine tl = layout->lineForTextPosition(anchorPosInParag); 0196 Q_ASSERT(tl.isValid()); 0197 relation.anchor->setOffset(QPointF(newPosition.x() - tl.cursorToX(anchorPosInParag) 0198 + tl.x(), 0)); 0199 relayoutInlineObject(child); 0200 } 0201 0202 // the rest of the code uses the shape baseline, at this time the bottom. So adjust 0203 newPosition.setY(newPosition.y() + child->size().height()); 0204 if (layout == 0) { 0205 QTextBlock block = document->findBlock(posInDocument); 0206 layout = block.layout(); 0207 anchorPosInParag = posInDocument - block.position(); 0208 } 0209 if (layout->lineCount() > 0) { 0210 KoTextShapeData *data = qobject_cast<KoTextShapeData*>(child->parent()->userData()); 0211 Q_ASSERT(data); 0212 QTextLine tl = layout->lineForTextPosition(anchorPosInParag); 0213 Q_ASSERT(tl.isValid()); 0214 qreal y = tl.y() - data->documentOffset() - newPosition.y() + child->size().height(); 0215 relation.anchor->setOffset(QPointF(relation.anchor->offset().x(), -y)); 0216 relayoutInlineObject(child); 0217 } 0218 } else { 0219 //TODO pavolk: handle position type change: absolute to realtive, etc .. 0220 child->setPosition(newPosition); 0221 relation.anchor->setOffset(relation.anchor->offset() + move); 0222 relayoutInlineObject(child); 0223 } 0224 0225 move.setX(0); // let the text layout move it. 0226 move.setY(0); 0227 } 0228 0229 bool KoTextShapeContainerModel::isChildLocked(const KoShape *child) const 0230 { 0231 return child->isGeometryProtected(); 0232 } 0233 0234 void KoTextShapeContainerModel::relayoutInlineObject(KoShape *child) 0235 { 0236 if (child == 0) { 0237 return; 0238 } 0239 KoTextShapeData *data = qobject_cast<KoTextShapeData*>(child->parent()->userData()); 0240 Q_ASSERT(data); 0241 data->setDirty(); 0242 } 0243