[FEATURE][composer] Add tools for drawing polygon and polylines

This commit is contained in:
Blottiere Paul 2016-03-23 11:10:51 +01:00 committed by Nyall Dawson
parent bde512646c
commit 7a8a5411e0
49 changed files with 4454 additions and 44 deletions

View File

@ -14,6 +14,8 @@ PyQgsComposerMap
PyQgsComposerMapGrid
PyQgsComposerPicture
PyQgsComposerShapes
PyQgsComposerPolygon
PyQgsComposerPolyline
PyQgsComposition
PyQgsConditionalStyle
PyQgsCoordinateTransform

View File

@ -115,6 +115,10 @@
<file>themes/default/mActionAddBasicShape.png</file>
<file>themes/default/mActionAddBasicShape.svg</file>
<file>themes/default/mActionAddBasicCircle.svg</file>
<file>themes/default/mActionEditNodesItem.svg</file>
<file>themes/default/mActionAddNodesItem.svg</file>
<file>themes/default/mActionAddPolygon.svg</file>
<file>themes/default/mActionAddPolyline.svg</file>
<file>themes/default/mActionAddBasicRectangle.svg</file>
<file>themes/default/mActionAddBasicTriangle.svg</file>
<file>themes/default/mActionAddGPSLayer.png</file>

View File

@ -0,0 +1,332 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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"
width="24"
height="24"
id="svg5692"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="mActionAddPointsBasedShape.svg"
inkscape:export-filename="/home/denis/Desktop/oracle.png"
inkscape:export-xdpi="67.5"
inkscape:export-ydpi="67.5">
<title
id="title2829">GIS icon theme 0.2</title>
<defs
id="defs5694">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective3486" />
<inkscape:perspective
id="perspective3496"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3600"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7871"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8710"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective9811"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4762"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<filter
y="-0.25"
x="-0.25"
height="1.5"
width="1.5"
inkscape:label="Drop shadow"
id="filter4128"
color-interpolation-filters="sRGB">
<feGaussianBlur
result="blur"
stdDeviation="2.000000"
in="SourceAlpha"
id="feGaussianBlur4130" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.351000 0 "
type="matrix"
result="bluralpha"
id="feColorMatrix4132" />
<feOffset
result="offsetBlur"
dy="7.500000"
dx="7.500000"
in="bluralpha"
id="feOffset4134" />
<feMerge
id="feMerge4136">
<feMergeNode
in="offsetBlur"
id="feMergeNode4138" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode4140" />
</feMerge>
</filter>
<inkscape:perspective
id="perspective2850"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2491"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.269514"
inkscape:cx="27.137027"
inkscape:cy="12.539424"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
borderlayer="false"
inkscape:window-width="1918"
inkscape:window-height="1059"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:snap-global="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-grids="true"
inkscape:object-paths="false">
<inkscape:grid
type="xygrid"
id="grid5700"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
dotted="false"
originx="0"
originy="0" />
</sodipodi:namedview>
<metadata
id="metadata5697">
<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>GIS icon theme 0.2</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:rights>
<dc:subject>
<rdf:Bag>
<rdf:li>GIS icons</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:coverage>GIS icons</dc:coverage>
<dc:description>http://robert.szczepanek.pl/</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer"
style="display:inline"
transform="translate(0,-8)">
<g
id="orginal-6"
style="fill-rule:nonzero;stroke:#415a75;stroke-miterlimit:4;stroke-opacity:1"
transform="matrix(0.04360941,0,0,0.04360941,-23.975751,6.5017873)" />
<path
inkscape:connector-curvature="0"
id="path2484"
style="fill-rule:nonzero;stroke:#415a75;stroke-width:0.13082823;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
d="" />
<g
style="display:inline"
id="g3772"
transform="matrix(0.69230769,0,0,0.69230769,1.8461539,9.8461539)">
<rect
ry="2.6149368"
inkscape:export-ydpi="120"
inkscape:export-xdpi="120"
y="19"
x="19"
height="13"
width="13"
id="rect3563"
style="fill:#5a8c5a;fill-opacity:1;stroke:#555753;stroke-width:0;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
inkscape:export-filename="C:\Program Files\QGIS-Dev\themes\gis-0.1\mActionAddOgrLayer.png"
rx="2.6149371" />
<path
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 21.6,25.499999 7.8,0"
id="path3807"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path3809"
d="M 25.5,29.399999 25.5,21.6"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsssc"
id="path6992"
d="m 20.3,25.499999 10.4,0 c 0,0 0,0 0,-2.6 C 30.7,20.3 30.05,20.3 25.5,20.3 c -4.55,0 -5.2,0 -5.2,2.599999 0,2.6 0,2.6 0,2.6 z"
style="opacity:0.3;fill:#fcffff;fill-rule:evenodd;stroke:none;display:inline;enable-background:new" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 0,8 0,8"
id="path3872"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;display:inline"
d="M 5.5991742,18.641711 18.400826,10.35829"
id="path3080"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
transform="translate(0,8)"
inkscape:connection-end="#path4188-0-8-5-9-4"
inkscape:connection-end-point="d4"
inkscape:connection-start="#path4188-0-8-5-9-6"
inkscape:connection-start-point="d4" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 18.263443,7.8817218 10.736557,4.1182786"
id="path3255"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
transform="translate(0,8)"
inkscape:connection-end="#path4188-0-8-5-9"
inkscape:connection-end-point="d4"
inkscape:connection-start="#path4188-0-8-5-9-4"
inkscape:connection-start-point="d4" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,4.9705882,5.1176476)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9-4"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,16.970588,11.117648)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9-6"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,-0.02941183,22.117648)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 7.7944002,5.3990395 4.2055998,17.600961"
id="path3311"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5-9"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-5-9-6"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,355 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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"
width="24"
height="24"
id="svg5692"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="mActionAddPolygon.svg"
inkscape:export-filename="/home/denis/Desktop/oracle.png"
inkscape:export-xdpi="67.5"
inkscape:export-ydpi="67.5">
<title
id="title2829">GIS icon theme 0.2</title>
<defs
id="defs5694">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective3486" />
<inkscape:perspective
id="perspective3496"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3600"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7871"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8710"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective9811"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4762"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<filter
y="-0.25"
x="-0.25"
height="1.5"
width="1.5"
inkscape:label="Drop shadow"
id="filter4128"
color-interpolation-filters="sRGB">
<feGaussianBlur
result="blur"
stdDeviation="2.000000"
in="SourceAlpha"
id="feGaussianBlur4130" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.351000 0 "
type="matrix"
result="bluralpha"
id="feColorMatrix4132" />
<feOffset
result="offsetBlur"
dy="7.500000"
dx="7.500000"
in="bluralpha"
id="feOffset4134" />
<feMerge
id="feMerge4136">
<feMergeNode
in="offsetBlur"
id="feMergeNode4138" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode4140" />
</feMerge>
</filter>
<inkscape:perspective
id="perspective2850"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2491"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.269514"
inkscape:cx="11.475305"
inkscape:cy="12.539424"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
borderlayer="false"
inkscape:window-width="1918"
inkscape:window-height="1059"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:snap-global="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-grids="true"
inkscape:object-paths="false">
<inkscape:grid
type="xygrid"
id="grid5700"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
dotted="false"
originx="0"
originy="0" />
</sodipodi:namedview>
<metadata
id="metadata5697">
<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>GIS icon theme 0.2</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:rights>
<dc:subject>
<rdf:Bag>
<rdf:li>GIS icons</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:coverage>GIS icons</dc:coverage>
<dc:description>http://robert.szczepanek.pl/</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer"
style="display:inline"
transform="translate(0,-8)">
<g
id="orginal-6"
style="fill-rule:nonzero;stroke:#415a75;stroke-miterlimit:4;stroke-opacity:1"
transform="matrix(0.04360941,0,0,0.04360941,-23.975751,6.5017873)" />
<path
inkscape:connector-curvature="0"
id="path2484"
style="fill-rule:nonzero;stroke:#415a75;stroke-width:0.13082823;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
d="" />
<g
style="display:inline"
id="g3772"
transform="matrix(0.69230769,0,0,0.69230769,1.8461539,9.8461539)">
<rect
ry="2.6149368"
inkscape:export-ydpi="120"
inkscape:export-xdpi="120"
y="19"
x="19"
height="13"
width="13"
id="rect3563"
style="fill:#5a8c5a;fill-opacity:1;stroke:#555753;stroke-width:0;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
inkscape:export-filename="C:\Program Files\QGIS-Dev\themes\gis-0.1\mActionAddOgrLayer.png"
rx="2.6149371" />
<path
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 21.6,25.499999 7.8,0"
id="path3807"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path3809"
d="M 25.5,29.399999 25.5,21.6"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsssc"
id="path6992"
d="m 20.3,25.499999 10.4,0 c 0,0 0,0 0,-2.6 C 30.7,20.3 30.05,20.3 25.5,20.3 c -4.55,0 -5.2,0 -5.2,2.599999 0,2.6 0,2.6 0,2.6 z"
style="opacity:0.3;fill:#fcffff;fill-rule:evenodd;stroke:none;display:inline;enable-background:new" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 0,8 0,8"
id="path3872"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,0.4705882,5.6176474)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,15.970588,5.1176476)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-4"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,-0.02941178,18.117648)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-1"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,7.4705882,22.617648)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 3.5999216,13.501961 3.9000784,5.9980392"
id="path3116"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5-4"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-5"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 6.4987252,3.4193958 17.001275,3.080604"
id="path3118"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-5-9"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 18.407492,5.2492817 12.092508,18.250719"
id="path3120"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5-9"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-5-1"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 8.8559448,19.213567 5.6440553,17.286433"
id="path3122"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5-1"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-5-4"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,344 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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"
width="24"
height="24"
id="svg5692"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="mActionAddPolyline.svg"
inkscape:export-filename="/home/denis/Desktop/oracle.png"
inkscape:export-xdpi="67.5"
inkscape:export-ydpi="67.5">
<title
id="title2829">GIS icon theme 0.2</title>
<defs
id="defs5694">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective3486" />
<inkscape:perspective
id="perspective3496"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3600"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7871"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8710"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective9811"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4762"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<filter
y="-0.25"
x="-0.25"
height="1.5"
width="1.5"
inkscape:label="Drop shadow"
id="filter4128"
color-interpolation-filters="sRGB">
<feGaussianBlur
result="blur"
stdDeviation="2.000000"
in="SourceAlpha"
id="feGaussianBlur4130" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.351000 0 "
type="matrix"
result="bluralpha"
id="feColorMatrix4132" />
<feOffset
result="offsetBlur"
dy="7.500000"
dx="7.500000"
in="bluralpha"
id="feOffset4134" />
<feMerge
id="feMerge4136">
<feMergeNode
in="offsetBlur"
id="feMergeNode4138" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode4140" />
</feMerge>
</filter>
<inkscape:perspective
id="perspective2850"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2491"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.269514"
inkscape:cx="11.475305"
inkscape:cy="12.539424"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
borderlayer="false"
inkscape:window-width="1918"
inkscape:window-height="1059"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:snap-global="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-grids="true"
inkscape:object-paths="false">
<inkscape:grid
type="xygrid"
id="grid5700"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
dotted="false"
originx="0"
originy="0" />
</sodipodi:namedview>
<metadata
id="metadata5697">
<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>GIS icon theme 0.2</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:rights>
<dc:subject>
<rdf:Bag>
<rdf:li>GIS icons</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:coverage>GIS icons</dc:coverage>
<dc:description>http://robert.szczepanek.pl/</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer"
style="display:inline"
transform="translate(0,-8)">
<g
id="orginal-6"
style="fill-rule:nonzero;stroke:#415a75;stroke-miterlimit:4;stroke-opacity:1"
transform="matrix(0.04360941,0,0,0.04360941,-23.975751,6.5017873)" />
<path
inkscape:connector-curvature="0"
id="path2484"
style="fill-rule:nonzero;stroke:#415a75;stroke-width:0.13082823;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
d="" />
<g
style="display:inline"
id="g3772"
transform="matrix(0.69230769,0,0,0.69230769,1.8461539,9.8461539)">
<rect
ry="2.6149368"
inkscape:export-ydpi="120"
inkscape:export-xdpi="120"
y="19"
x="19"
height="13"
width="13"
id="rect3563"
style="fill:#5a8c5a;fill-opacity:1;stroke:#555753;stroke-width:0;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
inkscape:export-filename="C:\Program Files\QGIS-Dev\themes\gis-0.1\mActionAddOgrLayer.png"
rx="2.6149371" />
<path
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 21.6,25.499999 7.8,0"
id="path3807"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path3809"
d="M 25.5,29.399999 25.5,21.6"
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccsssc"
id="path6992"
d="m 20.3,25.499999 10.4,0 c 0,0 0,0 0,-2.6 C 30.7,20.3 30.05,20.3 25.5,20.3 c -4.55,0 -5.2,0 -5.2,2.599999 0,2.6 0,2.6 0,2.6 z"
style="opacity:0.3;fill:#fcffff;fill-rule:evenodd;stroke:none;display:inline;enable-background:new" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 0,8 0,8"
id="path3872"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,-0.02941178,14.117648)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 5.7092162,5.3723515 4.2907838,9.6276485"
id="path3076"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
transform="translate(0,8)"
inkscape:connection-end-point="d4"
inkscape:connection-end="#path4188-0-8"
inkscape:connection-start="#path4188-0-8-5"
inkscape:connection-start-point="d4" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,2.9705882,5.1176476)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-4"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,16.970588,6.1176476)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-7"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,5.9705882,23.117648)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 8.9937522,3.1781252 18.006248,3.8218748"
id="path3247"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-4"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 4.8868972,14.080346 3.2262057,4.839309"
id="path3255"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-7"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,423 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="24"
height="24"
id="svg5692"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="mActionEditNodesItem.svg"
inkscape:export-filename="/home/denis/Desktop/oracle.png"
inkscape:export-xdpi="67.5"
inkscape:export-ydpi="67.5">
<title
id="title2829">GIS icon theme 0.2</title>
<defs
id="defs5694">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 16 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="32 : 16 : 1"
inkscape:persp3d-origin="16 : 10.666667 : 1"
id="perspective3486" />
<inkscape:perspective
id="perspective3496"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective3600"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective7871"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective8710"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective9811"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective4762"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<filter
y="-0.25"
x="-0.25"
height="1.5"
width="1.5"
inkscape:label="Drop shadow"
id="filter4128"
color-interpolation-filters="sRGB">
<feGaussianBlur
result="blur"
stdDeviation="2.000000"
in="SourceAlpha"
id="feGaussianBlur4130" />
<feColorMatrix
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.351000 0 "
type="matrix"
result="bluralpha"
id="feColorMatrix4132" />
<feOffset
result="offsetBlur"
dy="7.500000"
dx="7.500000"
in="bluralpha"
id="feOffset4134" />
<feMerge
id="feMerge4136">
<feMergeNode
in="offsetBlur"
id="feMergeNode4138" />
<feMergeNode
in="SourceGraphic"
id="feMergeNode4140" />
</feMerge>
</filter>
<inkscape:perspective
id="perspective2850"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
<inkscape:perspective
id="perspective2491"
inkscape:persp3d-origin="270.04437 : 185.57625 : 1"
inkscape:vp_z="540.08875 : 278.36438 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 278.36438 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3408"
id="linearGradient4404"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.10786508,0.87849049,0.87408031,0.10732357,-1.811623,758.65836)"
x1="304.76001"
y1="64.294998"
x2="335.29999"
y2="81.926003" />
<linearGradient
x1="304.76001"
y1="64.294998"
gradientTransform="matrix(1.7376,0,0,1.728,-530.46,-8.9744)"
x2="335.29999"
gradientUnits="userSpaceOnUse"
y2="81.926003"
id="linearGradient3408">
<stop
offset="0"
style="stop-color:#d3d7cf"
id="stop4436" />
<stop
offset=".18304"
style="stop-color:#babdb6"
id="stop4438" />
<stop
offset=".31893"
style="stop-color:#fff"
id="stop4440" />
<stop
offset=".87644"
style="stop-color:#babdb6"
id="stop4442" />
<stop
offset="1"
style="stop-color:#eeeeec"
id="stop4444" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3420"
id="linearGradient3615"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.34112292,0.26690344,0.34708506,0.44633485,7.3860378,1027.6433)"
x1="-6.3077998"
y1="44.229"
x2="-9.7747002"
y2="44.139999" />
<linearGradient
x1="-6.3077998"
y1="44.229"
gradientTransform="matrix(0.63166,-0.62958,1.0718,1.0683,-15.764,65.934)"
x2="-9.7747002"
gradientUnits="userSpaceOnUse"
y2="44.139999"
id="linearGradient3420">
<stop
offset="0"
id="stop6223" />
<stop
offset="1"
style="stop-opacity:0"
id="stop6225" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3416-4"
id="linearGradient3498"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.67481701,0.52736572,0.29432462,0.37835898,77.717559,981.12162)"
x1="97.442001"
y1="35.152"
x2="90.221001"
y2="35.078999" />
<linearGradient
x1="97.442001"
y1="35.152"
gradientTransform="matrix(1.0384,-1.036,0.90828,0.90612,-106.63,180.04)"
x2="90.221001"
gradientUnits="userSpaceOnUse"
y2="35.078999"
id="linearGradient3416-4">
<stop
offset="0"
style="stop-color:#f8e27e;stop-opacity:1;"
id="stop4958-5" />
<stop
offset="1"
style="stop-color:#e3d189;stop-opacity:1;"
id="stop4960-0" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.269514"
inkscape:cx="27.137027"
inkscape:cy="12.539424"
inkscape:current-layer="layer2"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
borderlayer="false"
inkscape:window-width="1918"
inkscape:window-height="1059"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="1"
inkscape:snap-global="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-grids="true"
inkscape:object-paths="false">
<inkscape:grid
type="xygrid"
id="grid5700"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
dotted="false"
originx="0"
originy="0" />
</sodipodi:namedview>
<metadata
id="metadata5697">
<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>GIS icon theme 0.2</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:rights>
<dc:subject>
<rdf:Bag>
<rdf:li>GIS icons</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:coverage>GIS icons</dc:coverage>
<dc:description>http://robert.szczepanek.pl/</dc:description>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Layer"
style="display:inline"
transform="translate(0,-8)">
<g
id="orginal-6"
style="fill-rule:nonzero;stroke:#415a75;stroke-miterlimit:4;stroke-opacity:1"
transform="matrix(0.04360941,0,0,0.04360941,-23.975751,6.5017873)" />
<path
inkscape:connector-curvature="0"
id="path2484"
style="fill-rule:nonzero;stroke:#415a75;stroke-width:0.13082823;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1"
d="" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 0,8 0,8"
id="path3872"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:1, 1;stroke-dashoffset:0;display:inline"
d="M 5.5991742,18.641711 18.400826,10.35829"
id="path3080"
inkscape:connector-type="polyline"
inkscape:connector-curvature="3"
transform="translate(0,8)"
inkscape:connection-end="#path4188-0-8-5-9-4"
inkscape:connection-end-point="d4"
inkscape:connection-start="#path4188-0-8-5-9-6"
inkscape:connection-start-point="d4" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
d="M 18.263443,7.8817218 10.736557,4.1182786"
id="path3255"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
transform="translate(0,8)"
inkscape:connection-end="#path4188-0-8-5-9"
inkscape:connection-end-point="d4"
inkscape:connection-start="#path4188-0-8-5-9-4"
inkscape:connection-start-point="d4" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,4.9705882,5.1176476)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9-4"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,16.970588,11.117648)" />
<circle
style="fill:#2a7fff;fill-opacity:1;stroke:#333333;stroke-width:1.00173461;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:0.40000001;stroke-opacity:0.97254902;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
id="path4188-0-8-5-9-6"
cx="12"
cy="20"
r="8.5"
d="m 20.5,20 c 0,4.69442 -3.80558,8.5 -8.5,8.5 -4.6944204,0 -8.5,-3.80558 -8.5,-8.5 0,-4.69442 3.8055796,-8.5 8.5,-8.5 4.69442,0 8.5,3.80558 8.5,8.5 z"
sodipodi:cx="12"
sodipodi:cy="20"
sodipodi:rx="8.5"
sodipodi:ry="8.5"
transform="matrix(0.29411765,0,0,0.29411762,-0.02941183,22.117648)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 7.7944002,5.3990395 4.2055998,17.600961"
id="path3311"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path4188-0-8-5-9"
inkscape:connection-start-point="d4"
inkscape:connection-end="#path4188-0-8-5-9-6"
inkscape:connection-end-point="d4"
transform="translate(0,8)" />
<g
transform="matrix(0.69569501,0,0,0.55166157,1.5141484,-548.95126)"
id="g3501">
<path
inkscape:connector-curvature="0"
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"
style="fill:url(#linearGradient4404);fill-rule:evenodd;stroke:#1f1b1e;stroke-width:1.0266068;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.3612;enable-background:new"
id="path6912" />
<path
inkscape:connector-curvature="0"
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"
style="opacity:0.23106001;fill:url(#linearGradient3615)"
id="rect6533" />
<path
inkscape:connector-curvature="0"
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 l -9.3e-5,0 z"
style="fill:#f0f3f2;fill-opacity:1;fill-rule:evenodd;enable-background:new"
id="path7379" />
<path
inkscape:connector-curvature="0"
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"
style="fill:url(#linearGradient3498);stroke:#1d1b21;stroke-width:0.86699998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.7;enable-background:new"
id="path6899-9"
sodipodi:nodetypes="cccccccscccs" />
<rect
transform="matrix(0.82455744,-0.56577825,0.66205623,0.74945417,0,0)"
y="874.67072"
x="-679.10767"
height="0.5771094"
width="3.5710487"
id="rect4406"
style="fill:#ffffff;fill-opacity:0.57758622;stroke:#1f1b1e;stroke-width:1.28935945;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -15,6 +15,8 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
#include <qgscomposerpicture.h>
#include <qgscomposerscalebar.h>
#include <qgscomposershape.h>
#include <qgscomposerpolygon.h>
#include <qgscomposerpolyline.h>
#include <qgscomposertable.h>
#include <qgscomposertexttable.h>
#include <qgscomposerattributetable.h>
@ -65,6 +67,14 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
sipType = sipType_QgsComposerShape;
*sipCppRet = static_cast<QgsComposerShape*>(sipCpp);
break;
case QgsComposerItem::ComposerPolygon:
sipType = sipType_QgsComposerPolygon;
*sipCppRet = static_cast<QgsComposerPolygon*>(sipCpp);
break;
case QgsComposerItem::ComposerPolyline:
sipType = sipType_QgsComposerPolyline;
*sipCppRet = static_cast<QgsComposerPolyline*>(sipCpp);
break;
case QgsComposerItem::ComposerTable:
sipType = sipType_QgsComposerTable;
*sipCppRet = static_cast<QgsComposerTable*>(sipCpp);
@ -103,6 +113,8 @@ class QgsComposerItem : QgsComposerObject, QGraphicsRectItem
ComposerPicture,
ComposerScaleBar,
ComposerShape,
ComposerPolygon,
ComposerPolyline,
ComposerTable,
ComposerAttributeTable,
ComposerTextTable,

View File

@ -0,0 +1,111 @@
class QgsComposerNodesItem: QgsComposerItem
{
%TypeHeaderCode
#include <qgscomposernodesitem.h>
%End
public:
QgsComposerNodesItem( QString mTagName, QgsComposition* c );
QgsComposerNodesItem( QString mTagName, QPolygonF polygon, QgsComposition* c );
~QgsComposerNodesItem();
/** Add a node in current shape.
* @param pt is the location of the new node
* @param checkArea is a flag to indicate if there's a space constraint.
* @param radius is the space contraint and is used only if checkArea is
* true. Typically, if this flag is true, the new node has to be nearest
* than radius to the shape to be added.
*/
bool addNode( const QPointF &pt, const bool checkArea = true, const double radius = 10 );
/** Set a tag to indicate if we want to draw or not the shape's nodes.
* @param display
*/
void setDisplayNodes( const bool display = true );
/** Move a node to a new position.
* @param index the index of the node to move
* @param node is the new position in scene coordinate
*/
bool moveNode( const int index, const QPointF &node );
/** \brief Reimplementation of QCanvasItem::paint - draw on canvas */
void paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget );
/** Search the nearest node in shape within a maximal area. Returns the
* index of the nearest node or -1.
* @param node is where a shape's node is searched
* @param searchInRadius is a flag to indicate if the area of research is
* limited in space.
* @param radius is only used if searchInRadius is true
*/
int nodeAtPosition( const QPointF &node, const bool searchInRadius = true, const double radius = 10 );
/** Gets the position of a node in scene coordinate.
* @param index of the node
* @param position the position of the node
* @return true if the index is valid and the position is set, false otherwise
*/
bool nodePosition( const int index, QPointF &position );
/** Sets state from Dom document
* @param itemElem is Dom node corresponding to item tag
* @param doc is Dom document
*/
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );
/** Remove a node from the shape.
* @param index of the node to delete
*/
bool removeNode( const int index );
/** Returns the number of nodes in the shape. */
int nodesSize();
/** Select a node.
* @param index the node to select
*/
bool setSelectedNode( const int index );
/** Returns the currently selected node.
* @return the index of the selected node, -1 otherwise
*/
int selectedNode();
/** Unselect a node.
*/
void unselectNode();
/** Stores state in Dom element
* @param elem is Dom element corresponding to 'Composer' tag
* @param doc write template file
*/
bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
protected:
/** Method called in addNode. */
virtual bool _addNode( const int nodeIndex, const QPointF &newPoint, const double radius ) = 0;
/** Method called in paint. */
virtual void _draw( QPainter *painter ) = 0;
/** Method called in readXML. */
virtual void _readXMLStyle( const QDomElement &elmt ) = 0;
/** Method called in writeXML. */
virtual void _writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const = 0;
/** Rescale the current shape according to the boudning box. Useful when
* the shape is resized thanks to the rubber band. */
void rescaleToFitBoundingBox();
/** Compute an euclidian distance between 2 nodes. */
double computeDistance(const QPointF &pt1, const QPointF &pt2) const;
/** Convert scene coordinate to item coordinates */
QPointF convertToItemCoordinate(const QPointF &node);
/** Update the current scene rectangle for this item. */
void updateSceneRect();
};

View File

@ -0,0 +1,41 @@
class QgsComposerPolygon: QgsComposerNodesItem
{
%TypeHeaderCode
#include <qgscomposerpolygon.h>
%End
public:
QgsComposerPolygon( QgsComposition* c );
QgsComposerPolygon( QPolygonF polygon, QgsComposition* c );
~QgsComposerPolygon();
/** Overridden to return shape name */
virtual QString displayName() const;
/** Returns the QgsSymbolV2 used to draw the shape. */
QgsFillSymbolV2* polygonStyleSymbol();
/** Set the QgsSymbolV2 used to draw the shape. */
void setPolygonStyleSymbol( QgsFillSymbolV2* symbol );
/** Return correct graphics item type. */
virtual int type() const;
protected:
/** Add the point newPoint at the given position according to some
* criteres. */
bool _addNode( const int indexPoint, const QPointF &newPoint, const double radius );
/** Draw points for the current shape. */
void _draw( QPainter *painter );
/** Read symbol in XML. */
void _readXMLStyle( const QDomElement &elmt );
/** Write the symbol in an XML document. */
void _writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const;
/** Create a default symbol. */
void createDefaultPolygonStyleSymbol();
};

View File

@ -0,0 +1,42 @@
class QgsComposerPolyline: QgsComposerNodesItem
{
%TypeHeaderCode
#include <qgscomposerpolyline.h>
%End
public:
QgsComposerPolyline( QgsComposition* c );
QgsComposerPolyline( QPolygonF polyline, QgsComposition* c );
~QgsComposerPolyline();
/** Overridden to return shape name */
virtual QString displayName() const;
/** Returns the QgsSymbolV2 used to draw the shape. */
QgsLineSymbolV2* polylineStyleSymbol();
/** Set the QgsSymbolV2 used to draw the shape. */
void setPolylineStyleSymbol( QgsLineSymbolV2* symbol );
/** Overridden to return shape type */
virtual int type() const;
protected:
/** Add the point newPoint at the given position according to some
* criteres. */
bool _addNode( const int indexPoint, const QPointF &newPoint, const double radius );
/** Draw points for the current shape. */
void _draw( QPainter *painter );
/** Read symbol in XML. */
void _readXMLStyle( const QDomElement &elmt );
/** Write the symbol in an XML document. */
void _writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const;
/** Create a default symbol. */
void createDefaultPolylineStyleSymbol();
};

View File

@ -546,22 +546,26 @@ class QgsComposition : QGraphicsScene
void addMultiFrame( QgsComposerMultiFrame* multiFrame );
/** Removes multi frame (but does not delete it)*/
void removeMultiFrame( QgsComposerMultiFrame* multiFrame );
/** Adds an arrow item to the graphics scene and advices composer to create a widget for it (through signal)
/** Adds an arrow item to the graphics scene and advises composer to create a widget for it (through signal)
@note not available in python bindings*/
void addComposerArrow( QgsComposerArrow* arrow );
/** Adds label to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds label to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerLabel( QgsComposerLabel* label );
/** Adds map to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds map to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerMap( QgsComposerMap* map, const bool setDefaultPreviewStyle = true );
/** Adds scale bar to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds scale bar to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerScaleBar( QgsComposerScaleBar* scaleBar );
/** Adds legend to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds legend to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerLegend( QgsComposerLegend* legend );
/** Adds picture to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds picture to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerPicture( QgsComposerPicture* picture );
/** Adds a composer shape to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds a composer shape to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerShape( QgsComposerShape* shape );
/** Adds a composer table to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds a composer polygon and advises composer to create a widget for it (through signal)*/
void addComposerPolygon( QgsComposerPolygon* polygon );
/** Adds a composer polyline and advises composer to create a widget for it (through signal)*/
void addComposerPolyline( QgsComposerPolyline* polyline );
/** Adds a composer table to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerTable( QgsComposerAttributeTable* table );
/** Adds composer html frame and advises composer to create a widget for it (through signal)*/
void addComposerHtmlFrame( QgsComposerHtml* html /Transfer/, QgsComposerFrame* frame /Transfer/);
@ -828,6 +832,10 @@ class QgsComposition : QGraphicsScene
void selectedItemChanged( QgsComposerItem* selected );
/** Is emitted when new composer arrow has been added to the view*/
void composerArrowAdded( QgsComposerArrow* arrow );
/** Is emitted when new composer polygon has been added to the view*/
void composerPolygonAdded( QgsComposerPolygon* polygon );
/** Is emitted when new composer polyline has been added to the view*/
void composerPolylineAdded( QgsComposerPolyline* polyline );
/** Is emitted when a new composer html has been added to the view*/
void composerHtmlFrameAdded( QgsComposerHtml* html, QgsComposerFrame* frame );
/** Is emitted when new composer label has been added to the view*/

View File

@ -186,6 +186,9 @@
%Include composer/qgscomposerpicture.sip
%Include composer/qgscomposerscalebar.sip
%Include composer/qgscomposershape.sip
%Include composer/qgscomposernodesitem.sip
%Include composer/qgscomposerpolygon.sip
%Include composer/qgscomposerpolyline.sip
%Include composer/qgscomposertable.sip
%Include composer/qgscomposertablecolumn.sip
%Include composer/qgscomposertablev2.sip

View File

@ -135,6 +135,8 @@ SET(QGIS_APP_SRCS
composer/qgscomposermapwidget.cpp
composer/qgscomposerscalebarwidget.cpp
composer/qgscomposershapewidget.cpp
composer/qgscomposerpolygonwidget.cpp
composer/qgscomposerpolylinewidget.cpp
composer/qgscomposertablewidget.cpp
composer/qgscomposertablebackgroundcolorsdialog.cpp
composer/qgscomposerlegenditemdialog.cpp
@ -306,6 +308,8 @@ SET (QGIS_APP_MOC_HDRS
composer/qgscomposertablewidget.h
composer/qgscomposertablebackgroundcolorsdialog.h
composer/qgscomposershapewidget.h
composer/qgscomposerpolygonwidget.h
composer/qgscomposerpolylinewidget.h
composer/qgscompositionwidget.h
composer/qgsatlascompositionwidget.h

View File

@ -28,6 +28,10 @@
#include "qgscomposermodel.h"
#include "qgsatlascompositionwidget.h"
#include "qgscomposerarrow.h"
#include "qgscomposerpolygon.h"
#include "qgscomposerpolyline.h"
#include "qgscomposerpolygonwidget.h"
#include "qgscomposerpolylinewidget.h"
#include "qgscomposerarrowwidget.h"
#include "qgscomposerattributetablewidget.h"
#include "qgscomposerframe.h"
@ -159,8 +163,20 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
shapeToolButton->setToolTip( tr( "Add Shape" ) );
mItemToolbar->insertWidget( mActionAddArrow, shapeToolButton );
QToolButton* nodesItemButton = new QToolButton( mItemToolbar );
nodesItemButton->setIcon( QgsApplication::getThemeIcon( "/mActionAddNodesItem.svg" ) );
nodesItemButton->setCheckable( true );
nodesItemButton->setPopupMode( QToolButton::InstantPopup );
nodesItemButton->setAutoRaise( true );
nodesItemButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
nodesItemButton->addAction( mActionAddPolygon );
nodesItemButton->addAction( mActionAddPolyline );
nodesItemButton->setToolTip( tr( "Add Nodes item" ) );
mItemToolbar->insertWidget( mActionAddArrow, nodesItemButton );
QActionGroup* toggleActionGroup = new QActionGroup( this );
toggleActionGroup->addAction( mActionMoveItemContent );
toggleActionGroup->addAction( mActionEditNodesItem );
toggleActionGroup->addAction( mActionPan );
toggleActionGroup->addAction( mActionMouseZoom );
toggleActionGroup->addAction( mActionAddNewMap );
@ -172,6 +188,8 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
toggleActionGroup->addAction( mActionAddRectangle );
toggleActionGroup->addAction( mActionAddTriangle );
toggleActionGroup->addAction( mActionAddEllipse );
toggleActionGroup->addAction( mActionAddPolygon );
toggleActionGroup->addAction( mActionAddPolyline );
toggleActionGroup->addAction( mActionAddArrow );
//toggleActionGroup->addAction( mActionAddTable );
toggleActionGroup->addAction( mActionAddAttributeTable );
@ -185,6 +203,7 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
mActionAddNewScalebar->setCheckable( true );
mActionAddImage->setCheckable( true );
mActionMoveItemContent->setCheckable( true );
mActionEditNodesItem->setCheckable( true );
mActionPan->setCheckable( true );
mActionMouseZoom->setCheckable( true );
mActionAddArrow->setCheckable( true );
@ -370,6 +389,12 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
shapeMenu->addAction( mActionAddRectangle );
shapeMenu->addAction( mActionAddTriangle );
shapeMenu->addAction( mActionAddEllipse );
QMenu *nodesItemMenu = layoutMenu->addMenu( "Add Nodes Item" );
nodesItemMenu->setIcon( QgsApplication::getThemeIcon( "/mActionAddNodesItem.svg" ) );
nodesItemMenu->addAction( mActionAddPolygon );
nodesItemMenu->addAction( mActionAddPolyline );
layoutMenu->addAction( mActionAddArrow );
//layoutMenu->addAction( mActionAddTable );
layoutMenu->addAction( mActionAddAttributeTable );
@ -377,6 +402,7 @@ QgsComposer::QgsComposer( QgisApp *qgis, const QString& title )
layoutMenu->addSeparator();
layoutMenu->addAction( mActionSelectMoveItem );
layoutMenu->addAction( mActionMoveItemContent );
layoutMenu->addAction( mActionEditNodesItem );
layoutMenu->addSeparator();
layoutMenu->addAction( mActionGroupItems );
layoutMenu->addAction( mActionUngroupItems );
@ -703,12 +729,15 @@ void QgsComposer::setupTheme()
mActionAddRectangle->setIcon( QgsApplication::getThemeIcon( "/mActionAddBasicRectangle.svg" ) );
mActionAddTriangle->setIcon( QgsApplication::getThemeIcon( "/mActionAddBasicTriangle.svg" ) );
mActionAddEllipse->setIcon( QgsApplication::getThemeIcon( "/mActionAddBasicCircle.svg" ) );
mActionAddPolygon->setIcon( QgsApplication::getThemeIcon( "/mActionAddPolygon.svg" ) );
mActionAddPolyline->setIcon( QgsApplication::getThemeIcon( "/mActionAddPolyline.svg" ) );
mActionAddArrow->setIcon( QgsApplication::getThemeIcon( "/mActionAddArrow.svg" ) );
mActionAddTable->setIcon( QgsApplication::getThemeIcon( "/mActionAddTable.svg" ) );
mActionAddAttributeTable->setIcon( QgsApplication::getThemeIcon( "/mActionAddTable.svg" ) );
mActionAddHtml->setIcon( QgsApplication::getThemeIcon( "/mActionAddHtml.svg" ) );
mActionSelectMoveItem->setIcon( QgsApplication::getThemeIcon( "/mActionSelect.svg" ) );
mActionMoveItemContent->setIcon( QgsApplication::getThemeIcon( "/mActionMoveItemContent.svg" ) );
mActionEditNodesItem->setIcon( QgsApplication::getThemeIcon( "/mActionEditNodesItem.svg" ) );
mActionGroupItems->setIcon( QgsApplication::getThemeIcon( "/mActionGroupItems.png" ) );
mActionUngroupItems->setIcon( QgsApplication::getThemeIcon( "/mActionUngroupItems.png" ) );
mActionRaiseItems->setIcon( QgsApplication::getThemeIcon( "/mActionRaiseItems.png" ) );
@ -761,6 +790,8 @@ void QgsComposer::connectCompositionSlots()
connect( mComposition, SIGNAL( selectedItemChanged( QgsComposerItem* ) ), this, SLOT( showItemOptions( QgsComposerItem* ) ) );
connect( mComposition, SIGNAL( composerArrowAdded( QgsComposerArrow* ) ), this, SLOT( addComposerArrow( QgsComposerArrow* ) ) );
connect( mComposition, SIGNAL( composerPolygonAdded( QgsComposerPolygon* ) ), this, SLOT( addComposerPolygon( QgsComposerPolygon* ) ) );
connect( mComposition, SIGNAL( composerPolylineAdded( QgsComposerPolyline* ) ), this, SLOT( addComposerPolyline( QgsComposerPolyline* ) ) );
connect( mComposition, SIGNAL( composerHtmlFrameAdded( QgsComposerHtml*, QgsComposerFrame* ) ), this, SLOT( addComposerHtmlFrame( QgsComposerHtml*, QgsComposerFrame* ) ) );
connect( mComposition, SIGNAL( composerLabelAdded( QgsComposerLabel* ) ), this, SLOT( addComposerLabel( QgsComposerLabel* ) ) );
connect( mComposition, SIGNAL( composerMapAdded( QgsComposerMap* ) ), this, SLOT( addComposerMap( QgsComposerMap* ) ) );
@ -2916,6 +2947,22 @@ void QgsComposer::on_mActionAddEllipse_triggered()
}
}
void QgsComposer::on_mActionAddPolygon_triggered()
{
if ( mView )
{
mView->setCurrentTool( QgsComposerView::AddPolygon );
}
}
void QgsComposer::on_mActionAddPolyline_triggered()
{
if ( mView )
{
mView->setCurrentTool( QgsComposerView::AddPolyline );
}
}
void QgsComposer::on_mActionAddTable_triggered()
{
if ( mView )
@ -3117,6 +3164,14 @@ void QgsComposer::on_mActionMoveItemContent_triggered()
}
}
void QgsComposer::on_mActionEditNodesItem_triggered()
{
if ( mView )
{
mView->setCurrentTool( QgsComposerView::EditNodesItem );
}
}
void QgsComposer::on_mActionPan_triggered()
{
if ( mView )
@ -3647,6 +3702,28 @@ void QgsComposer::addComposerArrow( QgsComposerArrow* arrow )
mItemWidgetMap.insert( arrow, arrowWidget );
}
void QgsComposer::addComposerPolygon( QgsComposerPolygon* polygon )
{
if ( !polygon )
{
return;
}
QgsComposerPolygonWidget* polygonWidget = new QgsComposerPolygonWidget( polygon );
mItemWidgetMap.insert( polygon, polygonWidget );
}
void QgsComposer::addComposerPolyline( QgsComposerPolyline* polyline )
{
if ( !polyline )
{
return;
}
QgsComposerPolylineWidget* polylineWidget = new QgsComposerPolylineWidget( polyline );
mItemWidgetMap.insert( polyline, polylineWidget );
}
void QgsComposer::addComposerMap( QgsComposerMap* map )
{
if ( !map )

View File

@ -23,6 +23,8 @@
class QgisApp;
class QgsComposerArrow;
class QgsComposerPolygon;
class QgsComposerPolyline;
class QgsComposerFrame;
class QgsComposerHtml;
class QgsComposerLabel;
@ -188,6 +190,11 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
void on_mActionAddEllipse_triggered();
//! Nodes based shape
void on_mActionEditNodesItem_triggered();
void on_mActionAddPolygon_triggered();
void on_mActionAddPolyline_triggered();
//! Add attribute table
void on_mActionAddTable_triggered();
@ -376,6 +383,12 @@ class QgsComposer: public QMainWindow, private Ui::QgsComposerBase
/** Add a composer arrow to the item/widget map and creates a configuration widget for it*/
void addComposerArrow( QgsComposerArrow* arrow );
/** Add a composer polygon to the item/widget map and creates a configuration widget for it*/
void addComposerPolygon( QgsComposerPolygon* polygon );
/** Add a composer polyline to the item/widget map and creates a configuration widget for it*/
void addComposerPolyline( QgsComposerPolyline* polyline );
/** Add a composer map to the item/widget map and creates a configuration widget for it*/
void addComposerMap( QgsComposerMap* map );

View File

@ -0,0 +1,94 @@
/***************************************************************************
qgscomposerpolygonwidget.cpp
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 "qgscomposerpolygonwidget.h"
#include "qgscomposerpolygon.h"
#include "qgscomposeritemwidget.h"
#include "qgssymbolv2selectordialog.h"
#include "qgsstylev2.h"
#include "qgssymbollayerv2utils.h"
QgsComposerPolygonWidget::QgsComposerPolygonWidget( QgsComposerPolygon* composerPolygon ):
QgsComposerItemBaseWidget( nullptr, composerPolygon )
, mComposerPolygon( composerPolygon )
{
setupUi( this );
//add widget for general composer item properties
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, composerPolygon );
//shapes don't use background or frame, since the symbol style is set through a QgsSymbolV2SelectorDialog
itemPropertiesWidget->showBackgroundGroup( false );
itemPropertiesWidget->showFrameGroup( false );
mainLayout->addWidget( itemPropertiesWidget );
// update style icon
updatePolygonStyle();
if ( mComposerPolygon )
{
connect( mComposerPolygon, SIGNAL( itemChanged() ), this, SLOT( setGuiElementValues() ) );
}
}
QgsComposerPolygonWidget::~QgsComposerPolygonWidget()
{
}
void QgsComposerPolygonWidget::on_mPolygonStyleButton_clicked()
{
if ( !mComposerPolygon )
{
return;
}
// use the atlas coverage layer, if any
QgsVectorLayer* coverageLayer = atlasCoverageLayer();
QScopedPointer<QgsFillSymbolV2> newSymbol;
newSymbol.reset( mComposerPolygon->polygonStyleSymbol()->clone() );
QgsSymbolV2SelectorDialog d( newSymbol.data(), QgsStyleV2::defaultStyle(),
coverageLayer, this );
d.setExpressionContext( mComposerPolygon->createExpressionContext() );
if ( d.exec() == QDialog::Accepted )
{
mComposerPolygon->beginCommand( tr( "Polygon style changed" ) );
mComposerPolygon->setPolygonStyleSymbol( newSymbol.data() );
updatePolygonStyle();
mComposerPolygon->endCommand();
}
}
void QgsComposerPolygonWidget::setGuiElementValues()
{
if ( !mComposerPolygon )
{
return;
}
updatePolygonStyle();
}
void QgsComposerPolygonWidget::updatePolygonStyle()
{
if ( mComposerPolygon )
{
QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( mComposerPolygon->polygonStyleSymbol(), mPolygonStyleButton->iconSize() );
mPolygonStyleButton->setIcon( icon );
}
}

View File

@ -0,0 +1,48 @@
/***************************************************************************
qgscomposerpolygonwidget.h
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 QGSCOMPOSERPOLYGONWIDGET_H
#define QGSCOMPOSERPOLYGONWIDGET_H
#include "ui_qgscomposerpolygonwidgetbase.h"
#include "qgscomposeritemwidget.h"
class QgsComposerPolygon;
/**
* Input widget for QgsComposerPolygon
* @note added in QGIS 2.16
*/
class QgsComposerPolygonWidget: public QgsComposerItemBaseWidget, private Ui::QgsComposerPolygonWidgetBase
{
Q_OBJECT
public:
explicit QgsComposerPolygonWidget( QgsComposerPolygon* composerPolygon );
~QgsComposerPolygonWidget();
private:
QgsComposerPolygon* mComposerPolygon;
void updatePolygonStyle();
private slots:
void on_mPolygonStyleButton_clicked();
/** Sets the GUI elements to the currentValues of mComposerShape*/
void setGuiElementValues();
};
#endif // QGSCOMPOSERPOLYGONWIDGET_H

View File

@ -0,0 +1,84 @@
/***************************************************************************
qgscomposerpolylinewidget.cpp
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 "qgscomposerpolylinewidget.h"
#include "qgscomposerpolyline.h"
#include "qgscomposeritemwidget.h"
#include "qgssymbolv2selectordialog.h"
#include "qgsstylev2.h"
#include "qgssymbollayerv2utils.h"
QgsComposerPolylineWidget::QgsComposerPolylineWidget( QgsComposerPolyline* composerPolyline ):
QgsComposerItemBaseWidget( nullptr, composerPolyline )
, mComposerPolyline( composerPolyline )
{
setupUi( this );
//add widget for general composer item properties
QgsComposerItemWidget* itemPropertiesWidget = new QgsComposerItemWidget( this, composerPolyline );
itemPropertiesWidget->showBackgroundGroup( false );
itemPropertiesWidget->showFrameGroup( false );
mainLayout->addWidget( itemPropertiesWidget );
// update style icon
updatePolylineStyle();
if ( mComposerPolyline )
connect( mComposerPolyline, SIGNAL( itemChanged() ), this, SLOT( setGuiElementValues() ) );
}
QgsComposerPolylineWidget::~QgsComposerPolylineWidget()
{
}
void QgsComposerPolylineWidget::on_mLineStyleButton_clicked()
{
if ( !mComposerPolyline )
return;
QScopedPointer<QgsLineSymbolV2> newSymbol;
newSymbol.reset( mComposerPolyline->polylineStyleSymbol()->clone() );
QgsSymbolV2SelectorDialog d( newSymbol.data(), QgsStyleV2::defaultStyle(),
nullptr, this );
d.setExpressionContext( mComposerPolyline->createExpressionContext() );
if ( d.exec() == QDialog::Accepted )
{
mComposerPolyline->beginCommand( tr( "Polyline style changed" ) );
mComposerPolyline->setPolylineStyleSymbol( newSymbol.data() );
updatePolylineStyle();
mComposerPolyline->endCommand();
}
}
void QgsComposerPolylineWidget::setGuiElementValues()
{
if ( !mComposerPolyline )
return;
updatePolylineStyle();
}
void QgsComposerPolylineWidget::updatePolylineStyle()
{
if ( mComposerPolyline )
{
QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( mComposerPolyline->polylineStyleSymbol(), mLineStyleButton->iconSize() );
mLineStyleButton->setIcon( icon );
}
}

View File

@ -0,0 +1,48 @@
/***************************************************************************
qgscomposerpolylinewidget.h
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 QGSCOMPOSERPOLYLINEWIDGET_H
#define QGSCOMPOSERPOLYLINEWIDGET_H
#include "ui_qgscomposerpolylinewidgetbase.h"
#include "qgscomposeritemwidget.h"
class QgsComposerPolyline;
/**
* Input widget for QgsComposerPolyline
* @note added in QGIS 2.16
*/
class QgsComposerPolylineWidget: public QgsComposerItemBaseWidget, private Ui::QgsComposerPolylineWidgetBase
{
Q_OBJECT
public:
explicit QgsComposerPolylineWidget( QgsComposerPolyline* composerPolyline );
~QgsComposerPolylineWidget();
private:
QgsComposerPolyline* mComposerPolyline;
void updatePolylineStyle();
private slots:
void on_mLineStyleButton_clicked();
/** Sets the GUI elements to the currentValues of mComposerShape*/
void setGuiElementValues();
};
#endif // QGSCOMPOSERPOLYLINEWIDGET_H

View File

@ -245,6 +245,9 @@ SET(QGIS_CORE_SRCS
composer/qgscomposerpicture.cpp
composer/qgscomposerscalebar.cpp
composer/qgscomposershape.cpp
composer/qgscomposernodesitem.cpp
composer/qgscomposerpolygon.cpp
composer/qgscomposerpolyline.cpp
composer/qgscomposertable.cpp
composer/qgscomposertablecolumn.cpp
composer/qgscomposertablev2.cpp
@ -506,6 +509,9 @@ SET(QGIS_CORE_MOC_HDRS
composer/qgscomposerpicture.h
composer/qgscomposerscalebar.h
composer/qgscomposershape.h
composer/qgscomposernodesitem.h
composer/qgscomposerpolygon.h
composer/qgscomposerpolyline.h
composer/qgscomposertablecolumn.h
composer/qgscomposertable.h
composer/qgscomposertablev2.h

View File

@ -56,6 +56,8 @@ class CORE_EXPORT QgsComposerItem: public QgsComposerObject, public QGraphicsRec
ComposerPicture,
ComposerScaleBar,
ComposerShape,
ComposerPolygon,
ComposerPolyline,
ComposerTable,
ComposerAttributeTable,
ComposerTextTable,

View File

@ -0,0 +1,425 @@
/***************************************************************************
qgscomposernodesitem.cpp
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 "qgscomposernodesitem.h"
#include "qgscomposition.h"
#include "qgscomposerutils.h"
#include "qgssymbollayerv2utils.h"
#include "qgssymbolv2.h"
#include <limits>
#include <math.h>
QgsComposerNodesItem::QgsComposerNodesItem( QString tagName,
QgsComposition* c )
: QgsComposerItem( c )
, mTagName( tagName )
, mSelectedNode( -1 )
, mDrawNodes( false )
{
}
QgsComposerNodesItem::QgsComposerNodesItem( QString tagName,
QPolygonF polygon,
QgsComposition* c )
: QgsComposerItem( c ),
mTagName( tagName ),
mSelectedNode( -1 ),
mDrawNodes( false )
{
const QRectF boundingRect = polygon.boundingRect();
setSceneRect( boundingRect );
const QPointF topLeft = boundingRect.topLeft();
mPolygon = polygon.translated( -topLeft );
}
QgsComposerNodesItem::~QgsComposerNodesItem()
{
}
double QgsComposerNodesItem::computeDistance( const QPointF &pt1,
const QPointF &pt2 ) const
{
return sqrt( pow( pt1.x() - pt2.x(), 2 ) + pow( pt1.y() - pt2.y(), 2 ) );
}
bool QgsComposerNodesItem::addNode( const QPointF &pt,
const bool checkArea,
const double radius )
{
const QPointF start = convertToItemCoordinate( pt );
double minDistance = std::numeric_limits<double>::max();
double maxDistance = ( checkArea ) ? radius : minDistance;
bool rc = false;
int idx = -1;
for ( int i = 0; i != mPolygon.size(); i++ )
{
// get nodes of polyline
const QPointF pt1 = mPolygon.at( i );
QPointF pt2 = mPolygon.first();
if (( i + 1 ) != mPolygon.size() )
pt2 = mPolygon.at( i + 1 );
// compute line eq
const double coef = ( pt2.y() - pt1.y() ) / ( pt2.x() - pt1.x() );
const double b = pt1.y() - coef * pt1.x();
double distance = std::numeric_limits<double>::max();
if ( isinf( coef ) )
distance = qAbs( pt1.x() - start.x() );
else
{
const double coef2 = ( -1 / coef );
const double b2 = start.y() - coef2 * start.x();
QPointF inter;
if ( isinf( coef2 ) )
{
distance = qAbs( pt1.y() - start.y() );
inter.setX( start.x() );
inter.setY( pt1.y() );
}
else
{
const double interx = ( b - b2 ) / ( coef2 - coef );
const double intery = interx * coef2 + b2;
inter.setX( interx );
inter.setY( intery );
}
// check if intersection is within the line
const double length1 = computeDistance( inter, pt1 );
const double length2 = computeDistance( inter, pt2 );
const double length3 = computeDistance( pt1, pt2 );
const double length4 = length1 + length2;
if ( qAbs( length3 - length4 ) < std::numeric_limits<float>::epsilon() )
distance = computeDistance( inter, start );
}
if ( distance < minDistance && distance < maxDistance )
{
minDistance = distance;
idx = i;
}
}
if ( idx >= 0 )
{
rc = _addNode( idx, start, maxDistance );
updateSceneRect();
}
return rc;
}
QPointF QgsComposerNodesItem::convertToItemCoordinate( QPointF node )
{
QTransform transform = QTransform().rotate( -mItemRotation );
node -= scenePos();
return transform.map( node );
}
void QgsComposerNodesItem::drawNodes( QPainter *painter ) const
{
double rectSize = 3.0 / horizontalViewScaleFactor();
QgsStringMap properties;
properties.insert( "name", "cross" );
properties.insert( "color_border", "red" );
QScopedPointer<QgsMarkerSymbolV2> symbol;
symbol.reset( QgsMarkerSymbolV2::createSimple( properties ) );
symbol.data()->setSize( rectSize );
symbol.data()->setAngle( 45 );
QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
context.setForceVectorOutput( true );
QScopedPointer<QgsExpressionContext> expressionContext;
expressionContext.reset( createExpressionContext() );
context.setExpressionContext( *expressionContext.data() );
symbol.data()->startRender( context );
Q_FOREACH ( QPointF pt, mPolygon )
symbol.data()->renderPoint( pt, nullptr, context );
symbol.data()->stopRender( context );
if ( mSelectedNode >= 0 && mSelectedNode < mPolygon.size() )
drawSelectedNode( painter );
}
void QgsComposerNodesItem::drawSelectedNode( QPainter *painter ) const
{
double rectSize = 3.0 / horizontalViewScaleFactor();
QgsStringMap properties;
properties.insert( "name", "square" );
properties.insert( "color", "0, 0, 0, 0" );
properties.insert( "color_border", "blue" );
properties.insert( "width_border", "4" );
QScopedPointer<QgsMarkerSymbolV2> symbol;
symbol.reset( QgsMarkerSymbolV2::createSimple( properties ) );
symbol.data()->setSize( rectSize );
QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
context.setForceVectorOutput( true );
QScopedPointer<QgsExpressionContext> expressionContext;
expressionContext.reset( createExpressionContext() );
context.setExpressionContext( *expressionContext.data() );
symbol.data()->startRender( context );
symbol.data()->renderPoint( mPolygon.at( mSelectedNode ), nullptr, context );
symbol.data()->stopRender( context );
}
void QgsComposerNodesItem::paint( QPainter* painter,
const QStyleOptionGraphicsItem* itemStyle,
QWidget* pWidget )
{
Q_UNUSED( itemStyle );
Q_UNUSED( pWidget );
if ( !painter )
return;
painter->save();
painter->setPen( Qt::NoPen );
painter->setBrush( brush() );
painter->setRenderHint( QPainter::Antialiasing, true );
rescaleToFitBoundingBox();
_draw( painter );
if ( mDrawNodes && composition()->plotStyle() == QgsComposition::Preview )
drawNodes( painter );
painter->restore();
}
int QgsComposerNodesItem::nodeAtPosition( const QPointF &node,
const bool searchInRadius,
const double radius )
{
const QPointF pt = convertToItemCoordinate( node );
double nearestDistance = std::numeric_limits<double>::max();
double maxDistance = ( searchInRadius ) ? radius : nearestDistance;
double distance = 0;
int idx = -1;
QVector<QPointF>::const_iterator it = mPolygon.constBegin();
for ( ; it != mPolygon.constEnd(); ++it )
{
distance = computeDistance( pt, *it );
if ( distance < nearestDistance && distance < maxDistance )
{
nearestDistance = distance;
idx = it - mPolygon.constBegin();
}
}
return idx;
}
bool QgsComposerNodesItem::nodePosition( const int index, QPointF &position )
{
bool rc( false );
if ( index >= 0 && index < mPolygon.size() )
{
// get position in item coordinate
position = mPolygon.at( index );
// transform in scene coordinate
const double rotRad = mItemRotation * M_PI / 180.;
const double hypo = sqrt( pow( position.x(), 2 ) + pow( position.y(), 2 ) );
const double betaRad = acos( position.x() / hypo );
const double gammaRad = rotRad + betaRad;
position.setX( cos( gammaRad ) * hypo + scenePos().x() );
position.setY( sin( gammaRad ) * hypo + scenePos().y() );
rc = true;
}
return rc;
}
bool QgsComposerNodesItem::removeNode( const int index )
{
bool rc( false );
if ( index >= 0 && index < mPolygon.size() )
{
mPolygon.remove( index );
if ( mPolygon.size() < 3 )
mPolygon.clear();
else
{
int newSelectNode = index;
if ( index == mPolygon.size() )
newSelectNode = 0;
setSelectedNode( newSelectNode );
}
updateSceneRect();
rc = true;
}
return rc;
}
bool QgsComposerNodesItem::moveNode( const int index, const QPointF &pt )
{
bool rc( false );
if ( index >= 0 && index < mPolygon.size() )
{
QPointF nodeItem = convertToItemCoordinate( pt );
mPolygon.replace( index, nodeItem );
updateSceneRect();
rc = true;
}
return rc;
}
bool QgsComposerNodesItem::readXML( const QDomElement& itemElem,
const QDomDocument& doc )
{
// restore general composer item properties
const QDomNodeList composerItemList = itemElem.elementsByTagName( "ComposerItem" );
if ( !composerItemList.isEmpty() )
{
QDomElement composerItemElem = composerItemList.at( 0 ).toElement();
if ( !qgsDoubleNear( composerItemElem.attribute( "rotation", "0" ).toDouble(), 0.0 ) )
setItemRotation( composerItemElem.attribute( "rotation", "0" ).toDouble() );
_readXML( composerItemElem, doc );
}
// restore style
QDomElement styleSymbolElem = itemElem.firstChildElement( "symbol" );
if ( !styleSymbolElem.isNull() )
_readXMLStyle( styleSymbolElem );
// restore nodes
mPolygon.clear();
QDomNodeList nodesList = itemElem.elementsByTagName( "node" );
for ( int i = 0; i < nodesList.size(); i++ )
{
QDomElement nodeElem = nodesList.at( i ).toElement();
QPointF newPt;
newPt.setX( nodeElem.attribute( "x" ).toDouble() );
newPt.setY( nodeElem.attribute( "y" ).toDouble() );
mPolygon.append( newPt );
}
emit itemChanged();
return true;
}
void QgsComposerNodesItem::rescaleToFitBoundingBox()
{
// get the bounding rect for the polygon currently displayed
const QRectF boundingRect = mPolygon.boundingRect();
// compute x/y ratio
const float ratioX = rect().width() / boundingRect.width();
const float ratioY = rect().height() / boundingRect.height();
// scaling
QTransform trans;
trans = trans.scale( ratioX, ratioY );
mPolygon = trans.map( mPolygon );
}
bool QgsComposerNodesItem::setSelectedNode( const int index )
{
bool rc = false;
if ( index >= 0 && index < mPolygon.size() )
{
mSelectedNode = index;
rc = true;
}
return rc;
}
void QgsComposerNodesItem::updateSceneRect()
{
// set the new scene rectangle
const QRectF br = mPolygon.boundingRect();
const QPointF topLeft = br.topLeft();
const double angle = mItemRotation * M_PI / 180.;
const double member = topLeft.x() - tan( angle ) * topLeft.y();
const double newTopLeftX = cos( angle ) * member + scenePos().x();
const double newTopLeftY = topLeft.y() / cos( angle ) + sin( angle ) * member + scenePos().y();
QRectF sceneRect = QRectF( newTopLeftX, newTopLeftY, br.width(), br.height() );
setSceneRect( sceneRect );
// update polygon position
mPolygon.translate( -br.topLeft().x(), -br.topLeft().y() );
// update
prepareGeometryChange();
update();
emit itemChanged();
}
bool QgsComposerNodesItem::writeXML( QDomElement& elem, QDomDocument & doc ) const
{
QDomElement composerPolygonElem = doc.createElement( mTagName );
// style
_writeXMLStyle( doc, composerPolygonElem );
// write nodes
QDomElement nodesElem = doc.createElement( "nodes" );
Q_FOREACH ( QPointF pt, mPolygon )
{
QDomElement nodeElem = doc.createElement( "node" );
nodeElem.setAttribute( "x", QString::number( pt.x() ) );
nodeElem.setAttribute( "y", QString::number( pt.y() ) );
nodesElem.appendChild( nodeElem );
}
composerPolygonElem.appendChild( nodesElem );
elem.appendChild( composerPolygonElem );
return _writeXML( composerPolygonElem, doc );
}

View File

@ -0,0 +1,169 @@
/***************************************************************************
qgscomposernodesitem.h
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 QGSCOMPOSERNODESITEM_H
#define QGSCOMPOSERNODESITEM_H
#include "qgscomposeritem.h"
#include <QBrush>
#include <QPen>
/** An abstract composer item that provides generic methods for nodes based
* shapes such as polygon or polylines.
* @note added in QGIS 2.16
*/
class CORE_EXPORT QgsComposerNodesItem: public QgsComposerItem
{
Q_OBJECT
public:
/** Constructor
* @param mTagName tag used in XML file
* @param c parent composition
*/
QgsComposerNodesItem( QString mTagName, QgsComposition* c );
/** Constructor
* @param mTagName tag used in XML file
* @param polygon nodes of the shape
* @param c parent composition
*/
QgsComposerNodesItem( QString mTagName, QPolygonF polygon, QgsComposition* c );
/** Destructor */
~QgsComposerNodesItem();
/** Add a node in current shape.
* @param pt is the location of the new node
* @param checkArea is a flag to indicate if there's a space constraint.
* @param radius is the space contraint and is used only if checkArea is
* true. Typically, if this flag is true, the new node has to be nearest
* than radius to the shape to be added.
*/
bool addNode( const QPointF &pt, const bool checkArea = true, const double radius = 10 );
/** Set a tag to indicate if we want to draw or not the shape's nodes.
* @param display
*/
void setDisplayNodes( const bool display = true ) { mDrawNodes = display; };
/** Move a node to a new position.
* @param index the index of the node to move
* @param node is the new position in scene coordinate
*/
bool moveNode( const int index, const QPointF &node );
/** \brief Reimplementation of QCanvasItem::paint - draw on canvas */
void paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget ) override;
/** Search the nearest node in shape within a maximal area. Returns the
* index of the nearest node or -1.
* @param node is where a shape's node is searched
* @param searchInRadius is a flag to indicate if the area of research is
* limited in space.
* @param radius is only used if searchInRadius is true
*/
int nodeAtPosition( const QPointF &node, const bool searchInRadius = true, const double radius = 10 );
/** Gets the position of a node in scene coordinate.
* @param index of the node
* @param position the position of the node
* @return true if the index is valid and the position is set, false otherwise
*/
bool nodePosition( const int index, QPointF &position );
/** Sets state from Dom document
* @param itemElem is Dom node corresponding to item tag
* @param doc is Dom document
*/
bool readXML( const QDomElement& itemElem, const QDomDocument& doc ) override;
/** Remove a node from the shape.
* @param index of the node to delete
*/
bool removeNode( const int index );
/** Returns the number of nodes in the shape. */
int nodesSize() { return mPolygon.size(); }
/** Select a node.
* @param index the node to select
*/
bool setSelectedNode( const int index );
/** Returns the currently selected node.
* @return the index of the selected node, -1 otherwise
*/
int selectedNode() { return mSelectedNode; };
/** Unselect a node.
*/
void unselectNode() { mSelectedNode = -1; };
/** Stores state in Dom element
* @param elem is Dom element corresponding to 'Composer' tag
* @param doc write template file
*/
bool writeXML( QDomElement& elem, QDomDocument & doc ) const override;
protected:
/** Storage meaning for shape's nodes. */
QPolygonF mPolygon;
/** Method called in addNode. */
virtual bool _addNode( const int nodeIndex, const QPointF &newNode, const double radius ) = 0;
/** Method called in paint. */
virtual void _draw( QPainter *painter ) = 0;
/** Method called in readXML. */
virtual void _readXMLStyle( const QDomElement &elmt ) = 0;
/** Method called in writeXML. */
virtual void _writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const = 0;
/** Rescale the current shape according to the boudning box. Useful when
* the shape is resized thanks to the rubber band. */
void rescaleToFitBoundingBox();
/** Compute an euclidian distance between 2 nodes. */
double computeDistance( const QPointF &pt1, const QPointF &pt2 ) const;
/** Convert scene coordinate to item coordinates */
QPointF convertToItemCoordinate( QPointF node );
/** Update the current scene rectangle for this item. */
void updateSceneRect();
private:
/** This tag is used to write the XML document. */
QString mTagName;
/** The index of the node currently selected. */
int mSelectedNode;
/** This tag is used to indicate if we have to draw nodes or not during
* the painting. */
bool mDrawNodes;
/** Draw nodes */
void drawNodes( QPainter *painter ) const;
void drawSelectedNode( QPainter *painter ) const;
};
#endif // QGSCOMPOSERNODESITEM_H

View File

@ -0,0 +1,122 @@
/***************************************************************************
qgscomposerpolygon.cpp
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 "qgscomposerpolygon.h"
#include "qgscomposition.h"
#include "qgscomposerutils.h"
#include "qgssymbollayerv2utils.h"
#include "qgssymbolv2.h"
#include <limits>
QgsComposerPolygon::QgsComposerPolygon( QgsComposition* c )
: QgsComposerNodesItem( "ComposerPolygon", c )
, mPolygonStyleSymbol( nullptr )
{
createDefaultPolygonStyleSymbol();
}
QgsComposerPolygon::QgsComposerPolygon( QPolygonF polygon, QgsComposition* c )
: QgsComposerNodesItem( "ComposerPolygon", polygon, c )
, mPolygonStyleSymbol( nullptr )
{
createDefaultPolygonStyleSymbol();
}
QgsComposerPolygon::~QgsComposerPolygon()
{
}
bool QgsComposerPolygon::_addNode( const int indexPoint,
const QPointF &newPoint,
const double radius )
{
Q_UNUSED( radius );
mPolygon.insert( indexPoint + 1, newPoint );
return true;
}
void QgsComposerPolygon::createDefaultPolygonStyleSymbol()
{
QgsStringMap properties;
properties.insert( "color", "white" );
properties.insert( "style", "solid" );
properties.insert( "style_border", "solid" );
properties.insert( "color_border", "black" );
properties.insert( "width_border", "0.3" );
properties.insert( "joinstyle", "miter" );
mPolygonStyleSymbol.reset( QgsFillSymbolV2::createSimple( properties ) );
emit frameChanged();
}
QString QgsComposerPolygon::displayName() const
{
if ( !id().isEmpty() )
return id();
return tr( "<polygon>" );
}
void QgsComposerPolygon::_draw( QPainter *painter )
{
//setup painter scaling to dots so that raster symbology is drawn to scale
const double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
context.setForceVectorOutput( true );
QScopedPointer<QgsExpressionContext> expressionContext;
expressionContext.reset( createExpressionContext() );
context.setExpressionContext( *expressionContext.data() );
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
QTransform t = QTransform::fromScale( dotsPerMM, dotsPerMM );
QList<QPolygonF> rings; //empty
QPainterPath polygonPath;
polygonPath.addPolygon( mPolygon );
mPolygonStyleSymbol->startRender( context );
mPolygonStyleSymbol->renderPolygon( polygonPath.toFillPolygon( t ), &rings,
nullptr, context );
mPolygonStyleSymbol->stopRender( context );
painter->scale( dotsPerMM, dotsPerMM );
}
void QgsComposerPolygon::_readXMLStyle( const QDomElement &elmt )
{
mPolygonStyleSymbol.reset( QgsSymbolLayerV2Utils::loadSymbol<QgsFillSymbolV2>( elmt ) );
}
void QgsComposerPolygon::setPolygonStyleSymbol( QgsFillSymbolV2* symbol )
{
mPolygonStyleSymbol.reset( static_cast<QgsFillSymbolV2*>( symbol->clone() ) );
update();
emit frameChanged();
}
void QgsComposerPolygon::_writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const
{
const QDomElement pe = QgsSymbolLayerV2Utils::saveSymbol( QString(),
mPolygonStyleSymbol.data(),
doc );
elmt.appendChild( pe );
}

View File

@ -0,0 +1,85 @@
/***************************************************************************
qgscomposerpolygon.h
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 QGSCOMPOSERPOLYGON_H
#define QGSCOMPOSERPOLYGON_H
#include "qgscomposernodesitem.h"
#include <QBrush>
#include <QPen>
class QgsFillSymbolV2;
/**
* Composer item for polygons.
* @note added in QGIS 2.16
*/
class CORE_EXPORT QgsComposerPolygon: public QgsComposerNodesItem
{
Q_OBJECT
public:
/** Constructor
* @param c parent composition
*/
QgsComposerPolygon( QgsComposition* c );
/** Constructor
* @param polygon nodes of the shape
* @param c parent composition
*/
QgsComposerPolygon( QPolygonF polygon, QgsComposition* c );
/** Destructor */
~QgsComposerPolygon();
/** Overridden to return shape name */
virtual QString displayName() const override;
/** Returns the QgsSymbolV2 used to draw the shape. */
QgsFillSymbolV2* polygonStyleSymbol() { return mPolygonStyleSymbol.data(); }
/** Set the QgsSymbolV2 used to draw the shape. */
void setPolygonStyleSymbol( QgsFillSymbolV2* symbol );
/** Return correct graphics item type. */
virtual int type() const override { return ComposerPolygon; }
protected:
/** QgsSymbolV2 use to draw the shape. */
QScopedPointer<QgsFillSymbolV2> mPolygonStyleSymbol;
/** Add the node newPoint at the given position according to some
* criteres. */
bool _addNode( const int indexPoint, const QPointF &newPoint, const double radius ) override;
/** Draw nodes for the current shape. */
void _draw( QPainter *painter ) override;
/** Read symbol in XML. */
void _readXMLStyle( const QDomElement &elmt ) override;
/** Write the symbol in an XML document. */
void _writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const override;
/** Create a default symbol. */
void createDefaultPolygonStyleSymbol();
};
#endif // QGSCOMPOSERPOLYGON_H

View File

@ -0,0 +1,124 @@
/***************************************************************************
qgscomposerpolyline.cpp
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 "qgscomposerpolyline.h"
#include "qgscomposition.h"
#include "qgscomposerutils.h"
#include "qgssymbollayerv2utils.h"
#include "qgssymbolv2.h"
#include <limits>
QgsComposerPolyline::QgsComposerPolyline( QgsComposition* c )
: QgsComposerNodesItem( "ComposerPolyline", c )
, mPolylineStyleSymbol( nullptr )
{
createDefaultPolylineStyleSymbol();
}
QgsComposerPolyline::QgsComposerPolyline( QPolygonF polyline, QgsComposition* c )
: QgsComposerNodesItem( "ComposerPolyline", polyline, c )
, mPolylineStyleSymbol( nullptr )
{
createDefaultPolylineStyleSymbol();
}
QgsComposerPolyline::~QgsComposerPolyline()
{
}
bool QgsComposerPolyline::_addNode( const int indexPoint,
const QPointF &newPoint,
const double radius )
{
const double distStart = computeDistance( newPoint, mPolygon[0] );
const double distEnd = computeDistance( newPoint, mPolygon[mPolygon.size()-1] );
if ( indexPoint == ( mPolygon.size() - 1 ) )
{
if ( distEnd < radius )
mPolygon.append( newPoint );
else if ( distStart < radius )
mPolygon.insert( 0, newPoint );
}
else
mPolygon.insert( indexPoint + 1, newPoint );
return true;
}
void QgsComposerPolyline::createDefaultPolylineStyleSymbol()
{
QgsStringMap properties;
properties.insert( "color", "0,0,0,255" );
properties.insert( "width", "0.3" );
properties.insert( "capstyle", "square" );
mPolylineStyleSymbol.reset( QgsLineSymbolV2::createSimple( properties ) );
emit frameChanged();
}
QString QgsComposerPolyline::displayName() const
{
if ( !id().isEmpty() )
return id();
return tr( "<polyline>" );
}
void QgsComposerPolyline::_draw( QPainter *painter )
{
double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
QgsMapSettings ms = mComposition->mapSettings();
ms.setOutputDpi( painter->device()->logicalDpiX() );
QgsRenderContext context = QgsRenderContext::fromMapSettings( ms );
context.setPainter( painter );
context.setForceVectorOutput( true );
QScopedPointer<QgsExpressionContext> expressionContext;
expressionContext.reset( createExpressionContext() );
context.setExpressionContext( *expressionContext.data() );
painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
QTransform t = QTransform::fromScale( dotsPerMM, dotsPerMM );
mPolylineStyleSymbol->startRender( context );
mPolylineStyleSymbol->renderPolyline( t.map( mPolygon ), nullptr, context );
mPolylineStyleSymbol->stopRender( context );
painter->scale( dotsPerMM, dotsPerMM );
}
void QgsComposerPolyline::_readXMLStyle( const QDomElement &elmt )
{
mPolylineStyleSymbol.reset( QgsSymbolLayerV2Utils::loadSymbol<QgsLineSymbolV2>( elmt ) );
}
void QgsComposerPolyline::setPolylineStyleSymbol( QgsLineSymbolV2* symbol )
{
mPolylineStyleSymbol.reset( static_cast<QgsLineSymbolV2*>( symbol->clone() ) );
update();
emit frameChanged();
}
void QgsComposerPolyline::_writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const
{
const QDomElement pe = QgsSymbolLayerV2Utils::saveSymbol( QString(),
mPolylineStyleSymbol.data(),
doc );
elmt.appendChild( pe );
}

View File

@ -0,0 +1,85 @@
/***************************************************************************
qgscomposerpolyline.h
begin : March 2016
copyright : (C) 2016 Paul Blottiere, Oslandia
email : paul dot blottiere at oslandia 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 QGSCOMPOSERPOLYLINE_H
#define QGSCOMPOSERPOLYLINE_H
#include "qgscomposernodesitem.h"
#include <QBrush>
#include <QPen>
class QgsLineSymbolV2;
/**
* Composer item for polylines.
* @note added in QGIS 2.16
*/
class CORE_EXPORT QgsComposerPolyline: public QgsComposerNodesItem
{
Q_OBJECT
public:
/** Constructor
* @param c parent composition
*/
QgsComposerPolyline( QgsComposition* c );
/** Constructor
* @param polyline nodes of the shape
* @param c parent composition
*/
QgsComposerPolyline( QPolygonF polyline, QgsComposition* c );
/** Destructor */
~QgsComposerPolyline();
/** Overridden to return shape name */
virtual QString displayName() const override;
/** Returns the QgsSymbolV2 used to draw the shape. */
QgsLineSymbolV2* polylineStyleSymbol() { return mPolylineStyleSymbol.data(); }
/** Set the QgsSymbolV2 used to draw the shape. */
void setPolylineStyleSymbol( QgsLineSymbolV2* symbol );
/** Overridden to return shape type */
virtual int type() const override { return ComposerPolyline; }
protected:
/** QgsSymbolV2 use to draw the shape. */
QScopedPointer<QgsLineSymbolV2> mPolylineStyleSymbol;
/** Add the node newPoint at the given position according to some
* criteres. */
bool _addNode( const int indexPoint, const QPointF &newPoint, const double radius ) override;
/** Draw nodes for the current shape. */
void _draw( QPainter *painter ) override;
/** Read symbol in XML. */
void _readXMLStyle( const QDomElement &elmt ) override;
/** Write the symbol in an XML document. */
void _writeXMLStyle( QDomDocument &doc, QDomElement &elmt ) const override;
/** Create a default symbol. */
void createDefaultPolylineStyleSymbol();
};
#endif // QGSCOMPOSERPOLYLINE_H

View File

@ -17,6 +17,8 @@
#include "qgscomposition.h"
#include "qgscomposerutils.h"
#include "qgscomposerarrow.h"
#include "qgscomposerpolygon.h"
#include "qgscomposerpolyline.h"
#include "qgscomposerframe.h"
#include "qgscomposerhtml.h"
#include "qgscomposerlabel.h"
@ -1384,6 +1386,69 @@ void QgsComposition::addItemsFromXML( const QDomElement& elem, const QDomDocumen
pushAddRemoveCommand( newShape, tr( "Shape added" ) );
}
}
// polygon
QDomNodeList composerPolygonList = elem.elementsByTagName( "ComposerPolygon" );
for ( int i = 0; i < composerPolygonList.size(); ++i )
{
QDomElement currentComposerPolygonElem = composerPolygonList.at( i ).toElement();
QgsComposerPolygon* newPolygon = new QgsComposerPolygon( this );
newPolygon->readXML( currentComposerPolygonElem, doc );
if ( pos )
{
if ( pasteInPlace )
{
newPolygon->setItemPosition( newPolygon->pos().x(), fmod( newPolygon->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
newPolygon->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
}
else
{
newPolygon->move( pasteShiftPos.x(), pasteShiftPos.y() );
}
newPolygon->setSelected( true );
lastPastedItem = newPolygon;
}
addComposerPolygon( newPolygon );
newPolygon->setZValue( newPolygon->zValue() + zOrderOffset );
if ( addUndoCommands )
{
pushAddRemoveCommand( newPolygon, tr( "Polygon added" ) );
}
}
// polyline
QDomNodeList addComposerPolylineList = elem.elementsByTagName( "ComposerPolyline" );
for ( int i = 0; i < addComposerPolylineList.size(); ++i )
{
QDomElement currentComposerPolylineElem = addComposerPolylineList.at( i ).toElement();
QgsComposerPolyline* newPolyline = new QgsComposerPolyline( this );
newPolyline->readXML( currentComposerPolylineElem, doc );
if ( pos )
{
if ( pasteInPlace )
{
newPolyline->setItemPosition( newPolyline->pos().x(), fmod( newPolyline->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
newPolyline->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
}
else
{
newPolyline->move( pasteShiftPos.x(), pasteShiftPos.y() );
}
newPolyline->setSelected( true );
lastPastedItem = newPolyline;
}
addComposerPolyline( newPolyline );
newPolyline->setZValue( newPolyline->zValue() + zOrderOffset );
if ( addUndoCommands )
{
pushAddRemoveCommand( newPolyline, tr( "Polyline added" ) );
}
}
// picture
QDomNodeList composerPictureList = elem.elementsByTagName( "ComposerPicture" );
for ( int i = 0; i < composerPictureList.size(); ++i )
@ -2442,6 +2507,26 @@ void QgsComposition::addComposerArrow( QgsComposerArrow* arrow )
emit composerArrowAdded( arrow );
}
void QgsComposition::addComposerPolygon( QgsComposerPolygon *polygon )
{
addItem( polygon );
updateBounds();
connect( polygon, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
emit composerPolygonAdded( polygon );
}
void QgsComposition::addComposerPolyline( QgsComposerPolyline *polyline )
{
addItem( polyline );
updateBounds();
connect( polyline, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
emit composerPolylineAdded( polyline );
}
void QgsComposition::addComposerLabel( QgsComposerLabel* label )
{
addItem( label );
@ -2690,6 +2775,20 @@ void QgsComposition::sendItemAddedSignal( QgsComposerItem* item )
emit selectedItemChanged( shape );
return;
}
QgsComposerPolygon* polygon = dynamic_cast<QgsComposerPolygon*>( item );
if ( polygon )
{
emit composerPolygonAdded( polygon );
emit selectedItemChanged( polygon );
return;
}
QgsComposerPolyline* polyline = dynamic_cast<QgsComposerPolyline*>( item );
if ( polyline )
{
emit composerPolylineAdded( polyline );
emit selectedItemChanged( polyline );
return;
}
QgsComposerAttributeTable* table = dynamic_cast<QgsComposerAttributeTable*>( item );
if ( table )
{

View File

@ -44,6 +44,8 @@ class QGraphicsRectItem;
class QgsMapRenderer;
class QDomElement;
class QgsComposerArrow;
class QgsComposerPolygon;
class QgsComposerPolyline;
class QgsComposerMouseHandles;
class QgsComposerHtml;
class QgsComposerTableV2;
@ -609,22 +611,26 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
void addMultiFrame( QgsComposerMultiFrame* multiFrame );
/** Removes multi frame (but does not delete it)*/
void removeMultiFrame( QgsComposerMultiFrame* multiFrame );
/** Adds an arrow item to the graphics scene and advices composer to create a widget for it (through signal)
/** Adds an arrow item to the graphics scene and advises composer to create a widget for it (through signal)
@note not available in python bindings*/
void addComposerArrow( QgsComposerArrow* arrow );
/** Adds label to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds label to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerLabel( QgsComposerLabel* label );
/** Adds map to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds map to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerMap( QgsComposerMap* map, const bool setDefaultPreviewStyle = true );
/** Adds scale bar to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds scale bar to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerScaleBar( QgsComposerScaleBar* scaleBar );
/** Adds legend to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds legend to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerLegend( QgsComposerLegend* legend );
/** Adds picture to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds picture to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerPicture( QgsComposerPicture* picture );
/** Adds a composer shape to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds a composer shape to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerShape( QgsComposerShape* shape );
/** Adds a composer table to the graphics scene and advices composer to create a widget for it (through signal)*/
/** Adds a composer polygon and advises composer to create a widget for it (through signal)*/
void addComposerPolygon( QgsComposerPolygon* polygon );
/** Adds a composer polyline and advises composer to create a widget for it (through signal)*/
void addComposerPolyline( QgsComposerPolyline* polyline );
/** Adds a composer table to the graphics scene and advises composer to create a widget for it (through signal)*/
void addComposerTable( QgsComposerAttributeTable* table );
/** Adds composer html frame and advises composer to create a widget for it (through signal)*/
void addComposerHtmlFrame( QgsComposerHtml* html, QgsComposerFrame* frame );
@ -1059,6 +1065,10 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
void selectedItemChanged( QgsComposerItem* selected );
/** Is emitted when new composer arrow has been added to the view*/
void composerArrowAdded( QgsComposerArrow* arrow );
/** Is emitted when new composer polygon has been added to the view*/
void composerPolygonAdded( QgsComposerPolygon* polygon );
/** Is emitted when new composer polyline has been added to the view*/
void composerPolylineAdded( QgsComposerPolyline* polyline );
/** Is emitted when a new composer html has been added to the view*/
void composerHtmlFrameAdded( QgsComposerHtml* html, QgsComposerFrame* frame );
/** Is emitted when new composer label has been added to the view*/

View File

@ -29,6 +29,8 @@
#include "qgscomposerview.h"
#include "qgscomposerarrow.h"
#include "qgscomposerframe.h"
#include "qgscomposerpolygon.h"
#include "qgscomposerpolyline.h"
#include "qgscomposerhtml.h"
#include "qgscomposerlabel.h"
#include "qgscomposerlegend.h"
@ -40,7 +42,6 @@
#include "qgscomposerscalebar.h"
#include "qgscomposershape.h"
#include "qgscomposerattributetablev2.h"
#include "qgslogger.h"
#include "qgsaddremovemultiframecommand.h"
#include "qgspaperitem.h"
#include "qgsmapcanvas.h" //for QgsMapCanvas::WheelAction
@ -60,6 +61,9 @@ QgsComposerView::QgsComposerView( QWidget* parent, const char* name, const Qt::W
, mPaintingEnabled( true )
, mHorizontalRuler( nullptr )
, mVerticalRuler( nullptr )
, mMoveContentSearchRadius( 25 )
, mNodesItem( nullptr )
, mNodesItemIndex( -1 )
, mToolPanning( false )
, mMousePanning( false )
, mKeyPanning( false )
@ -87,6 +91,15 @@ void QgsComposerView::setCurrentTool( QgsComposerView::Tool t )
{
return;
}
// do not display points of NodesItem by default
mNodesItemIndex = -1;
mNodesItem = nullptr;
mPolygonItem.reset();
mPolylineItem.reset();
displayNodes( false );
unselectNode();
switch ( t )
{
case QgsComposerView::Pan:
@ -113,6 +126,8 @@ void QgsComposerView::setCurrentTool( QgsComposerView::Tool t )
case QgsComposerView::AddPicture:
case QgsComposerView::AddRectangle:
case QgsComposerView::AddEllipse:
case QgsComposerView::AddPolygon:
case QgsComposerView::AddPolyline:
case QgsComposerView::AddTriangle:
case QgsComposerView::AddTable:
case QgsComposerView::AddAttributeTable:
@ -123,6 +138,16 @@ void QgsComposerView::setCurrentTool( QgsComposerView::Tool t )
viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
break;
}
case QgsComposerView::EditNodesItem:
{
composition()->setPreventCursorChange( true );
viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
displayNodes();
break;
}
default:
{
//not using pan tool, composer items can change cursor
@ -326,6 +351,49 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
return;
}
case EditNodesItem:
{
QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos().x(), e->pos().y(),
mMoveContentSearchRadius,
mMoveContentSearchRadius );
if ( itemsAtCursorPos.isEmpty() )
return;
mNodesItemIndex = -1;
mNodesItem = nullptr;
QList<QGraphicsItem*>::iterator itemIter = itemsAtCursorPos.begin();
for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
{
QgsComposerItem* item = dynamic_cast<QgsComposerItem *>(( *itemIter ) );
if ( item && !item->positionLock() )
{
if (( item->type() == QgsComposerItem::ComposerPolygon
|| item->type() == QgsComposerItem::ComposerPolyline ) )
{
QgsComposerNodesItem* itemP = dynamic_cast<QgsComposerNodesItem *>( item );
int index = itemP->nodeAtPosition( scenePoint );
if ( index != -1 )
{
mNodesItemIndex = index;
mNodesItem = itemP;
mMoveContentStartPos = scenePoint;
}
}
}
if ( mNodesItemIndex != -1 )
{
composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
setSelectedNode( mNodesItem, mNodesItemIndex );
break;
}
}
break;
}
//create rubber band for adding line items
case AddArrow:
{
@ -385,6 +453,36 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
}
break;
case AddPolygon:
{
if ( mPolygonItem.isNull() )
{
mPolygonItem.reset( new QGraphicsPolygonItem() );
mPolygonItem.data()->setBrush( Qt::NoBrush );
mPolygonItem.data()->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
mPolygonItem.data()->setZValue( 1000 );
scene()->addItem( mPolygonItem.data() );
scene()->update();
}
break;
}
case AddPolyline:
{
if ( mPolylineItem.isNull() && mPolygonItem.isNull() )
{
mPolygonItem.reset( new QGraphicsPolygonItem() );
mPolylineItem.reset( new QGraphicsPathItem() );
mPolylineItem.data()->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
mPolylineItem.data()->setZValue( 1000 );
}
break;
}
default:
break;
}
@ -409,11 +507,16 @@ QCursor QgsComposerView::defaultCursorForTool( Tool currentTool )
case MoveItemContent:
return Qt::ArrowCursor;
case EditNodesItem:
return Qt::CrossCursor;
case AddArrow:
case AddMap:
case AddRectangle:
case AddTriangle:
case AddEllipse:
case AddPolygon:
case AddPolyline:
case AddHtml:
case AddLabel:
case AddScalebar:
@ -684,6 +787,77 @@ void QgsComposerView::mouseReleaseEvent( QMouseEvent* e )
viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
}
if ( e->button() == Qt::RightButton )
{
switch ( mCurrentTool )
{
case AddPolygon:
{
if ( ! mPolygonItem.isNull() )
{
QPolygonF poly = mPolygonItem.data()->polygon();
if ( poly.size() >= 3 )
{
mPolygonItem.data()->setPolygon( poly );
// add polygon in composition
QgsComposerPolygon *composerPolygon = new QgsComposerPolygon( mPolygonItem.data()->polygon(), composition() );
composition()->addComposerPolygon( composerPolygon );
// select the polygon
composition()->setAllUnselected();
composerPolygon->setSelected( true );
emit selectedItemChanged( composerPolygon );
composition()->pushAddRemoveCommand( composerPolygon, tr( "Polygon added" ) );
}
// clean
scene()->removeItem( mPolygonItem.data() );
mPolygonItem.reset();
emit actionFinished();
}
break;
}
case AddPolyline:
{
if ( ! mPolygonItem.isNull() && ! mPolylineItem.isNull() )
{
// ignore the last point due to release event before doubleClick event
QPolygonF poly = mPolygonItem.data()->polygon();
if ( poly.size() >= 3 )
{
mPolygonItem.data()->setPolygon( poly );
// add polygon in composition
QgsComposerPolyline *composerPolyline = new QgsComposerPolyline( mPolygonItem.data()->polygon(), composition() );
composition()->addComposerPolyline( composerPolyline );
// select the polygon
composition()->setAllUnselected();
composerPolyline->setSelected( true );
emit selectedItemChanged( composerPolyline );
composition()->pushAddRemoveCommand( composerPolyline, tr( "Polyline added" ) );
}
// clean
scene()->removeItem( mPolylineItem.data() );
mPolygonItem.reset();
mPolylineItem.reset();
emit actionFinished();
}
break;
}
default:
e->ignore();
}
}
//for every other tool, ignore clicks of non-left button
if ( e->button() != Qt::LeftButton )
{
@ -735,6 +909,20 @@ void QgsComposerView::mouseReleaseEvent( QMouseEvent* e )
}
break;
}
case EditNodesItem:
{
if ( mNodesItemIndex != -1 )
{
if ( scenePoint != mMoveContentStartPos )
composition()->endCommand();
else
composition()->cancelCommand();
}
break;
}
case AddArrow:
if ( !composition() || !mRubberBandLineItem )
{
@ -766,6 +954,32 @@ void QgsComposerView::mouseReleaseEvent( QMouseEvent* e )
addShape( mCurrentTool );
break;
case AddPolygon:
{
if ( ! mPolygonItem.isNull() )
addPolygonNode( scenePoint );
break;
}
case AddPolyline:
{
if ( ! mPolygonItem.isNull() && ! mPolylineItem.isNull() )
{
addPolygonNode( scenePoint );
// rebuild a new qpainter path
QPainterPath path;
path.addPolygon( mPolygonItem.data()->polygon() );
mPolylineItem.data()->setPath( path );
// add it to the scene
scene()->addItem( mPolylineItem.data() );
scene()->update();
}
break;
}
case AddMap:
if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
{
@ -1001,7 +1215,7 @@ void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
mMouseLastXY = e->pos();
return;
}
else if ( e->buttons() == Qt::NoButton )
else if (( e->buttons() == Qt::NoButton ) && ( mPolygonItem.isNull() ) )
{
if ( mCurrentTool == Select )
{
@ -1046,6 +1260,29 @@ void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
break;
}
case AddPolygon:
{
if ( ! mPolygonItem.isNull() )
movePolygonNode( scenePoint );
break;
}
case AddPolyline:
{
if ( ! mPolygonItem.isNull() && ! mPolylineItem.isNull() )
{
movePolygonNode( scenePoint );
// rebuild a new qpainter path
QPainterPath path;
path.addPolygon( mPolygonItem.data()->polygon() );
mPolylineItem.data()->setPath( path );
}
break;
}
case MoveItemContent:
{
//update map preview if composer map
@ -1057,6 +1294,19 @@ void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
}
break;
}
case EditNodesItem:
{
if ( mNodesItemIndex != -1 )
{
QPointF scenePoint = mapToScene( e->pos() );
mNodesItem->moveNode( mNodesItemIndex, scenePoint );
scene()->update();
}
break;
}
default:
break;
}
@ -1158,7 +1408,70 @@ void QgsComposerView::updateRubberBandLine( QPointF pos, const bool constrainAng
void QgsComposerView::mouseDoubleClickEvent( QMouseEvent* e )
{
e->ignore();
QPointF scenePoint = mapToScene( e->pos() );
switch ( mCurrentTool )
{
case EditNodesItem:
{
// erase status previously set by the mousePressEvent method
if ( mNodesItemIndex != -1 )
{
mNodesItem = nullptr;
mNodesItemIndex = -1;
unselectNode();
}
// search items in composer
QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos().x(), e->pos().y(),
mMoveContentSearchRadius,
mMoveContentSearchRadius );
if ( itemsAtCursorPos.isEmpty() )
return;
bool rc = false;
QList<QGraphicsItem*>::iterator itemIter = itemsAtCursorPos.begin();
for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
{
QgsComposerItem* item = dynamic_cast<QgsComposerItem *>(( *itemIter ) );
if ( item && !item->positionLock() )
{
if (( item->type() == QgsComposerItem::ComposerPolygon
|| item->type() == QgsComposerItem::ComposerPolyline ) )
{
QgsComposerNodesItem* itemP = dynamic_cast<QgsComposerNodesItem *>( item );
composition()->beginCommand( itemP, tr( "Add item node" ) );
rc = itemP->addNode( scenePoint );
if ( rc )
{
composition()->endCommand();
mNodesItem = itemP;
mNodesItemIndex = mNodesItem->nodeAtPosition( scenePoint );
}
else
composition()->cancelCommand();
}
}
if ( rc )
break;
}
if ( rc )
{
setSelectedNode( mNodesItem, mNodesItemIndex );
scene()->update();
}
break;
}
default:
break;
}
}
void QgsComposerView::copyItems( ClipboardMode mode )
@ -1259,15 +1572,47 @@ void QgsComposerView::deleteSelectedItems()
return;
}
QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
//delete selected items
for ( ; itemIt != composerItemList.end(); ++itemIt )
if ( mCurrentTool == QgsComposerView::EditNodesItem )
{
if ( composition() )
if ( mNodesItemIndex != -1 )
{
composition()->removeComposerItem( *itemIt );
composition()->beginCommand( mNodesItem, tr( "Remove item node" ) );
bool rc = mNodesItem->removeNode( mNodesItemIndex );
composition()->endCommand();
bool nodeDeleted = true;
if ( rc )
{
mNodesItemIndex = mNodesItem->selectedNode();
if ( mNodesItemIndex != -1 )
{
nodeDeleted = false;
setSelectedNode( mNodesItem, mNodesItemIndex );
}
}
if ( nodeDeleted )
{
scene()->update();
mNodesItemIndex = -1;
mNodesItem = nullptr;
}
}
}
else
{
QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
//delete selected items
for ( ; itemIt != composerItemList.end(); ++itemIt )
{
if ( composition() )
{
composition()->removeComposerItem( *itemIt );
}
}
}
}
@ -1457,38 +1802,122 @@ void QgsComposerView::keyPressEvent( QKeyEvent * e )
if ( e->key() == Qt::Key_Left )
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
if ( mCurrentTool == EditNodesItem )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( -1 * increment, 0.0 );
( *itemIt )->endCommand();
if ( mNodesItemIndex != -1 )
{
QPointF currentPos;
if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
{
currentPos.setX( currentPos.x() - 1 );
composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
mNodesItem->moveNode( mNodesItemIndex, currentPos );
composition()->endCommand();
scene()->update();
}
}
}
else
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( -1 * increment, 0.0 );
( *itemIt )->endCommand();
}
}
}
else if ( e->key() == Qt::Key_Right )
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
if ( mCurrentTool == EditNodesItem )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( increment, 0.0 );
( *itemIt )->endCommand();
if ( mNodesItemIndex != -1 )
{
QPointF currentPos;
if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
{
currentPos.setX( currentPos.x() + 1 );
composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
mNodesItem->moveNode( mNodesItemIndex, currentPos );
composition()->endCommand();
scene()->update();
}
}
}
else
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( increment, 0.0 );
( *itemIt )->endCommand();
}
}
}
else if ( e->key() == Qt::Key_Down )
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
if ( mCurrentTool == EditNodesItem )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( 0.0, increment );
( *itemIt )->endCommand();
if ( mNodesItemIndex != -1 )
{
QPointF currentPos;
if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
{
currentPos.setY( currentPos.y() + 1 );
composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
mNodesItem->moveNode( mNodesItemIndex, currentPos );
composition()->endCommand();
scene()->update();
}
}
}
else
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( 0.0, increment );
( *itemIt )->endCommand();
}
}
}
else if ( e->key() == Qt::Key_Up )
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
if ( mCurrentTool == EditNodesItem )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( 0.0, -1 * increment );
( *itemIt )->endCommand();
if ( mNodesItemIndex != -1 )
{
QPointF currentPos;
if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
{
currentPos.setY( currentPos.y() - 1 );
composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
mNodesItem->moveNode( mNodesItemIndex, currentPos );
composition()->endCommand();
scene()->update();
}
}
}
else
{
for ( ; itemIt != composerItemList.end(); ++itemIt )
{
( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
( *itemIt )->move( 0.0, -1 * increment );
( *itemIt )->endCommand();
}
}
}
}
@ -1840,3 +2269,72 @@ QMainWindow* QgsComposerView::composerWindow()
return nullptr;
}
void QgsComposerView::addPolygonNode( const QPointF & scenePoint )
{
QPolygonF polygon = mPolygonItem.data()->polygon();
polygon.append( QPointF( scenePoint.x(), scenePoint.y() ) );
if ( polygon.size() == 1 )
polygon.append( QPointF( scenePoint.x(), scenePoint.y() ) );
mPolygonItem.data()->setPolygon( polygon );
}
void QgsComposerView::movePolygonNode( const QPointF & scenePoint )
{
QPolygonF polygon = mPolygonItem.data()->polygon();
if ( polygon.size() > 0 )
{
polygon.replace( polygon.size() - 1, scenePoint );
mPolygonItem.data()->setPolygon( polygon );
}
}
void QgsComposerView::displayNodes( const bool display )
{
QList<QgsComposerNodesItem*> nodesShapes;
composition()->composerItems( nodesShapes );
QList<QgsComposerNodesItem*>::iterator it = nodesShapes.begin();
for ( ; it != nodesShapes.end(); ++it )
( *it )->setDisplayNodes( display );
scene()->update();
}
void QgsComposerView::setSelectedNode( QgsComposerNodesItem *shape,
const int index )
{
QList<QgsComposerNodesItem*> nodesShapes;
composition()->composerItems( nodesShapes );
QList<QgsComposerNodesItem*>::iterator it = nodesShapes.begin();
for ( ; it != nodesShapes.end(); ++it )
{
if (( *it ) == shape )
{
( *it )->setSelectedNode( index );
selectNone();
( *it )->setSelected( true );
emit selectedItemChanged(( *it ) );
}
else
( *it )->unselectNode();
}
scene()->update();
}
void QgsComposerView::unselectNode()
{
QList<QgsComposerNodesItem*> nodesShapes;
composition()->composerItems( nodesShapes );
QList<QgsComposerNodesItem*>::iterator it = nodesShapes.begin();
for ( ; it != nodesShapes.end(); ++it )
( *it )->unselectNode();
scene()->update();
}

View File

@ -20,6 +20,7 @@
#include <QGraphicsView>
#include "qgsaddremoveitemcommand.h"
#include "qgsprevieweffect.h" // for QgsPreviewEffect::PreviewMode
#include <QGraphicsPolygonItem>
class QDomDocument;
class QDomElement;
@ -36,6 +37,7 @@ class QgsComposerPicture;
class QgsComposerRuler;
class QgsComposerScaleBar;
class QgsComposerShape;
class QgsComposerNodesItem;
class QgsComposerAttributeTableV2;
/** \ingroup MapComposer
@ -63,10 +65,13 @@ class GUI_EXPORT QgsComposerView: public QGraphicsView
AddPicture, // add raster/vector picture
AddRectangle,
AddEllipse,
AddPolygon,
AddPolyline,
AddTriangle,
AddTable, // add attribute table
AddAttributeTable,
MoveItemContent, // move content of item (e.g. content of map)
EditNodesItem,
Pan,
Zoom
};
@ -208,6 +213,19 @@ class GUI_EXPORT QgsComposerView: public QGraphicsView
/** Draw a shape on the canvas */
void addShape( Tool currentTool );
/** Point based shape stuff */
void addPolygonNode( const QPointF & scenePoint );
void movePolygonNode( const QPointF & scenePoint );
void displayNodes( const bool display = true );
void setSelectedNode( QgsComposerNodesItem *shape, const int index );
void unselectNode();
float mMoveContentSearchRadius;
QgsComposerNodesItem* mNodesItem;
int mNodesItemIndex;
QScopedPointer<QGraphicsPolygonItem> mPolygonItem;
QScopedPointer<QGraphicsPathItem> mPolylineItem;
/** True if user is currently panning by clicking and dragging with the pan tool*/
bool mToolPanning;
/** True if user is currently panning by holding the middle mouse button*/

View File

@ -52,8 +52,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>118</width>
<height>78</height>
<width>116</width>
<height>76</height>
</rect>
</property>
</widget>
@ -133,6 +133,7 @@
<addaction name="mActionMouseZoom"/>
<addaction name="mActionSelectMoveItem"/>
<addaction name="mActionMoveItemContent"/>
<addaction name="mActionEditNodesItem"/>
<addaction name="separator"/>
<addaction name="mActionAddNewMap"/>
<addaction name="mActionAddImage"/>
@ -1057,6 +1058,47 @@
<string>Show pages</string>
</property>
</action>
<action name="mActionAddPolygon">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Add Polygon</string>
</property>
<property name="toolTip">
<string>Add polygon</string>
</property>
</action>
<action name="mActionNodesItem">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Nodes item</string>
</property>
<property name="toolTip">
<string>Nodes item</string>
</property>
</action>
<action name="mActionAddPolyline">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Add Polyline</string>
</property>
<property name="toolTip">
<string>Add polyline</string>
</property>
</action>
<action name="mActionEditNodesItem">
<property name="text">
<string>Edit Nodes Item</string>
</property>
<property name="toolTip">
<string>Edit Nodes Item</string>
</property>
</action>
</widget>
<resources>
<include location="../../../images/images.qrc"/>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsComposerPolygonWidgetBase</class>
<widget class="QWidget" name="QgsComposerPolygonWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>285</width>
<height>100</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">padding: 2px; font-weight: bold; background-color: rgb(200, 200, 200);</string>
</property>
<property name="text">
<string>Shape</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>281</width>
<height>78</height>
</rect>
</property>
<layout class="QVBoxLayout" name="mainLayout">
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="title">
<string>Main properties</string>
</property>
<property name="syncGroup" stdset="0">
<string notr="true">composeritem</string>
</property>
<property name="collapsed" stdset="0">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Style</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="mPolygonStyleButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Change...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsCollapsibleGroupBoxBasic</class>
<extends>QGroupBox</extends>
<header location="global">qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>groupBox</tabstop>
<tabstop>scrollArea</tabstop>
<tabstop>mPolygonStyleButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsComposerPolylineWidgetBase</class>
<widget class="QWidget" name="QgsComposerPolylineWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>115</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">padding: 2px; font-weight: bold; background-color: rgb(200, 200, 200);</string>
</property>
<property name="text">
<string>Arrow</string>
</property>
</widget>
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>330</width>
<height>93</height>
</rect>
</property>
<layout class="QVBoxLayout" name="mainLayout">
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="title">
<string>Main properties</string>
</property>
<property name="syncGroup" stdset="0">
<string notr="true">composeritem</string>
</property>
<property name="collapsed" stdset="0">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="mLineStyleButton">
<property name="text">
<string>Line style...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsCollapsibleGroupBoxBasic</class>
<extends>QGroupBox</extends>
<header location="global">qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>scrollArea</tabstop>
<tabstop>mLineStyleButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -23,6 +23,8 @@ ADD_PYTHON_TEST(PyQgsComposerMap test_qgscomposermap.py)
ADD_PYTHON_TEST(PyQgsComposerMapGrid test_qgscomposermapgrid.py)
ADD_PYTHON_TEST(PyQgsComposerPicture test_qgscomposerpicture.py)
ADD_PYTHON_TEST(PyQgsComposerShapes test_qgscomposershapes.py)
ADD_PYTHON_TEST(PyQgsComposerPolygon test_qgscomposerpolygon.py)
ADD_PYTHON_TEST(PyQgsComposerPolyline test_qgscomposerpolyline.py)
ADD_PYTHON_TEST(PyQgsComposition test_qgscomposition.py)
ADD_PYTHON_TEST(PyQgsConditionalStyle test_qgsconditionalstyle.py)
ADD_PYTHON_TEST(PyQgsCoordinateTransform test_qgscoordinatetransform.py)

View File

@ -0,0 +1,234 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsComposerPolygon.
.. note:: 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.
"""
__author__ = '(C) 2016 by Paul Blottiere'
__date__ = '14/03/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis
from PyQt4.QtGui import QColor
from PyQt4.QtGui import QPolygonF
from PyQt4.QtCore import QPointF
from qgis.core import (QgsComposerPolygon,
QgsComposerItem,
QgsComposition,
QgsMapSettings,
QgsFillSymbolV2
)
from qgis.testing import (start_app,
unittest
)
from utilities import unitTestDataPath
from qgscompositionchecker import QgsCompositionChecker
start_app()
TEST_DATA_DIR = unitTestDataPath()
class TestQgsComposerPolygon(unittest.TestCase):
def __init__(self, methodName):
"""Run once on class initialization."""
unittest.TestCase.__init__(self, methodName)
self.mapSettings = QgsMapSettings()
# create composition
self.mComposition = QgsComposition(self.mapSettings)
self.mComposition.setPaperSize(297, 210)
# create
polygon = QPolygonF()
polygon.append(QPointF(0.0, 0.0))
polygon.append(QPointF(100.0, 0.0))
polygon.append(QPointF(200.0, 100.0))
polygon.append(QPointF(100.0, 200.0))
self.mComposerPolygon = QgsComposerPolygon(polygon, self.mComposition)
self.mComposition.addComposerPolygon(self.mComposerPolygon)
# style
props = {}
props["color"] = "green"
props["style"] = "solid"
props["style_border"] = "solid"
props["color_border"] = "black"
props["width_border"] = "10.0"
props["joinstyle"] = "miter"
style = QgsFillSymbolV2.createSimple(props)
self.mComposerPolygon.setPolygonStyleSymbol(style)
def testDisplayName(self):
"""Test if displayName is valid"""
self.assertEqual(self.mComposerPolygon.displayName(), "<polygon>")
def testType(self):
"""Test if type is valid"""
self.assertEqual(
self.mComposerPolygon.type(), QgsComposerItem.ComposerPolygon)
def testDefaultStyle(self):
"""Test polygon rendering with default style."""
self.mComposerPolygon.setDisplayNodes(False)
checker = QgsCompositionChecker(
'composerpolygon_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testDisplayNodes(self):
"""Test displayNodes method"""
self.mComposerPolygon.setDisplayNodes(True)
checker = QgsCompositionChecker(
'composerpolygon_displaynodes', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
self.mComposerPolygon.setDisplayNodes(False)
checker = QgsCompositionChecker(
'composerpolygon_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testSelectedNode(self):
"""Test selectedNode and unselectNode methods"""
self.mComposerPolygon.setDisplayNodes(True)
self.mComposerPolygon.setSelectedNode(3)
checker = QgsCompositionChecker(
'composerpolygon_selectednode', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
self.mComposerPolygon.unselectNode()
self.mComposerPolygon.setDisplayNodes(False)
checker = QgsCompositionChecker(
'composerpolygon_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testRemoveNode(self):
"""Test removeNode method"""
rc = self.mComposerPolygon.removeNode(100)
self.assertEqual(rc, False)
checker = QgsCompositionChecker(
'composerpolygon_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
rc = self.mComposerPolygon.removeNode(3)
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolygon.nodesSize(), 3)
checker = QgsCompositionChecker(
'composerpolygon_removednode', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testAddNode(self):
"""Test addNode method"""
# default searching radius is 10
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
rc = self.mComposerPolygon.addNode(QPointF(50.0, 10.0))
self.assertEqual(rc, False)
# default searching radius is 10
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
rc = self.mComposerPolygon.addNode(QPointF(50.0, 9.99))
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolygon.nodesSize(), 5)
def testAddNodeCustomRadius(self):
"""Test addNode with custom radius"""
# default searching radius is 10
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
rc = self.mComposerPolygon.addNode(QPointF(50.0, 8.1), True, 8.0)
self.assertEqual(rc, False)
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
# default searching radius is 10
rc = self.mComposerPolygon.addNode(QPointF(50.0, 7.9), True, 8.0)
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolygon.nodesSize(), 5)
def testAddNodeWithoutCheckingArea(self):
"""Test addNode without checking the maximum distance allowed"""
# default searching radius is 10
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
rc = self.mComposerPolygon.addNode(QPointF(50.0, 20.0))
self.assertEqual(rc, False)
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
# default searching radius is 10
self.assertEqual(self.mComposerPolygon.nodesSize(), 4)
rc = self.mComposerPolygon.addNode(QPointF(50.0, 20.0), False)
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolygon.nodesSize(), 5)
checker = QgsCompositionChecker(
'composerpolygon_addnode', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testMoveNode(self):
"""Test moveNode method"""
rc = self.mComposerPolygon.moveNode(30, QPointF(100.0, 300.0))
self.assertEqual(rc, False)
rc = self.mComposerPolygon.moveNode(3, QPointF(100.0, 150.0))
self.assertEqual(rc, True)
checker = QgsCompositionChecker(
'composerpolygon_movenode', self.mComposition)
checker.setControlPathPrefix("composer_polygon")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testNodeAtPosition(self):
"""Test nodeAtPosition method"""
# default searching radius is 10
rc = self.mComposerPolygon.nodeAtPosition(QPointF(100.0, 210.0))
self.assertEqual(rc, -1)
# default searching radius is 10
rc = self.mComposerPolygon.nodeAtPosition(
QPointF(100.0, 210.0), False)
self.assertEqual(rc, 3)
# default searching radius is 10
rc = self.mComposerPolygon.nodeAtPosition(
QPointF(100.0, 210.0), True, 10.1)
self.assertEqual(rc, 3)
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1,232 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsComposerPolyline.
.. note:: 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.
"""
__author__ = '(C) 2016 by Paul Blottiere'
__date__ = '14/03/2016'
__copyright__ = 'Copyright 2016, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis
from PyQt4.QtGui import QColor
from PyQt4.QtGui import QPolygonF
from PyQt4.QtCore import QPointF
from qgis.core import (QgsComposerPolyline,
QgsComposerItem,
QgsComposition,
QgsMapSettings,
QgsLineSymbolV2
)
from qgis.testing import (start_app,
unittest
)
from utilities import unitTestDataPath
from qgscompositionchecker import QgsCompositionChecker
start_app()
TEST_DATA_DIR = unitTestDataPath()
class TestQgsComposerPolyline(unittest.TestCase):
def __init__(self, methodName):
"""Run once on class initialization."""
unittest.TestCase.__init__(self, methodName)
self.mapSettings = QgsMapSettings()
# create composition
self.mComposition = QgsComposition(self.mapSettings)
self.mComposition.setPaperSize(297, 210)
# create
polygon = QPolygonF()
polygon.append(QPointF(0.0, 0.0))
polygon.append(QPointF(100.0, 0.0))
polygon.append(QPointF(200.0, 100.0))
polygon.append(QPointF(100.0, 200.0))
self.mComposerPolyline = QgsComposerPolyline(
polygon, self.mComposition)
self.mComposition.addComposerPolyline(self.mComposerPolyline)
# style
props = {}
props["color"] = "0,0,0,255"
props["width"] = "10.0"
props["capstyle"] = "square"
style = QgsLineSymbolV2.createSimple(props)
self.mComposerPolyline.setPolylineStyleSymbol(style)
def testDisplayName(self):
"""Test if displayName is valid"""
self.assertEqual(self.mComposerPolyline.displayName(), "<polyline>")
def testType(self):
"""Test if type is valid"""
self.assertEqual(
self.mComposerPolyline.type(), QgsComposerItem.ComposerPolyline)
def testDefaultStyle(self):
"""Test polygon rendering with default style."""
self.mComposerPolyline.setDisplayNodes(False)
checker = QgsCompositionChecker(
'composerpolyline_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testDisplayNodes(self):
"""Test displayNodes method"""
self.mComposerPolyline.setDisplayNodes(True)
checker = QgsCompositionChecker(
'composerpolyline_displaynodes', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
self.mComposerPolyline.setDisplayNodes(False)
checker = QgsCompositionChecker(
'composerpolyline_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testSelectedNode(self):
"""Test selectedNode and unselectNode methods"""
self.mComposerPolyline.setDisplayNodes(True)
self.mComposerPolyline.setSelectedNode(3)
checker = QgsCompositionChecker(
'composerpolyline_selectednode', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
self.mComposerPolyline.unselectNode()
self.mComposerPolyline.setDisplayNodes(False)
checker = QgsCompositionChecker(
'composerpolyline_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testRemoveNode(self):
"""Test removeNode method"""
rc = self.mComposerPolyline.removeNode(100)
self.assertEqual(rc, False)
checker = QgsCompositionChecker(
'composerpolyline_defaultstyle', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
rc = self.mComposerPolyline.removeNode(3)
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolyline.nodesSize(), 3)
checker = QgsCompositionChecker(
'composerpolyline_removednode', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testAddNode(self):
"""Test addNode method"""
# default searching radius is 10
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
rc = self.mComposerPolyline.addNode(QPointF(50.0, 10.0))
self.assertEqual(rc, False)
# default searching radius is 10
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
rc = self.mComposerPolyline.addNode(QPointF(50.0, 9.99))
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolyline.nodesSize(), 5)
def testAddNodeCustomRadius(self):
"""Test addNode with custom radius"""
# default searching radius is 10
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
rc = self.mComposerPolyline.addNode(QPointF(50.0, 8.1), True, 8.0)
self.assertEqual(rc, False)
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
# default searching radius is 10
rc = self.mComposerPolyline.addNode(QPointF(50.0, 7.9), True, 8.0)
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolyline.nodesSize(), 5)
def testAddNodeWithoutCheckingArea(self):
"""Test addNode without checking the maximum distance allowed"""
# default searching radius is 10
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
rc = self.mComposerPolyline.addNode(QPointF(50.0, 20.0))
self.assertEqual(rc, False)
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
# default searching radius is 10
self.assertEqual(self.mComposerPolyline.nodesSize(), 4)
rc = self.mComposerPolyline.addNode(QPointF(50.0, 20.0), False)
self.assertEqual(rc, True)
self.assertEqual(self.mComposerPolyline.nodesSize(), 5)
checker = QgsCompositionChecker(
'composerpolyline_addnode', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testMoveNode(self):
"""Test moveNode method"""
rc = self.mComposerPolyline.moveNode(30, QPointF(100.0, 300.0))
self.assertEqual(rc, False)
rc = self.mComposerPolyline.moveNode(3, QPointF(100.0, 150.0))
self.assertEqual(rc, True)
checker = QgsCompositionChecker(
'composerpolyline_movenode', self.mComposition)
checker.setControlPathPrefix("composer_polyline")
myTestResult, myMessage = checker.testComposition()
assert myTestResult, myMessage
def testNodeAtPosition(self):
"""Test nodeAtPosition method"""
# default searching radius is 10
rc = self.mComposerPolyline.nodeAtPosition(QPointF(100.0, 210.0))
self.assertEqual(rc, -1)
# default searching radius is 10
rc = self.mComposerPolyline.nodeAtPosition(
QPointF(100.0, 210.0), False)
self.assertEqual(rc, 3)
# default searching radius is 10
rc = self.mComposerPolyline.nodeAtPosition(
QPointF(100.0, 210.0), True, 10.1)
self.assertEqual(rc, 3)
if __name__ == '__main__':
unittest.main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB