-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4625 from nyalldawson/comp_extent
[FEATURE] New decoration type for showing composer map extents
- Loading branch information
Showing
10 changed files
with
661 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
/*************************************************************************** | ||
qgsdecorationlayoutextent.cpp | ||
---------------------- | ||
begin : May 2017 | ||
copyright : (C) 2017 by Nyall Dawson | ||
email : nyall dot dawson at gmail dot com | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsdecorationlayoutextent.h" | ||
#include "qgsdecorationlayoutextentdialog.h" | ||
|
||
#include "qgslayoutmanager.h" | ||
#include "qgscomposition.h" | ||
#include "qgscomposermap.h" | ||
#include "qgsgeometry.h" | ||
#include "qgscsexception.h" | ||
#include "qgslinesymbollayer.h" | ||
#include "qgscomposer.h" | ||
#include "qgisapp.h" | ||
#include "qgsapplication.h" | ||
#include "qgslogger.h" | ||
#include "qgsmapcanvas.h" | ||
#include "qgsproject.h" | ||
#include "qgssymbollayerutils.h" | ||
#include "qgsreadwritecontext.h" | ||
|
||
#include <QPainter> | ||
|
||
QgsDecorationLayoutExtent::QgsDecorationLayoutExtent( QObject *parent ) | ||
: QgsDecorationItem( parent ) | ||
{ | ||
mPlacement = BottomRight; | ||
mMarginUnit = QgsUnitTypes::RenderMillimeters; | ||
|
||
setName( "Layout Extent" ); | ||
projectRead(); | ||
} | ||
|
||
void QgsDecorationLayoutExtent::projectRead() | ||
{ | ||
QgsDecorationItem::projectRead(); | ||
|
||
QDomDocument doc; | ||
QDomElement elem; | ||
QgsReadWriteContext rwContext; | ||
rwContext.setPathResolver( QgsProject::instance()->pathResolver() ); | ||
QString xml = QgsProject::instance()->readEntry( mNameConfig, QStringLiteral( "/Symbol" ) ); | ||
mSymbol.reset( nullptr ); | ||
if ( !xml.isEmpty() ) | ||
{ | ||
doc.setContent( xml ); | ||
elem = doc.documentElement(); | ||
mSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsFillSymbol>( elem, rwContext ) ); | ||
} | ||
if ( ! mSymbol ) | ||
{ | ||
mSymbol.reset( new QgsFillSymbol() ); | ||
QgsSimpleLineSymbolLayer *layer = new QgsSimpleLineSymbolLayer( QColor( 0, 0, 0, 100 ), 0, Qt::DashLine ); | ||
mSymbol->changeSymbolLayer( 0, layer ); | ||
} | ||
|
||
QString textXml = QgsProject::instance()->readEntry( mNameConfig, QStringLiteral( "/Font" ) ); | ||
if ( !textXml.isEmpty() ) | ||
{ | ||
doc.setContent( textXml ); | ||
elem = doc.documentElement(); | ||
mTextFormat.readXml( elem, rwContext ); | ||
} | ||
mLabelExtents = QgsProject::instance()->readBoolEntry( mNameConfig, QStringLiteral( "/Labels" ), true ); | ||
} | ||
|
||
void QgsDecorationLayoutExtent::saveToProject() | ||
{ | ||
QgsDecorationItem::saveToProject(); | ||
// write symbol info to xml | ||
QDomDocument doc; | ||
QDomElement elem; | ||
QgsReadWriteContext rwContext; | ||
rwContext.setPathResolver( QgsProject::instance()->pathResolver() ); | ||
if ( mSymbol ) | ||
{ | ||
elem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "Symbol" ), mSymbol.get(), doc, rwContext ); | ||
doc.appendChild( elem ); | ||
// FIXME this works, but XML will not be valid as < is replaced by < | ||
QgsProject::instance()->writeEntry( mNameConfig, QStringLiteral( "/Symbol" ), doc.toString() ); | ||
} | ||
|
||
QDomDocument textDoc; | ||
QDomElement textElem = mTextFormat.writeXml( textDoc, rwContext ); | ||
textDoc.appendChild( textElem ); | ||
QgsProject::instance()->writeEntry( mNameConfig, QStringLiteral( "/Font" ), textDoc.toString() ); | ||
QgsProject::instance()->writeEntry( mNameConfig, QStringLiteral( "/Labels" ), mLabelExtents ); | ||
} | ||
|
||
void QgsDecorationLayoutExtent::run() | ||
{ | ||
QgsDecorationLayoutExtentDialog dlg( *this, QgisApp::instance() ); | ||
dlg.exec(); | ||
} | ||
|
||
|
||
void QgsDecorationLayoutExtent::render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) | ||
{ | ||
if ( !enabled() ) | ||
return; | ||
|
||
if ( !mSymbol ) | ||
return; | ||
|
||
context.painter()->save(); | ||
context.painter()->setRenderHint( QPainter::Antialiasing, true ); | ||
mSymbol->startRender( context ); | ||
|
||
const QgsMapToPixel &m2p = mapSettings.mapToPixel(); | ||
QTransform transform = m2p.transform(); | ||
|
||
// only loop through open composers | ||
Q_FOREACH ( QgsComposer *composer, QgisApp::instance()->printComposers() ) | ||
{ | ||
QgsComposition *composition = composer->composition(); | ||
Q_FOREACH ( const QgsComposerMap *map, composition->composerMapItems() ) | ||
{ | ||
QPolygonF extent = map->visibleExtentPolygon(); | ||
QPointF labelPoint = extent.at( 1 ); | ||
QgsGeometry g = QgsGeometry::fromQPolygonF( extent ); | ||
|
||
if ( map->crs() != | ||
mapSettings.destinationCrs() ) | ||
{ | ||
// reproject extent | ||
QgsCoordinateTransform ct( map->crs(), | ||
mapSettings.destinationCrs() ); | ||
g = g.densifyByCount( 20 ); | ||
try | ||
{ | ||
g.transform( ct ); | ||
labelPoint = ct.transform( labelPoint.x(), labelPoint.y() ).toQPointF(); | ||
} | ||
catch ( QgsCsException & ) | ||
{ | ||
} | ||
} | ||
|
||
g.transform( transform ); | ||
labelPoint = transform.map( labelPoint ); | ||
extent = g.asQPolygonF(); | ||
mSymbol->renderPolygon( extent, nullptr, nullptr, context ); | ||
|
||
if ( mLabelExtents ) | ||
{ | ||
QgsTextRenderer::drawText( labelPoint, ( map->mapRotation() - mapSettings.rotation() ) * M_PI / 180.0, QgsTextRenderer::AlignRight, QStringList() << tr( "%1: %2" ).arg( composition->name(), map->displayName() ), | ||
context, mTextFormat ); | ||
} | ||
} | ||
} | ||
mSymbol->stopRender( context ); | ||
context.painter()->restore(); | ||
} | ||
|
||
bool QgsDecorationLayoutExtent::labelExtents() const | ||
{ | ||
return mLabelExtents; | ||
} | ||
|
||
void QgsDecorationLayoutExtent::setLabelExtents( bool labelExtents ) | ||
{ | ||
mLabelExtents = labelExtents; | ||
} | ||
|
||
QgsFillSymbol *QgsDecorationLayoutExtent::symbol() const | ||
{ | ||
return mSymbol.get(); | ||
} | ||
|
||
void QgsDecorationLayoutExtent::setSymbol( QgsFillSymbol *symbol ) | ||
{ | ||
mSymbol.reset( symbol ); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/*************************************************************************** | ||
qgsdecorationlayoutextent.h | ||
------------------- | ||
begin : May 2017 | ||
copyright : (C) 2017 by Nyall Dawson | ||
email : nyall dot dawson at gmail dot com | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
#ifndef QGSDECORATIONLAYOUTEXTENT_H | ||
#define QGSDECORATIONLAYOUTEXTENT_H | ||
|
||
#include "qgsdecorationitem.h" | ||
|
||
#include <QColor> | ||
#include <QFont> | ||
#include <QObject> | ||
#include "qgis_app.h" | ||
#include "qgssymbol.h" | ||
#include "qgstextrenderer.h" | ||
#include <memory> | ||
|
||
class QgsDecorationLayoutExtentDialog; | ||
|
||
class APP_EXPORT QgsDecorationLayoutExtent : public QgsDecorationItem | ||
{ | ||
Q_OBJECT | ||
public: | ||
|
||
/** | ||
* Constructor for QgsDecorationLayoutExtent. | ||
*/ | ||
QgsDecorationLayoutExtent( QObject *parent = nullptr ); | ||
|
||
/** | ||
* Returns the fill symbol used for shading layout extents. | ||
* \see setSymbol() | ||
*/ | ||
QgsFillSymbol *symbol() const; | ||
|
||
/** | ||
* Sets the fill \a symbol used for shading layout extents. Ownership of | ||
* \a symbol is transferred. | ||
* \see symbol() | ||
*/ | ||
void setSymbol( QgsFillSymbol *symbol SIP_TRANSFER ); | ||
|
||
/** | ||
* Returns the text format for extent labels. | ||
* \see setTextFormat() | ||
* \see labelExtents() | ||
*/ | ||
QgsTextFormat textFormat() const { return mTextFormat; } | ||
|
||
/** | ||
* Sets the text \a format for extent labels. | ||
* \see textFormat() | ||
* \see setLabelExtents() | ||
*/ | ||
void setTextFormat( const QgsTextFormat &format ) { mTextFormat = format; } | ||
|
||
/** | ||
* Returns true if layout extents should be labeled with the name of the associated layout & map. | ||
* \see setLabelExtents() | ||
* \see textFormat() | ||
*/ | ||
bool labelExtents() const; | ||
|
||
/** | ||
* Sets whether layout extents should be labeled with the name of the associated layout & map. | ||
* \see labelExtents() | ||
* \see setTextFormat() | ||
*/ | ||
void setLabelExtents( bool labelExtents ); | ||
|
||
public slots: | ||
void projectRead() override; | ||
void saveToProject() override; | ||
void run() override; | ||
void render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) override; | ||
|
||
private: | ||
std::unique_ptr< QgsFillSymbol > mSymbol; | ||
QgsTextFormat mTextFormat; | ||
bool mLabelExtents = true; | ||
|
||
friend class QgsDecorationLayoutExtentDialog; | ||
}; | ||
|
||
#endif //QGSDECORATIONLAYOUTEXTENT_H |
Oops, something went wrong.