dtmerge.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. # -*- coding: utf-8 -*-
  2. """
  3. dtmerge
  4. `````````````
  5. """
  6. """
  7. Part of DigitizingTools, a QGIS plugin that
  8. subsumes different tools neded during digitizing sessions
  9. Tool: Merge features to a new feature _without deleting all of them_
  10. see http://hub.qgis.org/issues/13490
  11. * begin : 2015-11-09
  12. * copyright : (C) 2015 by Bernhard Ströbl
  13. * email : bernhard.stroebl@jena.de
  14. This program is free software; you can redistribute it and/or modify
  15. it under the terms of the GNU General Public License as published by
  16. the Free Software Foundation; either version 2 of the License, or
  17. (at your option) any later version.
  18. """
  19. from builtins import str
  20. from qgis.PyQt import QtCore, QtGui, QtWidgets
  21. from qgis.core import *
  22. import dt_icons_rc
  23. from dttools import DtSingleButton
  24. from dtToolsDialog import DigitizingToolsChooseRemaining
  25. class DtMerge(DtSingleButton):
  26. '''Merge selected features of active layer'''
  27. def __init__(self, iface, toolBar):
  28. super().__init__(iface, toolBar,
  29. QtGui.QIcon(":/Merge.png"),
  30. QtCore.QCoreApplication.translate("digitizingtools",
  31. "Merge selected features"),
  32. geometryTypes = [1, 2, 3, 4, 5, 6], dtName = "dtMerge")
  33. self.enable()
  34. def process(self):
  35. '''Function that does all the real work'''
  36. title = QtCore.QCoreApplication.translate("digitizingtools", "Merge")
  37. processLayer = self.iface.activeLayer()
  38. pkAtts = processLayer.primaryKeyAttributes()
  39. if len(pkAtts) == 1:
  40. pkFld = pkAtts[0]
  41. else:
  42. pkFld = None
  43. pkValues = {}
  44. featDict = {}
  45. fidsToDelete = []
  46. for aFeat in processLayer.selectedFeatures():
  47. aFid = aFeat.id()
  48. featDict[aFid] = aFeat
  49. if aFid >= 0: # only already existing features
  50. if pkFld == None:
  51. pkValues["Feature ID " + str(aFid)] = aFid
  52. else:
  53. aPkValue = aFeat[pkFld]
  54. pkValues[str(aPkValue)] = aFid
  55. if len(pkValues) > 1:
  56. dlg = DigitizingToolsChooseRemaining(self.iface, processLayer, pkValues, featDict, title)
  57. doContinue = dlg.exec_()
  58. if doContinue == 1:
  59. pkValueToKeep = dlg.pkValueToKeep
  60. elif len(pkValues) == 1:
  61. doContinue = 1
  62. pkValueToKeep = list(pkValues.keys())[0]
  63. else: # all new features
  64. doContinue = 1
  65. pkValueToKeep = None
  66. if doContinue == 1:
  67. processLayer.beginEditCommand(
  68. QtCore.QCoreApplication.translate("editcommand",
  69. "Merge Features"))
  70. if pkValueToKeep != None:
  71. outFeat = featDict.pop(pkValues[pkValueToKeep])
  72. else:
  73. outFeat = featDict.popitem()[1] # use any
  74. outFid = outFeat.id()
  75. outGeom = QgsGeometry(outFeat.geometry())
  76. for aFeatVal in list(featDict.values()):
  77. fidsToDelete.append(aFeatVal.id())
  78. outGeom = outGeom.combine(QgsGeometry(aFeatVal.geometry()))
  79. if not self.geometryTypeMatchesLayer(processLayer, outGeom):
  80. self.iface.messageBar().pushCritical("DigitizingTools",
  81. QtWidgets.QApplication.translate("DigitizingTools",
  82. "The geometry type of the result is not valid in this layer!"))
  83. processLayer.destroyEditCommand()
  84. else:
  85. processLayer.removeSelection()
  86. success = processLayer.changeGeometry(outFid, outGeom)
  87. for aFid in fidsToDelete:
  88. if not processLayer.deleteFeature(aFid):
  89. processLayer.destroyEditCommand()
  90. return None
  91. processLayer.endEditCommand()
  92. self.iface.mapCanvas().refresh()
  93. def enable(self):
  94. '''Enables/disables the corresponding button.'''
  95. DtSingleButton.enable(self) # call parent's method
  96. if self.act.isEnabled():
  97. layer = self.iface.activeLayer()
  98. try:
  99. layer.selectionChanged.disconnect(self.enable) # disconnect, will be reconnected
  100. except:
  101. pass
  102. doEnable = layer.selectedFeatureCount() > 1
  103. self.act.setEnabled(doEnable)
  104. layer.selectionChanged.connect(self.enable)