From 719c78c2c7938f33282a201667ec1d5f4695ef69 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 30 Dec 2013 19:50:00 +1100 Subject: [PATCH] [composer] Clean up item rotation api, seperate item rotation (for shapes, labels) from map rotation and picture rotation. Maintain compatibility with 2.0 api, deprecate ambiguous rotation/setRotation methods --- python/core/composer/qgscomposeritem.sip | 36 ++++++++- .../core/composer/qgscomposeritemcommand.sip | 8 +- python/core/composer/qgscomposerlabel.sip | 6 ++ python/core/composer/qgscomposermap.sip | 34 +++++++++ python/core/composer/qgscomposerpicture.sip | 39 +++++++++- python/core/composer/qgscomposershape.sip | 2 +- src/app/composer/qgscomposerlabelwidget.cpp | 6 +- src/app/composer/qgscomposermapwidget.cpp | 4 +- src/app/composer/qgscomposermapwidget.h | 2 +- src/app/composer/qgscomposerpicturewidget.cpp | 29 +++++--- src/app/composer/qgscomposerpicturewidget.h | 6 +- src/app/composer/qgscomposershapewidget.cpp | 8 +- src/core/composer/qgscomposeritem.cpp | 58 +++++++++++---- src/core/composer/qgscomposeritem.h | 44 +++++++++-- src/core/composer/qgscomposeritemcommand.h | 6 +- src/core/composer/qgscomposerlabel.cpp | 26 +++++-- src/core/composer/qgscomposerlabel.h | 6 ++ src/core/composer/qgscomposermap.cpp | 73 +++++++++++++++---- src/core/composer/qgscomposermap.h | 37 ++++++++++ src/core/composer/qgscomposerpicture.cpp | 69 ++++++++++++++---- src/core/composer/qgscomposerpicture.h | 42 ++++++++++- src/core/composer/qgscomposershape.cpp | 14 +++- src/core/composer/qgscomposershape.h | 2 +- src/ui/qgscomposermapwidgetbase.ui | 8 +- src/ui/qgscomposerpicturewidgetbase.ui | 4 +- tests/src/core/testqgscomposermap.cpp | 2 +- tests/src/python/test_qgscomposermap.py | 2 +- 27 files changed, 473 insertions(+), 100 deletions(-) diff --git a/python/core/composer/qgscomposeritem.sip b/python/core/composer/qgscomposeritem.sip index 9cf39027361..3260e3be429 100644 --- a/python/core/composer/qgscomposeritem.sip +++ b/python/core/composer/qgscomposeritem.sip @@ -332,6 +332,14 @@ class QgsComposerItem: QObject, QGraphicsRectItem @note this method was added in version 1.2*/ bool positionLock() const; + /**Returns the rotation for the composer item + @note this method was added in version 2.1*/ + double itemRotation() const; + + /**Returns the rotation for the composer item + * @deprecated Use itemRotation() + * instead + */ double rotation() const; /**Updates item, with the possibility to do custom update for subclasses*/ @@ -351,7 +359,15 @@ class QgsComposerItem: QObject, QGraphicsRectItem QString uuid() const; public slots: + /**Sets the item rotation + * @deprecated Use setItemRotation( double rotation ) instead + */ virtual void setRotation( double r ); + + /**Sets the item rotation + @note this method was added in version 2.1 + */ + virtual void setItemRotation( double r ); void repaint(); protected: @@ -394,11 +410,27 @@ class QgsComposerItem: QObject, QGraphicsRectItem //some utility functions /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation*/ + bool imageSizeConsideringRotation( double& width, double& height, double rotation ) const; + /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation + * @deprecated Use bool imageSizeConsideringRotation( double& width, double& height, double rotation ) + * instead + */ bool imageSizeConsideringRotation( double& width, double& height ) const; + /**Calculates corner point after rotation and scaling*/ + bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) const; + /**Calculates corner point after rotation and scaling + * @deprecated Use bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) + * instead + */ bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const; - /**Calculates width / height of the bounding box of a rotated rectangle (mRotation)*/ + /**Calculates width / height of the bounding box of a rotated rectangle*/ + void sizeChangedByRotation( double& width, double& height, double rotation ); + /**Calculates width / height of the bounding box of a rotated rectangle + * @deprecated Use void sizeChangedByRotation( double& width, double& height, double rotation ) + * instead + */ void sizeChangedByRotation( double& width, double& height ); /**Rotates a point / vector @param angle rotation angle in degrees, counterclockwise @@ -416,7 +448,7 @@ class QgsComposerItem: QObject, QGraphicsRectItem signals: /**Is emitted on rotation change to notify north arrow pictures*/ - void rotationChanged( double newRotation ); + void itemRotationChanged( double newRotation ); /**Used e.g. by the item widgets to update the gui elements*/ void itemChanged(); /**Emitted if the rectangle changes*/ diff --git a/python/core/composer/qgscomposeritemcommand.sip b/python/core/composer/qgscomposeritemcommand.sip index da49e851143..0ecbaef4a9b 100644 --- a/python/core/composer/qgscomposeritemcommand.sip +++ b/python/core/composer/qgscomposeritemcommand.sip @@ -46,7 +46,6 @@ class QgsComposerMergeCommand : QgsComposerItemCommand //composer label ComposerLabelSetText, ComposerLabelSetId, - ComposerLabelRotation, //composer map ComposerMapRotation, ComposerMapAnnotationDistance, @@ -57,6 +56,8 @@ class QgsComposerMergeCommand : QgsComposerItemCommand LegendEqualColumnWidth, LegendSymbolWidth, LegendSymbolHeight, + LegendWmsLegendWidth, + LegendWmsLegendHeight, LegendTitleSpaceBottom, LegendGroupSpace, LegendLayerSpace, @@ -81,14 +82,15 @@ class QgsComposerMergeCommand : QgsComposerItemCommand TableMargin, TableGridStrokeWidth, //composer shape - ShapeRotation, + ShapeCornerRadius, ShapeOutlineWidth, //composer arrow ArrowOutlineWidth, ArrowHeadWidth, //item ItemOutlineWidth, - ItemMove + ItemMove, + ItemRotation }; QgsComposerMergeCommand( Context c, QgsComposerItem* item, const QString& text ); diff --git a/python/core/composer/qgscomposerlabel.sip b/python/core/composer/qgscomposerlabel.sip index 50fb35b31c5..361c19393a3 100644 --- a/python/core/composer/qgscomposerlabel.sip +++ b/python/core/composer/qgscomposerlabel.sip @@ -79,5 +79,11 @@ class QgsComposerLabel : QgsComposerItem bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); public slots: + /* Sets rotation for the label + * @deprecated Use setItemRotation( double rotation ) instead + */ virtual void setRotation( double r ); + + /* Sets rotation for the label */ + virtual void setItemRotation( double r ); }; diff --git a/python/core/composer/qgscomposermap.sip b/python/core/composer/qgscomposermap.sip index c6172ac85a6..647805d5d40 100644 --- a/python/core/composer/qgscomposermap.sip +++ b/python/core/composer/qgscomposermap.sip @@ -293,7 +293,22 @@ class QgsComposerMap : QgsComposerItem void setCrossLength( double l ); double crossLength(); + /**Sets rotation for the map - this does not affect the composer item shape, only the + way the map is drawn within the item + * @deprecated Use setMapRotation( double rotation ) instead + */ + void setRotation( double r ); + /**Returns the rotation used for drawing the map within the composer item + * @deprecated Use mapRotation() instead + */ + double rotation() const; + + /**Sets rotation for the map - this does not affect the composer item shape, only the + way the map is drawn within the item + @note this function was added in version 2.1*/ void setMapRotation( double r ); + /**Returns the rotation used for drawing the map within the composer item*/ + double mapRotation() const; void updateItem(); @@ -336,9 +351,28 @@ class QgsComposerMap : QgsComposerItem /**Sets mId to a number not yet used in the composition. mId is kept if it is not in use. Usually, this function is called before adding the composer map to the composition*/ void assignFreeId(); + + /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation + * @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation ) + * instead + */ + bool imageSizeConsideringRotation( double& width, double& height ) const; + /**Calculates corner point after rotation and scaling + * @deprecated Use QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) + * instead + */ + bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const; + /**Calculates width / height of the bounding box of a rotated rectangle + * @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation ) + * instead + */ + void sizeChangedByRotation( double& width, double& height ); signals: void extentChanged(); + + /**Is emitted on rotation change to notify north arrow pictures*/ + void mapRotationChanged( double newRotation ); public slots: diff --git a/python/core/composer/qgscomposerpicture.sip b/python/core/composer/qgscomposerpicture.sip index 7bcf25c29d8..1bcdcdcc096 100644 --- a/python/core/composer/qgscomposerpicture.sip +++ b/python/core/composer/qgscomposerpicture.sip @@ -38,6 +38,15 @@ class QgsComposerPicture: QgsComposerItem */ bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); + /**Returns the rotation used for drawing the picture within the composer item + * @deprecated Use pictureRotation() instead + */ + double rotation() const; + + /**Returns the rotation used for drawing the picture within the item + @note this function was added in version 2.1*/ + double pictureRotation() const; + /**Sets the map object for rotation (by id). A value of -1 disables the map rotation*/ void setRotationMap( int composerMapId ); /**Returns the id of the rotation map*/ @@ -45,7 +54,35 @@ class QgsComposerPicture: QgsComposerItem /**True if the rotation is taken from a map item*/ bool useRotationMap() const; + /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation + * @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation ) + * instead + */ + bool imageSizeConsideringRotation( double& width, double& height ) const; + /**Calculates corner point after rotation and scaling + * @deprecated Use QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) + * instead + */ + bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const; + /**Calculates width / height of the bounding box of a rotated rectangle + * @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation ) + * instead + */ + void sizeChangedByRotation( double& width, double& height ); + public slots: - /**Sets the rotation and adapts the item rect*/ + /**Sets the picture rotation within the item bounds. This does not affect the item rectangle, + only the way the picture is drawn within the item. + * @deprecated Use setPictureRotation( double rotation ) instead + */ virtual void setRotation( double r ); + + /**Sets the picture rotation within the item bounds. This does not affect the item rectangle, + only the way the picture is drawn within the item. + @note this function was added in version 2.1*/ + virtual void setPictureRotation( double r ); + + signals: + /**Is emitted on picture rotation change*/ + void pictureRotationChanged( double newRotation ); }; diff --git a/python/core/composer/qgscomposershape.sip b/python/core/composer/qgscomposershape.sip index 68f3fb5aa10..4318f56300b 100644 --- a/python/core/composer/qgscomposershape.sip +++ b/python/core/composer/qgscomposershape.sip @@ -50,7 +50,7 @@ class QgsComposerShape: QgsComposerItem public slots: /**Sets item rotation and resizes item bounds such that the shape always has the same size*/ - virtual void setRotation( double r ); + virtual void setItemRotation( double r ); protected: /* reimplement drawFrame, since it's not a rect, but a custom shape */ diff --git a/src/app/composer/qgscomposerlabelwidget.cpp b/src/app/composer/qgscomposerlabelwidget.cpp index d658cd51a45..0421cea3e5a 100644 --- a/src/app/composer/qgscomposerlabelwidget.cpp +++ b/src/app/composer/qgscomposerlabelwidget.cpp @@ -232,8 +232,8 @@ void QgsComposerLabelWidget::on_mRotationSpinBox_valueChanged( double v ) { if ( mComposerLabel ) { - mComposerLabel->beginCommand( tr( "Label rotation changed" ), QgsComposerMergeCommand::ComposerLabelRotation ); - mComposerLabel->setRotation( v ); + mComposerLabel->beginCommand( tr( "Label rotation changed" ), QgsComposerMergeCommand::ItemRotation ); + mComposerLabel->setItemRotation( v ); mComposerLabel->update(); mComposerLabel->endCommand(); } @@ -252,7 +252,7 @@ void QgsComposerLabelWidget::setGuiElementValues() mLeftRadioButton->setChecked( mComposerLabel->hAlign() == Qt::AlignLeft ); mCenterRadioButton->setChecked( mComposerLabel->hAlign() == Qt::AlignHCenter ); mRightRadioButton->setChecked( mComposerLabel->hAlign() == Qt::AlignRight ); - mRotationSpinBox->setValue( mComposerLabel->rotation() ); + mRotationSpinBox->setValue( mComposerLabel->itemRotation() ); blockAllSignals( false ); } diff --git a/src/app/composer/qgscomposermapwidget.cpp b/src/app/composer/qgscomposermapwidget.cpp index 4f263ec268e..ff1e2bdbaa4 100644 --- a/src/app/composer/qgscomposermapwidget.cpp +++ b/src/app/composer/qgscomposermapwidget.cpp @@ -161,7 +161,7 @@ void QgsComposerMapWidget::on_mScaleLineEdit_editingFinished() mComposerMap->endCommand(); } -void QgsComposerMapWidget::on_mRotationSpinBox_valueChanged( double value ) +void QgsComposerMapWidget::on_mMapRotationSpinBox_valueChanged( double value ) { if ( !mComposerMap ) { @@ -291,7 +291,7 @@ void QgsComposerMapWidget::updateGuiElements() mYMinLineEdit->setText( QString::number( composerMapExtent.yMinimum(), 'f', 3 ) ); mYMaxLineEdit->setText( QString::number( composerMapExtent.yMaximum(), 'f', 3 ) ); - mRotationSpinBox->setValue( mComposerMap->rotation() ); + mMapRotationSpinBox->setValue( mComposerMap->mapRotation() ); //keep layer list check box if ( mComposerMap->keepLayerSet() ) diff --git a/src/app/composer/qgscomposermapwidget.h b/src/app/composer/qgscomposermapwidget.h index a5f5ac1cc7d..f68fabf6d59 100644 --- a/src/app/composer/qgscomposermapwidget.h +++ b/src/app/composer/qgscomposermapwidget.h @@ -37,7 +37,7 @@ class QgsComposerMapWidget: public QWidget, private Ui::QgsComposerMapWidgetBase public slots: void on_mPreviewModeComboBox_activated( int i ); void on_mScaleLineEdit_editingFinished(); - void on_mRotationSpinBox_valueChanged( double value ); + void on_mMapRotationSpinBox_valueChanged( double value ); void on_mSetToMapCanvasExtentButton_clicked(); void on_mUpdatePreviewButton_clicked(); void on_mKeepLayerListCheckBox_stateChanged( int state ); diff --git a/src/app/composer/qgscomposerpicturewidget.cpp b/src/app/composer/qgscomposerpicturewidget.cpp index 5ea3d9d56b4..653fbc7c957 100644 --- a/src/app/composer/qgscomposerpicturewidget.cpp +++ b/src/app/composer/qgscomposerpicturewidget.cpp @@ -50,7 +50,7 @@ QgsComposerPictureWidget::QgsComposerPictureWidget( QgsComposerPicture* picture connect( mSearchDirectoriesGroupBox, SIGNAL( collapsedStateChanged( bool ) ), this, SLOT( loadPicturePreviews( bool ) ) ); connect( mPicture, SIGNAL( itemChanged() ), this, SLOT( setGuiElementValues() ) ); - connect( mPicture, SIGNAL( rotationChanged( double ) ), this, SLOT( setGuiElementValues() ) ); + connect( mPicture, SIGNAL( pictureRotationChanged( double ) ), this, SLOT( setPicRotationSpinValue( double ) ) ); } QgsComposerPictureWidget::~QgsComposerPictureWidget() @@ -121,13 +121,12 @@ void QgsComposerPictureWidget::on_mPictureLineEdit_editingFinished() } -void QgsComposerPictureWidget::on_mRotationSpinBox_valueChanged( double d ) +void QgsComposerPictureWidget::on_mPictureRotationSpinBox_valueChanged( double d ) { if ( mPicture ) { mPicture->beginCommand( tr( "Picture rotation changed" ), QgsComposerMergeCommand::ComposerPictureRotation ); - mPicture->setRotation( d ); - mPicture->update(); + mPicture->setPictureRotation( d ); mPicture->endCommand(); } } @@ -210,8 +209,9 @@ void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged( if ( state == Qt::Unchecked ) { mPicture->setRotationMap( -1 ); - mRotationSpinBox->setEnabled( true ); + mPictureRotationSpinBox->setEnabled( true ); mComposerMapComboBox->setEnabled( false ); + mPicture->setPictureRotation( mPictureRotationSpinBox->value() ); } else { @@ -223,7 +223,7 @@ void QgsComposerPictureWidget::on_mRotationFromComposerMapCheckBox_stateChanged( int composerId = mComposerMapComboBox->itemData( currentItemIndex, Qt::UserRole ).toInt(); mPicture->setRotationMap( composerId ); - mRotationSpinBox->setEnabled( false ); + mPictureRotationSpinBox->setEnabled( false ); mComposerMapComboBox->setEnabled( true ); } mPicture->endCommand(); @@ -310,26 +310,33 @@ void QgsComposerPictureWidget::refreshMapComboBox() mComposerMapComboBox->blockSignals( false ); } +void QgsComposerPictureWidget::setPicRotationSpinValue( double r ) +{ + mPictureRotationSpinBox->blockSignals( true ); + mPictureRotationSpinBox->setValue( r ); + mPictureRotationSpinBox->blockSignals( false ); +} + void QgsComposerPictureWidget::setGuiElementValues() { //set initial gui values if ( mPicture ) { - mRotationSpinBox->blockSignals( true ); + mPictureRotationSpinBox->blockSignals( true ); mPictureLineEdit->blockSignals( true ); mComposerMapComboBox->blockSignals( true ); mRotationFromComposerMapCheckBox->blockSignals( true ); mPictureLineEdit->setText( mPicture->pictureFile() ); // QRectF pictureRect = mPicture->rect(); - mRotationSpinBox->setValue( mPicture->rotation() ); + mPictureRotationSpinBox->setValue( mPicture->pictureRotation() ); refreshMapComboBox(); if ( mPicture->useRotationMap() ) { mRotationFromComposerMapCheckBox->setCheckState( Qt::Checked ); - mRotationSpinBox->setEnabled( false ); + mPictureRotationSpinBox->setEnabled( false ); mComposerMapComboBox->setEnabled( true ); QString mapText = tr( "Map %1" ).arg( mPicture->rotationMap() ); int itemId = mComposerMapComboBox->findText( mapText ); @@ -341,13 +348,13 @@ void QgsComposerPictureWidget::setGuiElementValues() else { mRotationFromComposerMapCheckBox->setCheckState( Qt::Unchecked ); - mRotationSpinBox->setEnabled( true ); + mPictureRotationSpinBox->setEnabled( true ); mComposerMapComboBox->setEnabled( false ); } mRotationFromComposerMapCheckBox->blockSignals( false ); - mRotationSpinBox->blockSignals( false ); + mPictureRotationSpinBox->blockSignals( false ); mPictureLineEdit->blockSignals( false ); mComposerMapComboBox->blockSignals( false ); } diff --git a/src/app/composer/qgscomposerpicturewidget.h b/src/app/composer/qgscomposerpicturewidget.h index 00557b40df7..6f1f2827e88 100644 --- a/src/app/composer/qgscomposerpicturewidget.h +++ b/src/app/composer/qgscomposerpicturewidget.h @@ -39,7 +39,7 @@ class QgsComposerPictureWidget: public QWidget, private Ui::QgsComposerPictureWi public slots: void on_mPictureBrowseButton_clicked(); void on_mPictureLineEdit_editingFinished(); - void on_mRotationSpinBox_valueChanged( double d ); + void on_mPictureRotationSpinBox_valueChanged( double d ); void on_mPreviewListWidget_currentItemChanged( QListWidgetItem* current, QListWidgetItem* previous ); void on_mAddDirectoryButton_clicked(); void on_mRemoveDirectoryButton_clicked(); @@ -53,6 +53,10 @@ class QgsComposerPictureWidget: public QWidget, private Ui::QgsComposerPictureWi private slots: /**Sets the GUI elements to the values of mPicture*/ void setGuiElementValues(); + + /**Sets the picture rotation GUI control value*/ + void setPicRotationSpinValue( double r ); + /** Load SVG and pixel-based image previews * @param collapsed Whether the parent group box is collapsed * @note added in 1.9 diff --git a/src/app/composer/qgscomposershapewidget.cpp b/src/app/composer/qgscomposershapewidget.cpp index 7a63b2a80ad..7926e8aade6 100644 --- a/src/app/composer/qgscomposershapewidget.cpp +++ b/src/app/composer/qgscomposershapewidget.cpp @@ -66,7 +66,7 @@ void QgsComposerShapeWidget::setGuiElementValues() blockAllSignals( true ); - mRotationSpinBox->setValue( mComposerShape->rotation() ); + mRotationSpinBox->setValue( mComposerShape->itemRotation() ); mCornerRadiusSpinBox->setValue( mComposerShape->cornerRadius() ); if ( mComposerShape->shapeType() == QgsComposerShape::Ellipse ) { @@ -91,8 +91,8 @@ void QgsComposerShapeWidget::on_mRotationSpinBox_valueChanged( int val ) { if ( mComposerShape ) { - mComposerShape->beginCommand( tr( "Shape rotation changed" ), QgsComposerMergeCommand::ShapeRotation ); - mComposerShape->setRotation( val ); + mComposerShape->beginCommand( tr( "Shape rotation changed" ), QgsComposerMergeCommand::ItemRotation ); + mComposerShape->setItemRotation( val ); mComposerShape->update(); mComposerShape->endCommand(); } @@ -102,7 +102,7 @@ void QgsComposerShapeWidget::on_mCornerRadiusSpinBox_valueChanged( double val ) { if ( mComposerShape ) { - mComposerShape->beginCommand( tr( "Shape radius changed" ), QgsComposerMergeCommand::ShapeRotation ); + mComposerShape->beginCommand( tr( "Shape radius changed" ), QgsComposerMergeCommand::ShapeCornerRadius ); mComposerShape->setCornerRadius( val ); mComposerShape->update(); mComposerShape->endCommand(); diff --git a/src/core/composer/qgscomposeritem.cpp b/src/core/composer/qgscomposeritem.cpp index c0bbc8cd3de..c6b4b2c401f 100644 --- a/src/core/composer/qgscomposeritem.cpp +++ b/src/core/composer/qgscomposeritem.cpp @@ -54,7 +54,7 @@ QgsComposerItem::QgsComposerItem( QgsComposition* composition, bool manageZValue , mBackgroundColor( QColor( 255, 255, 255, 255 ) ) , mItemPositionLocked( false ) , mLastValidViewScaleFactor( -1 ) - , mRotation( 0 ) + , mItemRotation( 0 ) , mBlendMode( QPainter::CompositionMode_SourceOver ) , mEffectsEnabled( true ) , mTransparency( 0 ) @@ -77,7 +77,7 @@ QgsComposerItem::QgsComposerItem( qreal x, qreal y, qreal width, qreal height, Q , mBackgroundColor( QColor( 255, 255, 255, 255 ) ) , mItemPositionLocked( false ) , mLastValidViewScaleFactor( -1 ) - , mRotation( 0 ) + , mItemRotation( 0 ) , mBlendMode( QPainter::CompositionMode_SourceOver ) , mEffectsEnabled( true ) , mTransparency( 0 ) @@ -170,7 +170,7 @@ bool QgsComposerItem::_writeXML( QDomElement& itemElem, QDomDocument& doc ) cons composerItemElem.setAttribute( "positionMode", QString::number(( int ) mLastUsedPositionMode ) ); composerItemElem.setAttribute( "zValue", QString::number( zValue() ) ); composerItemElem.setAttribute( "outlineWidth", QString::number( pen().widthF() ) ); - composerItemElem.setAttribute( "rotation", QString::number( mRotation ) ); + composerItemElem.setAttribute( "itemRotation", QString::number( mItemRotation ) ); composerItemElem.setAttribute( "uuid", mUuid ); composerItemElem.setAttribute( "id", mId ); //position lock for mouse moves/resizes @@ -224,7 +224,10 @@ bool QgsComposerItem::_readXML( const QDomElement& itemElem, const QDomDocument& } //rotation - mRotation = itemElem.attribute( "rotation", "0" ).toDouble(); + if ( itemElem.attribute( "itemRotation", "0" ).toDouble() != 0 ) + { + mItemRotation = itemElem.attribute( "itemRotation", "0" ).toDouble(); + } //uuid mUuid = itemElem.attribute( "uuid", QUuid::createUuid().toString() ); @@ -697,27 +700,40 @@ double QgsComposerItem::lockSymbolSize() const } void QgsComposerItem::setRotation( double r ) +{ + //kept for api compatibility with QGIS 2.0 + //remove after 2.0 series + setItemRotation( r ); +} + +void QgsComposerItem::setItemRotation( double r ) { if ( r > 360 ) { - mRotation = (( int )r ) % 360; + mItemRotation = (( int )r ) % 360; } else { - mRotation = r; + mItemRotation = r; } - emit rotationChanged( r ); + emit itemRotationChanged( r ); update(); } bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height ) const { - if ( qAbs( mRotation ) <= 0.0 ) //width and height stays the same if there is no rotation + //kept for api compatibility with QGIS 2.0, use item rotation + return imageSizeConsideringRotation( width, height, mItemRotation ); +} + +bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation ) const +{ + if ( qAbs( rotation ) <= 0.0 ) //width and height stays the same if there is no rotation { return true; } - if ( qgsDoubleNear( qAbs( mRotation ), 90 ) || qgsDoubleNear( qAbs( mRotation ), 270 ) ) + if ( qgsDoubleNear( qAbs( rotation ), 90 ) || qgsDoubleNear( qAbs( rotation ), 270 ) ) { double tmp = width; width = height; @@ -775,9 +791,15 @@ bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& heigh } bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const +{ + //kept for api compatibility with QGIS 2.0, use item rotation + return cornerPointOnRotatedAndScaledRect( x, y, width, height, mItemRotation ); +} + +bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) const { //first rotate point clockwise - double rotToRad = mRotation * M_PI / 180.0; + double rotToRad = rotation * M_PI / 180.0; QPointF midpoint( width / 2.0, height / 2.0 ); double xVector = x - midpoint.x(); double yVector = y - midpoint.y(); @@ -813,7 +835,13 @@ bool QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, d void QgsComposerItem::sizeChangedByRotation( double& width, double& height ) { - if ( mRotation == 0.0 ) + //kept for api compatibility with QGIS 2.0, use item rotation + return sizeChangedByRotation( width, height, mItemRotation ); +} + +void QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation ) +{ + if ( rotation == 0.0 ) { return; } @@ -821,19 +849,19 @@ void QgsComposerItem::sizeChangedByRotation( double& width, double& height ) //vector to p1 double x1 = -width / 2.0; double y1 = -height / 2.0; - rotate( mRotation, x1, y1 ); + rotate( rotation, x1, y1 ); //vector to p2 double x2 = width / 2.0; double y2 = -height / 2.0; - rotate( mRotation, x2, y2 ); + rotate( rotation, x2, y2 ); //vector to p3 double x3 = width / 2.0; double y3 = height / 2.0; - rotate( mRotation, x3, y3 ); + rotate( rotation, x3, y3 ); //vector to p4 double x4 = -width / 2.0; double y4 = height / 2.0; - rotate( mRotation, x4, y4 ); + rotate( rotation, x4, y4 ); //double midpoint QPointF midpoint( width / 2.0, height / 2.0 ); diff --git a/src/core/composer/qgscomposeritem.h b/src/core/composer/qgscomposeritem.h index ef8cb93168b..1a019edf7b4 100644 --- a/src/core/composer/qgscomposeritem.h +++ b/src/core/composer/qgscomposeritem.h @@ -287,7 +287,15 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem @note this method was added in version 1.2*/ bool positionLock() const {return mItemPositionLocked;} - double rotation() const {return mRotation;} + /**Returns the rotation for the composer item + @note this method was added in version 2.1*/ + double itemRotation() const {return mItemRotation;} + + /**Returns the rotation for the composer item + * @deprecated Use itemRotation() + * instead + */ + double rotation() const {return mItemRotation;} /**Updates item, with the possibility to do custom update for subclasses*/ virtual void updateItem() { QGraphicsRectItem::update(); } @@ -306,7 +314,16 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem QString uuid() const { return mUuid; } public slots: + /**Sets the item rotation + * @deprecated Use setItemRotation( double rotation ) instead + */ virtual void setRotation( double r ); + + /**Sets the item rotation + @note this method was added in version 2.1 + */ + virtual void setItemRotation( double r ); + void repaint(); protected: @@ -339,7 +356,7 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem mutable double mLastValidViewScaleFactor; /**Item rotation in degrees, clockwise*/ - double mRotation; + double mItemRotation; /**Composition blend mode for item*/ QPainter::CompositionMode mBlendMode; @@ -384,12 +401,29 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem //some utility functions /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation*/ + bool imageSizeConsideringRotation( double& width, double& height, double rotation ) const; + /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation + * @deprecated Use bool imageSizeConsideringRotation( double& width, double& height, double rotation ) + * instead + */ bool imageSizeConsideringRotation( double& width, double& height ) const; + /**Calculates corner point after rotation and scaling*/ + bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) const; + /**Calculates corner point after rotation and scaling + * @deprecated Use bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) + * instead + */ bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const; - /**Calculates width / height of the bounding box of a rotated rectangle (mRotation)*/ + /**Calculates width / height of the bounding box of a rotated rectangle*/ + void sizeChangedByRotation( double& width, double& height, double rotation ); + /**Calculates width / height of the bounding box of a rotated rectangle + * @deprecated Use void sizeChangedByRotation( double& width, double& height, double rotation ) + * instead + */ void sizeChangedByRotation( double& width, double& height ); + /**Rotates a point / vector @param angle rotation angle in degrees, counterclockwise @param x in/out: x coordinate before / after the rotation @@ -405,8 +439,8 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem void deleteAlignItems(); signals: - /**Is emitted on rotation change to notify north arrow pictures*/ - void rotationChanged( double newRotation ); + /**Is emitted on item rotation change*/ + void itemRotationChanged( double newRotation ); /**Used e.g. by the item widgets to update the gui elements*/ void itemChanged(); /**Emitted if the rectangle changes*/ diff --git a/src/core/composer/qgscomposeritemcommand.h b/src/core/composer/qgscomposeritemcommand.h index 64245ac08b5..83e66ed777a 100644 --- a/src/core/composer/qgscomposeritemcommand.h +++ b/src/core/composer/qgscomposeritemcommand.h @@ -74,7 +74,6 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand //composer label ComposerLabelSetText, ComposerLabelSetId, - ComposerLabelRotation, //composer map ComposerMapRotation, ComposerMapAnnotationDistance, @@ -111,14 +110,15 @@ class CORE_EXPORT QgsComposerMergeCommand: public QgsComposerItemCommand TableMargin, TableGridStrokeWidth, //composer shape - ShapeRotation, + ShapeCornerRadius, ShapeOutlineWidth, //composer arrow ArrowOutlineWidth, ArrowHeadWidth, //item ItemOutlineWidth, - ItemMove + ItemMove, + ItemRotation }; QgsComposerMergeCommand( Context c, QgsComposerItem* item, const QString& text ); diff --git a/src/core/composer/qgscomposerlabel.cpp b/src/core/composer/qgscomposerlabel.cpp index dbf59652327..063fb34c933 100644 --- a/src/core/composer/qgscomposerlabel.cpp +++ b/src/core/composer/qgscomposerlabel.cpp @@ -66,7 +66,7 @@ void QgsComposerLabel::paint( QPainter* painter, const QStyleOptionGraphicsItem* double penWidth = pen().widthF(); QRectF painterRect( penWidth + mMargin, penWidth + mMargin, mTextBoxWidth - 2 * penWidth - 2 * mMargin, mTextBoxHeight - 2 * penWidth - 2 * mMargin ); painter->translate( rect().width() / 2.0, rect().height() / 2.0 ); - painter->rotate( mRotation ); + painter->rotate( mItemRotation ); painter->translate( -mTextBoxWidth / 2.0, -mTextBoxHeight / 2.0 ); if ( mHtmlState ) @@ -246,10 +246,16 @@ QFont QgsComposerLabel::font() const } void QgsComposerLabel::setRotation( double r ) +{ + //kept for api compatibility with QGIS 2.0 + setItemRotation( r ); +} + +void QgsComposerLabel::setItemRotation( double r ) { double width = mTextBoxWidth; double height = mTextBoxHeight; - QgsComposerItem::setRotation( r ); + QgsComposerItem::setItemRotation( r ); sizeChangedByRotation( width, height ); double x = pos().x() + rect().width() / 2.0 - width / 2.0; @@ -359,6 +365,14 @@ bool QgsComposerLabel::readXML( const QDomElement& itemElem, const QDomDocument& if ( composerItemList.size() > 0 ) { QDomElement composerItemElem = composerItemList.at( 0 ).toElement(); + + //rotation + if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 ) + { + //check for old (pre 2.1) rotation attribute + mItemRotation = composerItemElem.attribute( "rotation", "0" ).toDouble(); + } + _readXML( composerItemElem, doc ); } emit itemChanged(); @@ -373,7 +387,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d xShift = 0; yShift = 0; - if ( mRotation >= 0 && mRotation < 90 ) + if ( mItemRotation >= 0 && mItemRotation < 90 ) { if ( mHAlignment == Qt::AlignHCenter ) { @@ -392,7 +406,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d yShift = - ( newHeight - currentHeight ); } } - if ( mRotation >= 90 && mRotation < 180 ) + if ( mItemRotation >= 90 && mItemRotation < 180 ) { if ( mHAlignment == Qt::AlignHCenter ) { @@ -411,7 +425,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d xShift = -( newWidth - currentWidth / 2.0 ); } } - else if ( mRotation >= 180 && mRotation < 270 ) + else if ( mItemRotation >= 180 && mItemRotation < 270 ) { if ( mHAlignment == Qt::AlignHCenter ) { @@ -430,7 +444,7 @@ void QgsComposerLabel::itemShiftAdjustSize( double newWidth, double newHeight, d yShift = ( newHeight - currentHeight ); } } - else if ( mRotation >= 270 && mRotation < 360 ) + else if ( mItemRotation >= 270 && mItemRotation < 360 ) { if ( mHAlignment == Qt::AlignHCenter ) { diff --git a/src/core/composer/qgscomposerlabel.h b/src/core/composer/qgscomposerlabel.h index eab7ff90e1a..78ccd7f2941 100644 --- a/src/core/composer/qgscomposerlabel.h +++ b/src/core/composer/qgscomposerlabel.h @@ -102,8 +102,14 @@ class CORE_EXPORT QgsComposerLabel: public QgsComposerItem bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); public slots: + /* Sets rotation for the label + * @deprecated Use setItemRotation( double rotation ) instead + */ virtual void setRotation( double r ); + /* Sets rotation for the label */ + virtual void setItemRotation( double r ); + private slots: void loadingHtmlFinished( bool ); diff --git a/src/core/composer/qgscomposermap.cpp b/src/core/composer/qgscomposermap.cpp index 0762291296b..450ca288b13 100644 --- a/src/core/composer/qgscomposermap.cpp +++ b/src/core/composer/qgscomposermap.cpp @@ -40,7 +40,7 @@ #include QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int width, int height ) - : QgsComposerItem( x, y, width, height, composition ), mKeepLayerSet( false ), + : QgsComposerItem( x, y, width, height, composition ), mMapRotation( 0 ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false ), mGridEnabled( false ), mGridStyle( Solid ), mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ), @@ -98,7 +98,7 @@ QgsComposerMap::QgsComposerMap( QgsComposition *composition, int x, int y, int w } QgsComposerMap::QgsComposerMap( QgsComposition *composition ) - : QgsComposerItem( 0, 0, 10, 10, composition ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ), + : QgsComposerItem( 0, 0, 10, 10, composition ), mMapRotation( 0 ), mKeepLayerSet( false ), mOverviewFrameMapId( -1 ), mOverviewBlendMode( QPainter::CompositionMode_SourceOver ), mOverviewInverted( false ), mOverviewCentered( false ), mGridEnabled( false ), mGridStyle( Solid ), mGridIntervalX( 0.0 ), mGridIntervalY( 0.0 ), mGridOffsetX( 0.0 ), mGridOffsetY( 0.0 ), mGridAnnotationFontColor( QColor( 0, 0, 0 ) ), @@ -385,7 +385,7 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i painter->translate( mXOffset, mYOffset ); painter->translate( xTopLeftShift, yTopLeftShift ); - painter->rotate( mRotation ); + painter->rotate( mMapRotation ); painter->translate( xShiftMM, -yShiftMM ); painter->scale( scale, scale ); painter->drawImage( 0, 0, mCacheImage ); @@ -434,7 +434,7 @@ void QgsComposerMap::paint( QPainter* painter, const QStyleOptionGraphicsItem* i painter->save(); painter->translate( mXOffset, mYOffset ); painter->translate( xTopLeftShift, yTopLeftShift ); - painter->rotate( mRotation ); + painter->rotate( mMapRotation ); painter->translate( xShiftMM, -yShiftMM ); draw( painter, requestRectangle, theSize, 25.4 ); //scene coordinates seem to be in mm @@ -654,11 +654,18 @@ void QgsComposerMap::setOffset( double xOffset, double yOffset ) mYOffset = yOffset; } +void QgsComposerMap::setRotation( double r ) +{ + //kept for api compatibility with QGIS 2.0 + setMapRotation( r ); +} + void QgsComposerMap::setMapRotation( double r ) { - setRotation( r ); - emit rotationChanged( r ); + mMapRotation = r; + emit mapRotationChanged( r ); emit itemChanged(); + update(); } void QgsComposerMap::updateItem() @@ -842,6 +849,9 @@ bool QgsComposerMap::writeXML( QDomElement& elem, QDomDocument & doc ) const extentElem.setAttribute( "ymax", qgsDoubleToString( mExtent.yMaximum() ) ); composerMapElem.appendChild( extentElem ); + //map rotation + composerMapElem.setAttribute( "mapRotation", QString::number( mMapRotation ) ); + //layer set QDomElement layerSetElem = doc.createElement( "LayerSet" ); QStringList::const_iterator layerIt = mLayerSet.constBegin(); @@ -1000,6 +1010,12 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d mExtent = QgsRectangle( xmin, ymin, xmax, ymax ); } + //map rotation + if ( itemElem.attribute( "mapRotation", "0" ).toDouble() != 0 ) + { + mMapRotation = itemElem.attribute( "mapRotation", "0" ).toDouble(); + } + //mKeepLayerSet flag QString keepLayerSetFlag = itemElem.attribute( "keepLayerSet" ); if ( keepLayerSetFlag.compare( "true", Qt::CaseInsensitive ) == 0 ) @@ -1161,6 +1177,13 @@ bool QgsComposerMap::readXML( const QDomElement& itemElem, const QDomDocument& d if ( composerItemList.size() > 0 ) { QDomElement composerItemElem = composerItemList.at( 0 ).toElement(); + + if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 ) + { + //in versions prior to 2.1 map rotation was stored in the rotation attribute + mMapRotation = composerItemElem.attribute( "rotation", "0" ).toDouble(); + } + _readXML( composerItemElem, doc ); } @@ -1637,7 +1660,7 @@ int QgsComposerMap::xGridLines( QList< QPair< double, QLineF > >& lines ) const double roundCorrection = mapBoundingRect.top() > 0 ? 1.0 : 0.0; double currentLevel = ( int )(( mapBoundingRect.top() - mGridOffsetY ) / mGridIntervalY + roundCorrection ) * mGridIntervalY + mGridOffsetY; - if ( qgsDoubleNear( mRotation, 0.0 ) ) + if ( qgsDoubleNear( mMapRotation, 0.0 ) ) { //no rotation. Do it 'the easy way' @@ -1705,7 +1728,7 @@ int QgsComposerMap::yGridLines( QList< QPair< double, QLineF > >& lines ) const double roundCorrection = mapBoundingRect.left() > 0 ? 1.0 : 0.0; double currentLevel = ( int )(( mapBoundingRect.left() - mGridOffsetX ) / mGridIntervalX + roundCorrection ) * mGridIntervalX + mGridOffsetX; - if ( qgsDoubleNear( mRotation, 0.0 ) ) + if ( qgsDoubleNear( mMapRotation, 0.0 ) ) { //no rotation. Do it 'the easy way' double xCanvasCoord; @@ -1888,7 +1911,7 @@ double QgsComposerMap::maxExtension() const void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) const { poly.clear(); - if ( mRotation == 0 ) + if ( mMapRotation == 0 ) { poly << QPointF( extent.xMinimum(), extent.yMaximum() ); poly << QPointF( extent.xMaximum(), extent.yMaximum() ); @@ -1904,25 +1927,25 @@ void QgsComposerMap::mapPolygon( const QgsRectangle& extent, QPolygonF& poly ) c //top left point dx = rotationPoint.x() - extent.xMinimum(); dy = rotationPoint.y() - extent.yMaximum(); - rotate( mRotation, dx, dy ); + rotate( mMapRotation, dx, dy ); poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy ); //top right point dx = rotationPoint.x() - extent.xMaximum(); dy = rotationPoint.y() - extent.yMaximum(); - rotate( mRotation, dx, dy ); + rotate( mMapRotation, dx, dy ); poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy ); //bottom right point dx = rotationPoint.x() - extent.xMaximum(); dy = rotationPoint.y() - extent.yMinimum(); - rotate( mRotation, dx, dy ); + rotate( mMapRotation, dx, dy ); poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy ); //bottom left point dx = rotationPoint.x() - extent.xMinimum(); dy = rotationPoint.y() - extent.yMinimum(); - rotate( mRotation, dx, dy ); + rotate( mMapRotation, dx, dy ); poly << QPointF( rotationPoint.x() + dx, rotationPoint.y() + dy ); } @@ -1935,7 +1958,7 @@ void QgsComposerMap::requestedExtent( QgsRectangle& extent ) const { QgsRectangle newExtent; extentCenteredOnOverview( newExtent ); - if ( mRotation == 0 ) + if ( mMapRotation == 0 ) { extent = newExtent; } @@ -2019,7 +2042,7 @@ void QgsComposerMap::transformShift( double& xShift, double& yShift ) const double dxScaled = xShift * mmToMapUnits; double dyScaled = - yShift * mmToMapUnits; - rotate( mRotation, dxScaled, dyScaled ); + rotate( mMapRotation, dxScaled, dyScaled ); xShift = dxScaled; yShift = dyScaled; @@ -2037,7 +2060,7 @@ QPointF QgsComposerMap::mapToItemCoords( const QPointF& mapCoords ) const QgsPoint rotationPoint(( tExtent.xMaximum() + tExtent.xMinimum() ) / 2.0, ( tExtent.yMaximum() + tExtent.yMinimum() ) / 2.0 ); double dx = mapCoords.x() - rotationPoint.x(); double dy = mapCoords.y() - rotationPoint.y(); - rotate( -mRotation, dx, dy ); + rotate( -mMapRotation, dx, dy ); QgsPoint backRotatedCoords( rotationPoint.x() + dx, rotationPoint.y() + dy ); QgsRectangle unrotatedExtent = transformedExtent(); @@ -2419,3 +2442,21 @@ void QgsComposerMap::assignFreeId() } mId = maxId + 1; } + +bool QgsComposerMap::imageSizeConsideringRotation( double& width, double& height ) const +{ + //kept for api compatibility with QGIS 2.0 - use mMapRotation + return QgsComposerItem::imageSizeConsideringRotation( width, height, mMapRotation ); +} + +bool QgsComposerMap::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const +{ + //kept for api compatibility with QGIS 2.0 - use mMapRotation + return QgsComposerItem::cornerPointOnRotatedAndScaledRect( x, y, width, height, mMapRotation ); +} + +void QgsComposerMap::sizeChangedByRotation( double& width, double& height ) +{ + //kept for api compatibility with QGIS 2.0 - use mMapRotation + return QgsComposerItem::sizeChangedByRotation( width, height, mMapRotation ); +} diff --git a/src/core/composer/qgscomposermap.h b/src/core/composer/qgscomposermap.h index 0c2a63f51c7..609c970d93c 100644 --- a/src/core/composer/qgscomposermap.h +++ b/src/core/composer/qgscomposermap.h @@ -325,7 +325,22 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem void setCrossLength( double l ) {mCrossLength = l;} double crossLength() {return mCrossLength;} + /**Sets rotation for the map - this does not affect the composer item shape, only the + way the map is drawn within the item + * @deprecated Use setMapRotation( double rotation ) instead + */ + void setRotation( double r ); + /**Returns the rotation used for drawing the map within the composer item + * @deprecated Use mapRotation() instead + */ + double rotation() const { return mMapRotation;}; + + /**Sets rotation for the map - this does not affect the composer item shape, only the + way the map is drawn within the item + @note this function was added in version 2.1*/ void setMapRotation( double r ); + /**Returns the rotation used for drawing the map within the composer item*/ + double mapRotation() const { return mMapRotation;}; void updateItem(); @@ -375,9 +390,28 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem Usually, this function is called before adding the composer map to the composition*/ void assignFreeId(); + /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation + * @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation ) + * instead + */ + bool imageSizeConsideringRotation( double& width, double& height ) const; + /**Calculates corner point after rotation and scaling + * @deprecated Use QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) + * instead + */ + bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const; + /**Calculates width / height of the bounding box of a rotated rectangle + * @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation ) + * instead + */ + void sizeChangedByRotation( double& width, double& height ); + signals: void extentChanged(); + /**Is emitted on rotation change to notify north arrow pictures*/ + void mapRotationChanged( double newRotation ); + public slots: /**Called if map canvas has changed*/ @@ -425,6 +459,9 @@ class CORE_EXPORT QgsComposerMap : public QgsComposerItem /**Offset in y direction for showing map cache image*/ double mYOffset; + /**Map rotation*/ + double mMapRotation; + /**Flag if layers to be displayed should be read from qgis canvas (true) or from stored list in mLayerSet (false)*/ bool mKeepLayerSet; diff --git a/src/core/composer/qgscomposerpicture.cpp b/src/core/composer/qgscomposerpicture.cpp index ef5a01fcdb3..bd39e2bbcd1 100644 --- a/src/core/composer/qgscomposerpicture.cpp +++ b/src/core/composer/qgscomposerpicture.cpp @@ -28,12 +28,12 @@ QgsComposerPicture::QgsComposerPicture( QgsComposition *composition ) - : QgsComposerItem( composition ), mMode( Unknown ), mRotationMap( 0 ) + : QgsComposerItem( composition ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 ) { mPictureWidth = rect().width(); } -QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mRotationMap( 0 ) +QgsComposerPicture::QgsComposerPicture(): QgsComposerItem( 0 ), mMode( Unknown ), mPictureRotation( 0 ), mRotationMap( 0 ) { mPictureHeight = rect().height(); } @@ -76,7 +76,7 @@ void QgsComposerPicture::paint( QPainter* painter, const QStyleOptionGraphicsIte painter->save(); painter->translate( rect().width() / 2.0, rect().height() / 2.0 ); - painter->rotate( mRotation ); + painter->rotate( mPictureRotation ); painter->translate( -boundRectWidthMM / 2.0, -boundRectHeightMM / 2.0 ); if ( mMode == SVG ) @@ -214,6 +214,12 @@ void QgsComposerPicture::setSceneRect( const QRectF& rectangle ) } void QgsComposerPicture::setRotation( double r ) +{ + //kept for compatibility for QGIS2.0 api + setPictureRotation( r ); +} + +void QgsComposerPicture::setPictureRotation( double r ) { //adapt rectangle size double width = mPictureWidth; @@ -225,7 +231,9 @@ void QgsComposerPicture::setRotation( double r ) double y = pos().y() + rect().height() / 2.0 - height / 2.0; QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) ); - QgsComposerItem::setRotation( r ); + mPictureRotation = r; + update(); + emit pictureRotationChanged( mPictureRotation ); } void QgsComposerPicture::setRotationMap( int composerMapId ) @@ -237,7 +245,7 @@ void QgsComposerPicture::setRotationMap( int composerMapId ) if ( composerMapId == -1 ) //disable rotation from map { - QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); + QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) ); mRotationMap = 0; } @@ -248,12 +256,13 @@ void QgsComposerPicture::setRotationMap( int composerMapId ) } if ( mRotationMap ) { - QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); + QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) ); } - mRotation = map->rotation(); - QObject::connect( map, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); + mPictureRotation = map->mapRotation(); + QObject::connect( map, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setPictureRotation( double ) ) ); mRotationMap = map; - setRotation( map->rotation() ); + update(); + emit pictureRotationChanged( mPictureRotation ); } QString QgsComposerPicture::pictureFile() const @@ -271,6 +280,9 @@ bool QgsComposerPicture::writeXML( QDomElement& elem, QDomDocument & doc ) const composerPictureElem.setAttribute( "file", QgsProject::instance()->writePath( mSourceFile.fileName() ) ); composerPictureElem.setAttribute( "pictureWidth", QString::number( mPictureWidth ) ); composerPictureElem.setAttribute( "pictureHeight", QString::number( mPictureHeight ) ); + + //rotation + composerPictureElem.setAttribute( "pictureRotation", QString::number( mPictureRotation ) ); if ( !mRotationMap ) { composerPictureElem.setAttribute( "mapId", -1 ); @@ -298,15 +310,28 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" ); if ( composerItemList.size() > 0 ) { - _readXML( composerItemList.at( 0 ).toElement(), doc ); - } + QDomElement composerItemElem = composerItemList.at( 0 ).toElement(); + if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 ) + { + //in versions prior to 2.1 picture rotation was stored in the rotation attribute + mPictureRotation = composerItemElem.attribute( "rotation", "0" ).toDouble(); + } + + _readXML( composerItemElem, doc ); + } mDefaultSvgSize = QSize( 0, 0 ); QString fileName = QgsProject::instance()->readPath( itemElem.attribute( "file" ) ); setPictureFile( fileName ); + //picture rotation + if ( itemElem.attribute( "pictureRotation", "0" ).toDouble() != 0 ) + { + mPictureRotation = itemElem.attribute( "pictureRotation", "0" ).toDouble(); + } + //rotation map int rotationMapId = itemElem.attribute( "mapId", "-1" ).toInt(); if ( rotationMapId == -1 ) @@ -318,10 +343,10 @@ bool QgsComposerPicture::readXML( const QDomElement& itemElem, const QDomDocumen if ( mRotationMap ) { - QObject::disconnect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); + QObject::disconnect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); } mRotationMap = mComposition->getComposerMapById( rotationMapId ); - QObject::connect( mRotationMap, SIGNAL( rotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); + QObject::connect( mRotationMap, SIGNAL( mapRotationChanged( double ) ), this, SLOT( setRotation( double ) ) ); } emit itemChanged(); @@ -339,3 +364,21 @@ int QgsComposerPicture::rotationMap() const return mRotationMap->id(); } } + +bool QgsComposerPicture::imageSizeConsideringRotation( double& width, double& height ) const +{ + //kept for api compatibility with QGIS 2.0 - use mPictureRotation + return QgsComposerItem::imageSizeConsideringRotation( width, height, mPictureRotation ); +} + +bool QgsComposerPicture::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const +{ + //kept for api compatibility with QGIS 2.0 - use mPictureRotation + return QgsComposerItem::cornerPointOnRotatedAndScaledRect( x, y, width, height, mPictureRotation ); +} + +void QgsComposerPicture::sizeChangedByRotation( double& width, double& height ) +{ + //kept for api compatibility with QGIS 2.0 - use mPictureRotation + return QgsComposerItem::sizeChangedByRotation( width, height, mPictureRotation ); +} diff --git a/src/core/composer/qgscomposerpicture.h b/src/core/composer/qgscomposerpicture.h index e2a80025ffc..da09c74e522 100644 --- a/src/core/composer/qgscomposerpicture.h +++ b/src/core/composer/qgscomposerpicture.h @@ -60,6 +60,15 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem */ bool readXML( const QDomElement& itemElem, const QDomDocument& doc ); + /**Returns the rotation used for drawing the picture within the composer item + * @deprecated Use pictureRotation() instead + */ + double rotation() const { return mPictureRotation;}; + + /**Returns the rotation used for drawing the picture within the item + @note this function was added in version 2.1*/ + double pictureRotation() const { return mPictureRotation;}; + /**Sets the map object for rotation (by id). A value of -1 disables the map rotation*/ void setRotationMap( int composerMapId ); /**Returns the id of the rotation map*/ @@ -67,10 +76,38 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem /**True if the rotation is taken from a map item*/ bool useRotationMap() const {return mRotationMap;} + /**Calculates width and hight of the picture (in mm) such that it fits into the item frame with the given rotation + * @deprecated Use bool QgsComposerItem::imageSizeConsideringRotation( double& width, double& height, double rotation ) + * instead + */ + bool imageSizeConsideringRotation( double& width, double& height ) const; + /**Calculates corner point after rotation and scaling + * @deprecated Use QgsComposerItem::cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height, double rotation ) + * instead + */ + bool cornerPointOnRotatedAndScaledRect( double& x, double& y, double width, double height ) const; + /**Calculates width / height of the bounding box of a rotated rectangle + * @deprecated Use QgsComposerItem::sizeChangedByRotation( double& width, double& height, double rotation ) + * instead + */ + void sizeChangedByRotation( double& width, double& height ); + public slots: - /**Sets the rotation and adapts the item rect*/ + /**Sets the picture rotation within the item bounds. This does not affect the item rectangle, + only the way the picture is drawn within the item. + * @deprecated Use setPictureRotation( double rotation ) instead + */ virtual void setRotation( double r ); + /**Sets the picture rotation within the item bounds. This does not affect the item rectangle, + only the way the picture is drawn within the item. + @note this function was added in version 2.1*/ + virtual void setPictureRotation( double r ); + + signals: + /**Is emitted on picture rotation change*/ + void pictureRotationChanged( double newRotation ); + private: enum Mode //SVG or raster graphic format @@ -94,6 +131,9 @@ class CORE_EXPORT QgsComposerPicture: public QgsComposerItem Mode mMode; QSize mDefaultSvgSize; + + /**Image rotation*/ + double mPictureRotation; /**Map that sets the rotation (or 0 if this picture uses map independent rotation)*/ const QgsComposerMap* mRotationMap; /**Width of the picture (in mm)*/ diff --git a/src/core/composer/qgscomposershape.cpp b/src/core/composer/qgscomposershape.cpp index 2094e0e87d5..be554fc81d7 100644 --- a/src/core/composer/qgscomposershape.cpp +++ b/src/core/composer/qgscomposershape.cpp @@ -61,7 +61,7 @@ void QgsComposerShape::drawShape( QPainter* p ) p->setRenderHint( QPainter::Antialiasing ); p->translate( rect().width() / 2.0, rect().height() / 2.0 ); - p->rotate( mRotation ); + p->rotate( mItemRotation ); p->translate( -rect().width() / 2.0, -rect().height() / 2.0 ); switch ( mShape ) @@ -135,6 +135,14 @@ bool QgsComposerShape::readXML( const QDomElement& itemElem, const QDomDocument& if ( composerItemList.size() > 0 ) { QDomElement composerItemElem = composerItemList.at( 0 ).toElement(); + + //rotation + if ( composerItemElem.attribute( "rotation", "0" ).toDouble() != 0 ) + { + //check for old (pre 2.1) rotation attribute + mItemRotation = composerItemElem.attribute( "rotation", "0" ).toDouble(); + } + _readXML( composerItemElem, doc ); } emit itemChanged(); @@ -142,7 +150,7 @@ bool QgsComposerShape::readXML( const QDomElement& itemElem, const QDomDocument& } -void QgsComposerShape::setRotation( double r ) +void QgsComposerShape::setItemRotation( double r ) { //adapt rectangle size double width = rect().width(); @@ -154,7 +162,7 @@ void QgsComposerShape::setRotation( double r ) double y = pos().y() + rect().height() / 2.0 - height / 2.0; QgsComposerItem::setSceneRect( QRectF( x, y, width, height ) ); - QgsComposerItem::setRotation( r ); + QgsComposerItem::setItemRotation( r ); } void QgsComposerShape::setCornerRadius( double radius ) diff --git a/src/core/composer/qgscomposershape.h b/src/core/composer/qgscomposershape.h index 5ad29bff433..bed9d303b6f 100644 --- a/src/core/composer/qgscomposershape.h +++ b/src/core/composer/qgscomposershape.h @@ -72,7 +72,7 @@ class CORE_EXPORT QgsComposerShape: public QgsComposerItem public slots: /**Sets item rotation and resizes item bounds such that the shape always has the same size*/ - virtual void setRotation( double r ); + virtual void setItemRotation( double r ); protected: /* reimplement drawFrame, since it's not a rect, but a custom shape */ diff --git a/src/ui/qgscomposermapwidgetbase.ui b/src/ui/qgscomposermapwidgetbase.ui index 229f01849e4..4f8a75d610b 100644 --- a/src/ui/qgscomposermapwidgetbase.ui +++ b/src/ui/qgscomposermapwidgetbase.ui @@ -123,16 +123,16 @@ - + - Rotation + Map Rotation - + - degrees + ° 360.000000000000000 diff --git a/src/ui/qgscomposerpicturewidgetbase.ui b/src/ui/qgscomposerpicturewidgetbase.ui index f0e567f9b27..c4253f66de6 100644 --- a/src/ui/qgscomposerpicturewidgetbase.ui +++ b/src/ui/qgscomposerpicturewidgetbase.ui @@ -213,7 +213,7 @@ - Rotation + Image Rotation composeritem @@ -239,7 +239,7 @@ - + ° diff --git a/tests/src/core/testqgscomposermap.cpp b/tests/src/core/testqgscomposermap.cpp index f316c3e3ece..d9063a597fa 100644 --- a/tests/src/core/testqgscomposermap.cpp +++ b/tests/src/core/testqgscomposermap.cpp @@ -256,7 +256,7 @@ void TestQgsComposerMap::overviewMapCenter() void TestQgsComposerMap::worldFileGeneration() { mComposerMap->setNewExtent( QgsRectangle( 781662.375, 3339523.125, 793062.375, 3345223.125 ) ); - mComposerMap->setRotation( 30.0 ); + mComposerMap->setMapRotation( 30.0 ); mComposition->setGenerateWorldFile( true ); mComposition->setWorldFileMap( mComposerMap ); diff --git a/tests/src/python/test_qgscomposermap.py b/tests/src/python/test_qgscomposermap.py index 3e40be8d599..46a371b3b21 100644 --- a/tests/src/python/test_qgscomposermap.py +++ b/tests/src/python/test_qgscomposermap.py @@ -220,7 +220,7 @@ class TestQgsComposerMap(TestCase): def testWorldFileGeneration( self ): myRectangle = QgsRectangle(781662.375, 3339523.125, 793062.375, 3345223.125) self.mComposerMap.setNewExtent( myRectangle ) - self.mComposerMap.setRotation( 30.0 ) + self.mComposerMap.setMapRotation( 30.0 ) self.mComposition.setGenerateWorldFile( True ) self.mComposition.setWorldFileMap( self.mComposerMap )