[FEATURE] add functionnality to copy/move feature to move feature map tool

This commit is contained in:
Denis Rouzaud 2016-11-01 16:03:05 +01:00
parent 9ddf78e39f
commit a373f95707
26 changed files with 3467 additions and 41 deletions

View File

@ -583,6 +583,9 @@
<file>themes/default/mIconSnappingSegment.svg</file>
<file>themes/default/mIconTopologicalEditing.svg</file>
<file>themes/default/mIconSnappingIntersection.svg</file>
<file>themes/default/mActionMoveFeatureCopy.svg</file>
<file>themes/default/mActionMoveFeatureCopyLine.svg</file>
<file>themes/default/mActionMoveFeatureCopyPoint.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 39 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1,729 @@
<?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.91 r13725"
sodipodi:docname="mActionMoveFeatureCopyPoint.svg"
inkscape:export-filename="/home/robert/prv/projekty/osgeographics/trunk/toolbar-icons/24x24/ring-fill2.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
style="display:inline"
viewBox="0 0 24 24">
<title
id="title3062">ring fill</title>
<defs
id="defs5694">
<linearGradient
id="linearGradient3657">
<stop
style="stop-color:#fce94f;stop-opacity:1;"
offset="0"
id="stop3659" />
<stop
style="stop-color:#e7ce04;stop-opacity:1;"
offset="1"
id="stop3661" />
</linearGradient>
<linearGradient
id="linearGradient2877">
<stop
style="stop-color:#edd400;stop-opacity:1;"
offset="0"
id="stop2879" />
<stop
style="stop-color:#c2ad00;stop-opacity:1;"
offset="1"
id="stop2881" />
</linearGradient>
<linearGradient
id="linearGradient4042">
<stop
style="stop-color:#f2d6a9;stop-opacity:1;"
offset="0"
id="stop4044" />
<stop
style="stop-color:#e9b96e;stop-opacity:1;"
offset="1"
id="stop4046" />
</linearGradient>
<linearGradient
id="linearGradient2843">
<stop
style="stop-color:#eeeeec;stop-opacity:1;"
offset="0"
id="stop2845" />
<stop
style="stop-color:#c8c8c2;stop-opacity:1;"
offset="1"
id="stop2847" />
</linearGradient>
<linearGradient
id="linearGradient2835">
<stop
style="stop-color:#ccf2a6;stop-opacity:1;"
offset="0"
id="stop2837" />
<stop
style="stop-color:#8ae234;stop-opacity:1;"
offset="1"
id="stop2839" />
</linearGradient>
<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="perspective3257" />
<inkscape:perspective
id="perspective6979"
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="perspective7934"
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="perspective8023"
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="perspective8057"
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="perspective8095"
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="perspective8219"
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="perspective8279"
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="perspective3803"
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="perspective3869"
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="perspective3929"
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="perspective3968"
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="perspective4002"
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="perspective4032"
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="perspective4053"
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="perspective2905"
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="perspective2979"
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="perspective2842"
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="perspective2978"
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="perspective3238"
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" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042"
id="radialGradient4048"
cx="0.5"
cy="17.838446"
fx="0.5"
fy="17.838446"
r="6.1587391"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-0.4170292)"
gradientUnits="userSpaceOnUse" />
<inkscape:perspective
id="perspective4058"
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" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042-2"
id="radialGradient4048-2"
cx="8.5770311"
cy="3.8663561"
fx="8.5770311"
fy="3.8663561"
r="6.1587391"
gradientTransform="matrix(0.81185454,1.1365964,-1.1707271,0.83623306,20.063146,-1.4817979)"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient4042-2">
<stop
style="stop-color:#f2d6a9;stop-opacity:1;"
offset="0"
id="stop4044-8" />
<stop
style="stop-color:#e9b96e;stop-opacity:1;"
offset="1"
id="stop4046-4" />
</linearGradient>
<radialGradient
r="6.1587391"
fy="17.838446"
fx="0.5"
cy="17.838446"
cx="0.5"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-8.4170292)"
gradientUnits="userSpaceOnUse"
id="radialGradient4067"
xlink:href="#linearGradient4042-2"
inkscape:collect="always" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042-2"
id="radialGradient4094"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.81185454,1.1365964,-1.1707271,0.83623306,20.063146,-1.4817979)"
cx="8.5770311"
cy="3.8663561"
fx="8.5770311"
fy="3.8663561"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042-2"
id="radialGradient4097"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.81185454,1.1365964,-1.1707271,0.83623306,20.063146,-1.4817979)"
cx="8.5770311"
cy="3.8663561"
fx="8.5770311"
fy="3.8663561"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042-2"
id="radialGradient4100"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.81185454,1.1365964,-1.1707271,0.83623306,20.063146,-1.4817979)"
cx="8.5770311"
cy="3.8663561"
fx="8.5770311"
fy="3.8663561"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042-2"
id="radialGradient4103"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.81185454,1.1365964,-1.1707271,0.83623306,20.063146,-1.4817979)"
cx="8.5770311"
cy="3.8663561"
fx="8.5770311"
fy="3.8663561"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042"
id="radialGradient4106"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-0.4170292)"
cx="0.5"
cy="17.838446"
fx="0.5"
fy="17.838446"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042"
id="radialGradient4109"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-0.4170292)"
cx="0.5"
cy="17.838446"
fx="0.5"
fy="17.838446"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042"
id="radialGradient4112"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-0.4170292)"
cx="0.5"
cy="17.838446"
fx="0.5"
fy="17.838446"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042"
id="radialGradient4115"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-0.4170292)"
cx="0.5"
cy="17.838446"
fx="0.5"
fy="17.838446"
r="6.1587391" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient4042"
id="radialGradient4118"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8118545,0.97422537,-1.1052481,0.9210397,19.809981,-0.4170292)"
cx="0.5"
cy="17.838446"
fx="0.5"
fy="17.838446"
r="6.1587391" />
<inkscape:perspective
id="perspective8198"
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" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3657"
id="linearGradient3663"
x1="10.5"
y1="10.5"
x2="13.5"
y2="18.5"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3657"
id="linearGradient3669"
gradientUnits="userSpaceOnUse"
x1="10.5"
y1="10.5"
x2="13.5"
y2="18.5"
gradientTransform="translate(0,-3)" />
<inkscape:perspective
id="perspective4821"
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="perspective5232"
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="perspective6154"
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="perspective6239"
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" />
<linearGradient
y2="20"
x2="10"
y1="20"
x1="2"
gradientUnits="userSpaceOnUse"
id="linearGradient4708"
xlink:href="#linearGradient4661"
inkscape:collect="always" />
<linearGradient
id="linearGradient4661">
<stop
id="stop4663"
offset="0"
style="stop-color:#969696;stop-opacity:1;" />
<stop
id="stop4665"
offset="1"
style="stop-color:#969696;stop-opacity:0.26618704;" />
</linearGradient>
<inkscape:perspective
id="perspective4824"
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="perspective4958"
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="perspective7037"
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="perspective7037-6"
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="perspective9252"
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" />
<linearGradient
gradientUnits="userSpaceOnUse"
y2="5"
x2="4"
y1="9"
x1="10"
id="linearGradient4697"
xlink:href="#linearGradient4691"
inkscape:collect="always" />
<linearGradient
id="linearGradient4691">
<stop
id="stop4693"
offset="0"
style="stop-color:#bebebe;stop-opacity:1;" />
<stop
id="stop4695"
offset="1"
style="stop-color:#d7d7d7;stop-opacity:1;" />
</linearGradient>
<inkscape:perspective
id="perspective9601"
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="perspective9668"
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="perspective9711"
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="perspective9763"
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" />
<linearGradient
id="linearGradient4691-5">
<stop
id="stop4693-1"
offset="0"
style="stop-color:#5a8c5a;stop-opacity:1;" />
<stop
id="stop4695-3"
offset="1"
style="stop-color:#9dc09d;stop-opacity:1;" />
</linearGradient>
<linearGradient
y2="5"
x2="4"
y1="9"
x1="10"
gradientTransform="matrix(1.4943452,0,0,1.5138186,-1.3825451,-1.7707278)"
gradientUnits="userSpaceOnUse"
id="linearGradient3079"
xlink:href="#linearGradient4691-5"
inkscape:collect="always" />
<linearGradient
gradientTransform="translate(0,8)"
y2="21"
x2="23"
y1="15"
x1="23"
gradientUnits="userSpaceOnUse"
id="linearGradient5188"
xlink:href="#linearGradient4137"
inkscape:collect="always" />
<linearGradient
id="linearGradient4137">
<stop
id="stop4139"
offset="0"
style="stop-color:#555753;stop-opacity:1;" />
<stop
id="stop4141"
offset="1"
style="stop-color:#555753;stop-opacity:0;" />
</linearGradient>
<linearGradient
y2="21"
x2="23"
y1="15"
x1="23"
gradientTransform="translate(-33)"
gradientUnits="userSpaceOnUse"
id="linearGradient3111"
xlink:href="#linearGradient4137"
inkscape:collect="always" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4137"
id="linearGradient3111-0"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(27.5,1.9999985)"
x1="23"
y1="15"
x2="23"
y2="21" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="45.254832"
inkscape:cx="10.453881"
inkscape:cy="14.579098"
inkscape:current-layer="layer4"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
borderlayer="false"
inkscape:window-width="1916"
inkscape:window-height="1155"
inkscape:window-x="4"
inkscape:window-y="1"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid5700"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
dotted="true"
originx="0.5px"
originy="0.5px"
spacingx="0.5px"
spacingy="0.5px" />
</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>ring fill</dc:title>
<dc:date>2014-02-04</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Robert Szczepanek</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:rights>
<dc:subject>
<rdf:Bag>
<rdf:li>ring fill</rdf:li>
</rdf:Bag>
</dc:subject>
<dc:coverage>GIS icons 0.2</dc:coverage>
<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="layer4"
inkscape:label="1"
style="display:inline"
transform="translate(0,-8)">
<rect
style="opacity:1;fill:#72b072;fill-opacity:1;stroke:#383838;stroke-width:1.33333325;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.93333334"
id="rect4294"
width="6.6666665"
height="6.6666665"
x="1.6666666"
y="15.666667"
rx="4.1666665"
ry="4.1666665" />
<rect
style="display:inline;opacity:1;fill:#a6cca6;fill-opacity:1;stroke:#5f615f;stroke-width:1.33333325;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.95686275"
id="rect4294-9"
width="6.6666665"
height="6.6666665"
x="10.412337"
y="9.6995983"
rx="4.1666665"
ry="4.1666665" />
<g
style="display:inline"
id="g4394"
transform="translate(-27.5,6.0000005)">
<rect
rx="2.0114901"
style="display:inline;fill:#3c5a6e;fill-opacity:1;stroke:url(#linearGradient3111-0);stroke-width:0;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
id="rect2730-8"
width="11"
height="11"
x="40.5"
y="14.999999"
inkscape:export-xdpi="120"
inkscape:export-ydpi="120"
ry="2.0114901" />
<path
inkscape:connector-curvature="0"
style="display:inline;opacity:0.3;fill:#fcffff;fill-rule:evenodd;stroke:none;enable-background:new"
d="M 41.500001,20.999999 50.5,20.9904 c 0,0 0,0 0,-2 0,-2.990401 -1,-2.990401 -4.5,-2.990401 -3.5,0 -4.5,0 -4.5,3 0,2 0,2 10e-7,2 z"
id="path4133-4"
sodipodi:nodetypes="ccsssc" />
<path
sodipodi:nodetypes="cccccccc"
inkscape:connector-curvature="0"
id="path4638"
d="M 45.5,15.999999 V 19 h -4 v 3 h 4 v 2.999999 l 5,-4 z"
style="display:inline;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -139,6 +139,7 @@
%Include qgstextrenderer.sip
%Include qgstolerance.sip
%Include qgstracer.sip
%Include qgstrackedvectorlayertools.sip
%Include qgsunittypes.sip
%Include qgsvectordataprovider.sip
%Include qgsvectorfilewriter.sip
@ -148,6 +149,7 @@
%Include qgsvectorlayereditpassthrough.sip
%Include qgsvectorlayerimport.sip
%Include qgsvectorlayerjoinbuffer.sip
%Include qgsvectorlayertools.sip
%Include qgsvectorlayerundocommand.sip
%Include qgsvectorlayerutils.sip
%Include qgsvectorsimplifymethod.sip

View File

@ -25,6 +25,7 @@ class QgsTrackedVectorLayerTools : QgsVectorLayerTools
bool startEditing( QgsVectorLayer* layer ) const ;
bool stopEditing( QgsVectorLayer* layer, bool allowCancel ) const ;
bool saveEdits( QgsVectorLayer* layer ) const ;
bool copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest &request, double dx = 0, double dy = 0, QString *errorMsg = nullptr ) const;
/**
* Set the vector layer tools that will be used to interact with the data

View File

@ -1,9 +1,12 @@
class QgsVectorLayerTools
class QgsVectorLayerTools : QObject
{
%TypeHeaderCode
#include <qgsvectorlayertools.h>
%End
public:
QgsVectorLayerTools();
virtual ~QgsVectorLayerTools();
/**
* This method should/will be called, whenever a new feature will be added to the layer
@ -45,4 +48,17 @@ class QgsVectorLayerTools
*/
virtual bool saveEdits( QgsVectorLayer* layer ) const = 0;
/**
* Copy and move features with defined translation.
*
* @param layer The layer
* @param request The request for the features to be moved. It will be assigned to a new feature request with the newly copied features.
* @param dx The translation on x
* @param dy The translation on y
* @param errorMsg If given, it will contain the error message
* @return True if all features could be copied.
*
* TODO QGIS 3: remove const qualifier
*/
virtual bool copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest &request /In,Out/, double dx = 0, double dy = 0, QString* errorMsg /Out/ = nullptr ) const;
};

View File

@ -165,12 +165,10 @@
%Include qgstextannotationitem.sip
%Include qgstextformatwidget.sip
%Include qgstextpreview.sip
%Include qgstrackedvectorlayertools.sip
%Include qgstreewidgetitem.sip
%Include qgsunitselectionwidget.sip
%Include qgsuserinputdockwidget.sip
%Include qgsvariableeditorwidget.sip
%Include qgsvectorlayertools.sip
%Include qgsvertexmarker.sip
%Include attributetable/qgsattributetabledelegate.sip

View File

@ -61,7 +61,6 @@ def get_iface():
canvas = QgsMapCanvas(my_iface.mainWindow())
canvas.resize(QSize(400, 400))
my_iface.mapCanvas.return_value = canvas
return my_iface

View File

@ -1248,6 +1248,7 @@ QgisApp::~QgisApp()
delete mMapTools.mMeasureArea;
delete mMapTools.mMeasureDist;
delete mMapTools.mMoveFeature;
delete mMapTools.mMoveFeatureCopy;
delete mMapTools.mMoveLabel;
delete mMapTools.mNodeTool;
delete mMapTools.mOffsetCurve;
@ -1584,6 +1585,7 @@ void QgisApp::createActions()
connect( mActionCircularStringCurvePoint, SIGNAL( triggered() ), this, SLOT( circularStringCurvePoint() ) );
connect( mActionCircularStringRadius, SIGNAL( triggered() ), this, SLOT( circularStringRadius() ) );
connect( mActionMoveFeature, SIGNAL( triggered() ), this, SLOT( moveFeature() ) );
connect( mActionMoveFeatureCopy, &QAction::triggered, this, &QgisApp::moveFeatureCopy );
connect( mActionRotateFeature, SIGNAL( triggered() ), this, SLOT( rotateFeature() ) );
connect( mActionReshapeFeatures, SIGNAL( triggered() ), this, SLOT( reshapeFeatures() ) );
@ -1876,6 +1878,7 @@ void QgisApp::createActionGroups()
mMapToolGroup->addAction( mActionCircularStringCurvePoint );
mMapToolGroup->addAction( mActionCircularStringRadius );
mMapToolGroup->addAction( mActionMoveFeature );
mMapToolGroup->addAction( mActionMoveFeatureCopy );
mMapToolGroup->addAction( mActionRotateFeature );
mMapToolGroup->addAction( mActionOffsetCurve );
mMapToolGroup->addAction( mActionReshapeFeatures );
@ -2328,6 +2331,25 @@ void QgisApp::createToolBars()
layout->itemAt( i )->setAlignment( Qt::AlignLeft );
}
// move feature tool button
QToolButton* moveFeatureButton = new QToolButton( mDigitizeToolBar );
moveFeatureButton->setPopupMode( QToolButton::MenuButtonPopup );
moveFeatureButton->addAction( mActionMoveFeature );
moveFeatureButton->addAction( mActionMoveFeatureCopy );
QAction* defAction = mActionMoveFeature;
switch ( settings.value( QStringLiteral( "/UI/defaultMoveTool" ), 0 ).toInt() )
{
case 0:
defAction = mActionMoveFeature;
break;
case 1:
defAction = mActionMoveFeatureCopy;
break;
};
moveFeatureButton->setDefaultAction( defAction );
connect( moveFeatureButton, SIGNAL( triggered( QAction * ) ), this, SLOT( toolButtonActionTriggered( QAction * ) ) );
mDigitizeToolBar->insertWidget( mActionNodeTool, moveFeatureButton );
//circular string digitize tool button
QToolButton* tbAddCircularString = new QToolButton( mDigitizeToolBar );
tbAddCircularString->setPopupMode( QToolButton::MenuButtonPopup );
@ -2617,6 +2639,7 @@ void QgisApp::setTheme( const QString& theThemeName )
mActionPasteFeatures->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionEditPaste.svg" ) ) );
mActionAddFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) ) );
mActionMoveFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeaturePoint.svg" ) ) );
mActionMoveFeatureCopy->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeatureCopyPoint.svg" ) ) );
mActionRotateFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRotateFeature.svg" ) ) );
mActionReshapeFeatures->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionReshape.svg" ) ) );
mActionSplitFeatures->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSplitFeatures.svg" ) ) );
@ -2855,8 +2878,10 @@ void QgisApp::createCanvasTools()
mMapTools.mCircularStringCurvePoint->setAction( mActionCircularStringCurvePoint );
mMapTools.mCircularStringRadius = new QgsMapToolCircularStringRadius( dynamic_cast<QgsMapToolAddFeature*>( mMapTools.mAddFeature ), mMapCanvas );
mMapTools.mCircularStringRadius->setAction( mActionCircularStringRadius );
mMapTools.mMoveFeature = new QgsMapToolMoveFeature( mMapCanvas );
mMapTools.mMoveFeature = new QgsMapToolMoveFeature( mMapCanvas, QgsMapToolMoveFeature::Move );
mMapTools.mMoveFeature->setAction( mActionMoveFeature );
mMapTools.mMoveFeatureCopy = new QgsMapToolMoveFeature( mMapCanvas, QgsMapToolMoveFeature::CopyMove );
mMapTools.mMoveFeatureCopy->setAction( mActionMoveFeatureCopy );
mMapTools.mRotateFeature = new QgsMapToolRotateFeature( mMapCanvas );
mMapTools.mRotateFeature->setAction( mActionRotateFeature );
mMapTools.mOffsetCurve = new QgsMapToolOffsetCurve( mMapCanvas );
@ -6485,6 +6510,11 @@ void QgisApp::moveFeature()
mMapCanvas->setMapTool( mMapTools.mMoveFeature );
}
void QgisApp::moveFeatureCopy()
{
mMapCanvas->setMapTool( mMapTools.mMoveFeatureCopy );
}
void QgisApp::offsetCurve()
{
mMapCanvas->setMapTool( mMapTools.mOffsetCurve );
@ -10526,6 +10556,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionCircularStringCurvePoint->setEnabled( false );
mActionCircularStringRadius->setEnabled( false );
mActionMoveFeature->setEnabled( false );
mActionMoveFeatureCopy->setEnabled( false );
mActionRotateFeature->setEnabled( false );
mActionOffsetCurve->setEnabled( false );
mActionNodeTool->setEnabled( false );
@ -10680,6 +10711,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddPart->setEnabled( isEditable && canChangeGeometry );
mActionDeletePart->setEnabled( isEditable && canChangeGeometry );
mActionMoveFeature->setEnabled( isEditable && canChangeGeometry );
mActionMoveFeatureCopy->setEnabled( isEditable && canChangeGeometry );
mActionRotateFeature->setEnabled( isEditable && canChangeGeometry );
mActionNodeTool->setEnabled( isEditable && canChangeGeometry );
@ -10690,6 +10722,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
{
mActionAddFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePoint.svg" ) ) );
mActionMoveFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeaturePoint.svg" ) ) );
mActionMoveFeatureCopy->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeatureCopyPoint.svg" ) ) );
mActionAddRing->setEnabled( false );
mActionFillRing->setEnabled( false );
@ -10718,6 +10751,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
{
mActionAddFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionCaptureLine.svg" ) ) );
mActionMoveFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeatureLine.svg" ) ) );
mActionMoveFeatureCopy->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeatureCopyLine.svg" ) ) );
mActionReshapeFeatures->setEnabled( isEditable && canChangeGeometry );
mActionSplitFeatures->setEnabled( isEditable && canAddFeatures );
@ -10733,6 +10767,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
{
mActionAddFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionCapturePolygon.svg" ) ) );
mActionMoveFeature->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeature.svg" ) ) );
mActionMoveFeatureCopy->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMoveFeatureCopy.svg" ) ) );
mActionAddRing->setEnabled( isEditable && canChangeGeometry );
mActionFillRing->setEnabled( isEditable && canChangeGeometry );
@ -10819,6 +10854,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddPart->setEnabled( false );
mActionNodeTool->setEnabled( false );
mActionMoveFeature->setEnabled( false );
mActionMoveFeatureCopy->setEnabled( false );
mActionRotateFeature->setEnabled( false );
mActionOffsetCurve->setEnabled( false );
mActionCopyFeatures->setEnabled( false );
@ -11846,6 +11882,10 @@ void QgisApp::toolButtonActionTriggered( QAction *action )
settings.setValue( QStringLiteral( "/UI/defaultMapService" ), 0 );
else if ( action == mActionAddAmsLayer )
settings.setValue( QStringLiteral( "/UI/defaultMapService" ), 1 );
else if ( action == mActionMoveFeature )
settings.setValue( QStringLiteral( "/UI/defaultMoveTool" ), 0 );
else if ( action == mActionMoveFeatureCopy )
settings.setValue( QStringLiteral( "/UI/defaultMoveTool" ), 1 );
bt->setDefaultAction( action );
}

View File

@ -331,6 +331,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QAction *actionDeleteSelected() { return mActionDeleteSelected; }
QAction *actionAddFeature() { return mActionAddFeature; }
QAction *actionMoveFeature() { return mActionMoveFeature; }
QAction *actionMoveFeatureCopy() { return mActionMoveFeatureCopy; }
QAction *actionRotateFeature() { return mActionRotateFeature;}
QAction *actionSplitFeatures() { return mActionSplitFeatures; }
QAction *actionSplitParts() { return mActionSplitParts; }
@ -1068,6 +1069,8 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void circularStringRadius();
//! activates the move feature tool
void moveFeature();
//! activates the copy and move feature tool
void moveFeatureCopy();
//! activates the offset curve tool
void offsetCurve();
//! activates the reshape features tool
@ -1634,6 +1637,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsMapTool *mCircularStringCurvePoint;
QgsMapTool *mCircularStringRadius;
QgsMapTool *mMoveFeature;
QgsMapTool *mMoveFeatureCopy;
QgsMapTool *mOffsetCurve;
QgsMapTool *mReshapeFeatures;
QgsMapTool *mSplitFeatures;

View File

@ -17,19 +17,21 @@
#include <QToolButton>
#include "qgsguivectorlayertools.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsmessagebar.h"
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsmessageviewer.h"
#include "qgsfeatureaction.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmessagebar.h"
#include "qgsmessagebaritem.h"
#include "qgsmessageviewer.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
QgsGuiVectorLayerTools::QgsGuiVectorLayerTools()
: QObject( nullptr )
: QgsVectorLayerTools()
{}
bool QgsGuiVectorLayerTools::addFeature( QgsVectorLayer* layer, const QgsAttributeMap& defaultValues, const QgsGeometry& defaultGeometry, QgsFeature* feat ) const
@ -95,7 +97,6 @@ bool QgsGuiVectorLayerTools::saveEdits( QgsVectorLayer* layer ) const
return res;
}
bool QgsGuiVectorLayerTools::stopEditing( QgsVectorLayer* layer, bool allowCancel ) const
{
bool res = true;

View File

@ -23,7 +23,7 @@
* or a feature is added.
*/
class QgsGuiVectorLayerTools : public QObject, public QgsVectorLayerTools
class QgsGuiVectorLayerTools : public QgsVectorLayerTools
{
Q_OBJECT
@ -73,6 +73,7 @@ class QgsGuiVectorLayerTools : public QObject, public QgsVectorLayerTools
private:
void commitError( QgsVectorLayer* vlayer ) const;
};
#endif // QGSGUIVECTORLAYERTOOLS_H

View File

@ -13,27 +13,39 @@
* *
***************************************************************************/
#include "qgsmaptoolmovefeature.h"
#include "qgisapp.h"
#include "qgsadvanceddigitizingdockwidget.h"
#include "qgsfeatureiterator.h"
#include "qgsgeometry.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmaptoolmovefeature.h"
#include "qgsrubberband.h"
#include "qgsvectorlayer.h"
#include "qgstolerance.h"
#include "qgisapp.h"
#include "qgsadvanceddigitizingdockwidget.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayertools.h"
#include <QMouseEvent>
#include <QSettings>
#include <limits>
QgsMapToolMoveFeature::QgsMapToolMoveFeature( QgsMapCanvas* canvas )
QgsMapToolMoveFeature::QgsMapToolMoveFeature( QgsMapCanvas* canvas , MoveMode mode )
: QgsMapToolAdvancedDigitizing( canvas, QgisApp::instance()->cadDockWidget() )
, mRubberBand( nullptr )
, mMode( mode )
{
mToolName = tr( "Move feature" );
mCaptureMode = QgsMapToolAdvancedDigitizing::CaptureSegment;
switch ( mode )
{
case Move:
mCaptureMode = QgsMapToolAdvancedDigitizing::CaptureSegment;
break;
case CopyMove:
mCaptureMode = QgsMapToolAdvancedDigitizing::CaptureLine; // we copy/move several times
break;
}
}
QgsMapToolMoveFeature::~QgsMapToolMoveFeature()
@ -138,12 +150,12 @@ void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
}
else
{
delete mRubberBand;
mRubberBand = nullptr;
// copy and move mode
if ( e->button() != Qt::LeftButton )
{
cadDockWidget()->clear();
delete mRubberBand;
mRubberBand = nullptr;
return;
}
@ -152,13 +164,35 @@ void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();
vlayer->beginEditCommand( tr( "Feature moved" ) );
Q_FOREACH ( QgsFeatureId id, mMovedFeatures )
vlayer->beginEditCommand( mMode == Move ? tr( "Feature moved" ) : tr( "Feature copied and moved" ) );
switch ( mMode )
{
vlayer->translateFeature( id, dx, dy );
case Move:
Q_FOREACH ( QgsFeatureId id, mMovedFeatures )
{
vlayer->translateFeature( id, dx, dy );
}
delete mRubberBand;
mRubberBand = nullptr;
break;
case CopyMove:
QgsFeatureRequest request;
request.setFilterFids( mMovedFeatures );
QString* errorMsg = new QString();
if ( !QgisApp::instance()->vectorLayerTools()->copyMoveFeatures( vlayer, request, dx, dy, errorMsg ) )
{
emit messageEmitted( *errorMsg, QgsMessageBar::CRITICAL );
delete mRubberBand;
mRubberBand = nullptr;
}
break;
}
delete mRubberBand;
mRubberBand = nullptr;
vlayer->endEditCommand();
vlayer->triggerRepaint();
}

View File

@ -23,7 +23,14 @@ class APP_EXPORT QgsMapToolMoveFeature: public QgsMapToolAdvancedDigitizing
{
Q_OBJECT
public:
QgsMapToolMoveFeature( QgsMapCanvas* canvas );
//! Mode for moving features
enum MoveMode
{
Move, //!< Move feature
CopyMove //!< Copy and move feature
};
QgsMapToolMoveFeature( QgsMapCanvas* canvas, MoveMode mode = Move );
virtual ~QgsMapToolMoveFeature();
virtual void cadCanvasMoveEvent( QgsMapMouseEvent* e ) override;
@ -45,6 +52,8 @@ class APP_EXPORT QgsMapToolMoveFeature: public QgsMapToolAdvancedDigitizing
QPoint mPressPos;
MoveMode mMode;
};
#endif

View File

@ -213,6 +213,7 @@ SET(QGIS_CORE_SRCS
qgstextrenderer.cpp
qgstolerance.cpp
qgstracer.cpp
qgstrackedvectorlayertools.cpp
qgstransaction.cpp
qgstransactiongroup.cpp
qgsunittypes.cpp
@ -230,6 +231,7 @@ SET(QGIS_CORE_SRCS
qgsvectorlayerlabeling.cpp
qgsvectorlayerlabelprovider.cpp
qgsvectorlayerrenderer.cpp
qgsvectorlayertools.cpp
qgsvectorlayerundocommand.cpp
qgsvectorlayerutils.cpp
qgsvectorsimplifymethod.cpp
@ -491,6 +493,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsrunprocess.h
qgssnappingutils.h
qgstracer.h
qgstrackedvectorlayertools.h
qgstransaction.h
qgstransactiongroup.h
qgsunittypes.h
@ -500,6 +503,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsvectorlayereditpassthrough.h
qgsvectorlayer.h
qgsvectorlayerjoinbuffer.h
qgsvectorlayertools.h
qgsmapthemecollection.h
qgswebpage.h
qgswebview.h

View File

@ -17,7 +17,7 @@
#include "qgsvectorlayer.h"
QgsTrackedVectorLayerTools::QgsTrackedVectorLayerTools()
: mBackend( nullptr )
: mBackend()
{
}
@ -57,6 +57,11 @@ bool QgsTrackedVectorLayerTools::saveEdits( QgsVectorLayer* layer ) const
return mBackend->saveEdits( layer );
}
bool QgsTrackedVectorLayerTools::copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest& request, double dx, double dy, QString* errorMsg ) const
{
return mBackend->copyMoveFeatures( layer, request, dx, dy, errorMsg );
}
void QgsTrackedVectorLayerTools::setVectorLayerTools( const QgsVectorLayerTools* tools )
{
mBackend = tools;

View File

@ -21,8 +21,9 @@
/** \ingroup gui
* \class QgsTrackedVectorLayerTools
*/
class GUI_EXPORT QgsTrackedVectorLayerTools : public QgsVectorLayerTools
class CORE_EXPORT QgsTrackedVectorLayerTools : public QgsVectorLayerTools
{
Q_OBJECT
public:
QgsTrackedVectorLayerTools();
@ -30,6 +31,7 @@ class GUI_EXPORT QgsTrackedVectorLayerTools : public QgsVectorLayerTools
bool startEditing( QgsVectorLayer* layer ) const override;
bool stopEditing( QgsVectorLayer* layer, bool allowCancel ) const override;
bool saveEdits( QgsVectorLayer* layer ) const override;
bool copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest &request, double dx = 0, double dy = 0, QString *errorMsg = nullptr ) const override;
/**
* Set the vector layer tools that will be used to interact with the data

View File

@ -0,0 +1,107 @@
/***************************************************************************
qgsvectorlayertools.cpp
---------------------
begin : 09.11.2016
copyright : (C) 2016 by Denis Rouzaud
email : denis.rouzaud@gmail.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 "qgsvectorlayer.h"
#include "qgsvectorlayertools.h"
#include "qgsfeaturerequest.h"
#include "qgslogger.h"
QgsVectorLayerTools::QgsVectorLayerTools()
: QObject( nullptr )
{}
QgsVectorLayerTools::~QgsVectorLayerTools()
{}
bool QgsVectorLayerTools::copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest& request, double dx, double dy, QString* errorMsg ) const
{
bool res = false;
if ( !layer || !layer->isEditable() )
{
return false;
}
QgsFeatureIterator fi = layer->getFeatures( request );
QgsFeature f;
QgsAttributeList pkAttrList = layer->pkAttributeList();
int browsedFeatureCount = 0;
int couldNotWriteCount = 0;
int noGeometryCount = 0;
QgsFeatureIds fidList;
while ( fi.nextFeature( f ) )
{
browsedFeatureCount++;
// remove pkey values
Q_FOREACH ( auto idx, pkAttrList )
{
f.setAttribute( idx, QVariant() );
}
// translate
if ( f.hasGeometry() )
{
QgsGeometry geom = f.geometry();
geom.translate( dx, dy );
f.setGeometry( geom );
#ifdef QGISDEBUG
const QgsFeatureId fid = f.id();
#endif
// paste feature
if ( !layer->addFeature( f, false ) )
{
couldNotWriteCount++;
QgsDebugMsg( QString( "Could not add new feature. Original copied feature id: %1" ).arg( fid ) );
}
else
{
fidList.insert( f.id() );
}
}
else
{
noGeometryCount++;
}
}
request = QgsFeatureRequest();
request.setFilterFids( fidList );
if ( !couldNotWriteCount && !noGeometryCount )
{
res = true;
}
else if ( errorMsg )
{
errorMsg = new QString( QString( tr( "Only %1 out of %2 features were copied." ) )
.arg( browsedFeatureCount - couldNotWriteCount - noGeometryCount, browsedFeatureCount ) );
if ( noGeometryCount )
{
errorMsg->append( " " );
errorMsg->append( tr( "Some features have no geometry." ) );
}
if ( couldNotWriteCount )
{
errorMsg->append( " " );
errorMsg->append( tr( "Some could not be created on the layer." ) );
}
}
return res;
}

View File

@ -16,9 +16,12 @@
#ifndef QGSVECTORLAYERTOOLS_H
#define QGSVECTORLAYERTOOLS_H
#include <QObject>
#include "qgsfeature.h"
#include "qgsgeometry.h"
class QgsFeatureRequest;
class QgsVectorLayer;
/** \ingroup gui
@ -30,12 +33,14 @@ class QgsVectorLayer;
* in your application.
*
*/
class GUI_EXPORT QgsVectorLayerTools
class CORE_EXPORT QgsVectorLayerTools : public QObject
{
public:
QgsVectorLayerTools() {}
Q_OBJECT
virtual ~QgsVectorLayerTools() {}
public:
QgsVectorLayerTools();
virtual ~QgsVectorLayerTools();
/**
* This method should/will be called, whenever a new feature will be added to the layer
@ -85,6 +90,20 @@ class GUI_EXPORT QgsVectorLayerTools
*/
virtual bool saveEdits( QgsVectorLayer* layer ) const = 0;
/**
* Copy and move features with defined translation.
*
* @param layer The layer
* @param request The request for the features to be moved. It will be assigned to a new feature request with the newly copied features.
* @param dx The translation on x
* @param dy The translation on y
* @param errorMsg If given, it will contain the error message
* @return True if all features could be copied.
*
* TODO QGIS 3: remove const qualifier
*/
virtual bool copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest &request, double dx = 0, double dy = 0, QString *errorMsg = nullptr ) const;
};
#endif // QGSVECTORLAYERTOOLS_H

View File

@ -311,7 +311,6 @@ SET(QGIS_GUI_SRCS
qgstextannotationitem.cpp
qgstextformatwidget.cpp
qgstextpreview.cpp
qgstrackedvectorlayertools.cpp
qgstreewidgetitem.cpp
qgsunitselectionwidget.cpp
qgsuserinputdockwidget.cpp
@ -662,9 +661,7 @@ SET(QGIS_GUI_HDRS
qgssvgannotationitem.h
qgstablewidgetitem.h
qgstextannotationitem.h
qgstrackedvectorlayertools.h
qgsuserinputdockwidget.h
qgsvectorlayertools.h
qgsvertexmarker.h
qgsfiledownloader.h

View File

@ -17,7 +17,7 @@
<x>0</x>
<y>0</y>
<width>1018</width>
<height>28</height>
<height>22</height>
</rect>
</property>
<property name="toolTip">
@ -369,7 +369,6 @@
<addaction name="mActionToggleEditing"/>
<addaction name="mActionSaveLayerEdits"/>
<addaction name="mActionAddFeature"/>
<addaction name="mActionMoveFeature"/>
<addaction name="mActionNodeTool"/>
<addaction name="mActionDeleteSelected"/>
<addaction name="mActionCutFeatures"/>
@ -2564,6 +2563,21 @@ Acts on currently active editable layer</string>
<string>F3</string>
</property>
</action>
<action name="mActionMoveFeatureCopy">
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionMoveFeatureCopy.svg</normaloff>:/images/themes/default/mActionMoveFeatureCopy.svg</iconset>
</property>
<property name="text">
<string>Copy and Move Feature(s)</string>
</property>
<property name="toolTip">
<string>Copy and Move Feature(s)</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>

View File

@ -143,6 +143,7 @@ ENDIF (WITH_DESKTOP)
IF (ENABLE_PGTEST)
ADD_PYTHON_TEST(PyQgsPostgresProvider test_provider_postgres.py)
ADD_PYTHON_TEST(PyQgsRelationEditWidget test_qgsrelationeditwidget.py)
ADD_PYTHON_TEST(PyQgsVectorLayerTools test_qgsvectorlayertools.py)
ENDIF (ENABLE_PGTEST)
IF (ENABLE_MSSQLTEST)

View File

@ -23,14 +23,14 @@ from qgis.core import (
QgsRelation,
QgsMapLayerRegistry,
QgsTransaction,
QgsFeatureRequest
QgsFeatureRequest,
QgsVectorLayerTools
)
from qgis.gui import (
QgsEditorWidgetRegistry,
QgsRelationWidgetWrapper,
QgsAttributeEditorContext,
QgsVectorLayerTools
QgsAttributeEditorContext
)
from qgis.PyQt.QtCore import QTimer

View File

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
"""QGIS Unit test utils for provider tests.
.. 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.
"""
from builtins import str
from builtins import object
__author__ = 'Denis Rouzaud'
__date__ = '2016-11-07'
__copyright__ = 'Copyright 2015, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from qgis.core import QgsFeatureRequest, QgsVectorLayer, QgsMapLayerRegistry, QgsVectorLayerTools
from qgis.testing import start_app, unittest
import os
start_app()
class SubQgsVectorLayerTools(QgsVectorLayerTools):
def __init__(self):
super().__init__()
def addFeature(self, layer):
pass
def startEditing(self, layer):
pass
def stopEditing(self, layer):
pass
def saveEdits(self, layer):
pass
class TestQgsVectorLayerTools(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""
Setup the involved layers and relations for a n:m relation
:return:
"""
cls.dbconn = 'service=\'qgis_test\''
if 'QGIS_PGTEST_DB' in os.environ:
cls.dbconn = os.environ['QGIS_PGTEST_DB']
# Create test layer
cls.vl = QgsVectorLayer(cls.dbconn + ' sslmode=disable key=\'pk\' table="qgis_test"."someData" (geom) sql=', 'layer', 'postgres')
QgsMapLayerRegistry.instance().addMapLayer(cls.vl)
cls.vltools = SubQgsVectorLayerTools()
def testCopyMoveFeature(self):
""" Test copy and move features"""
rqst = QgsFeatureRequest()
rqst.setFilterFid(4)
self.vl.startEditing()
(ok, rqst, msg) = self.vltools.copyMoveFeatures(self.vl, rqst, -0.1, 0.2)
self.assertTrue(ok)
for f in self.vl.getFeatures(rqst):
geom = f.geometry()
self.assertAlmostEqual(geom.asPoint().x(), -65.42)
self.assertAlmostEqual(geom.asPoint().y(), 78.5)
if __name__ == '__main__':
unittest.main()