00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "KoShape.h"
00023 #include "KoShapeContainer.h"
00024 #include "KoSelection.h"
00025 #include "KoPointerEvent.h"
00026 #include "KoInsets.h"
00027 #include "KoShapeBorderModel.h"
00028 #include "KoShapeManager.h"
00029 #include "KoShapeUserData.h"
00030 #include "KoViewConverter.h"
00031
00032 #include <QPainter>
00033 #include <QtDebug>
00034 #include <QVariant>
00035 #include <QPainterPath>
00036
00037 KoShape::KoShape()
00038 : m_backgroundBrush(Qt::NoBrush)
00039 , m_border(0)
00040 , m_scaleX( 1 )
00041 , m_scaleY( 1 )
00042 , m_angle( 0 )
00043 , m_shearX( 0 )
00044 , m_shearY( 0 )
00045 , m_size( 50, 50 )
00046 , m_pos( 0, 0 )
00047 , m_zIndex( 0 )
00048 , m_parent( 0 )
00049 , m_visible( true )
00050 , m_locked( false )
00051 , m_keepAspect( false )
00052 , m_selectable( true )
00053 , m_userData(0)
00054 {
00055 recalcMatrix();
00056 }
00057
00058 KoShape::~KoShape()
00059 {
00060 delete m_userData;
00061 }
00062
00063 void KoShape::paintDecorations(QPainter &painter, const KoViewConverter &converter, bool selected) {
00064 if ( selected )
00065 {
00066
00067 QPen pen( Qt::blue );
00068 pen.setWidth( 0 );
00069 painter.setPen( pen );
00070 painter.setBrush( Qt::NoBrush );
00071 for ( int i = 0; i < m_connectors.size(); ++i )
00072 {
00073 QPointF p = converter.documentToView(m_connectors[ i ]);
00074 painter.drawLine( QPointF( p.x() - 2, p.y() + 2 ), QPointF( p.x() + 2, p.y() - 2 ) );
00075 painter.drawLine( QPointF( p.x() + 2, p.y() + 2 ), QPointF( p.x() - 2, p.y() - 2 ) );
00076 }
00077 }
00078 }
00079
00080 void KoShape::scale( double sx, double sy )
00081 {
00082 if(m_scaleX == sx && m_scaleY == sy)
00083 return;
00084 m_scaleX = sx;
00085 m_scaleY = sy;
00086 recalcMatrix();
00087 shapeChanged(ScaleChanged);
00088 }
00089
00090 void KoShape::rotate( double angle )
00091 {
00092 if(m_angle == angle)
00093 return;
00094 m_angle = angle;
00095 while(m_angle >= 360) m_angle -= 360;
00096 while(m_angle <= -360) m_angle += 360;
00097 recalcMatrix();
00098 shapeChanged(RotationChanged);
00099 }
00100
00101 void KoShape::shear( double sx, double sy )
00102 {
00103 if(m_shearX == sx && m_shearY == sy)
00104 return;
00105 m_shearX = sx;
00106 m_shearY = sy;
00107 recalcMatrix();
00108 shapeChanged(ShearChanged);
00109 }
00110
00111 void KoShape::resize( const QSizeF &newSize )
00112 {
00113 QSizeF s( size() );
00114 if(s == newSize)
00115 return;
00116
00117 double fx = newSize.width() / s.width();
00118 double fy = newSize.height() / s.height();
00119
00120 m_size = newSize;
00121
00122 for ( int i = 0; i < m_connectors.size(); ++i )
00123 {
00124 QPointF &point = m_connectors[i];
00125 point.setX(point.x() * fx);
00126 point.setY(point.y() * fy);
00127 }
00128 recalcMatrix();
00129 shapeChanged(SizeChanged);
00130 }
00131
00132 void KoShape::setPosition( const QPointF &position )
00133 {
00134 if(m_pos == position)
00135 return;
00136 m_pos = position;
00137 recalcMatrix();
00138 shapeChanged(PositionChanged);
00139 }
00140
00141 bool KoShape::hitTest( const QPointF &position ) const
00142 {
00143 if(m_parent && m_parent->childClipped(this) && !m_parent->hitTest(position))
00144 return false;
00145
00146 QPointF point( position * m_invMatrix );
00147 KoInsets insets(0, 0, 0, 0);
00148 if(m_border)
00149 m_border->borderInsets(this, insets);
00150
00151 QSizeF s( size() );
00152 return point.x() >= -insets.left && point.x() <= s.width() + insets.right &&
00153 point.y() >= -insets.top && point.y() <= s.height() + insets.bottom;
00154 }
00155
00156 QRectF KoShape::boundingRect() const
00157 {
00158 QRectF bb( QPointF(0, 0), size() );
00159 return m_matrix.mapRect( bb );
00160 }
00161
00162 void KoShape::recalcMatrix()
00163 {
00164 m_matrix = transformationMatrix(0);
00165 m_invMatrix = m_matrix.inverted();
00166 updateTree();
00167 }
00168
00169 QMatrix KoShape::transformationMatrix(const KoViewConverter *converter) const {
00170 QMatrix matrix;
00171 QRectF zoomedRect = QRectF(position(), size());
00172 if(converter)
00173 zoomedRect = converter->documentToView(zoomedRect);
00174 matrix.translate( zoomedRect.x(), zoomedRect.y() );
00175
00176
00177 KoShapeContainer *container = m_parent;
00178 KoShape const *child = this;
00179 while(container) {
00180 if(container->childClipped(child))
00181 matrix *= container->transformationMatrix(0);
00182 else {
00183 QPointF containerPos =container->position();
00184 if(converter)
00185 containerPos = converter->documentToView(containerPos);
00186 matrix.translate(containerPos.x(), containerPos.y());
00187 }
00188 container = dynamic_cast<KoShapeContainer*>(container->parent());
00189 child = child->parent();
00190 }
00191
00192 if ( m_angle != 0 )
00193 {
00194 matrix.translate( zoomedRect.width() / 2.0 * m_scaleX, zoomedRect.height() / 2.0 * m_scaleY );
00195 matrix.translate( zoomedRect.height() / 2.0 * m_shearX, zoomedRect.width() / 2.0 * m_shearY );
00196 matrix.rotate( m_angle );
00197 matrix.translate( -zoomedRect.width() / 2.0 * m_scaleX, -zoomedRect.height() / 2.0 * m_scaleY );
00198 matrix.translate( -zoomedRect.height() / 2.0 * m_shearX, -zoomedRect.width() / 2.0 * m_shearY );
00199 }
00200 matrix.shear( m_shearX, m_shearY );
00201 matrix.scale( m_scaleX, m_scaleY );
00202 return matrix;
00203 }
00204
00205
00206 bool KoShape::compareShapeZIndex(KoShape *g1, KoShape *g2) {
00207 return g1->zIndex() < g2->zIndex();
00208 }
00209
00210 void KoShape::setParent(KoShapeContainer *parent) {
00211 if(dynamic_cast<KoShape*>(parent) != this)
00212 m_parent = parent;
00213 else
00214 m_parent = 0;
00215 recalcMatrix();
00216 shapeChanged(ParentChanged);
00217 }
00218
00219 int KoShape::zIndex() const {
00220 if(parent())
00221 return qMax(m_zIndex, parent()->zIndex());
00222 return m_zIndex;
00223 }
00224
00225 void KoShape::repaint() const {
00226 if ( !m_shapeManagers.empty() )
00227 {
00228 foreach( KoShapeManager * manager, m_shapeManagers )
00229 {
00230 QRectF rect(QPointF(0, 0), size() );
00231 if(m_border) {
00232 KoInsets insets(0, 0, 0, 0);
00233 m_border->borderInsets(this, insets);
00234 rect.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
00235 }
00236 rect = m_matrix.mapRect(rect);
00237 manager->repaint( rect, this, true );
00238 }
00239 }
00240 }
00241
00242 void KoShape::repaint(const QRectF &shape) const {
00243 if ( !m_shapeManagers.empty() && isVisible() )
00244 {
00245 foreach( KoShapeManager * manager, m_shapeManagers )
00246 {
00247 QRectF rect(m_matrix.mapRect(shape));
00248 manager->repaint(rect);
00249 }
00250 }
00251 }
00252
00253 void KoShape::repaint(double x, double y, double width, double height) const {
00254 QRectF rect(x, y, width, height);
00255 repaint(rect);
00256 }
00257
00258 const QPainterPath KoShape::outline() const {
00259 QPainterPath path;
00260 path.addRect(QRectF( QPointF(0, 0), size() ));
00261 return path;
00262 }
00263
00264 QPointF KoShape::absolutePosition() const {
00265 return m_matrix.map(QPointF(size().width() / 2.0 , size().height() / 2.0));
00266 }
00267
00268 void KoShape::setAbsolutePosition(QPointF newPosition) {
00269 QPointF zero(0, 0);
00270 QMatrix matrix;
00271
00272 KoShapeContainer *container = m_parent;
00273 KoShape const *child = this;
00274 while(container) {
00275 if(container->childClipped(child)) {
00276 matrix *= container->transformationMatrix(0);
00277 break;
00278 }
00279 else {
00280 QPointF containerPos =container->position();
00281 matrix.translate(containerPos.x(), containerPos.y());
00282 }
00283 container = dynamic_cast<KoShapeContainer*>(container->parent());
00284 child = child->parent();
00285 }
00286 QPointF vector1 = matrix.inverted().map(zero);
00287
00288 matrix = QMatrix();
00289 if ( m_angle != 0 )
00290 {
00291 matrix.translate( size().width() / 2.0 * m_scaleX, size().height() / 2.0 * m_scaleY );
00292 matrix.translate( size().height() / 2.0 * m_shearX, size().width() / 2.0 * m_shearY );
00293 matrix.rotate( m_angle );
00294 matrix.translate( -size().width() / 2.0 * m_scaleX, -size().height() / 2.0 * m_scaleY );
00295 matrix.translate( -size().height() / 2.0 * m_shearX, -size().width() / 2.0 * m_shearY );
00296 }
00297 matrix.shear( m_shearX, m_shearY );
00298 matrix.scale( m_scaleX, m_scaleY );
00299
00300 QPointF vector2 = matrix.map( QPointF(size().width() / 2.0, size().height() / 2.0) );
00301
00302
00303 setPosition(newPosition + vector1 - vector2);
00304 }
00305
00306 void KoShape::copySettings(const KoShape *shape) {
00307 m_pos = shape->position();
00308 m_scaleX = shape->scaleX();
00309 m_scaleY = shape->scaleY();
00310 m_angle = shape->rotation();
00311 m_shearX = shape->shearX();
00312 m_shearY = shape->shearY();
00313 m_size = shape->size();
00314 m_connectors.clear();
00315 foreach(QPointF point, shape->connectors())
00316 addConnectionPoint(point);
00317 m_zIndex = shape->zIndex();
00318 m_visible = shape->isVisible();
00319 m_locked = shape->isLocked();
00320 m_keepAspect = shape->keepAspectRatio();
00321 }
00322
00323 void KoShape::moveBy(double distanceX, double distanceY) {
00324 QPointF p = absolutePosition();
00325 setAbsolutePosition(QPointF(p.x() + distanceX, p.y() + distanceY));
00326 }
00327
00328 void KoShape::updateTree()
00329 {
00330 foreach( KoShapeManager * manager, m_shapeManagers )
00331 {
00332 manager->updateTree( this );
00333 }
00334 }
00335
00336 void KoShape::setUserData(KoShapeUserData *userData) {
00337 if(m_userData)
00338 delete m_userData;
00339 m_userData = userData;
00340 }
00341
00342 KoShapeUserData *KoShape::userData() const {
00343 return m_userData;
00344 }
00345
00346 bool KoShape::hasTransparency() {
00347 if(m_backgroundBrush.style() == Qt::NoBrush)
00348 return true;
00349 return !m_backgroundBrush.isOpaque();
00350 }
00351
00352
00353 void KoShape::applyConversion(QPainter &painter, const KoViewConverter &converter) {
00354 double zoomX, zoomY;
00355 converter.zoom(&zoomX, &zoomY);
00356 painter.scale(zoomX, zoomY);
00357 }
00358