Warning, file /office/calligra/libs/flake/KoSelection.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 0003 Copyright (C) 2006 Boudewijn Rempt <boud@valdyas.org> 0004 Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org> 0005 Copyright (C) 2006 Jan Hambrecht <jaham@gmx.net> 0006 Copyright (C) 2006-2007,2009 Thomas Zander <zander@kde.org> 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 * Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #include "KoSelection.h" 0025 #include "KoSelection_p.h" 0026 #include "KoShapeContainer.h" 0027 #include "KoShapeGroup.h" 0028 #include "KoPointerEvent.h" 0029 #include "KoShapePaintingContext.h" 0030 0031 #include <QPainter> 0032 #include <QTimer> 0033 0034 QRectF KoSelectionPrivate::sizeRect() 0035 { 0036 bool first = true; 0037 QRectF bb; 0038 0039 QTransform invSelectionTransform = q->absoluteTransformation(0).inverted(); 0040 0041 QRectF bound; 0042 0043 if (!selectedShapes.isEmpty()) { 0044 QList<KoShape*>::const_iterator it = selectedShapes.constBegin(); 0045 for (; it != selectedShapes.constEnd(); ++it) { 0046 if (dynamic_cast<KoShapeGroup*>(*it)) 0047 continue; 0048 0049 const QTransform shapeTransform = (*it)->absoluteTransformation(0); 0050 const QRectF shapeRect(QRectF(QPointF(), (*it)->size())); 0051 0052 if (first) { 0053 bb = (shapeTransform * invSelectionTransform).mapRect(shapeRect); 0054 bound = shapeTransform.mapRect(shapeRect); 0055 first = false; 0056 } else { 0057 bb = bb.united((shapeTransform * invSelectionTransform).mapRect(shapeRect)); 0058 bound = bound.united(shapeTransform.mapRect(shapeRect)); 0059 } 0060 } 0061 } 0062 0063 globalBound = bound; 0064 return bb; 0065 } 0066 0067 void KoSelectionPrivate::requestSelectionChangedEvent() 0068 { 0069 if (eventTriggered) 0070 return; 0071 eventTriggered = true; 0072 QTimer::singleShot(0, q, SLOT(selectionChangedEvent())); 0073 } 0074 0075 void KoSelectionPrivate::selectionChangedEvent() 0076 { 0077 eventTriggered = false; 0078 emit q->selectionChanged(); 0079 } 0080 0081 void KoSelectionPrivate::selectGroupChildren(KoShapeGroup *group) 0082 { 0083 if (! group) 0084 return; 0085 0086 foreach(KoShape *shape, group->shapes()) { 0087 if (selectedShapes.contains(shape)) 0088 continue; 0089 selectedShapes << shape; 0090 0091 KoShapeGroup *childGroup = dynamic_cast<KoShapeGroup*>(shape); 0092 if (childGroup) 0093 selectGroupChildren(childGroup); 0094 } 0095 } 0096 0097 void KoSelectionPrivate::deselectGroupChildren(KoShapeGroup *group) 0098 { 0099 if (! group) 0100 return; 0101 0102 foreach(KoShape *shape, group->shapes()) { 0103 if (selectedShapes.contains(shape)) 0104 selectedShapes.removeAll(shape); 0105 0106 KoShapeGroup *childGroup = dynamic_cast<KoShapeGroup*>(shape); 0107 if (childGroup) 0108 deselectGroupChildren(childGroup); 0109 } 0110 } 0111 0112 //////////// 0113 0114 KoSelection::KoSelection() 0115 : KoShape(*(new KoSelectionPrivate(this))) 0116 { 0117 } 0118 0119 KoSelection::~KoSelection() 0120 { 0121 } 0122 0123 void KoSelection::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext) 0124 { 0125 Q_UNUSED(painter); 0126 Q_UNUSED(converter); 0127 Q_UNUSED(paintcontext); 0128 } 0129 0130 void KoSelection::select(KoShape *shape, bool recursive) 0131 { 0132 Q_D(KoSelection); 0133 Q_ASSERT(shape != this); 0134 Q_ASSERT(shape); 0135 if (!shape->isSelectable() || !shape->isVisible(true)) 0136 return; 0137 0138 // save old number of selected shapes 0139 int oldSelectionCount = d->selectedShapes.count(); 0140 0141 if (!d->selectedShapes.contains(shape)) 0142 d->selectedShapes << shape; 0143 0144 // automatically recursively select all child shapes downwards in the hierarchy 0145 KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape); 0146 if (group) 0147 d->selectGroupChildren(group); 0148 0149 if (recursive) { 0150 // recursively select all parents and their children upwards the hierarchy 0151 KoShapeContainer *parent = shape->parent(); 0152 while (parent) { 0153 KoShapeGroup *parentGroup = dynamic_cast<KoShapeGroup*>(parent); 0154 if (! parentGroup) break; 0155 if (! d->selectedShapes.contains(parentGroup)) { 0156 d->selectedShapes << parentGroup; 0157 d->selectGroupChildren(parentGroup); 0158 } 0159 parent = parentGroup->parent(); 0160 } 0161 } 0162 0163 if (d->selectedShapes.count() == 1) { 0164 setTransformation(shape->absoluteTransformation(0)); 0165 updateSizeAndPosition(); 0166 } else { 0167 // reset global bound if there were no shapes selected before 0168 if (!oldSelectionCount) 0169 d->globalBound = QRectF(); 0170 0171 setTransformation(QTransform()); 0172 // we are resetting the transformation here anyway, 0173 // so we can just add the newly selected shapes to the bounding box 0174 // in document coordinates and then use that size and position 0175 int newSelectionCount = d->selectedShapes.count(); 0176 for (int i = oldSelectionCount; i < newSelectionCount; ++i) { 0177 KoShape *shape = d->selectedShapes[i]; 0178 0179 // don't add the rect of the group rect, as it can be invalid 0180 if (dynamic_cast<KoShapeGroup*>(shape)) { 0181 continue; 0182 } 0183 const QTransform shapeTransform = shape->absoluteTransformation(0); 0184 const QRectF shapeRect(QRectF(QPointF(), shape->size())); 0185 0186 d->globalBound = d->globalBound.united(shapeTransform.mapRect(shapeRect)); 0187 } 0188 setSize(d->globalBound.size()); 0189 setPosition(d->globalBound.topLeft()); 0190 } 0191 0192 d->requestSelectionChangedEvent(); 0193 } 0194 0195 void KoSelection::deselect(KoShape *shape, bool recursive) 0196 { 0197 Q_D(KoSelection); 0198 if (! d->selectedShapes.contains(shape)) 0199 return; 0200 0201 d->selectedShapes.removeAll(shape); 0202 0203 KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape); 0204 if (recursive) { 0205 // recursively find the top group upwards int the hierarchy 0206 KoShapeGroup *parentGroup = dynamic_cast<KoShapeGroup*>(shape->parent()); 0207 while (parentGroup) { 0208 group = parentGroup; 0209 parentGroup = dynamic_cast<KoShapeGroup*>(parentGroup->parent()); 0210 } 0211 } 0212 if (group) 0213 d->deselectGroupChildren(group); 0214 0215 if (count() == 1) 0216 setTransformation(firstSelectedShape()->absoluteTransformation(0)); 0217 0218 updateSizeAndPosition(); 0219 0220 d->requestSelectionChangedEvent(); 0221 } 0222 0223 void KoSelection::deselectAll() 0224 { 0225 Q_D(KoSelection); 0226 // reset the transformation matrix of the selection 0227 setTransformation(QTransform()); 0228 0229 if (d->selectedShapes.isEmpty()) 0230 return; 0231 d->selectedShapes.clear(); 0232 d->requestSelectionChangedEvent(); 0233 } 0234 0235 int KoSelection::count() const 0236 { 0237 Q_D(const KoSelection); 0238 int count = 0; 0239 foreach(KoShape *shape, d->selectedShapes) 0240 if (dynamic_cast<KoShapeGroup*>(shape) == 0) 0241 ++count; 0242 return count; 0243 } 0244 0245 bool KoSelection::hitTest(const QPointF &position) const 0246 { 0247 Q_D(const KoSelection); 0248 if (count() > 1) { 0249 QRectF bb(boundingRect()); 0250 return bb.contains(position); 0251 } else if (count() == 1) { 0252 return (*d->selectedShapes.begin())->hitTest(position); 0253 } else { // count == 0 0254 return false; 0255 } 0256 } 0257 void KoSelection::updateSizeAndPosition() 0258 { 0259 Q_D(KoSelection); 0260 QRectF bb = d->sizeRect(); 0261 QTransform matrix = absoluteTransformation(0); 0262 setSize(bb.size()); 0263 QPointF p = matrix.map(bb.topLeft() + matrix.inverted().map(position())); 0264 setPosition(p); 0265 } 0266 0267 QRectF KoSelection::boundingRect() const 0268 { 0269 return absoluteTransformation(0).mapRect(QRectF(QPointF(), size())); 0270 } 0271 0272 const QList<KoShape*> KoSelection::selectedShapes(KoFlake::SelectionType strip) const 0273 { 0274 Q_D(const KoSelection); 0275 QList<KoShape*> answer; 0276 // strip the child objects when there is also a parent included. 0277 bool doStripping = strip == KoFlake::StrippedSelection; 0278 foreach(KoShape *shape, d->selectedShapes) { 0279 KoShapeContainer *container = shape->parent(); 0280 if (strip != KoFlake::TopLevelSelection && dynamic_cast<KoShapeGroup*>(shape)) 0281 // since a KoShapeGroup 0282 // guarentees all its children are selected at the same time as itself 0283 // is selected we will only return its children. 0284 continue; 0285 bool add = true; 0286 while (doStripping && add && container) { 0287 if (dynamic_cast<KoShapeGroup*>(container) == 0 && d->selectedShapes.contains(container)) 0288 add = false; 0289 container = container->parent(); 0290 } 0291 if (strip == KoFlake::TopLevelSelection && container && d->selectedShapes.contains(container)) 0292 add = false; 0293 if (add) 0294 answer << shape; 0295 } 0296 return answer; 0297 } 0298 0299 bool KoSelection::isSelected(const KoShape *shape) const 0300 { 0301 Q_D(const KoSelection); 0302 if (shape == this) 0303 return true; 0304 0305 foreach (KoShape *s, d->selectedShapes) { 0306 if (s == shape) 0307 return true; 0308 } 0309 0310 return false; 0311 } 0312 0313 KoShape *KoSelection::firstSelectedShape(KoFlake::SelectionType strip) const 0314 { 0315 QList<KoShape*> set = selectedShapes(strip); 0316 if (set.isEmpty()) 0317 return 0; 0318 return *(set.begin()); 0319 } 0320 0321 void KoSelection::setActiveLayer(KoShapeLayer *layer) 0322 { 0323 Q_D(KoSelection); 0324 d->activeLayer = layer; 0325 emit currentLayerChanged(layer); 0326 } 0327 0328 KoShapeLayer* KoSelection::activeLayer() const 0329 { 0330 Q_D(const KoSelection); 0331 return d->activeLayer; 0332 } 0333 0334 void KoSelection::saveOdf(KoShapeSavingContext &) const 0335 { 0336 } 0337 0338 bool KoSelection::loadOdf(const KoXmlElement &, KoShapeLoadingContext &) 0339 { 0340 return true; 0341 } 0342 0343 //have to include this because of Q_PRIVATE_SLOT 0344 #include "moc_KoSelection.cpp"