Merge pull request #4253 from nyalldawson/multi_canvas2

[FEATURE] Multi canvas/additional map views
This commit is contained in:
Nyall Dawson 2017-03-15 10:06:39 +10:00 committed by GitHub
commit 738f4415d9
24 changed files with 1775 additions and 169 deletions

View File

@ -556,6 +556,9 @@
<file>themes/default/processingAlgorithm.svg</file>
<file>themes/default/processingResult.svg</file>
<file>themes/default/search.svg</file>
<file>themes/default/mActionNewMap.svg</file>
<file>themes/default/mActionMapSettings.svg</file>
<file>themes/default/mActionLockExtent.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="16"
width="16"
version="1.1"
id="svg20"
sodipodi:docname="mActionLockExtent.svg"
inkscape:version="0.92.1 r">
<metadata
id="metadata26">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs24" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1132"
inkscape:window-height="916"
id="namedview22"
showgrid="true"
inkscape:zoom="33.375"
inkscape:cx="7.1310861"
inkscape:cy="7.5927961"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:current-layer="svg20">
<inkscape:grid
type="xygrid"
id="grid4526" />
</sodipodi:namedview>
<path
style="fill:#6d97c4;fill-rule:evenodd;stroke:#415a75;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path4"
d="M 14.5,13.5 H 9.4999793 L 11.166653,11.833327 9.4999793,10.166653 11.166651,8.49998 12.833326,10.166653 14.499998,8.49998 Z" />
<path
style="opacity:0.7;fill:#fcffff;fill-rule:evenodd;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path10"
d="m 6.0854127,4.570286 c 1.2542366,-1.881355 2.7858151,-2.1309826 3.76271,-1.2542367 0.9768953,0.8767459 -1.2542368,0.6271183 -2.5084734,1.881355 -1.2542366,1.2542366 0,3.7627099 -1.2542366,3.7627099 -1.2542366,0 -1.2542366,-2.5084733 0,-4.3898282 z" />
<path
style="fill:#6d97c4;fill-rule:evenodd;stroke:#415a75;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path14"
d="M 14.5,1.5000002 V 6.5000209 L 12.833326,4.8333456 11.166652,6.5000209 9.4999793,4.8333468 11.166652,3.1666741 9.4999793,1.5000006 Z" />
<path
style="fill:#6d97c4;fill-rule:evenodd;stroke:#415a75;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path16"
d="M 2.5,1.5000002 H 7.5000208 L 5.8333464,3.1666739 7.5000208,4.8333475 5.833347,6.500021 4.1666735,4.8333475 2.5000002,6.500021 Z" />
<path
style="fill:#6d97c4;fill-rule:evenodd;stroke:#415a75;stroke-width:0.99999994;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:connector-curvature="0"
id="path14-3"
d="M 2.5,14.499999 V 9.4999798 l 1.6666739,1.6666742 1.6666728,-1.6666742 1.6666739,1.6666732 -1.6666739,1.666672 1.6666739,1.666673 z" />
<path
id="path2"
d="M 3.3724264,8.3336432 C 3.4582294,5.7125241 4.0588308,4.5258991 6.135095,4.6857259 8.2111253,4.8451683 8.67798,6.1128125 8.5917932,8.7341416"
inkscape:connector-curvature="0"
style="fill:none;stroke:#888a85;stroke-width:3;stroke-linecap:square;stroke-linejoin:round" />
<path
id="path4-6"
d="M 3.3712993,8.3336432 C 3.4560835,5.6317535 4.0495536,4.3772911 6.1011648,4.542043 8.152545,4.7063986 8.6138563,6.0443769 8.528693,8.7464831"
inkscape:connector-curvature="0"
style="fill:none;stroke:#eeeeec;stroke-width:0.99999994;stroke-linecap:square;stroke-linejoin:round" />
<rect
id="rect6"
y="8.4996204"
x="1.4999999"
width="9"
ry="0.85714287"
rx="0.69230771"
height="6.0000005"
style="fill:#f1db1e;stroke:#c4a000;stroke-width:0.99999976;stroke-linecap:square" />
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="24"
width="24"
version="1.1"
id="svg23"
sodipodi:docname="mActionMapSettings.svg"
inkscape:version="0.92.1 r">
<metadata
id="metadata29">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs27">
<linearGradient
id="a-3"
gradientTransform="matrix(-0.10786508,0.87849049,0.87408031,0.10732357,-1.811623,758.65836)"
gradientUnits="userSpaceOnUse"
x1="304.76001"
x2="335.29999"
y1="64.294998"
y2="81.926003">
<stop
offset="0"
stop-color="#d3d7cf"
id="stop2-6" />
<stop
offset=".18304"
stop-color="#babdb6"
id="stop4-7" />
<stop
offset=".31893"
stop-color="#fff"
id="stop6" />
<stop
offset=".87644"
stop-color="#babdb6"
id="stop8" />
<stop
offset="1"
stop-color="#eeeeec"
id="stop10" />
</linearGradient>
<linearGradient
id="b"
gradientTransform="matrix(-0.34112292,0.26690344,0.34708506,0.44633485,7.3860378,1027.6433)"
gradientUnits="userSpaceOnUse"
x1="-6.3077998"
x2="-9.7747002"
y1="44.229"
y2="44.139999">
<stop
offset="0"
id="stop13" />
<stop
offset="1"
stop-opacity="0"
id="stop15" />
</linearGradient>
<linearGradient
id="c"
gradientTransform="matrix(-0.67481701,0.52736572,0.29432462,0.37835898,77.717559,981.12162)"
gradientUnits="userSpaceOnUse"
x1="97.442001"
x2="90.221001"
y1="35.152"
y2="35.078999">
<stop
offset="0"
stop-color="#f8e27e"
id="stop18" />
<stop
offset="1"
stop-color="#e3d189"
id="stop20" />
</linearGradient>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview25"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="12.40678"
inkscape:cy="11.59322"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg23" />
<linearGradient
id="a"
gradientUnits="userSpaceOnUse"
x1="3.5"
x2="11.5"
y1="19.5"
y2="19.5">
<stop
offset="0"
stop-color="#b7b7b7"
id="stop2" />
<stop
offset="1"
stop-color="#e6e6e6"
id="stop4" />
</linearGradient>
<g
transform="translate(0 -8)"
id="g21">
<path
d="m21.5 29.5h-17c-1 0-1.977816-1.420625-2-2.5v-16.5h19z"
fill="url(#a)"
fill-rule="evenodd"
stroke="#9a9a9a"
id="path7" />
<path
d="m6.5 9.9999996c-1-.9999995-3-.9999995-4 0v16.0000004c1-1 3-1 4 0z"
fill="#e6e6e6"
fill-rule="evenodd"
stroke="#9a9a9a"
id="path9" />
<g
transform="matrix(.69230769 0 0 .69230769 1.8461539 9.8461539)"
id="g19" />
</g>
<g
id="g73"
transform="matrix(0.77430229,0,0,0.77430229,-0.92444663,-790.99716)">
<path
inkscape:connector-curvature="0"
id="path63"
style="fill:url(#a-3);fill-rule:evenodd;stroke:#3b3b3b;stroke-width:1.0266068;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:0.3612"
d="m 10.457382,1032.309 c -0.0557,-0.8562 0.634116,-0.2492 0.875491,0 1.024776,0.7434 2.030407,1.5156 3.067343,2.2407 0.725037,0.2552 1.421475,-0.3125 1.904389,-0.793 0.69153,-0.772 1.365424,-1.7692 1.239142,-2.855 -0.0999,-0.5511 -0.678194,-0.7556 -1.060023,-1.087 -0.948649,-0.7006 -1.905189,-1.3938 -2.848652,-2.099 0.0499,-0.5363 0.921102,-0.4312 1.352206,-0.4538 1.799481,0.032 3.760889,0.6193 4.847708,2.1483 0.893786,1.2432 1.095967,2.9098 0.645088,4.3593 0.248756,1.355 0.749129,2.6839 1.605411,3.7751 -1.055028,0.7755 -2.110005,1.5509 -3.165032,2.3264 -0.74403,-0.9699 -1.666431,-1.8128 -2.743678,-2.3982 -1.597268,0.2334 -3.230567,-0.5195 -4.193648,-1.7921 -0.762442,-0.9748 -1.327479,-2.1438 -1.525916,-3.3671 z" />
<path
inkscape:connector-curvature="0"
style="opacity:0.23106001;fill:url(#b)"
id="path65"
d="m 20.569654,1038.9536 c -0.377958,0.2957 -0.449831,0.8327 -0.161152,1.2039 l 5.276506,7.7275 c 0.288677,0.3713 1.28112,0.076 1.659095,-0.2199 0.377957,-0.2957 0.905829,-1.1891 0.617119,-1.5603 l -6.181727,-7.0148 c -0.288677,-0.3712 -0.825389,-0.432 -1.203364,-0.1363 z" />
<path
style="fill:#f0f3f2;fill-rule:evenodd"
inkscape:connector-curvature="0"
id="path67"
d="m 10.776308,1032.3503 c 0.0041,0.017 0.02652,0.01 0.02736,0 l 3.280939,2.4093 c 0.441955,0.3249 1.026164,0.2014 1.532663,-0.063 0.511499,-0.2667 1.030216,-0.7135 1.465827,-1.3248 0.436534,-0.6127 0.691989,-1.2801 0.782256,-1.8547 0.09008,-0.5733 -0.0071,-1.1337 -0.432392,-1.4464 l -3.308254,-2.4126 c -3.27e-4,-0.012 0.0053,-0.029 0.0034,-0.028 -0.02145,0.016 0.01356,0.01 0.02736,0 1.60773,-0.1726 3.391001,0.2382 4.500933,1.0542 1.518297,1.1161 2.06238,3.1241 1.496172,4.9767 -0.567334,1.8439 -2.398541,3.2549 -4.002325,3.466 -1.037771,0.1302 -2.105965,-0.1107 -2.984774,-0.7566 -1.106711,-0.8138 -2.046256,-2.4203 -2.389076,-4.0275 h -9.3e-5 z" />
<path
inkscape:connector-curvature="0"
id="path69"
style="fill:url(#c);stroke:#3b3b3b;stroke-width:0.86699998;stroke-linecap:round;stroke-linejoin:round;stroke-dashoffset:0.69999999"
d="m 21.969626,1036.9102 9.581585,11.1009 c 0.570734,0.7337 -0.03271,2.1379 -1.34119,3.1605 -1.308483,1.0226 -2.814237,1.2668 -3.384954,0.5331 l -8.399386,-12.0247 3.546142,-2.7701 z m 6.345662,11.8213 c -0.650481,0.5084 -0.785855,1.4312 -0.461469,1.8482 0.324412,0.4169 1.282238,0.4855 1.932707,-0.023 0.650479,-0.5084 0.754739,-1.407 0.430357,-1.8239 -0.324413,-0.417 -1.251126,-0.5098 -1.901595,0 z" />
<path
style="fill:#ffffff;fill-opacity:0.57758622;stroke:#3b3b3b;stroke-width:1.28935945"
inkscape:connector-curvature="0"
id="path71"
transform="matrix(0.82455744,-0.56577825,0.66205623,0.74945417,0,0)"
d="m -679.10767,874.67072 h 3.57105 v 0.57711 h -3.57105 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="24"
width="24"
version="1.1"
id="svg23"
sodipodi:docname="mActionNewMap.svg"
inkscape:version="0.92.1 r">
<metadata
id="metadata29">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs27" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1463"
inkscape:window-height="554"
id="namedview25"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="1.3220339"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="0"
inkscape:current-layer="svg23" />
<linearGradient
id="a"
gradientUnits="userSpaceOnUse"
x1="3.5"
x2="11.5"
y1="19.5"
y2="19.5"
gradientTransform="translate(0,-8)">
<stop
offset="0"
stop-color="#b7b7b7"
id="stop2" />
<stop
offset="1"
stop-color="#e6e6e6"
id="stop4" />
</linearGradient>
<path
inkscape:connector-curvature="0"
style="fill:url(#a);fill-rule:evenodd;stroke:#9a9a9a"
id="path7"
d="m 21.5,21.5 h -17 c -1,0 -1.977816,-1.420625 -2,-2.5 V 2.5 h 19 z" />
<path
style="fill:#e6e6e6;fill-rule:evenodd;stroke:#9a9a9a"
inkscape:connector-curvature="0"
id="path9"
d="m 6.5,1.9999996 c -1,-0.9999995 -3,-0.9999995 -4,0 V 18 c 1,-1 3,-1 4,0 z" />
<g
id="g16"
transform="translate(33)">
<rect
style="fill:#c4a000"
id="rect10"
y="13"
x="-20"
width="11"
rx="2.0114901"
height="11" />
<path
style="fill:#fcffff"
inkscape:connector-curvature="0"
id="path12"
d="m -15,14 v 2.0625 c -0.537663,0.111041 -1.024662,0.383291 -1.375,0.78125 l -1.78125,-1.03125 -0.5,0.875 1.78125,1.03125 C -16.957063,17.966182 -17,18.225145 -17,18.5 c 0,0.274855 0.04294,0.533818 0.125,0.78125 l -1.78125,1.03125 0.5,0.875 1.78125,-1.03125 c 0.352503,0.40042 0.832682,0.670182 1.375,0.78125 V 23 h 1 v -2.0625 c 0.537663,-0.111041 1.024662,-0.383291 1.375,-0.78125 l 1.78125,1.03125 0.5,-0.875 -1.78125,-1.03125 C -12.042937,19.033818 -12,18.774855 -12,18.5 c 0,-0.274855 -0.04294,-0.533818 -0.125,-0.78125 l 1.78125,-1.03125 -0.5,-0.875 -1.78125,1.03125 C -12.977503,16.44333 -13.457682,16.173568 -14,16.0625 V 14 Z m 0.5,3.5 c 0.552,0 1,0.448 1,1 0,0.552 -0.448,1 -1,1 -0.552,0 -1,-0.448 -1,-1 0,-0.552 0.448,-1 1,-1 z" />
<path
style="opacity:0.3;fill:#fcffff;fill-rule:evenodd"
inkscape:connector-curvature="0"
id="path14"
d="m -19,19 9,-0.0096 c 0,0 0,0 0,-2 C -10,14 -11,14 -14.5,14 c -3.5,0 -4.5,0 -4.5,3 0,2 0,2 0,2 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -58,7 +58,17 @@ class QgisInterface : QObject
/* Exposed functions */
//! Zoom to full extent of map layers
virtual QList< QgsMapCanvas* > mapCanvases() = 0;
virtual QgsMapCanvas* createNewMapCanvas( const QString& name ) = 0;
virtual void closeMapCanvas( const QString &name ) = 0;
public slots:
virtual void zoomFull() = 0;
//! Zoom to previous view extent

View File

@ -97,6 +97,10 @@ class QgsMapCanvas : QGraphicsView
void setSegmentationTolerance( double tolerance );
void setSegmentationToleranceType( QgsAbstractGeometry::SegmentationToleranceType type );
QList< QgsMapCanvasAnnotationItem *> annotationItems() const;
bool annotationsVisible() const;
void setAnnotationsVisible( bool visible );
public slots:
//! Repaints the canvas map

View File

@ -47,6 +47,7 @@ SET(QGIS_APP_SRCS
qgslabelinggui.cpp
qgslabelingwidget.cpp
qgsloadstylefromdbdialog.cpp
qgsmapcanvasdockwidget.cpp
qgsmaplayerstyleguiutils.cpp
qgsrulebasedlabelingwidget.cpp
qgssavestyletodbdialog.cpp
@ -225,6 +226,7 @@ SET (QGIS_APP_MOC_HDRS
qgslabelingwidget.h
qgslabelpropertydialog.h
qgsloadstylefromdbdialog.h
qgsmapcanvasdockwidget.h
qgsmaplayerstyleguiutils.h
qgsrulebasedlabelingwidget.h
qgssavestyletodbdialog.h

View File

@ -185,6 +185,7 @@
#include "qgslayertreeviewdefaultactions.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmapcanvasdockwidget.h"
#include "qgsmapcanvassnappingutils.h"
#include "qgsmapcanvastracer.h"
#include "qgsmaplayer.h"
@ -266,6 +267,7 @@
#include "qgsvectorlayerutils.h"
#include "qgshelp.h"
#include "qgsvectorfilewritertask.h"
#include "qgsnewnamedialog.h"
#include "qgssublayersdialog.h"
#include "ogr/qgsopenvectorlayerdialog.h"
@ -493,8 +495,8 @@ void QgisApp::layerTreeViewDoubleClicked( const QModelIndex &index )
void QgisApp::activeLayerChanged( QgsMapLayer *layer )
{
if ( mMapCanvas )
mMapCanvas->setCurrentLayer( layer );
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
canvas->setCurrentLayer( layer );
if ( mUndoWidget )
{
@ -786,7 +788,10 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
functionProfile( &QgisApp::createToolBars, this, QStringLiteral( "Toolbars" ) );
functionProfile( &QgisApp::createStatusBar, this, QStringLiteral( "Status bar" ) );
functionProfile( &QgisApp::createCanvasTools, this, QStringLiteral( "Create canvas tools" ) );
mMapCanvas->freeze();
applyDefaultSettingsToCanvas( mMapCanvas );
functionProfile( &QgisApp::initLayerTreeView, this, QStringLiteral( "Init Layer tree view" ) );
functionProfile( &QgisApp::createOverview, this, QStringLiteral( "Create overview" ) );
functionProfile( &QgisApp::createMapTips, this, QStringLiteral( "Create map tips" ) );
@ -1294,7 +1299,7 @@ QgisApp::QgisApp()
QgisApp::~QgisApp()
{
mMapCanvas->stopRendering();
stopRendering();
delete mInternalClipboard;
delete mQgisInterface;
@ -1465,7 +1470,7 @@ void QgisApp::dropEvent( QDropEvent *event )
void QgisApp::dropEventTimeout()
{
mMapCanvas->freeze();
freezeCanvases();
QStringList files = sender()->property( "files" ).toStringList();
sender()->deleteLater();
@ -1480,15 +1485,18 @@ void QgisApp::dropEventTimeout()
handleDropUriList( lst );
}
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
}
void QgisApp::annotationCreated( QgsAnnotation *annotation )
{
// create canvas annotation item for annotation
QgsMapCanvasAnnotationItem *canvasItem = new QgsMapCanvasAnnotationItem( annotation, mMapCanvas );
Q_UNUSED( canvasItem ); //item is already added automatically to canvas scene
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
{
QgsMapCanvasAnnotationItem *canvasItem = new QgsMapCanvasAnnotationItem( annotation, canvas );
Q_UNUSED( canvasItem ); //item is already added automatically to canvas scene
}
}
void QgisApp::registerCustomDropHandler( QgsCustomDropHandler *handler )
@ -1627,6 +1635,19 @@ void QgisApp::applyProjectSettingsToCanvas( QgsMapCanvas *canvas )
canvas->setSelectionColor( myColor );
}
void QgisApp::applyDefaultSettingsToCanvas( QgsMapCanvas *canvas )
{
QgsSettings settings;
canvas->enableAntiAliasing( settings.value( QStringLiteral( "qgis/enable_anti_aliasing" ), true ).toBool() );
double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
canvas->setWheelFactor( zoomFactor );
canvas->setCachingEnabled( settings.value( QStringLiteral( "qgis/enable_render_caching" ), true ).toBool() );
canvas->setParallelRenderingEnabled( settings.value( QStringLiteral( "qgis/parallel_rendering" ), true ).toBool() );
canvas->setMapUpdateInterval( settings.value( QStringLiteral( "qgis/map_update_interval" ), 250 ).toInt() );
canvas->setSegmentationTolerance( settings.value( QStringLiteral( "qgis/segmentationTolerance" ), "0.01745" ).toDouble() );
canvas->setSegmentationToleranceType( QgsAbstractGeometry::SegmentationToleranceType( settings.value( QStringLiteral( "qgis/segmentationToleranceType" ), "0" ).toInt() ) );
}
void QgisApp::readSettings()
{
QgsSettings settings;
@ -1663,6 +1684,7 @@ void QgisApp::createActions()
connect( mActionSaveProject, SIGNAL( triggered() ), this, SLOT( fileSave() ) );
connect( mActionSaveProjectAs, SIGNAL( triggered() ), this, SLOT( fileSaveAs() ) );
connect( mActionSaveMapAsImage, SIGNAL( triggered() ), this, SLOT( saveMapAsImage() ) );
connect( mActionNewMapCanvas, &QAction::triggered, this, &QgisApp::newMapCanvas );
connect( mActionNewPrintComposer, SIGNAL( triggered() ), this, SLOT( newPrintComposer() ) );
connect( mActionShowComposerManager, SIGNAL( triggered() ), this, SLOT( showComposerManager() ) );
connect( mActionExit, SIGNAL( triggered() ), this, SLOT( fileExit() ) );
@ -2539,7 +2561,7 @@ void QgisApp::createStatusBar()
"the rotation" ) );
mRotationEdit->setToolTip( tr( "Current clockwise map rotation in degrees" ) );
statusBar()->addPermanentWidget( mRotationEdit, 0 );
connect( mRotationEdit, SIGNAL( valueChanged( double ) ), this, SLOT( userRotation() ) );
connect( mRotationEdit, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgisApp::userRotation );
showRotation();
@ -2831,7 +2853,12 @@ void QgisApp::setupConnections()
connect( mMapCanvas, &QgsMapCanvas::zoomNextStatusChanged,
mActionZoomNext, &QAction::setEnabled );
connect( mRenderSuppressionCBox, &QAbstractButton::toggled,
mMapCanvas, &QgsMapCanvas::setRenderFlag );
this, [ = ]( bool flag )
{
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
canvas->setRenderFlag( flag );
}
);
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged,
this, &QgisApp::reprojectAnnotations );
@ -3032,20 +3059,6 @@ void QgisApp::createOverview()
mPanelMenu->addAction( mOverviewDock->toggleViewAction() );
mLayerTreeCanvasBridge->setOvervewCanvas( mOverviewCanvas );
// moved here to set anti aliasing to both map canvas and overview
QgsSettings mySettings;
// Anti Aliasing enabled by default as of QGIS 1.7
mMapCanvas->enableAntiAliasing( mySettings.value( QStringLiteral( "qgis/enable_anti_aliasing" ), true ).toBool() );
double zoomFactor = mySettings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
mMapCanvas->setWheelFactor( zoomFactor );
mMapCanvas->setCachingEnabled( mySettings.value( QStringLiteral( "qgis/enable_render_caching" ), true ).toBool() );
mMapCanvas->setParallelRenderingEnabled( mySettings.value( QStringLiteral( "qgis/parallel_rendering" ), true ).toBool() );
mMapCanvas->setMapUpdateInterval( mySettings.value( QStringLiteral( "qgis/map_update_interval" ), 250 ).toInt() );
}
void QgisApp::addDockWidget( Qt::DockWidgetArea area, QDockWidget *thepDockWidget )
@ -3063,7 +3076,7 @@ void QgisApp::addDockWidget( Qt::DockWidgetArea area, QDockWidget *thepDockWidge
thepDockWidget->show();
// refresh the map canvas
mMapCanvas->refresh();
refreshMapCanvas();
}
void QgisApp::removeDockWidget( QDockWidget *thepDockWidget )
@ -3105,6 +3118,101 @@ QgsMapCanvas *QgisApp::mapCanvas()
return mMapCanvas;
}
QgsMapCanvas *QgisApp::createNewMapCanvas( const QString &name, bool isFloating, const QRect &dockGeometry, bool synced, bool showCursor, bool scaleSynced, double scaleFactor )
{
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
{
if ( canvas->objectName() == name )
{
QString errorMessage = tr( "A map canvas with name '%1' already exists!" ).arg( name );
QgsDebugMsg( errorMessage );
return nullptr;
}
}
QgsMapCanvasDockWidget *mapCanvasWidget = new QgsMapCanvasDockWidget( name, this );
mapCanvasWidget->setAllowedAreas( Qt::AllDockWidgetAreas );
mapCanvasWidget->setMainCanvas( mMapCanvas );
mapCanvasWidget->setFloating( isFloating );
if ( dockGeometry.isEmpty() )
{
// try to guess a nice initial placement for view - about 3/4 along, half way down
mapCanvasWidget->setGeometry( QRect( rect().width() * 0.75, rect().height() * 0.5, 400, 400 ) );
}
else
{
mapCanvasWidget->setGeometry( dockGeometry );
}
QgsMapCanvas *mapCanvas = mapCanvasWidget->mapCanvas();
mapCanvas->freeze( true );
mapCanvas->setObjectName( name );
connect( mapCanvas, &QgsMapCanvas::messageEmitted, this, &QgisApp::displayMessage );
connect( mLayerTreeCanvasBridge, &QgsLayerTreeMapCanvasBridge::canvasLayersChanged, mapCanvas, &QgsMapCanvas::setLayers );
applyProjectSettingsToCanvas( mapCanvas );
applyDefaultSettingsToCanvas( mapCanvas );
mapCanvas->setLayers( mMapCanvas->layers() );
mapCanvas->setExtent( mMapCanvas->extent() );
mapCanvas->setDestinationCrs( QgsProject::instance()->crs() );
// add existing annotations to canvas
Q_FOREACH ( QgsAnnotation *annotation, QgsProject::instance()->annotationManager()->annotations() )
{
QgsMapCanvasAnnotationItem *canvasItem = new QgsMapCanvasAnnotationItem( annotation, mapCanvas );
Q_UNUSED( canvasItem ); //item is already added automatically to canvas scene
}
addDockWidget( Qt::RightDockWidgetArea, mapCanvasWidget );
mapCanvas->freeze( false );
markDirty();
connect( mapCanvasWidget, &QgsMapCanvasDockWidget::closed, this, &QgisApp::markDirty );
connect( mapCanvasWidget, &QgsMapCanvasDockWidget::renameTriggered, this, &QgisApp::renameView );
mapCanvasWidget->setViewCenterSynchronized( synced );
mapCanvasWidget->setCursorMarkerVisible( showCursor );
mapCanvasWidget->setScaleFactor( scaleFactor );
mapCanvasWidget->setViewScaleSynchronized( scaleSynced );
return mapCanvas;
}
void QgisApp::closeMapCanvas( const QString &name )
{
Q_FOREACH ( QgsMapCanvasDockWidget *w, findChildren< QgsMapCanvasDockWidget * >() )
{
if ( w->mapCanvas()->objectName() == name )
{
w->close();
delete w;
break;
}
}
}
void QgisApp::closeAdditionalMapCanvases()
{
freezeCanvases( true ); // closing docks may cause canvases to resize, and we don't want a map refresh occurring
Q_FOREACH ( QgsMapCanvasDockWidget *w, findChildren< QgsMapCanvasDockWidget * >() )
{
w->close();
delete w;
}
freezeCanvases( false );
}
void QgisApp::freezeCanvases( bool frozen )
{
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
{
canvas->freeze( frozen );
}
}
QgsMessageBar *QgisApp::messageBar()
{
Q_ASSERT( mInfoBar );
@ -3664,7 +3772,7 @@ QString QgisApp::crsAndFormatAdjustedLayerUri( const QString &uri, const QString
*/
void QgisApp::addVectorLayer()
{
mMapCanvas->freeze();
freezeCanvases();
QgsOpenVectorLayerDialog *ovl = new QgsOpenVectorLayerDialog( this );
if ( ovl->exec() )
@ -3677,8 +3785,8 @@ void QgisApp::addVectorLayer()
}
}
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
delete ovl;
}
@ -3729,7 +3837,7 @@ bool QgisApp::addVectorLayers( const QStringList &layerQStringList, const QStrin
if ( ! layer )
{
mMapCanvas->freeze( false );
freezeCanvases( false );
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
@ -3807,8 +3915,8 @@ bool QgisApp::addVectorLayers( const QStringList &layerQStringList, const QStrin
// Let the caller do it otherwise
if ( !wasfrozen )
{
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
}
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
@ -4210,11 +4318,11 @@ void QgisApp::addDatabaseLayers( QStringList const &layerPathList, QString const
// no layers to add so bail out, but
// allow mMapCanvas to handle events
// first
mMapCanvas->freeze( false );
freezeCanvases( false );
return;
}
mMapCanvas->freeze( true );
freezeCanvases( true );
QApplication::setOverrideCursor( Qt::WaitCursor );
@ -4228,7 +4336,7 @@ void QgisApp::addDatabaseLayers( QStringList const &layerPathList, QString const
if ( ! layer )
{
mMapCanvas->freeze( false );
freezeCanvases( false );
QApplication::restoreOverrideCursor();
// XXX insert meaningful whine to the user here
@ -4264,8 +4372,8 @@ void QgisApp::addDatabaseLayers( QStringList const &layerPathList, QString const
}
// draw the map
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
QApplication::restoreOverrideCursor();
}
@ -4474,10 +4582,10 @@ void QgisApp::addAfsLayer()
this, SLOT( addAfsLayer( QString, QString ) ) );
bool wasFrozen = mapCanvas()->isFrozen();
mapCanvas()->freeze( true );
freezeCanvases();
afss->exec();
if ( !wasFrozen )
mapCanvas()->freeze( false );
freezeCanvases( false );
delete afss;
}
@ -4508,10 +4616,10 @@ void QgisApp::addAmsLayer()
this, SLOT( addAmsLayer( QString, QString ) ) );
bool wasFrozen = mapCanvas()->isFrozen();
mapCanvas()->freeze( true );
freezeCanvases();
amss->exec();
if ( !wasFrozen )
mapCanvas()->freeze( false );
freezeCanvases( false );
delete amss;
}
@ -5656,11 +5764,11 @@ void QgisApp::toggleFullScreen()
// would otherwise cause two re-renders of the map, which can take a
// long time.
bool wasFrozen = mapCanvas()->isFrozen();
mapCanvas()->freeze();
freezeCanvases();
showNormal();
showMaximized();
if ( !wasFrozen )
mapCanvas()->freeze( false );
freezeCanvases( false );
mPrevScreenModeMaximized = false;
}
else
@ -5798,8 +5906,8 @@ void QgisApp::removeWindow( QAction *action )
void QgisApp::stopRendering()
{
if ( mMapCanvas )
mMapCanvas->stopRendering();
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
canvas->stopRendering();
}
//reimplements method from base (gui) class
@ -7044,6 +7152,11 @@ QList<QgsMapCanvasAnnotationItem *> QgisApp::annotationItems()
return itemList;
}
QList<QgsMapCanvas *> QgisApp::mapCanvases()
{
return findChildren< QgsMapCanvas * >();
}
void QgisApp::removeAnnotationItems()
{
if ( !mMapCanvas )
@ -7162,10 +7275,7 @@ void QgisApp::mergeAttributesOfSelectedFeatures()
vl->endEditCommand();
if ( mapCanvas() )
{
vl->triggerRepaint();
}
vl->triggerRepaint();
}
void QgisApp::modifyAttributesOfSelectedFeatures()
@ -7341,10 +7451,7 @@ void QgisApp::mergeSelectedFeatures()
vl->endEditCommand();
if ( mapCanvas() )
{
vl->triggerRepaint();
}
vl->triggerRepaint();
}
void QgisApp::nodeTool()
@ -7421,7 +7528,7 @@ void QgisApp::deselectAll()
{
// Turn off rendering to improve speed.
bool wasFrozen = mMapCanvas->isFrozen();
mMapCanvas->freeze();
freezeCanvases();
QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
for ( QMap<QString, QgsMapLayer *>::iterator it = layers.begin(); it != layers.end(); ++it )
@ -7435,7 +7542,7 @@ void QgisApp::deselectAll()
// Turn on rendering (if it was on previously)
if ( !wasFrozen )
mMapCanvas->freeze( false );
freezeCanvases( false );
}
void QgisApp::invertSelection()
@ -7453,13 +7560,13 @@ void QgisApp::invertSelection()
// Turn off rendering to improve speed.
bool wasFrozen = mMapCanvas->isFrozen();
mMapCanvas->freeze();
freezeCanvases();
vlayer->invertSelection();
// Turn on rendering (if it was on previously)
if ( !wasFrozen )
mMapCanvas->freeze( false );
freezeCanvases( false );
}
void QgisApp::selectAll()
@ -7477,13 +7584,13 @@ void QgisApp::selectAll()
// Turn off rendering to improve speed.
bool wasFrozen = mMapCanvas->isFrozen();
mMapCanvas->freeze();
freezeCanvases();
vlayer->selectAll();
// Turn on rendering (if it was on previously)
if ( !wasFrozen )
mMapCanvas->freeze( false );
freezeCanvases( false );
}
void QgisApp::selectByExpression()
@ -7723,12 +7830,12 @@ QgsVectorLayer *QgisApp::pasteAsNewMemoryVector( const QString &layerName )
layer->setName( layerNameCopy );
mMapCanvas->freeze();
freezeCanvases();
QgsProject::instance()->addMapLayer( layer );
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
return layer;
}
@ -7936,10 +8043,12 @@ void QgisApp::copyFeatures( QgsFeatureStore &featureStore )
void QgisApp::refreshMapCanvas()
{
//stop any current rendering
mMapCanvas->stopRendering();
mMapCanvas->refreshAllLayers();
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
{
//stop any current rendering
canvas->stopRendering();
canvas->refreshAllLayers();
}
}
void QgisApp::canvasRefreshStarted()
@ -8065,7 +8174,7 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
case QMessageBox::Discard:
QApplication::setOverrideCursor( Qt::WaitCursor );
mMapCanvas->freeze( true );
freezeCanvases();
if ( !vlayer->rollBack() )
{
messageBar()->pushMessage( tr( "Error" ),
@ -8073,7 +8182,7 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
QgsMessageBar::CRITICAL );
res = false;
}
mMapCanvas->freeze( false );
freezeCanvases( false );
vlayer->triggerRepaint();
@ -8086,9 +8195,9 @@ bool QgisApp::toggleEditing( QgsMapLayer *layer, bool allowCancel )
}
else //layer not modified
{
mMapCanvas->freeze( true );
freezeCanvases();
vlayer->rollBack();
mMapCanvas->freeze( false );
freezeCanvases( false );
res = true;
vlayer->triggerRepaint();
}
@ -8143,7 +8252,7 @@ void QgisApp::cancelEdits( QgsMapLayer *layer, bool leaveEditable, bool triggerR
if ( vlayer == activeLayer() && leaveEditable )
mSaveRollbackInProgress = true;
mMapCanvas->freeze( true );
freezeCanvases();
if ( !vlayer->rollBack( !leaveEditable ) )
{
mSaveRollbackInProgress = false;
@ -8154,7 +8263,7 @@ void QgisApp::cancelEdits( QgsMapLayer *layer, bool leaveEditable, bool triggerR
vlayer->name(),
vlayer->commitErrors().join( QStringLiteral( "\n " ) ) ) );
}
mMapCanvas->freeze( false );
freezeCanvases( false );
if ( leaveEditable )
{
@ -8172,7 +8281,7 @@ void QgisApp::saveEdits()
{
saveEdits( layer, true, false );
}
mMapCanvas->refresh();
refreshMapCanvas();
activateDeactivateLayerRelatedActions( activeLayer() );
}
@ -8188,7 +8297,7 @@ void QgisApp::saveAllEdits( bool verifyAction )
{
saveEdits( layer, true, false );
}
mMapCanvas->refresh();
refreshMapCanvas();
activateDeactivateLayerRelatedActions( activeLayer() );
}
@ -8198,7 +8307,7 @@ void QgisApp::rollbackEdits()
{
cancelEdits( layer, true, false );
}
mMapCanvas->refresh();
refreshMapCanvas();
activateDeactivateLayerRelatedActions( activeLayer() );
}
@ -8214,7 +8323,7 @@ void QgisApp::rollbackAllEdits( bool verifyAction )
{
cancelEdits( layer, true, false );
}
mMapCanvas->refresh();
refreshMapCanvas();
activateDeactivateLayerRelatedActions( activeLayer() );
}
@ -8224,7 +8333,7 @@ void QgisApp::cancelEdits()
{
cancelEdits( layer, false, false );
}
mMapCanvas->refresh();
refreshMapCanvas();
activateDeactivateLayerRelatedActions( activeLayer() );
}
@ -8240,7 +8349,7 @@ void QgisApp::cancelAllEdits( bool verifyAction )
{
cancelEdits( layer, false, false );
}
mMapCanvas->refresh();
refreshMapCanvas();
activateDeactivateLayerRelatedActions( activeLayer() );
}
@ -8527,7 +8636,7 @@ void QgisApp::removeLayer()
showStatusMessage( tr( "%n legend entries removed.", "number of removed legend entries", selectedNodes.count() ) );
mMapCanvas->refresh();
refreshMapCanvas();
}
void QgisApp::duplicateLayers( const QList<QgsMapLayer *> &lyrList )
@ -8543,7 +8652,7 @@ void QgisApp::duplicateLayers( const QList<QgsMapLayer *> &lyrList )
return;
}
mMapCanvas->freeze();
freezeCanvases();
QgsMapLayer *dupLayer = nullptr;
QString layerDupName, unSppType;
QList<QgsMessageBarItem *> msgBars;
@ -8672,7 +8781,7 @@ void QgisApp::duplicateLayers( const QList<QgsMapLayer *> &lyrList )
dupLayer = nullptr;
mMapCanvas->freeze( false );
freezeCanvases( false );
// display errors in message bar after duplication of layers
Q_FOREACH ( QgsMessageBarItem *msgBar, msgBars )
@ -8701,15 +8810,15 @@ void QgisApp::setLayerScaleVisibility()
}
if ( dlg->exec() )
{
mMapCanvas->freeze();
freezeCanvases();
Q_FOREACH ( QgsMapLayer *layer, layers )
{
layer->setScaleBasedVisibility( dlg->hasScaleVisibility() );
layer->setMinimumScale( 1.0 / dlg->maximumScale() );
layer->setMaximumScale( 1.0 / dlg->minimumScale() );
}
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
}
delete dlg;
}
@ -8781,7 +8890,7 @@ void QgisApp::setLayerCrs()
}
}
mMapCanvas->refresh();
refreshMapCanvas();
}
void QgisApp::setProjectCrsFromLayer()
@ -8849,7 +8958,7 @@ void QgisApp::legendLayerStretchUsingCurrentExtent()
layer->refreshContrastEnhancement( myRectangle );
mLayerTreeView->refreshLayerSymbology( layer->id() );
mMapCanvas->refresh();
refreshMapCanvas();
}
}
@ -9133,16 +9242,10 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString &currentPage )
setupLayerTreeViewFromSettings();
mMapCanvas->enableAntiAliasing( mySettings.value( QStringLiteral( "qgis/enable_anti_aliasing" ) ).toBool() );
double zoomFactor = mySettings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
mMapCanvas->setWheelFactor( zoomFactor );
mMapCanvas->setCachingEnabled( mySettings.value( QStringLiteral( "qgis/enable_render_caching" ), true ).toBool() );
mMapCanvas->setParallelRenderingEnabled( mySettings.value( QStringLiteral( "qgis/parallel_rendering" ), true ).toBool() );
mMapCanvas->setMapUpdateInterval( mySettings.value( QStringLiteral( "qgis/map_update_interval" ), 250 ).toInt() );
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
{
applyDefaultSettingsToCanvas( canvas );
}
if ( oldCapitalize != mySettings.value( QStringLiteral( "qgis/capitalizeLayerName" ), QVariant( false ) ).toBool() )
{
@ -9163,7 +9266,10 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString &currentPage )
}
//do we need this? TS
mMapCanvas->refresh();
Q_FOREACH ( QgsMapCanvas *canvas, mapCanvases() )
{
canvas->refresh();
}
mRasterFileFilter = QgsProviderRegistry::instance()->fileRasterFilters();
@ -9176,9 +9282,6 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString &currentPage )
qobject_cast<QgsMeasureTool *>( mMapTools.mMeasureArea )->updateSettings();
qobject_cast<QgsMapToolMeasureAngle *>( mMapTools.mMeasureAngle )->updateSettings();
mMapCanvas->setSegmentationTolerance( mySettings.value( QStringLiteral( "qgis/segmentationTolerance" ), "0.01745" ).toDouble() );
mMapCanvas->setSegmentationToleranceType( QgsAbstractGeometry::SegmentationToleranceType( mySettings.value( QStringLiteral( "qgis/segmentationToleranceType" ), "0" ).toInt() ) );
double factor = mySettings.value( QStringLiteral( "qgis/magnifier_factor_default" ), 1.0 ).toDouble();
mMagnifierWidget->setDefaultFactor( factor );
mMagnifierWidget->updateMagnification( factor );
@ -9439,7 +9542,7 @@ QgsVectorLayer *QgisApp::addVectorLayer( const QString &vectorLayerPath, const Q
{
bool wasfrozen = mMapCanvas->isFrozen();
mMapCanvas->freeze();
freezeCanvases();
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
@ -9499,7 +9602,7 @@ QgsVectorLayer *QgisApp::addVectorLayer( const QString &vectorLayerPath, const Q
messageBar()->pushMessage( tr( "Layer is not valid" ), msg, QgsMessageBar::CRITICAL, messageTimeout() );
delete layer;
mMapCanvas->freeze( false );
freezeCanvases( false );
return nullptr;
}
@ -9507,8 +9610,8 @@ QgsVectorLayer *QgisApp::addVectorLayer( const QString &vectorLayerPath, const Q
// Let the caller do it otherwise
if ( !wasfrozen )
{
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
}
// Let render() do its own cursor management
@ -9522,7 +9625,7 @@ QgsVectorLayer *QgisApp::addVectorLayer( const QString &vectorLayerPath, const Q
void QgisApp::addMapLayer( QgsMapLayer *mapLayer )
{
mMapCanvas->freeze();
freezeCanvases();
// Let render() do its own cursor management
// QApplication::setOverrideCursor(Qt::WaitCursor);
@ -9543,8 +9646,8 @@ void QgisApp::addMapLayer( QgsMapLayer *mapLayer )
}
// draw the map
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
@ -9557,7 +9660,7 @@ void QgisApp::embedLayers()
QgsProjectLayerGroupDialog d( this );
if ( d.exec() == QDialog::Accepted && d.isValid() )
{
mMapCanvas->freeze( true );
freezeCanvases();
QString projectFile = d.selectedProjectFile();
@ -9588,14 +9691,38 @@ void QgisApp::embedLayers()
}
}
mMapCanvas->freeze( false );
freezeCanvases( false );
if ( !groups.isEmpty() || !layerIds.isEmpty() )
{
mMapCanvas->refresh();
refreshMapCanvas();
}
}
}
void QgisApp::newMapCanvas()
{
int i = 1;
bool existing = true;
QList< QgsMapCanvas * > existingCanvases = mapCanvases();
QString name;
while ( existing )
{
name = tr( "Map %1" ).arg( i++ );
existing = false;
Q_FOREACH ( QgsMapCanvas *canvas, existingCanvases )
{
if ( canvas->objectName() == name )
{
existing = true;
break;
}
}
}
createNewMapCanvas( name, true );
}
void QgisApp::setExtent( const QgsRectangle &rect )
{
mMapCanvas->setExtent( rect );
@ -9639,7 +9766,7 @@ bool QgisApp::saveDirty()
}
QMessageBox::StandardButton answer( QMessageBox::Discard );
mMapCanvas->freeze( true );
freezeCanvases();
//QgsDebugMsg(QString("Layer count is %1").arg(mMapCanvas->layerCount()));
//QgsDebugMsg(QString("Project is %1dirty").arg( QgsProject::instance()->isDirty() ? "" : "not "));
@ -9669,7 +9796,7 @@ bool QgisApp::saveDirty()
}
}
mMapCanvas->freeze( false );
freezeCanvases( false );
return answer != QMessageBox::Cancel;
}
@ -9715,6 +9842,8 @@ void QgisApp::closeProject()
mLegendExpressionFilterButton->setChecked( false );
mActionFilterLegend->setChecked( false );
closeAdditionalMapCanvases();
deletePrintComposers();
removeAnnotationItems();
// clear out any stuff from project
@ -10433,7 +10562,7 @@ void QgisApp::layersWereAdded( const QList<QgsMapLayer *> &layers )
if ( provider )
{
connect( provider, &QgsDataProvider::dataChanged, layer, [layer] { layer->triggerRepaint(); } );
connect( provider, &QgsDataProvider::dataChanged, mMapCanvas, &QgsMapCanvas::refresh );
connect( provider, &QgsDataProvider::dataChanged, this, &QgisApp::refreshMapCanvas );
}
}
}
@ -10536,11 +10665,6 @@ void QgisApp::projectProperties()
&QgsStatusBarScaleWidget::updateScales );
QApplication::restoreOverrideCursor();
//pass any refresh signals off to canvases
// Line below was commented out by wonder three years ago (r4949).
// It is needed to refresh scale bar after changing display units.
connect( pp, SIGNAL( refresh() ), mMapCanvas, SLOT( refresh() ) );
// Display the modal dialog box.
pp->exec();
@ -10553,7 +10677,7 @@ void QgisApp::projectProperties()
// delete the property sheet object
delete pp;
} // QgisApp::projectProperties
}
QgsClipboard *QgisApp::clipboard()
@ -11068,6 +11192,37 @@ void QgisApp::refreshActionFeatureAction()
mActionFeatureAction->setEnabled( layerHasActions );
}
void QgisApp::renameView()
{
QgsMapCanvasDockWidget *view = qobject_cast< QgsMapCanvasDockWidget * >( sender() );
if ( !view )
return;
// calculate existing names
QStringList names;
Q_FOREACH ( QgsMapCanvas *c, mapCanvases() )
{
if ( c == view->mapCanvas() )
continue;
names << c->objectName();
}
QString currentName = view->mapCanvas()->objectName();
QgsNewNameDialog renameDlg( currentName, currentName, QStringList(), names, QRegExp(), Qt::CaseSensitive, this );
renameDlg.setWindowTitle( tr( "Map Views" ) );
//renameDlg.setHintString( tr( "Name of the new view" ) );
renameDlg.setOverwriteEnabled( false );
renameDlg.setConflictingNameWarning( tr( "A view with this name already exists" ) );
if ( renameDlg.exec() || renameDlg.name().isEmpty() )
{
QString newName = renameDlg.name();
view->setWindowTitle( newName );
view->mapCanvas()->setObjectName( newName );
}
}
/////////////////////////////////////////////////////////////////
//
//
@ -11143,7 +11298,7 @@ QgsRasterLayer *QgisApp::addRasterLayerPrivate(
{
// let the user know we're going to possibly be taking a while
// QApplication::setOverrideCursor( Qt::WaitCursor );
mMapCanvas->freeze( true );
freezeCanvases();
}
QgsDebugMsg( "Creating new raster layer using " + uri
@ -11200,7 +11355,7 @@ QgsRasterLayer *QgisApp::addRasterLayerPrivate(
if ( !ok )
{
if ( guiUpdate )
mMapCanvas->freeze( false );
freezeCanvases( false );
// don't show the gui warning if we are loading from command line
if ( guiWarning )
@ -11219,8 +11374,8 @@ QgsRasterLayer *QgisApp::addRasterLayerPrivate(
if ( guiUpdate )
{
// draw the map
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
}
@ -11262,11 +11417,11 @@ bool QgisApp::addRasterLayers( QStringList const &fileNameQStringList, bool guiW
// no files selected so bail out, but
// allow mMapCanvas to handle events
// first
mMapCanvas->freeze( false );
freezeCanvases( false );;
return false;
}
mMapCanvas->freeze( true );
freezeCanvases();
// this is messy since some files in the list may be rasters and others may
// be ogr layers. We'll set returnValue to false if one or more layers fail
@ -11331,8 +11486,8 @@ bool QgisApp::addRasterLayers( QStringList const &fileNameQStringList, bool guiW
}
}
mMapCanvas->freeze( false );
mMapCanvas->refresh();
freezeCanvases( false );
refreshMapCanvas();
// Let render() do its own cursor management
// QApplication::restoreOverrideCursor();
@ -11593,10 +11748,30 @@ void QgisApp::writeProject( QDomDocument &doc )
QDomElement oldLegendElem = QgsLayerTreeUtils::writeOldLegend( doc, QgsLayerTree::toGroup( clonedRoot ),
mLayerTreeCanvasBridge->hasCustomLayerOrder(), mLayerTreeCanvasBridge->customLayerOrder() );
delete clonedRoot;
doc.firstChildElement( QStringLiteral( "qgis" ) ).appendChild( oldLegendElem );
QDomElement qgisNode = doc.firstChildElement( QStringLiteral( "qgis" ) );
qgisNode.appendChild( oldLegendElem );
QgsProject::instance()->writeEntry( QStringLiteral( "Legend" ), QStringLiteral( "filterByMap" ), static_cast< bool >( layerTreeView()->layerTreeModel()->legendFilterMapSettings() ) );
// Save the position of the map view docks
QDomElement mapViewNode = doc.createElement( QStringLiteral( "mapViewDocks" ) );
Q_FOREACH ( QgsMapCanvasDockWidget *w, findChildren< QgsMapCanvasDockWidget * >() )
{
QDomElement node = doc.createElement( QStringLiteral( "view" ) );
node.setAttribute( QStringLiteral( "name" ), w->mapCanvas()->objectName() );
node.setAttribute( QStringLiteral( "x" ), w->x() );
node.setAttribute( QStringLiteral( "y" ), w->y() );
node.setAttribute( QStringLiteral( "width" ), w->width() );
node.setAttribute( QStringLiteral( "height" ), w->height() );
node.setAttribute( QStringLiteral( "floating" ), w->isFloating() );
node.setAttribute( QStringLiteral( "synced" ), w->isViewCenterSynchronized() );
node.setAttribute( QStringLiteral( "showCursor" ), w->isCursorMarkerVisible() );
node.setAttribute( QStringLiteral( "scaleSynced" ), w->isViewScaleSynchronized() );
node.setAttribute( QStringLiteral( "scaleFactor" ), w->scaleFactor() );
mapViewNode.appendChild( node );
}
qgisNode.appendChild( mapViewNode );
projectChanged( doc );
}
@ -11612,6 +11787,30 @@ void QgisApp::readProject( const QDomDocument &doc )
if ( autoSetupOnFirstLayer )
mLayerTreeCanvasBridge->setAutoSetupOnFirstLayer( true );
QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "mapViewDocks" ) );
if ( !nodes.isEmpty() )
{
QDomNode viewNode = nodes.at( 0 );
nodes = viewNode.childNodes();
for ( int i = 0; i < nodes.size(); ++i )
{
QDomElement elementNode = nodes.at( i ).toElement();
QString mapName = elementNode.attribute( QStringLiteral( "name" ) );
int x = elementNode.attribute( QStringLiteral( "x" ), QStringLiteral( "0" ) ).toInt();
int y = elementNode.attribute( QStringLiteral( "y" ), QStringLiteral( "0" ) ).toInt();
int w = elementNode.attribute( QStringLiteral( "width" ), QStringLiteral( "400" ) ).toInt();
int h = elementNode.attribute( QStringLiteral( "height" ), QStringLiteral( "400" ) ).toInt();
bool floating = elementNode.attribute( QStringLiteral( "floating" ), QStringLiteral( "0" ) ).toInt();
bool synced = elementNode.attribute( QStringLiteral( "synced" ), QStringLiteral( "0" ) ).toInt();
bool showCursor = elementNode.attribute( QStringLiteral( "showCursor" ), QStringLiteral( "0" ) ).toInt();
bool scaleSynced = elementNode.attribute( QStringLiteral( "scaleSynced" ), QStringLiteral( "0" ) ).toInt();
double scaleFactor = elementNode.attribute( QStringLiteral( "scaleFactor" ), QStringLiteral( "1" ) ).toDouble();
QgsMapCanvas *mapCanvas = createNewMapCanvas( mapName, floating, QRect( x, y, w, h ), synced, showCursor, scaleSynced, scaleFactor );
mapCanvas->readProject( doc );
}
}
}
void QgisApp::showLayerProperties( QgsMapLayer *ml )

View File

@ -231,6 +231,36 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Get the mapcanvas object from the app
QgsMapCanvas *mapCanvas();
/**
* Returns a list of all map canvases open in the app.
*/
QList< QgsMapCanvas * > mapCanvases();
/**
* Create a new map canvas with the specified unique \a name. The \a isFloating
* and \a dockGeometry arguments can be used to specify an initial floating state
* and widget geometry rect for the dock.
*/
QgsMapCanvas *createNewMapCanvas( const QString &name, bool isFloating = false, const QRect &dockGeometry = QRect(),
bool synced = false, bool showCursor = true, bool scaleSynced = false,
double scaleFactor = 1.0 );
/**
* Closes the additional map canvas with matching \a name.
*/
void closeMapCanvas( const QString &name );
/**
* Closes any additional map canvases. The main map canvas will not
* be affected.
*/
void closeAdditionalMapCanvases();
/**
* Freezes all map canvases (or thaws them if the \a frozen argument is false).
*/
void freezeCanvases( bool frozen = true );
//! Return the messageBar object which allows displaying unobtrusive messages to the user.
QgsMessageBar *messageBar();
@ -736,6 +766,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QMenu *panelMenu() { return mPanelMenu; }
void renameView();
protected:
//! Handle state changes (WindowTitleChange)
@ -1024,6 +1056,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void showAlignRasterTool();
void embedLayers();
//! Creates a new map canvas view
void newMapCanvas();
//! Create a new empty vector layer
void newVectorLayer();
//! Create a new memory layer
@ -1514,6 +1549,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Returns all annotation items in the canvas
QList<QgsMapCanvasAnnotationItem *> annotationItems();
//! Removes annotation items in the canvas
void removeAnnotationItems();
@ -1551,6 +1587,11 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
*/
void applyProjectSettingsToCanvas( QgsMapCanvas *canvas );
/**
* Applies global qgis settings to the specified canvas
*/
void applyDefaultSettingsToCanvas( QgsMapCanvas *canvas );
QgisAppStyleSheet *mStyleSheetBuilder = nullptr;
// actions for menus and toolbars -----------------
@ -1754,6 +1795,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QSplashScreen *mSplash = nullptr;
//! list of recently opened/saved project files
QList<QgsWelcomePageItemsModel::RecentProjectData> mRecentProjects;
//! Print composers of this project, accessible by id string
QSet<QgsComposer *> mPrintComposers;
//! QGIS-internal vector feature clipboard

View File

@ -331,6 +331,21 @@ QgsMapCanvas *QgisAppInterface::mapCanvas()
return qgis->mapCanvas();
}
QList<QgsMapCanvas *> QgisAppInterface::mapCanvases()
{
return qgis->mapCanvases();
}
QgsMapCanvas *QgisAppInterface::createNewMapCanvas( const QString &name )
{
return qgis->createNewMapCanvas( name );
}
void QgisAppInterface::closeMapCanvas( const QString &name )
{
qgis->closeMapCanvas( name );
}
QgsLayerTreeMapCanvasBridge *QgisAppInterface::layerTreeCanvasBridge()
{
return qgis->layerTreeCanvasBridge();

View File

@ -179,6 +179,10 @@ class APP_EXPORT QgisAppInterface : public QgisInterface
//! Return a pointer to the map canvas used by qgisapp
QgsMapCanvas *mapCanvas() override;
QList< QgsMapCanvas * > mapCanvases() override;
QgsMapCanvas *createNewMapCanvas( const QString &name ) override;
virtual void closeMapCanvas( const QString &name ) override;
/**
* Returns a pointer to the layer tree canvas bridge
*

View File

@ -130,7 +130,7 @@ bool QgsGuiVectorLayerTools::stopEditing( QgsVectorLayer *layer, bool allowCance
break;
case QMessageBox::Discard:
QgisApp::instance()->mapCanvas()->freeze( true );
QgisApp::instance()->freezeCanvases();
if ( !layer->rollBack() )
{
QgisApp::instance()->messageBar()->pushMessage( tr( "Error" ),
@ -138,7 +138,7 @@ bool QgsGuiVectorLayerTools::stopEditing( QgsVectorLayer *layer, bool allowCance
QgsMessageBar::CRITICAL );
res = false;
}
QgisApp::instance()->mapCanvas()->freeze( false );
QgisApp::instance()->freezeCanvases( false );
layer->triggerRepaint();
break;
@ -149,9 +149,9 @@ bool QgsGuiVectorLayerTools::stopEditing( QgsVectorLayer *layer, bool allowCance
}
else //layer not modified
{
QgisApp::instance()->mapCanvas()->freeze( true );
QgisApp::instance()->freezeCanvases( true );
layer->rollBack();
QgisApp::instance()->mapCanvas()->freeze( false );
QgisApp::instance()->freezeCanvases( false );
res = true;
layer->triggerRepaint();
}

View File

@ -0,0 +1,464 @@
/***************************************************************************
qgsmapcanvasdockwidget.cpp
--------------------------
begin : February 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 "qgsmapcanvasdockwidget.h"
#include "qgsmapcanvas.h"
#include "qgscsexception.h"
#include "qgsprojectionselectiondialog.h"
#include "qgsscalecombobox.h"
#include "qgsdoublespinbox.h"
#include "qgssettings.h"
#include "qgsmaptoolpan.h"
#include "qgsmapthemecollection.h"
#include "qgsproject.h"
#include "qgsmapthemes.h"
#include "qgslayertreeview.h"
#include "qgslayertreeviewdefaultactions.h"
#include "qgisapp.h"
#include "qgsvertexmarker.h"
#include <QMessageBox>
#include <QMenu>
#include <QToolBar>
#include <QToolButton>
QgsMapCanvasDockWidget::QgsMapCanvasDockWidget( const QString &name, QWidget *parent )
: QgsDockWidget( parent )
{
setupUi( this );
setAttribute( Qt::WA_DeleteOnClose );
mContents->layout()->setContentsMargins( 0, 0, 0, 0 );
mContents->layout()->setMargin( 0 );
static_cast< QVBoxLayout * >( mContents->layout() )->setSpacing( 0 );
setWindowTitle( name );
mMapCanvas = new QgsMapCanvas( this );
mXyMarker = new QgsVertexMarker( mMapCanvas );
mXyMarker->setIconType( QgsVertexMarker::ICON_CIRCLE );
mXyMarker->setIconSize( 6 );
mXyMarker->setColor( QColor( 30, 30, 30, 225 ) );
mPanTool = new QgsMapToolPan( mMapCanvas );
mMapCanvas->setMapTool( mPanTool );
mMainWidget->setLayout( new QVBoxLayout() );
mMainWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
mMainWidget->layout()->setMargin( 0 );
mMainWidget->layout()->addWidget( mMapCanvas );
connect( mActionSyncView, &QAction::toggled, this, [ = ]
{
syncViewCenter( mMainCanvas );
} );
mMenu = new QMenu();
connect( mMenu, &QMenu::aboutToShow, this, &QgsMapCanvasDockWidget::menuAboutToShow );
QToolButton *btnMapThemes = new QToolButton;
btnMapThemes->setAutoRaise( true );
btnMapThemes->setToolTip( tr( "Set View Theme" ) );
btnMapThemes->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ) );
btnMapThemes->setPopupMode( QToolButton::InstantPopup );
btnMapThemes->setMenu( mMenu );
mToolbar->addWidget( btnMapThemes );
QMenu *settingsMenu = new QMenu();
QToolButton *settingsButton = new QToolButton();
settingsButton->setAutoRaise( true );
settingsButton->setToolTip( tr( "View Settings" ) );
settingsButton->setMenu( settingsMenu );
settingsButton->setPopupMode( QToolButton::InstantPopup );
settingsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMapSettings.svg" ) ) );
mToolbar->addWidget( settingsButton );
connect( mActionSetCrs, &QAction::triggered, this, &QgsMapCanvasDockWidget::setMapCrs );
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsMapCanvasDockWidget::mapCrsChanged );
connect( mActionZoomFullExtent, &QAction::triggered, mMapCanvas, &QgsMapCanvas::zoomToFullExtent );
connect( mActionZoomToLayer, &QAction::triggered, mMapCanvas, [ = ] { QgisApp::instance()->layerTreeView()->defaultActions()->zoomToLayer( mMapCanvas ); } );
connect( mActionZoomToSelected, &QAction::triggered, mMapCanvas, [ = ] { mMapCanvas->zoomToSelected(); } );
mapCrsChanged();
QgsMapSettingsAction *settingsAction = new QgsMapSettingsAction( settingsMenu );
settingsMenu->addAction( settingsAction );
settingsMenu->addSeparator();
settingsMenu->addAction( mActionSetCrs );
settingsMenu->addAction( mActionShowAnnotations );
settingsMenu->addAction( mActionShowCursor );
settingsMenu->addAction( mActionRename );
connect( settingsMenu, &QMenu::aboutToShow, this, &QgsMapCanvasDockWidget::settingsMenuAboutToShow );
connect( mActionRename, &QAction::triggered, this, &QgsMapCanvasDockWidget::renameTriggered );
mActionShowAnnotations->setChecked( mMapCanvas->annotationsVisible() );
connect( mActionShowAnnotations, &QAction::toggled, this, [ = ]( bool checked ) { mMapCanvas->setAnnotationsVisible( checked ); } );
mActionShowCursor->setChecked( true );
connect( mActionShowCursor, &QAction::toggled, this, [ = ]( bool checked ) { mXyMarker->setVisible( checked ); } );
mScaleCombo = settingsAction->scaleCombo();
mRotationEdit = settingsAction->rotationSpinBox();
mMagnificationEdit = settingsAction->magnifierSpinBox();
mSyncScaleCheckBox = settingsAction->syncScaleCheckBox();
mScaleFactorWidget = settingsAction->scaleFactorSpinBox();
connect( mScaleCombo, &QgsScaleComboBox::scaleChanged, this, [ = ]( double scale )
{
if ( !mBlockScaleUpdate )
{
mBlockScaleUpdate = true;
mMapCanvas->zoomScale( 1.0 / scale );
mBlockScaleUpdate = false;
}
} );
connect( mMapCanvas, &QgsMapCanvas::scaleChanged, this, [ = ]( double scale )
{
if ( !mBlockScaleUpdate )
{
mBlockScaleUpdate = true;
mScaleCombo->setScale( 1.0 / scale );
mBlockScaleUpdate = false;
}
} );
connect( mRotationEdit, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( double value )
{
if ( !mBlockRotationUpdate )
{
mBlockRotationUpdate = true;
mMapCanvas->setRotation( value );
mMapCanvas->refresh();
mBlockRotationUpdate = false;
}
} );
connect( mMapCanvas, &QgsMapCanvas::rotationChanged, this, [ = ]( double rotation )
{
if ( !mBlockRotationUpdate )
{
mBlockRotationUpdate = true;
mRotationEdit->setValue( rotation );
mBlockRotationUpdate = false;
}
} );
connect( mMagnificationEdit, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, [ = ]( double value )
{
if ( !mBlockMagnificationUpdate )
{
mBlockMagnificationUpdate = true;
mMapCanvas->setMagnificationFactor( value / 100 );
mMapCanvas->refresh();
mBlockMagnificationUpdate = false;
}
} );
connect( mMapCanvas, &QgsMapCanvas::magnificationChanged, this, [ = ]( double factor )
{
if ( !mBlockMagnificationUpdate )
{
mBlockMagnificationUpdate = true;
mMagnificationEdit->setValue( factor * 100 );
mBlockMagnificationUpdate = false;
}
} );
connect( mScaleFactorWidget, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsMapCanvasDockWidget::mapScaleChanged );
connect( mSyncScaleCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
if ( checked )
mapScaleChanged();
}
);
mResizeTimer.setSingleShot( true );
connect( &mResizeTimer, &QTimer::timeout, this, [ = ]
{
mBlockExtentSync = false;
syncViewCenter( mMainCanvas );
} );
}
void QgsMapCanvasDockWidget::setMainCanvas( QgsMapCanvas *canvas )
{
if ( mMainCanvas )
{
disconnect( mMainCanvas, &QgsMapCanvas::xyCoordinates, this, &QgsMapCanvasDockWidget::syncMarker );
disconnect( mMainCanvas, &QgsMapCanvas::scaleChanged, this, &QgsMapCanvasDockWidget::mapScaleChanged );
disconnect( mMainCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::mapExtentChanged );
}
mMainCanvas = canvas;
connect( mMainCanvas, &QgsMapCanvas::xyCoordinates, this, &QgsMapCanvasDockWidget::syncMarker );
connect( mMainCanvas, &QgsMapCanvas::scaleChanged, this, &QgsMapCanvasDockWidget::mapScaleChanged );
connect( mMainCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::mapExtentChanged );
connect( mMapCanvas, &QgsMapCanvas::extentsChanged, this, &QgsMapCanvasDockWidget::mapExtentChanged, Qt::UniqueConnection );
}
QgsMapCanvas *QgsMapCanvasDockWidget::mapCanvas()
{
return mMapCanvas;
}
void QgsMapCanvasDockWidget::setViewCenterSynchronized( bool enabled )
{
mActionSyncView->setChecked( enabled );
}
bool QgsMapCanvasDockWidget::isViewCenterSynchronized() const
{
return mActionSyncView->isChecked();
}
void QgsMapCanvasDockWidget::setCursorMarkerVisible( bool visible )
{
mActionShowCursor->setChecked( visible );
}
bool QgsMapCanvasDockWidget::isCursorMarkerVisible() const
{
return mXyMarker->isVisible();
}
void QgsMapCanvasDockWidget::setScaleFactor( double factor )
{
mScaleFactorWidget->setValue( factor );
}
void QgsMapCanvasDockWidget::setViewScaleSynchronized( bool enabled )
{
mSyncScaleCheckBox->setChecked( enabled );
}
bool QgsMapCanvasDockWidget::isViewScaleSynchronized() const
{
return mSyncScaleCheckBox->isChecked();
}
double QgsMapCanvasDockWidget::scaleFactor() const
{
return mScaleFactorWidget->value();
}
void QgsMapCanvasDockWidget::resizeEvent( QResizeEvent * )
{
mBlockExtentSync = true;
mResizeTimer.start( 500 );
}
void QgsMapCanvasDockWidget::setMapCrs()
{
QgsProjectionSelectionDialog dlg;
dlg.setShowNoProjection( true );
dlg.setCrs( mMapCanvas->mapSettings().destinationCrs() );
if ( dlg.exec() )
{
mMapCanvas->setDestinationCrs( dlg.crs() );
}
}
void QgsMapCanvasDockWidget::syncViewCenter( QgsMapCanvas *sourceCanvas )
{
// avoid infinite recursion
mBlockExtentSync = true;
QgsMapCanvas *destCanvas = sourceCanvas == mMapCanvas ? mMainCanvas : mMapCanvas;
// reproject extent
QgsCoordinateTransform ct( sourceCanvas->mapSettings().destinationCrs(),
destCanvas->mapSettings().destinationCrs() );
try
{
destCanvas->setCenter( ct.transform( sourceCanvas->center() ) );
}
catch ( QgsCsException & )
{
destCanvas->setCenter( sourceCanvas->center() );
}
destCanvas->refresh();
mBlockExtentSync = false;
}
void QgsMapCanvasDockWidget::mapExtentChanged()
{
if ( mBlockExtentSync )
return;
QgsMapCanvas *sourceCanvas = qobject_cast< QgsMapCanvas * >( sender() );
if ( !sourceCanvas )
return;
if ( sourceCanvas == mMapCanvas && mSyncScaleCheckBox->isChecked() )
{
double newScaleFactor = mMainCanvas->scale() / mMapCanvas->scale();
mScaleFactorWidget->setValue( newScaleFactor );
}
if ( mActionSyncView->isChecked() )
syncViewCenter( sourceCanvas );
}
void QgsMapCanvasDockWidget::mapCrsChanged()
{
mActionSetCrs->setText( tr( "Change Map CRS (%1)…" ).arg( mMapCanvas->mapSettings().destinationCrs().isValid() ?
mMapCanvas->mapSettings().destinationCrs().authid() :
tr( "No projection" ) ) );
}
void QgsMapCanvasDockWidget::menuAboutToShow()
{
qDeleteAll( mMenuPresetActions );
mMenuPresetActions.clear();
QString currentTheme = mMapCanvas->theme();
QAction *actionFollowMain = new QAction( tr( "(default)" ), mMenu );
actionFollowMain->setCheckable( true );
if ( currentTheme.isEmpty() || !QgsProject::instance()->mapThemeCollection()->hasMapTheme( currentTheme ) )
{
actionFollowMain->setChecked( true );
}
connect( actionFollowMain, &QAction::triggered, this, [ = ]
{
mMapCanvas->setTheme( QString() );
mMapCanvas->refresh();
} );
mMenuPresetActions.append( actionFollowMain );
Q_FOREACH ( const QString &grpName, QgsProject::instance()->mapThemeCollection()->mapThemes() )
{
QAction *a = new QAction( grpName, mMenu );
a->setCheckable( true );
if ( grpName == currentTheme )
{
a->setChecked( true );
}
connect( a, &QAction::triggered, this, [a, this]
{
mMapCanvas->setTheme( a->text() );
mMapCanvas->refresh();
} );
mMenuPresetActions.append( a );
}
mMenu->addActions( mMenuPresetActions );
}
void QgsMapCanvasDockWidget::settingsMenuAboutToShow()
{
whileBlocking( mActionShowAnnotations )->setChecked( mMapCanvas->annotationsVisible() );
}
void QgsMapCanvasDockWidget::syncMarker( const QgsPoint &p )
{
if ( !mXyMarker->isVisible() )
return;
// reproject point
QgsCoordinateTransform ct( mMainCanvas->mapSettings().destinationCrs(),
mMapCanvas->mapSettings().destinationCrs() );
QgsPoint t = p;
try
{
t = ct.transform( p );
}
catch ( QgsCsException & )
{}
mXyMarker->setCenter( t );
}
void QgsMapCanvasDockWidget::mapScaleChanged()
{
if ( !mSyncScaleCheckBox->isChecked() )
return;
double newScale = mMainCanvas->scale() / mScaleFactorWidget->value();
bool prev = mBlockExtentSync;
mBlockExtentSync = true;
mMapCanvas->zoomScale( newScale );
mBlockExtentSync = prev;
}
QgsMapSettingsAction::QgsMapSettingsAction( QWidget *parent )
: QWidgetAction( parent )
{
QGridLayout *gLayout = new QGridLayout();
gLayout->setContentsMargins( 3, 2, 3, 2 );
QLabel *label = new QLabel( tr( "Scale" ) );
gLayout->addWidget( label, 0, 0 );
mScaleCombo = new QgsScaleComboBox();
gLayout->addWidget( mScaleCombo, 0, 1 );
mRotationWidget = new QgsDoubleSpinBox();
mRotationWidget->setClearValue( 0.0 );
mRotationWidget->setKeyboardTracking( false );
mRotationWidget->setMaximumWidth( 120 );
mRotationWidget->setDecimals( 1 );
mRotationWidget->setRange( -180.0, 180.0 );
mRotationWidget->setWrapping( true );
mRotationWidget->setSingleStep( 5.0 );
mRotationWidget->setToolTip( tr( "Current clockwise map rotation in degrees" ) );
label = new QLabel( tr( "Rotation" ) );
gLayout->addWidget( label, 1, 0 );
gLayout->addWidget( mRotationWidget, 1, 1 );
QgsSettings settings;
int minimumFactor = 100 * QgisGui::CANVAS_MAGNIFICATION_MIN;
int maximumFactor = 100 * QgisGui::CANVAS_MAGNIFICATION_MAX;
int defaultFactor = 100 * settings.value( QStringLiteral( "/qgis/magnifier_factor_default" ), 1.0 ).toDouble();
mMagnifierWidget = new QgsDoubleSpinBox();
mMagnifierWidget->setSuffix( QStringLiteral( "%" ) );
mMagnifierWidget->setKeyboardTracking( false );
mMagnifierWidget->setDecimals( 0 );
mMagnifierWidget->setRange( minimumFactor, maximumFactor );
mMagnifierWidget->setWrapping( false );
mMagnifierWidget->setSingleStep( 50 );
mMagnifierWidget->setToolTip( tr( "Magnifier level" ) );
mMagnifierWidget->setClearValueMode( QgsDoubleSpinBox::CustomValue );
mMagnifierWidget->setClearValue( defaultFactor );
mMagnifierWidget->setValue( defaultFactor );
label = new QLabel( tr( "Magnification" ) );
gLayout->addWidget( label, 2, 0 );
gLayout->addWidget( mMagnifierWidget, 2, 1 );
mSyncScaleCheckBox = new QCheckBox( tr( "Synchronize scale" ) );
gLayout->addWidget( mSyncScaleCheckBox, 3, 0, 1, 2 );
mScaleFactorWidget = new QgsDoubleSpinBox();
mScaleFactorWidget->setSuffix( QStringLiteral( "×" ) );
mScaleFactorWidget->setDecimals( 2 );
mScaleFactorWidget->setRange( 0.01, 100000 );
mScaleFactorWidget->setWrapping( false );
mScaleFactorWidget->setSingleStep( 0.1 );
mScaleFactorWidget->setToolTip( tr( "Multiplication factor for main canvas scale to view scale" ) );
mScaleFactorWidget->setClearValueMode( QgsDoubleSpinBox::CustomValue );
mScaleFactorWidget->setClearValue( 1.0 );
mScaleFactorWidget->setValue( 1.0 );
mScaleFactorWidget->setEnabled( false );
connect( mSyncScaleCheckBox, &QCheckBox::toggled, mScaleFactorWidget, &QgsDoubleSpinBox::setEnabled );
label = new QLabel( tr( "Scale factor" ) );
gLayout->addWidget( label, 4, 0 );
gLayout->addWidget( mScaleFactorWidget, 4, 1 );
QWidget *w = new QWidget();
w->setLayout( gLayout );
setDefaultWidget( w );
}

View File

@ -0,0 +1,176 @@
/***************************************************************************
qgsmapcanvasdockwidget.h
------------------------
begin : February 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 QGSMAPCANVASDOCKWIDGET_H
#define QGSMAPCANVASDOCKWIDGET_H
#include <ui_qgsmapcanvasdockwidgetbase.h>
#include "qgsdockwidget.h"
#include "qgspoint.h"
#include "qgis_app.h"
#include <QWidgetAction>
#include <QTimer>
#include <memory>
class QgsMapCanvas;
class QgsScaleComboBox;
class QgsDoubleSpinBox;
class QgsStatusBarMagnifierWidget;
class QgsMapToolPan;
class QgsVertexMarker;
class QCheckBox;
/**
* \class QgsMapCanvasDockWidget
* A dock widget with an embedded map canvas, for additional map views.
* \note added in QGIS 3.0
*/
class APP_EXPORT QgsMapCanvasDockWidget : public QgsDockWidget, private Ui::QgsMapCanvasDockWidgetBase
{
Q_OBJECT
public:
explicit QgsMapCanvasDockWidget( const QString &name, QWidget *parent = nullptr );
/**
* Sets the main app map canvas.
*/
void setMainCanvas( QgsMapCanvas *canvas );
/**
* Returns the map canvas contained in the dock widget.
*/
QgsMapCanvas *mapCanvas();
/**
* Sets whether the view center should be synchronized with the main canvas center.
* @see isViewCenterSynchronized()
*/
void setViewCenterSynchronized( bool enabled );
/**
* Returns true if the view extent is synchronized with the main canvas extent.
* @see setViewCenterSynchronized()
*/
bool isViewCenterSynchronized() const;
/**
* Sets whether the cursor position marker is visible.
* @see isCursorMarkerVisible()
*/
void setCursorMarkerVisible( bool visible );
/**
* Returns true if the cursor position marker is visible.
* @see setCursorMarkerVisible()
*/
bool isCursorMarkerVisible() const;
/**
* Returns the scaling factor for main canvas scale to view scale.
* @see setScaleFactor()
* @see isViewScaleSynchronized()
*/
double scaleFactor() const;
/**
* Sets the scaling \a factor for main canvas scale to view scale.
* @see scaleFactor()
* @see setViewScaleSynchronized()
*/
void setScaleFactor( double factor );
/**
* Sets whether the view scale should be synchronized with the main canvas center.
* @see isViewScaleSynchronized()
* @see setScaleFactor()
*/
void setViewScaleSynchronized( bool enabled );
/**
* Returns true if the view scale is synchronized with the main canvas extent.
* @see setViewScaleSynchronized()
* @see scaleFactor()
*/
bool isViewScaleSynchronized() const;
signals:
void renameTriggered();
protected:
void resizeEvent( QResizeEvent *e ) override;
private slots:
void setMapCrs();
void mapExtentChanged();
void mapCrsChanged();
void menuAboutToShow();
void settingsMenuAboutToShow();
void syncMarker( const QgsPoint &p );
void mapScaleChanged();
private:
QgsMapCanvas *mMapCanvas = nullptr;
QgsMapCanvas *mMainCanvas = nullptr;
QMenu *mMenu = nullptr;
QList<QAction *> mMenuPresetActions;
QgsScaleComboBox *mScaleCombo = nullptr;
QgsDoubleSpinBox *mRotationEdit = nullptr;
QgsDoubleSpinBox *mMagnificationEdit = nullptr;
QgsDoubleSpinBox *mScaleFactorWidget = nullptr;
QCheckBox *mSyncScaleCheckBox = nullptr;
bool mBlockScaleUpdate = false;
bool mBlockRotationUpdate = false;
bool mBlockMagnificationUpdate = false;
bool mBlockExtentSync = false;
QgsMapToolPan *mPanTool = nullptr;
QTimer mResizeTimer;
QgsVertexMarker *mXyMarker = nullptr;
void syncViewCenter( QgsMapCanvas *sourceCanvas );
};
/**
* \class QgsMapSettingsAction
* Allows embedding a scale, rotation and other map settings into a menu.
* \note added in QGIS 3.0
*/
class QgsMapSettingsAction: public QWidgetAction
{
Q_OBJECT
public:
QgsMapSettingsAction( QWidget *parent = nullptr );
QgsScaleComboBox *scaleCombo() { return mScaleCombo; }
QgsDoubleSpinBox *rotationSpinBox() { return mRotationWidget; }
QgsDoubleSpinBox *magnifierSpinBox() { return mMagnifierWidget; }
QgsDoubleSpinBox *scaleFactorSpinBox() { return mScaleFactorWidget; }
QCheckBox *syncScaleCheckBox() { return mSyncScaleCheckBox; }
private:
QgsScaleComboBox *mScaleCombo = nullptr;
QgsDoubleSpinBox *mRotationWidget = nullptr;
QgsDoubleSpinBox *mMagnifierWidget = nullptr;
QCheckBox *mSyncScaleCheckBox = nullptr;
QgsDoubleSpinBox *mScaleFactorWidget = nullptr;
};
#endif // QGSMAPCANVASDOCKWIDGET_H

View File

@ -336,24 +336,14 @@ QgsMapCanvasAnnotationItem *QgsMapToolAnnotation::selectedItem() const
QList<QgsMapCanvasAnnotationItem *> QgsMapToolAnnotation::annotationItems() const
{
QList<QgsMapCanvasAnnotationItem *> annotationItemList;
if ( !mCanvas || !mCanvas->scene() )
if ( !mCanvas )
{
return annotationItemList;
return QList<QgsMapCanvasAnnotationItem *>();
}
QList<QGraphicsItem *> itemList = mCanvas->scene()->items();
QList<QGraphicsItem *>::iterator it = itemList.begin();
for ( ; it != itemList.end(); ++it )
else
{
QgsMapCanvasAnnotationItem *aItem = dynamic_cast<QgsMapCanvasAnnotationItem *>( *it );
if ( aItem )
{
annotationItemList.push_back( aItem );
}
return mCanvas->annotationItems();
}
return annotationItemList;
}
void QgsMapToolAnnotation::toggleTextItemVisibilities()

View File

@ -811,21 +811,26 @@ void QgsProjectProperties::apply()
}
//set the color for selections
QColor myColor = pbnSelectionColor->color();
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorRedPart" ), myColor.red() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorGreenPart" ), myColor.green() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorBluePart" ), myColor.blue() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorAlphaPart" ), myColor.alpha() );
mMapCanvas->setSelectionColor( myColor );
QColor selectionColor = pbnSelectionColor->color();
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorRedPart" ), selectionColor.red() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorGreenPart" ), selectionColor.green() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorBluePart" ), selectionColor.blue() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/SelectionColorAlphaPart" ), selectionColor.alpha() );
//set the color for canvas
myColor = pbnCanvasColor->color();
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), myColor.red() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), myColor.green() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), myColor.blue() );
mMapCanvas->setCanvasColor( myColor );
QgisApp::instance()->mapOverviewCanvas()->setBackgroundColor( myColor );
QgisApp::instance()->mapOverviewCanvas()->refresh();
QColor canvasColor = pbnCanvasColor->color();
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorRedPart" ), canvasColor.red() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorGreenPart" ), canvasColor.green() );
QgsProject::instance()->writeEntry( QStringLiteral( "Gui" ), QStringLiteral( "/CanvasColorBluePart" ), canvasColor.blue() );
Q_FOREACH ( QgsMapCanvas *canvas, QgisApp::instance()->mapCanvases() )
{
canvas->setCanvasColor( canvasColor );
canvas->setSelectionColor( selectionColor );
canvas->enableMapTileRendering( mMapTileRenderingCheckBox->isChecked() );
}
QgisApp::instance()->mapOverviewCanvas()->setBackgroundColor( canvasColor );
//save project scales
QStringList myScales;
@ -1139,7 +1144,12 @@ void QgsProjectProperties::apply()
//save variables
QgsProject::instance()->setCustomVariables( mVariableEditor->variablesInActiveScope() );
emit refresh();
//refresh canvases to reflect new properties, eg background color and scale bar after changing display units.
Q_FOREACH ( QgsMapCanvas *canvas, QgisApp::instance()->mapCanvases() )
{
canvas->refresh();
}
QgisApp::instance()->mapOverviewCanvas()->refresh();
}
void QgsProjectProperties::showProjectionsTab()

View File

@ -162,9 +162,6 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
//! Signal used to inform listeners that project scale list may have changed
void scalesChanged( const QStringList &scales = QStringList() );
//! let listening canvases know to refresh
void refresh();
private:
//! Formats for displaying coordinates

View File

@ -104,6 +104,26 @@ class GUI_EXPORT QgisInterface : public QObject
*/
virtual bool removeCustomActionForLayerType( QAction *action ) = 0;
/**
* Returns a list of all map canvases open in the app.
* @note added in QGIS 3.0
*/
virtual QList< QgsMapCanvas * > mapCanvases() = 0;
/**
* Create a new map canvas with the specified unique \a name.
* @note added in QGIS 3.0
* @see closeMapCanvas()
*/
virtual QgsMapCanvas *createNewMapCanvas( const QString &name ) = 0;
/**
* Closes the additional map canvas with matching \a name.
* @note added in QGIS 3.0
* @see createNewMapCanvas()
*/
virtual void closeMapCanvas( const QString &name ) = 0;
public slots: // TODO: do these functions really need to be slots?
/* Exposed functions */

View File

@ -1544,7 +1544,6 @@ void QgsMapCanvas::unsetMapTool( QgsMapTool *tool )
}
}
//! Write property of QColor bgColor.
void QgsMapCanvas::setCanvasColor( const QColor &color )
{
// background of map's pixmap
@ -1561,7 +1560,7 @@ void QgsMapCanvas::setCanvasColor( const QColor &color )
// background of QGraphicsScene
mScene->setBackgroundBrush( bgBrush );
} // setBackgroundColor
}
QColor QgsMapCanvas::canvasColor() const
{
@ -1858,6 +1857,21 @@ void QgsMapCanvas::readProject( const QDomDocument &doc )
{
QDomNode node = nodes.item( 0 );
// Search the specific MapCanvas node using the name
if ( nodes.count() > 1 )
{
for ( int i = 0; i < nodes.size(); ++i )
{
QDomElement elementNode = nodes.at( i ).toElement();
if ( elementNode.hasAttribute( QStringLiteral( "name" ) ) && elementNode.attribute( QStringLiteral( "name" ) ) == objectName() )
{
node = nodes.at( i );
break;
}
}
}
QgsMapSettings tmpSettings;
tmpSettings.readXml( node );
setDestinationCrs( tmpSettings.destinationCrs() );
@ -1867,6 +1881,16 @@ void QgsMapCanvas::readProject( const QDomDocument &doc )
enableMapTileRendering( tmpSettings.testFlag( QgsMapSettings::RenderMapTile ) );
clearExtentHistory(); // clear the extent history on project load
QDomElement elem = node.toElement();
if ( elem.hasAttribute( QStringLiteral( "theme" ) ) )
{
if ( QgsProject::instance()->mapThemeCollection()->hasMapTheme( elem.attribute( QStringLiteral( "theme" ) ) ) )
{
setTheme( elem.attribute( QStringLiteral( "theme" ) ) );
}
}
setAnnotationsVisible( elem.attribute( QStringLiteral( "annotationsVisible" ), QStringLiteral( "1" ) ).toInt() );
}
else
{
@ -1887,6 +1911,10 @@ void QgsMapCanvas::writeProject( QDomDocument &doc )
QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element ok
QDomElement mapcanvasNode = doc.createElement( QStringLiteral( "mapcanvas" ) );
mapcanvasNode.setAttribute( QStringLiteral( "name" ), objectName() );
if ( !mTheme.isEmpty() )
mapcanvasNode.setAttribute( QStringLiteral( "theme" ), mTheme );
mapcanvasNode.setAttribute( QStringLiteral( "annotationsVisible" ), mAnnotationsVisible );
qgisNode.appendChild( mapcanvasNode );
mSettings.writeXml( mapcanvasNode, doc );
@ -2048,3 +2076,29 @@ void QgsMapCanvas::setSegmentationToleranceType( QgsAbstractGeometry::Segmentati
{
mSettings.setSegmentationToleranceType( type );
}
QList<QgsMapCanvasAnnotationItem *> QgsMapCanvas::annotationItems() const
{
QList<QgsMapCanvasAnnotationItem *> annotationItemList;
QList<QGraphicsItem *> itemList = mScene->items();
QList<QGraphicsItem *>::iterator it = itemList.begin();
for ( ; it != itemList.end(); ++it )
{
QgsMapCanvasAnnotationItem *aItem = dynamic_cast< QgsMapCanvasAnnotationItem *>( *it );
if ( aItem )
{
annotationItemList.push_back( aItem );
}
}
return annotationItemList;
}
void QgsMapCanvas::setAnnotationsVisible( bool show )
{
mAnnotationsVisible = show;
Q_FOREACH ( QgsMapCanvasAnnotationItem *item, annotationItems() )
{
item->setVisible( show );
}
}

View File

@ -63,7 +63,7 @@ class QgsMapOverviewCanvas;
class QgsMapTool;
class QgsSnappingUtils;
class QgsRubberBand;
class QgsMapCanvasAnnotationItem;
/** \ingroup gui
* Map canvas is a class for displaying all GIS data types on a canvas.
@ -468,6 +468,26 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
@param type the segmentation tolerance typename*/
void setSegmentationToleranceType( QgsAbstractGeometry::SegmentationToleranceType type );
/**
* Returns a list of all annotation items in the canvas.
* @note added in QGIS 3.0
*/
QList< QgsMapCanvasAnnotationItem *> annotationItems() const;
/**
* Returns true if annotations are visible within the map canvas.
* @note added in QGIS 3.0
* @see setAnnotationsVisible()
*/
bool annotationsVisible() const { return mAnnotationsVisible; }
/**
* Sets whether annotations are \a visible in the canvas.
* @note added in QGIS 3.0
* @see annotationsVisible()
*/
void setAnnotationsVisible( bool visible );
public slots:
//! Repaints the canvas map
@ -784,6 +804,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
QString mTheme;
bool mAnnotationsVisible = true;
//! Force a resize of the map canvas item
//! @note added in 2.16
void updateMapSize();

View File

@ -33,6 +33,9 @@ QgsMapCanvasAnnotationItem::QgsMapCanvasAnnotationItem( QgsAnnotation *annotatio
, mAnnotation( annotation )
{
setFlag( QGraphicsItem::ItemIsSelectable, true );
if ( mapCanvas && !mapCanvas->annotationsVisible() )
setVisible( false );
connect( mAnnotation, &QgsAnnotation::appearanceChanged, this, [this] { update(); } );
connect( mAnnotation, &QgsAnnotation::moved, this, [this] { updatePosition(); } );
connect( mAnnotation, &QgsAnnotation::moved, this, &QgsMapCanvasAnnotationItem::setFeatureForMapPosition );

View File

@ -54,6 +54,7 @@
<addaction name="mActionDwgImport"/>
<addaction name="separator"/>
<addaction name="mActionSnappingOptions"/>
<addaction name="separator"/>
<addaction name="mActionNewPrintComposer"/>
<addaction name="mActionShowComposerManager"/>
<addaction name="mPrintComposersMenu"/>
@ -91,6 +92,7 @@
<addaction name="mActionPreviewProtanope"/>
<addaction name="mActionPreviewDeuteranope"/>
</widget>
<addaction name="mActionNewMapCanvas"/>
<addaction name="mActionPan"/>
<addaction name="mActionPanToSelected"/>
<addaction name="mActionZoomIn"/>
@ -332,6 +334,7 @@
<addaction name="mActionOpenProject"/>
<addaction name="mActionSaveProject"/>
<addaction name="mActionSaveProjectAs"/>
<addaction name="mActionNewMapCanvas"/>
<addaction name="mActionNewPrintComposer"/>
<addaction name="mActionShowComposerManager"/>
</widget>
@ -640,6 +643,21 @@
<string>Save as &amp;Image...</string>
</property>
</action>
<action name="mActionNewMapCanvas">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionNewMap.svg</normaloff>:/images/themes/default/mActionNewMap.svg</iconset>
</property>
<property name="text">
<string>New &amp;Map View</string>
</property>
<property name="toolTip">
<string>New Map View</string>
</property>
<property name="shortcut">
<string>Ctrl+M</string>
</property>
</action>
<action name="mActionNewPrintComposer">
<property name="icon">
<iconset resource="../../images/images.qrc">

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsMapCanvasDockWidgetBase</class>
<widget class="QgsDockWidget" name="QgsMapCanvasDockWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>216</width>
<height>138</height>
</rect>
</property>
<property name="windowTitle">
<string>Map Canvas</string>
</property>
<widget class="QWidget" name="mContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolBar" name="mToolbar">
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<addaction name="mActionSyncView"/>
<addaction name="mActionZoomFullExtent"/>
<addaction name="mActionZoomToSelected"/>
<addaction name="mActionZoomToLayer"/>
</widget>
</item>
<item>
<widget class="QWidget" name="mMainWidget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>
<action name="mActionSetCrs">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/propertyicons/CRS.svg</normaloff>:/images/themes/default/propertyicons/CRS.svg</iconset>
</property>
<property name="text">
<string>Set Map CRS…</string>
</property>
<property name="toolTip">
<string>Set Map CRS</string>
</property>
</action>
<action name="mActionSyncView">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionLockExtent.svg</normaloff>:/images/themes/default/mActionLockExtent.svg</iconset>
</property>
<property name="text">
<string>Synchronize View</string>
</property>
<property name="toolTip">
<string>Synchronize View Center with Main Map</string>
</property>
</action>
<action name="mActionRename">
<property name="text">
<string>Rename View…</string>
</property>
<property name="toolTip">
<string>Rename View</string>
</property>
</action>
<action name="mActionZoomToSelected">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionZoomToSelected.svg</normaloff>:/images/themes/default/mActionZoomToSelected.svg</iconset>
</property>
<property name="text">
<string>Zoom to &amp;Selection</string>
</property>
</action>
<action name="mActionZoomToLayer">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionZoomToLayer.svg</normaloff>:/images/themes/default/mActionZoomToLayer.svg</iconset>
</property>
<property name="text">
<string>Zoom to &amp;Layer</string>
</property>
</action>
<action name="mActionZoomFullExtent">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionZoomFullExtent.svg</normaloff>:/images/themes/default/mActionZoomFullExtent.svg</iconset>
</property>
<property name="text">
<string>Zoom &amp;Full</string>
</property>
</action>
<action name="mActionShowAnnotations">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Annotations</string>
</property>
<property name="toolTip">
<string>Show Annotations</string>
</property>
</action>
<action name="mActionShowCursor">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Cursor Position</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>QgsDockWidget</class>
<extends>QDockWidget</extends>
<header>qgsdockwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../images/images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -14,7 +14,8 @@ __revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.core import (QgsCoordinateReferenceSystem,
from qgis.core import (QgsMapSettings,
QgsCoordinateReferenceSystem,
QgsRectangle,
QgsVectorLayer,
QgsFeature,
@ -23,10 +24,13 @@ from qgis.core import (QgsCoordinateReferenceSystem,
QgsFillSymbol,
QgsSingleSymbolRenderer,
QgsMapThemeCollection,
QgsProject)
QgsProject,
QgsApplication)
from qgis.gui import (QgsMapCanvas)
from qgis.PyQt.QtCore import QDir
from qgis.PyQt.QtCore import (Qt,
QDir)
from qgis.PyQt.QtXml import (QDomDocument, QDomElement)
import time
from qgis.testing import start_app, unittest
@ -337,6 +341,35 @@ class TestQgsMapCanvas(unittest.TestCase):
print((self.report))
return result
def testSaveMultipleCanvasesToProject(self):
# test saving/restoring canvas state to project with multiple canvases
c1 = QgsMapCanvas()
c1.setObjectName('c1')
c1.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:3111'))
c1.setRotation(45)
c2 = QgsMapCanvas()
c2.setObjectName('c2')
c2.setDestinationCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
c2.setRotation(65)
doc = QDomDocument("testdoc")
elem = doc.createElement("qgis")
doc.appendChild(elem)
c1.writeProject(doc)
c2.writeProject(doc)
c3 = QgsMapCanvas()
c3.setObjectName('c1')
c4 = QgsMapCanvas()
c4.setObjectName('c2')
c3.readProject(doc)
c4.readProject(doc)
self.assertEqual(c3.mapSettings().destinationCrs().authid(), 'EPSG:3111')
self.assertEqual(c3.rotation(), 45)
self.assertEqual(c4.mapSettings().destinationCrs().authid(), 'EPSG:4326')
self.assertEqual(c4.rotation(), 65)
if __name__ == '__main__':
unittest.main()