00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <QWidget>
00018 #include <QDomNode>
00019 #include <QFile>
00020 #include <QGraphicsScene>
00021 #include <QGraphicsSceneMouseEvent>
00022 #include <QGraphicsView>
00023 #include <QPainter>
00024
00025 #include "qgscomposition.h"
00026 #include "qgscomposeritem.h"
00027
00028
00029 #include <limits>
00030 #include "qgsapplication.h"
00031 #include "qgsrectangle.h"
00032 #include "qgslogger.h"
00033
00034 #ifndef Q_OS_MACX
00035 #include <cmath>
00036 #else
00037 #include <math.h>
00038 #endif
00039
00040 #define FONT_WORKAROUND_SCALE 10 //scale factor for upscaling fontsize and downscaling painter
00041
00042 QgsComposerItem::QgsComposerItem( QgsComposition* composition, bool manageZValue )
00043 : QObject( 0 )
00044 , QGraphicsRectItem( 0 )
00045 , mComposition( composition )
00046 , mBoundingResizeRectangle( 0 )
00047 , mFrame( true )
00048 , mItemPositionLocked( false )
00049 , mLastValidViewScaleFactor( -1 )
00050 , mRotation( 0 )
00051 {
00052 setFlag( QGraphicsItem::ItemIsSelectable, true );
00053 setAcceptsHoverEvents( true );
00054
00055
00056 setBrush( QBrush( QColor( 255, 255, 255, 255 ) ) );
00057 QPen defaultPen( QColor( 0, 0, 0 ) );
00058 defaultPen.setWidthF( 0.3 );
00059 setPen( defaultPen );
00060
00061
00062 if ( mComposition && manageZValue )
00063 {
00064 mComposition->addItemToZList( this );
00065 }
00066 }
00067
00068 QgsComposerItem::QgsComposerItem( qreal x, qreal y, qreal width, qreal height, QgsComposition* composition, bool manageZValue )
00069 : QObject( 0 )
00070 , QGraphicsRectItem( 0, 0, width, height, 0 )
00071 , mComposition( composition )
00072 , mBoundingResizeRectangle( 0 )
00073 , mFrame( true )
00074 , mItemPositionLocked( false )
00075 , mLastValidViewScaleFactor( -1 )
00076 , mRotation( 0 )
00077 {
00078 setFlag( QGraphicsItem::ItemIsSelectable, true );
00079 setAcceptsHoverEvents( true );
00080
00081 QTransform t;
00082 t.translate( x, y );
00083 setTransform( t );
00084
00085
00086 setBrush( QBrush( QColor( 255, 255, 255, 255 ) ) );
00087 QPen defaultPen( QColor( 0, 0, 0 ) );
00088 defaultPen.setWidthF( 0.3 );
00089 setPen( defaultPen );
00090
00091
00092 if ( mComposition && manageZValue )
00093 {
00094 mComposition->addItemToZList( this );
00095 }
00096 }
00097
00098 QgsComposerItem::~QgsComposerItem()
00099 {
00100 if ( mComposition )
00101 {
00102 mComposition->removeItemFromZList( this );
00103 }
00104
00105 delete mBoundingResizeRectangle;
00106 }
00107
00108 void QgsComposerItem::setSelected( bool s )
00109 {
00110 QgsDebugMsg( "entered." );
00111 QGraphicsRectItem::setSelected( s );
00112 update();
00113 }
00114
00115 bool QgsComposerItem::writeSettings( void ) { return true; }
00116
00117 bool QgsComposerItem::readSettings( void ) { return true; }
00118
00119 bool QgsComposerItem::removeSettings( void ) { return true; }
00120
00121 bool QgsComposerItem::_writeXML( QDomElement& itemElem, QDomDocument& doc ) const
00122 {
00123 if ( itemElem.isNull() )
00124 {
00125 return false;
00126 }
00127
00128 QDomElement composerItemElem = doc.createElement( "ComposerItem" );
00129
00130
00131 if ( mFrame )
00132 {
00133 composerItemElem.setAttribute( "frame", "true" );
00134 }
00135 else
00136 {
00137 composerItemElem.setAttribute( "frame", "false" );
00138 }
00139
00140
00141 composerItemElem.setAttribute( "x", transform().dx() );
00142 composerItemElem.setAttribute( "y", transform().dy() );
00143 composerItemElem.setAttribute( "width", rect().width() );
00144 composerItemElem.setAttribute( "height", rect().height() );
00145 composerItemElem.setAttribute( "zValue", QString::number( zValue() ) );
00146 composerItemElem.setAttribute( "outlineWidth", QString::number( pen().widthF() ) );
00147 composerItemElem.setAttribute( "rotation", mRotation );
00148
00149
00150 if ( mItemPositionLocked )
00151 {
00152 composerItemElem.setAttribute( "positionLock", "true" );
00153 }
00154 else
00155 {
00156 composerItemElem.setAttribute( "positionLock", "false" );
00157 }
00158
00159 composerItemElem.setAttribute( "lastValidViewScaleFactor", mLastValidViewScaleFactor );
00160
00161
00162
00163 QDomElement frameColorElem = doc.createElement( "FrameColor" );
00164 QColor frameColor = pen().color();
00165 frameColorElem.setAttribute( "red", QString::number( frameColor.red() ) );
00166 frameColorElem.setAttribute( "green", QString::number( frameColor.green() ) );
00167 frameColorElem.setAttribute( "blue", QString::number( frameColor.blue() ) );
00168 frameColorElem.setAttribute( "alpha", QString::number( frameColor.alpha() ) );
00169 composerItemElem.appendChild( frameColorElem );
00170
00171
00172 QDomElement bgColorElem = doc.createElement( "BackgroundColor" );
00173 QColor bgColor = brush().color();
00174 bgColorElem.setAttribute( "red", QString::number( bgColor.red() ) );
00175 bgColorElem.setAttribute( "green", QString::number( bgColor.green() ) );
00176 bgColorElem.setAttribute( "blue", QString::number( bgColor.blue() ) );
00177 bgColorElem.setAttribute( "alpha", QString::number( bgColor.alpha() ) );
00178 composerItemElem.appendChild( bgColorElem );
00179
00180 itemElem.appendChild( composerItemElem );
00181
00182 return true;
00183 }
00184
00185 bool QgsComposerItem::_readXML( const QDomElement& itemElem, const QDomDocument& doc )
00186 {
00187 if ( itemElem.isNull() )
00188 {
00189 return false;
00190 }
00191
00192
00193 mRotation = itemElem.attribute( "rotation", "0" ).toDouble();
00194
00195
00196 QString frame = itemElem.attribute( "frame" );
00197 if ( frame.compare( "true", Qt::CaseInsensitive ) == 0 )
00198 {
00199 mFrame = true;
00200 }
00201 else
00202 {
00203 mFrame = false;
00204 }
00205
00206
00207 QString positionLock = itemElem.attribute( "positionLock" );
00208 if ( positionLock.compare( "true", Qt::CaseInsensitive ) == 0 )
00209 {
00210 mItemPositionLocked = true;
00211 }
00212 else
00213 {
00214 mItemPositionLocked = false;
00215 }
00216
00217
00218 double x, y, width, height;
00219 bool xOk, yOk, widthOk, heightOk;
00220
00221 x = itemElem.attribute( "x" ).toDouble( &xOk );
00222 y = itemElem.attribute( "y" ).toDouble( &yOk );
00223 width = itemElem.attribute( "width" ).toDouble( &widthOk );
00224 height = itemElem.attribute( "height" ).toDouble( &heightOk );
00225
00226 if ( !xOk || !yOk || !widthOk || !heightOk )
00227 {
00228 return false;
00229 }
00230
00231 mLastValidViewScaleFactor = itemElem.attribute( "lastValidViewScaleFactor", "-1" ).toDouble();
00232
00233 setSceneRect( QRectF( x, y, width, height ) );
00234 setZValue( itemElem.attribute( "zValue" ).toDouble() );
00235
00236
00237 QDomNodeList frameColorList = itemElem.elementsByTagName( "FrameColor" );
00238 if ( frameColorList.size() > 0 )
00239 {
00240 QDomElement frameColorElem = frameColorList.at( 0 ).toElement();
00241 bool redOk, greenOk, blueOk, alphaOk, widthOk;
00242 int penRed, penGreen, penBlue, penAlpha;
00243 double penWidth;
00244
00245 penWidth = itemElem.attribute( "outlineWidth" ).toDouble( &widthOk );
00246 penRed = frameColorElem.attribute( "red" ).toDouble( &redOk );
00247 penGreen = frameColorElem.attribute( "green" ).toDouble( &greenOk );
00248 penBlue = frameColorElem.attribute( "blue" ).toDouble( &blueOk );
00249 penAlpha = frameColorElem.attribute( "alpha" ).toDouble( &alphaOk );
00250 if ( redOk && greenOk && blueOk && alphaOk && widthOk )
00251 {
00252 QPen framePen( QColor( penRed, penGreen, penBlue, penAlpha ) );
00253 framePen.setWidthF( penWidth );
00254 setPen( framePen );
00255 }
00256 }
00257
00258
00259 QDomNodeList bgColorList = itemElem.elementsByTagName( "BackgroundColor" );
00260 if ( bgColorList.size() > 0 )
00261 {
00262 QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
00263 bool redOk, greenOk, blueOk, alphaOk;
00264 int bgRed, bgGreen, bgBlue, bgAlpha;
00265 bgRed = bgColorElem.attribute( "red" ).toDouble( &redOk );
00266 bgGreen = bgColorElem.attribute( "green" ).toDouble( &greenOk );
00267 bgBlue = bgColorElem.attribute( "blue" ).toDouble( &blueOk );
00268 bgAlpha = bgColorElem.attribute( "alpha" ).toDouble( &alphaOk );
00269 if ( redOk && greenOk && blueOk && alphaOk )
00270 {
00271 QColor brushColor( bgRed, bgGreen, bgBlue, bgAlpha );
00272 setBrush( QBrush( brushColor ) );
00273 }
00274 }
00275 return true;
00276 }
00277
00278 void QgsComposerItem::mouseMoveEvent( QGraphicsSceneMouseEvent * event )
00279 {
00280 if ( mItemPositionLocked )
00281 {
00282 return;
00283 }
00284
00285 if ( mBoundingResizeRectangle )
00286 {
00287 double diffX = event->lastScenePos().x() - mLastMouseEventPos.x();
00288 double diffY = event->lastScenePos().y() - mLastMouseEventPos.y();
00289
00290 changeItemRectangle( event->lastScenePos(), mMouseMoveStartPos, this, diffX, diffY, mBoundingResizeRectangle );
00291 }
00292 mLastMouseEventPos = event->lastScenePos();
00293 }
00294
00295 void QgsComposerItem::mousePressEvent( QGraphicsSceneMouseEvent * event )
00296 {
00297 if ( mItemPositionLocked )
00298 {
00299 return;
00300 }
00301
00302
00303 mMouseMoveStartPos = event->lastScenePos();
00304 mLastMouseEventPos = event->lastScenePos();
00305 mCurrentMouseMoveAction = mouseMoveActionForPosition( event->pos() );
00306
00307
00308 if ( mBoundingResizeRectangle )
00309 {
00310 scene()->removeItem( mBoundingResizeRectangle );
00311 delete mBoundingResizeRectangle;
00312 mBoundingResizeRectangle = 0;
00313 }
00314
00315 mBoundingResizeRectangle = new QGraphicsRectItem( 0 );
00316 scene()->addItem( mBoundingResizeRectangle );
00317 mBoundingResizeRectangle->setRect( QRectF( 0, 0, rect().width(), rect().height() ) );
00318 QTransform resizeTransform;
00319 resizeTransform.translate( transform().dx(), transform().dy() );
00320 mBoundingResizeRectangle->setTransform( resizeTransform );
00321
00322 mBoundingResizeRectangle->setBrush( Qt::NoBrush );
00323 mBoundingResizeRectangle->setPen( QPen( QColor( 0, 0, 0 ), 0 ) );
00324 mBoundingResizeRectangle->setZValue( 90 );
00325 mBoundingResizeRectangle->show();
00326 }
00327
00328 void QgsComposerItem::mouseReleaseEvent( QGraphicsSceneMouseEvent * event )
00329 {
00330
00331 if ( mItemPositionLocked )
00332 {
00333 return;
00334 }
00335
00336
00337 if ( mBoundingResizeRectangle )
00338 {
00339 scene()->removeItem( mBoundingResizeRectangle );
00340 delete mBoundingResizeRectangle;
00341 mBoundingResizeRectangle = 0;
00342 }
00343
00344 QPointF mouseMoveStopPoint = event->lastScenePos();
00345 double diffX = mouseMoveStopPoint.x() - mMouseMoveStartPos.x();
00346 double diffY = mouseMoveStopPoint.y() - mMouseMoveStartPos.y();
00347
00348
00349 if ( abs( diffX ) < std::numeric_limits<double>::min() && abs( diffY ) < std::numeric_limits<double>::min() )
00350 {
00351 return;
00352 }
00353
00354 changeItemRectangle( mouseMoveStopPoint, mMouseMoveStartPos, this, diffX, diffY, this );
00355
00356
00357 mCurrentMouseMoveAction = QgsComposerItem::MoveItem;
00358 setCursor( Qt::ArrowCursor );
00359 }
00360
00361 Qt::CursorShape QgsComposerItem::cursorForPosition( const QPointF& itemCoordPos )
00362 {
00363 QgsComposerItem::MouseMoveAction mouseAction = mouseMoveActionForPosition( itemCoordPos );
00364
00365 if ( mouseAction == QgsComposerItem::NoAction )
00366 {
00367 return Qt::ForbiddenCursor;
00368 }
00369 if ( mouseAction == QgsComposerItem::MoveItem )
00370 {
00371 return Qt::ClosedHandCursor;
00372 }
00373 else if ( mouseAction == QgsComposerItem::ResizeLeftUp || mouseAction == QgsComposerItem::ResizeRightDown )
00374 {
00375 return Qt::SizeFDiagCursor;
00376 }
00377 else if ( mouseAction == QgsComposerItem::ResizeLeftDown || mouseAction == QgsComposerItem::ResizeRightUp )
00378 {
00379 return Qt::SizeBDiagCursor;
00380 }
00381 else if ( mouseAction == QgsComposerItem::ResizeUp || mouseAction == QgsComposerItem::ResizeDown )
00382 {
00383 return Qt::SizeVerCursor;
00384 }
00385 else
00386 {
00387 return Qt::SizeHorCursor;
00388 }
00389 }
00390
00391 QgsComposerItem::MouseMoveAction QgsComposerItem::mouseMoveActionForPosition( const QPointF& itemCoordPos )
00392 {
00393
00394
00395 if ( mItemPositionLocked )
00396 {
00397 return QgsComposerItem::NoAction;
00398 }
00399
00400 bool nearLeftBorder = false;
00401 bool nearRightBorder = false;
00402 bool nearLowerBorder = false;
00403 bool nearUpperBorder = false;
00404
00405 double borderTolerance = rectHandlerBorderTolerance();
00406
00407 if ( itemCoordPos.x() < borderTolerance )
00408 {
00409 nearLeftBorder = true;
00410 }
00411 if ( itemCoordPos.y() < borderTolerance )
00412 {
00413 nearUpperBorder = true;
00414 }
00415 if ( itemCoordPos.x() > ( rect().width() - borderTolerance ) )
00416 {
00417 nearRightBorder = true;
00418 }
00419 if ( itemCoordPos.y() > ( rect().height() - borderTolerance ) )
00420 {
00421 nearLowerBorder = true;
00422 }
00423
00424 if ( nearLeftBorder && nearUpperBorder )
00425 {
00426 return QgsComposerItem::ResizeLeftUp;
00427 }
00428 else if ( nearLeftBorder && nearLowerBorder )
00429 {
00430 return QgsComposerItem::ResizeLeftDown;
00431 }
00432 else if ( nearRightBorder && nearUpperBorder )
00433 {
00434 return QgsComposerItem::ResizeRightUp;
00435 }
00436 else if ( nearRightBorder && nearLowerBorder )
00437 {
00438 return QgsComposerItem::ResizeRightDown;
00439 }
00440 else if ( nearLeftBorder )
00441 {
00442 return QgsComposerItem::ResizeLeft;
00443 }
00444 else if ( nearRightBorder )
00445 {
00446 return QgsComposerItem::ResizeRight;
00447 }
00448 else if ( nearUpperBorder )
00449 {
00450 return QgsComposerItem::ResizeUp;
00451 }
00452 else if ( nearLowerBorder )
00453 {
00454 return QgsComposerItem::ResizeDown;
00455 }
00456
00457 return QgsComposerItem::MoveItem;
00458 }
00459
00460 void QgsComposerItem::changeItemRectangle( const QPointF& currentPosition, const QPointF& mouseMoveStartPos, const QGraphicsRectItem* originalItem, double dx, double dy, QGraphicsRectItem* changeItem )
00461 {
00462 if ( !changeItem || !originalItem || !mComposition )
00463 {
00464 return;
00465 }
00466
00467
00468 QgsComposerItem* changeComposerItem = dynamic_cast<QgsComposerItem *>( changeItem );
00469
00470 double mx = 0.0, my = 0.0, rx = 0.0, ry = 0.0;
00471 QPointF snappedPosition = mComposition->snapPointToGrid( currentPosition );
00472
00473
00474 double diffX = 0;
00475 double diffY = 0;
00476
00477 switch ( mCurrentMouseMoveAction )
00478 {
00479
00480 case QgsComposerItem::ResizeUp:
00481 diffY = snappedPosition.y() - originalItem->transform().dy();
00482 mx = 0; my = diffY; rx = 0; ry = -diffY;
00483 break;
00484
00485 case QgsComposerItem::ResizeDown:
00486 diffY = snappedPosition.y() - ( originalItem->transform().dy() + originalItem->rect().height() );
00487 mx = 0; my = 0; rx = 0; ry = diffY;
00488 break;
00489
00490
00491 case QgsComposerItem::ResizeLeft:
00492 diffX = snappedPosition.x() - originalItem->transform().dx();
00493 mx = diffX, my = 0; rx = -diffX; ry = 0;
00494 break;
00495
00496 case QgsComposerItem::ResizeRight:
00497 diffX = snappedPosition.x() - ( originalItem->transform().dx() + originalItem->rect().width() );
00498 mx = 0; my = 0; rx = diffX, ry = 0;
00499 break;
00500
00501
00502 case QgsComposerItem::ResizeLeftUp:
00503 diffX = snappedPosition.x() - originalItem->transform().dx();
00504 diffY = snappedPosition.y() - originalItem->transform().dy();
00505 mx = diffX, my = diffY; rx = -diffX; ry = -diffY;
00506 break;
00507
00508 case QgsComposerItem::ResizeRightDown:
00509 diffX = snappedPosition.x() - ( originalItem->transform().dx() + originalItem->rect().width() );
00510 diffY = snappedPosition.y() - ( originalItem->transform().dy() + originalItem->rect().height() );
00511 mx = 0; my = 0; rx = diffX, ry = diffY;
00512 break;
00513
00514 case QgsComposerItem::ResizeRightUp:
00515 diffX = snappedPosition.x() - ( originalItem->transform().dx() + originalItem->rect().width() );
00516 diffY = snappedPosition.y() - originalItem->transform().dy();
00517 mx = 0; my = diffY, rx = diffX, ry = -diffY;
00518 break;
00519
00520 case QgsComposerItem::ResizeLeftDown:
00521 diffX = snappedPosition.x() - originalItem->transform().dx();
00522 diffY = snappedPosition.y() - ( originalItem->transform().dy() + originalItem->rect().height() );
00523 mx = diffX, my = 0; rx = -diffX; ry = diffY;
00524 break;
00525
00526 case QgsComposerItem::MoveItem:
00527 {
00528
00529 double moveX = currentPosition.x() - mouseMoveStartPos.x();
00530 double moveY = currentPosition.y() - mouseMoveStartPos.y();
00531
00532 QPointF upperLeftPoint( originalItem->transform().dx() + moveX, originalItem->transform().dy() + moveY );
00533 QPointF snappedLeftPoint = mComposition->snapPointToGrid( upperLeftPoint );
00534
00535 double moveRectX = snappedLeftPoint.x() - originalItem->transform().dx();
00536 double moveRectY = snappedLeftPoint.y() - originalItem->transform().dy();
00537
00538 if ( !changeComposerItem )
00539 {
00540 QTransform moveTransform;
00541 moveTransform.translate( originalItem->transform().dx() + moveRectX, originalItem->transform().dy() + moveRectY );
00542 changeItem->setTransform( moveTransform );
00543 }
00544 else
00545 {
00546 changeComposerItem->setSceneRect( QRectF( originalItem->transform().dx() + moveRectX,
00547 originalItem->transform().dy() + moveRectY,
00548 originalItem->rect().width(), originalItem->rect().height() ) );
00549 }
00550 }
00551 return;
00552 case QgsComposerItem::NoAction:
00553 break;
00554 }
00555
00556 if ( !changeComposerItem )
00557 {
00558 QTransform itemTransform;
00559 itemTransform.translate( originalItem->transform().dx() + mx, originalItem->transform().dy() + my );
00560 changeItem->setTransform( itemTransform );
00561 QRectF itemRect( 0, 0, originalItem->rect().width() + rx, originalItem->rect().height() + ry );
00562 changeItem->setRect( itemRect );
00563 }
00564 else
00565 {
00566 changeComposerItem->setSceneRect( QRectF( originalItem->transform().dx() + mx, originalItem->transform().dy() + my,
00567 originalItem->rect().width() + rx, originalItem->rect().height() + ry ) );
00568 }
00569 }
00570
00571 void QgsComposerItem::drawSelectionBoxes( QPainter* p )
00572 {
00573 if ( !mComposition )
00574 {
00575 return;
00576 }
00577
00578 if ( mComposition->plotStyle() == QgsComposition::Preview )
00579 {
00580
00581 double rectHandlerSize = rectHandlerBorderTolerance();
00582 double sizeLockSymbol = lockSymbolSize();
00583
00584 if ( mItemPositionLocked )
00585 {
00586
00587 QString lockIconPath = QgsApplication::activeThemePath() + "/mIconLock.png";
00588 if ( !QFile::exists( lockIconPath ) )
00589 {
00590 lockIconPath = QgsApplication::defaultThemePath() + "/mIconLock.png";
00591 }
00592
00593 QImage lockImage( lockIconPath );
00594 if ( !lockImage.isNull() )
00595 {
00596 p->drawImage( QRectF( 0, 0, sizeLockSymbol, sizeLockSymbol ), lockImage, QRectF( 0, 0, lockImage.width(), lockImage.height() ) );
00597 }
00598 }
00599 else
00600 {
00601 p->setPen( QColor( 50, 100, 120, 200 ) );
00602 p->setBrush( QColor( 200, 200, 210, 120 ) );
00603 p->drawRect( QRectF( 0, 0, rectHandlerSize, rectHandlerSize ) );
00604 p->drawRect( QRectF( rect().width() - rectHandlerSize, 0, rectHandlerSize, rectHandlerSize ) );
00605 p->drawRect( QRectF( rect().width() - rectHandlerSize, rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
00606 p->drawRect( QRectF( 0, rect().height() - rectHandlerSize, rectHandlerSize, rectHandlerSize ) );
00607 }
00608 }
00609 }
00610
00611 void QgsComposerItem::drawFrame( QPainter* p )
00612 {
00613 if ( mFrame && p )
00614 {
00615 p->setPen( pen() );
00616 p->setBrush( Qt::NoBrush );
00617 p->setRenderHint( QPainter::Antialiasing, true );
00618 p->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
00619 }
00620 }
00621
00622 void QgsComposerItem::move( double dx, double dy )
00623 {
00624 QTransform t = transform();
00625 QRectF newSceneRect( t.dx() + dx, t.dy() + dy, rect().width(), rect().height() );
00626 setSceneRect( newSceneRect );
00627 }
00628
00629 void QgsComposerItem::setItemPosition( double x, double y, ItemPositionMode itemPoint )
00630 {
00631 double width = rect().width();
00632 double height = rect().height();
00633 setItemPosition( x, y, width, height, itemPoint );
00634 }
00635
00636 void QgsComposerItem::setItemPosition( double x, double y, double width, double height, ItemPositionMode itemPoint )
00637 {
00638 double upperLeftX = x;
00639 double upperLeftY = y;
00640
00641
00642 if ( itemPoint == UpperMiddle || itemPoint == Middle || itemPoint == LowerMiddle )
00643 {
00644 upperLeftX -= width / 2.0;
00645 }
00646 else if ( itemPoint == UpperRight || itemPoint == MiddleRight || itemPoint == LowerRight )
00647 {
00648 upperLeftX -= width;
00649 }
00650
00651
00652 if ( itemPoint == MiddleLeft || itemPoint == Middle || itemPoint == MiddleRight )
00653 {
00654 upperLeftY -= height / 2.0;
00655 }
00656 else if ( itemPoint == LowerLeft || itemPoint == LowerMiddle || itemPoint == LowerRight )
00657 {
00658 upperLeftY -= height;
00659 }
00660
00661 setSceneRect( QRectF( upperLeftX, upperLeftY, width, height ) );
00662 }
00663
00664 void QgsComposerItem::setSceneRect( const QRectF& rectangle )
00665 {
00666
00667 double newWidth = rectangle.width();
00668 double newHeight = rectangle.height();
00669 double xTranslation = rectangle.x();
00670 double yTranslation = rectangle.y();
00671
00672
00673 if ( rectangle.width() < 0 )
00674 {
00675 newWidth = - rectangle.width();
00676 xTranslation -= newWidth;
00677 }
00678
00679 if ( rectangle.height() < 0 )
00680 {
00681 newHeight = - rectangle.height();
00682 yTranslation -= newHeight;
00683 }
00684
00685 QRectF newRect( 0, 0, newWidth, newHeight );
00686 QGraphicsRectItem::setRect( newRect );
00687
00688
00689 QTransform t;
00690 t.translate( xTranslation, yTranslation );
00691 setTransform( t );
00692 }
00693
00694 void QgsComposerItem::drawBackground( QPainter* p )
00695 {
00696 if ( p )
00697 {
00698 p->setBrush( brush() );
00699 p->setPen( Qt::NoPen );
00700 p->setRenderHint( QPainter::Antialiasing, true );
00701 p->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
00702 }
00703 }
00704
00705 void QgsComposerItem::hoverMoveEvent( QGraphicsSceneHoverEvent * event )
00706 {
00707 if ( isSelected() )
00708 {
00709 setCursor( cursorForPosition( event->pos() ) );
00710 }
00711 }
00712
00713 void QgsComposerItem::drawText( QPainter* p, double x, double y, const QString& text, const QFont& font ) const
00714 {
00715 QFont textFont = scaledFontPixelSize( font );
00716
00717 p->save();
00718 p->setFont( textFont );
00719 p->setPen( QColor( 0, 0, 0 ) );
00720 double scaleFactor = 1.0 / FONT_WORKAROUND_SCALE;
00721 p->scale( scaleFactor, scaleFactor );
00722 p->drawText( QPointF( x * FONT_WORKAROUND_SCALE, y * FONT_WORKAROUND_SCALE ), text );
00723 p->restore();
00724 }
00725
00726 void QgsComposerItem::drawText( QPainter* p, const QRectF& rect, const QString& text, const QFont& font, Qt::AlignmentFlag halignement, Qt::AlignmentFlag valignment ) const
00727 {
00728 QFont textFont = scaledFontPixelSize( font );
00729
00730 QRectF scaledRect( rect.x() * FONT_WORKAROUND_SCALE, rect.y() * FONT_WORKAROUND_SCALE,
00731 rect.width() * FONT_WORKAROUND_SCALE, rect.height() * FONT_WORKAROUND_SCALE );
00732
00733 p->save();
00734 p->setFont( textFont );
00735 double scaleFactor = 1.0 / FONT_WORKAROUND_SCALE;
00736 p->scale( scaleFactor, scaleFactor );
00737 p->drawText( scaledRect, halignement | valignment | Qt::TextWordWrap, text );
00738 p->restore();
00739 }
00740 void QgsComposerItem::drawArrowHead( QPainter* p, double x, double y, double angle, double arrowHeadWidth ) const
00741 {
00742 if ( !p )
00743 {
00744 return;
00745 }
00746 double angleRad = angle / 180.0 * M_PI;
00747 QPointF middlePoint( x, y );
00748
00749 QPointF p1 = QPointF( -arrowHeadWidth / 2.0, arrowHeadWidth );
00750 QPointF p2 = QPointF( arrowHeadWidth / 2.0, arrowHeadWidth );
00751
00752 QPointF p1Rotated, p2Rotated;
00753 p1Rotated.setX( p1.x() * cos( angleRad ) + p1.y() * -sin( angleRad ) );
00754 p1Rotated.setY( p1.x() * sin( angleRad ) + p1.y() * cos( angleRad ) );
00755 p2Rotated.setX( p2.x() * cos( angleRad ) + p2.y() * -sin( angleRad ) );
00756 p2Rotated.setY( p2.x() * sin( angleRad ) + p2.y() * cos( angleRad ) );
00757
00758 QPolygonF arrowHeadPoly;
00759 arrowHeadPoly << middlePoint;
00760 arrowHeadPoly << QPointF( middlePoint.x() + p1Rotated.x(), middlePoint.y() + p1Rotated.y() );
00761 arrowHeadPoly << QPointF( middlePoint.x() + p2Rotated.x(), middlePoint.y() + p2Rotated.y() );
00762
00763 p->save();
00764
00765 QPen arrowPen = p->pen();
00766 arrowPen.setJoinStyle( Qt::RoundJoin );
00767 QBrush arrowBrush = p->brush();
00768 arrowBrush.setStyle( Qt::SolidPattern );
00769 p->setPen( arrowPen );
00770 p->setBrush( arrowBrush );
00771 arrowBrush.setStyle( Qt::SolidPattern );
00772 p->drawPolygon( arrowHeadPoly );
00773
00774 p->restore();
00775 }
00776
00777 double QgsComposerItem::textWidthMillimeters( const QFont& font, const QString& text ) const
00778 {
00779 QFont metricsFont = scaledFontPixelSize( font );
00780 QFontMetrics fontMetrics( metricsFont );
00781 return ( fontMetrics.width( text ) / FONT_WORKAROUND_SCALE );
00782 }
00783
00784 double QgsComposerItem::fontAscentMillimeters( const QFont& font ) const
00785 {
00786 QFont metricsFont = scaledFontPixelSize( font );
00787 QFontMetricsF fontMetrics( metricsFont );
00788 return ( fontMetrics.ascent() / FONT_WORKAROUND_SCALE );
00789 }
00790
00791 double QgsComposerItem::pixelFontSize( double pointSize ) const
00792 {
00793 return ( pointSize * 0.3527 );
00794 }
00795
00796 QFont QgsComposerItem::scaledFontPixelSize( const QFont& font ) const
00797 {
00798 QFont scaledFont = font;
00799 double pixelSize = pixelFontSize( font.pointSizeF() ) * FONT_WORKAROUND_SCALE + 0.5;
00800 scaledFont.setPixelSize( pixelSize );
00801 return scaledFont;
00802 }
00803
00804 double QgsComposerItem::angle( const QPointF& p1, const QPointF& p2 ) const
00805 {
00806 double xDiff = p2.x() - p1.x();
00807 double yDiff = p2.y() - p1.y();
00808 double length = sqrt( xDiff * xDiff + yDiff * yDiff );
00809 if ( length <= 0 )
00810 {
00811 return 0;
00812 }
00813
00814 double angle = acos(( -yDiff * length ) / ( length * length ) ) * 180 / M_PI;
00815 if ( xDiff < 0 )
00816 {
00817 return ( 360 - angle );
00818 }
00819 return angle;
00820 }
00821
00822 double QgsComposerItem::horizontalViewScaleFactor() const
00823 {
00824 double result = -1;
00825 if ( scene() )
00826 {
00827 QList<QGraphicsView*> viewList = scene()->views();
00828 if ( viewList.size() > 0 )
00829 {
00830 QGraphicsView* currentView = viewList.at( 0 );
00831 if ( currentView->isVisible() )
00832 {
00833 result = currentView->transform().m11();
00834 mLastValidViewScaleFactor = result;
00835 }
00836 }
00837 }
00838 return result;
00839 }
00840
00841 double QgsComposerItem::rectHandlerBorderTolerance() const
00842 {
00843
00844 double viewScaleFactor = horizontalViewScaleFactor();
00845 double rectHandlerSize = 10.0 / viewScaleFactor;
00846
00847
00848 if ( rectHandlerSize > ( rect().width() / 3 ) )
00849 {
00850 rectHandlerSize = rect().width() / 3;
00851 }
00852 if ( rectHandlerSize > ( rect().height() / 3 ) )
00853 {
00854 rectHandlerSize = rect().height() / 3;
00855 }
00856 return rectHandlerSize;
00857 }
00858
00859 double QgsComposerItem::lockSymbolSize() const
00860 {
00861 double lockSymbolSize = 20.0 / horizontalViewScaleFactor();
00862
00863 if ( lockSymbolSize > ( rect().width() / 3 ) )
00864 {
00865 lockSymbolSize = rect().width() / 3;
00866 }
00867 if ( lockSymbolSize > ( rect().height() / 3 ) )
00868 {
00869 lockSymbolSize = rect().height() / 3;
00870 }
00871 return lockSymbolSize;
00872 }
00873
00874 void QgsComposerItem::updateCursor( const QPointF& itemPos )
00875 {
00876 setCursor( cursorForPosition( itemPos ) );
00877 }
00878
00879 void QgsComposerItem::setRotation( double r )
00880 {
00881 if ( r > 360 )
00882 {
00883 mRotation = (( int )r ) % 360;
00884 }
00885 else
00886 {
00887 mRotation = r;
00888 }
00889 emit rotationChanged( r );
00890 update();
00891 }
00892
00893 bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height ) const
00894 {
00895 if ( abs( mRotation ) <= 0 )
00896 {
00897 return true;
00898 }
00899
00900 double x1 = 0;
00901 double y1 = 0;
00902 double x2 = width;
00903 double y2 = 0;
00904 double x3 = width;
00905 double y3 = height;
00906 double x4 = 0;
00907 double y4 = height;
00908 double midX = width / 2.0;
00909 double midY = height / 2.0;
00910
00911 if ( !cornerPointOnRotatedAndScaledRect( x1, y1, width, height ) )
00912 {
00913 return false;
00914 }
00915 if ( !cornerPointOnRotatedAndScaledRect( x2, y2, width, height ) )
00916 {
00917 return false;
00918 }
00919 if ( !cornerPointOnRotatedAndScaledRect( x3, y3, width, height ) )
00920 {
00921 return false;
00922 }
00923 if ( !cornerPointOnRotatedAndScaledRect( x4, y4, width, height ) )
00924 {
00925 return false;
00926 }
00927
00928
00929
00930 double distM1 = sqrt(( x1 - midX ) * ( x1 - midX ) + ( y1 - midY ) * ( y1 - midY ) );
00931 QPointF p2 = pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x2, y2 ), distM1 );
00932 QPointF p4 = pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x4, y4 ), distM1 );
00933
00934 if ( p2.x() < width && p2.x() > 0 && p2.y() < height && p2.y() > 0 )
00935 {
00936 width = sqrt(( p2.x() - x1 ) * ( p2.x() - x1 ) + ( p2.y() - y1 ) * ( p2.y() - y1 ) );
00937 height = sqrt(( x3 - p2.x() ) * ( x3 - p2.x() ) + ( y3 - p2.y() ) * ( y3 - p2.y() ) );
00938 return true;
00939 }
00940
00941
00942 double distM2 = sqrt(( x2 - midX ) * ( x2 - midX ) + ( y2 - midY ) * ( y2 - midY ) );
00943 QPointF p1 = pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x1, y1 ), distM2 );
00944 QPointF p3 = pointOnLineWithDistance( QPointF( midX, midY ), QPointF( x3, y3 ), distM2 );
00945 width = sqrt(( x2 - p1.x() ) * ( x2 - p1.x() ) + ( y2 - p1.y() ) * ( y2 - p1.y() ) );
00946 height = sqrt(( p3.x() - x2 ) * ( p3.x() - x2 ) + ( p3.y() - y2 ) * ( p3.y() - y2 ) );
00947 return true;
00948
00949
00950 #if 0
00951 double x1 = 0;
00952 double y1 = 0;
00953 double x2 = width;
00954 double y2 = 0;
00955 double x3 = width;
00956 double y3 = height;
00957
00958 if ( !cornerPointOnRotatedAndScaledRect( x1, y1, width, height ) )
00959 {
00960 return false;
00961 }
00962 if ( !cornerPointOnRotatedAndScaledRect( x2, y2, width, height ) )
00963 {
00964 return false;
00965 }
00966 if ( !cornerPointOnRotatedAndScaledRect( x3, y3, width, height ) )
00967 {
00968 return false;
00969 }
00970
00971 width = sqrt(( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) );
00972 height = sqrt(( x3 - x2 ) * ( x3 - x2 ) + ( y3 - y2 ) * ( y3 - y2 ) );
00973 return true;
00974 #endif //0
00975 }
00976
00977 bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const
00978 {
00979
00980 double rotToRad = mRotation * M_PI / 180.0;
00981 QPointF midpoint( width / 2.0, height / 2.0 );
00982 double xVector = x - midpoint.x();
00983 double yVector = y - midpoint.y();
00984
00985
00986 double xRotated = cos( rotToRad ) * xVector - sin( rotToRad ) * yVector;
00987 double yRotated = sin( rotToRad ) * xVector + cos( rotToRad ) * yVector;
00988
00989
00990 QLineF line( midpoint.x(), midpoint.y(), midpoint.x() + xRotated, midpoint.y() + yRotated );
00991
00992
00993 QList<QLineF> borders;
00994 borders << QLineF( 0, 0, width, 0 );
00995 borders << QLineF( width, 0, width, height );
00996 borders << QLineF( width, height, 0, height );
00997 borders << QLineF( 0, height, 0, 0 );
00998
00999 QList<QLineF>::const_iterator it = borders.constBegin();
01000 QPointF intersectionPoint;
01001
01002 for ( ; it != borders.constEnd(); ++it )
01003 {
01004 if ( line.intersect( *it, &intersectionPoint ) == QLineF::BoundedIntersection )
01005 {
01006 x = intersectionPoint.x();
01007 y = intersectionPoint.y();
01008 return true;
01009 }
01010 }
01011 return false;
01012 }
01013
01014 QPointF QgsComposerItem::pointOnLineWithDistance( const QPointF& startPoint, const QPointF& directionPoint, double distance ) const
01015 {
01016 double dx = directionPoint.x() - startPoint.x();
01017 double dy = directionPoint.y() - startPoint.y();
01018 double length = sqrt( dx * dx + dy * dy );
01019 double scaleFactor = distance / length;
01020 return QPointF( startPoint.x() + dx * scaleFactor, startPoint.y() + dy * scaleFactor );
01021 }
01022
01023 void QgsComposerItem::sizeChangedByRotation( double& width, double& height )
01024 {
01025 if ( mRotation == 0.0 )
01026 {
01027 return;
01028 }
01029
01030
01031 double x1 = -width / 2.0;
01032 double y1 = -height / 2.0;
01033 rotate( mRotation, x1, y1 );
01034
01035 double x2 = width / 2.0;
01036 double y2 = -height / 2.0;
01037 rotate( mRotation, x2, y2 );
01038
01039 double x3 = width / 2.0;
01040 double y3 = height / 2.0;
01041 rotate( mRotation, x3, y3 );
01042
01043 double x4 = -width / 2.0;
01044 double y4 = height / 2.0;
01045 rotate( mRotation, x4, y4 );
01046
01047
01048 QPointF midpoint( width / 2.0, height / 2.0 );
01049
01050 QPolygonF rotatedRectPoly;
01051 rotatedRectPoly << QPointF( midpoint.x() + x1, midpoint.y() + y1 );
01052 rotatedRectPoly << QPointF( midpoint.x() + x2, midpoint.y() + y2 );
01053 rotatedRectPoly << QPointF( midpoint.x() + x3, midpoint.y() + y3 );
01054 rotatedRectPoly << QPointF( midpoint.x() + x4, midpoint.y() + y4 );
01055 QRectF boundingRect = rotatedRectPoly.boundingRect();
01056 width = boundingRect.width();
01057 height = boundingRect.height();
01058 }
01059
01060 void QgsComposerItem::rotate( double angle, double& x, double& y ) const
01061 {
01062 double rotToRad = angle * M_PI / 180.0;
01063 double xRot, yRot;
01064 xRot = x * cos( rotToRad ) - y * sin( rotToRad );
01065 yRot = x * sin( rotToRad ) + y * cos( rotToRad );
01066 x = xRot;
01067 y = yRot;
01068 }
01069
01070 void QgsComposerItem::repaint()
01071 {
01072 update();
01073 }