mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-10-29 00:07:54 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			245 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import os
 | |
| from qgis.PyQt.QtCore import QCoreApplication
 | |
| from qgis.PyQt.QtWidgets import QAction, QMenu
 | |
| from qgis.PyQt.QtGui import QIcon
 | |
| from qgis.PyQt.QtWidgets import QApplication
 | |
| from processing.core.ProcessingConfig import ProcessingConfig, Setting
 | |
| from processing.gui.MessageDialog import MessageDialog
 | |
| from processing.gui.AlgorithmDialog import AlgorithmDialog
 | |
| from qgis.utils import iface
 | |
| from qgis.core import QgsApplication
 | |
| from processing.gui.MessageBarProgress import MessageBarProgress
 | |
| from processing.gui.AlgorithmExecutor import execute
 | |
| from processing.gui.Postprocessing import handleAlgorithmResults
 | |
| from processing.core.Processing import Processing
 | |
| from processing.tools import dataobjects
 | |
| 
 | |
| algorithmsToolbar = None
 | |
| menusSettingsGroup = 'Menus'
 | |
| 
 | |
| defaultMenuEntries = {}
 | |
| vectorMenu = QApplication.translate('MainWindow', 'Vect&or')
 | |
| analysisToolsMenu = vectorMenu + "/" + Processing.tr('&Analysis Tools')
 | |
| defaultMenuEntries.update({'qgis:distancematrix': analysisToolsMenu,
 | |
|                            'qgis:sumlinelengths': analysisToolsMenu,
 | |
|                            'qgis:pointsinpolygon': analysisToolsMenu,
 | |
|                            'qgis:countpointsinpolygon': analysisToolsMenu,
 | |
|                            'qgis:listuniquevalues': analysisToolsMenu,
 | |
|                            'qgis:basicstatisticsforfields': analysisToolsMenu,
 | |
|                            'qgis:nearestneighbouranalysis': analysisToolsMenu,
 | |
|                            'qgis:meancoordinates': analysisToolsMenu,
 | |
|                            'qgis:lineintersections': analysisToolsMenu})
 | |
| researchToolsMenu = vectorMenu + "/" + Processing.tr('&Research Tools')
 | |
| defaultMenuEntries.update({'qgis:randomselection': researchToolsMenu,
 | |
|                            'qgis:randomselectionwithinsubsets': researchToolsMenu,
 | |
|                            'qgis:randompointsinextent': researchToolsMenu,
 | |
|                            'qgis:randompointsinlayerbounds': researchToolsMenu,
 | |
|                            'qgis:randompointsinsidepolygonsfixed': researchToolsMenu,
 | |
|                            'qgis:randompointsinsidepolygonsvariable': researchToolsMenu,
 | |
|                            'qgis:regularpoints': researchToolsMenu,
 | |
|                            'qgis:vectorgrid': researchToolsMenu,
 | |
|                            'qgis:selectbylocation': researchToolsMenu,
 | |
|                            'qgis:polygonfromlayerextent': researchToolsMenu})
 | |
| 
 | |
| geoprocessingToolsMenu = vectorMenu + "/" + Processing.tr('&Geoprocessing Tools')
 | |
| defaultMenuEntries.update({'qgis:convexhull': geoprocessingToolsMenu,
 | |
|                            'qgis:fixeddistancebuffer': geoprocessingToolsMenu,
 | |
|                            'qgis:variabledistancebuffer': geoprocessingToolsMenu,
 | |
|                            'qgis:intersection': geoprocessingToolsMenu,
 | |
|                            'qgis:union': geoprocessingToolsMenu,
 | |
|                            'qgis:symmetricaldifference': geoprocessingToolsMenu,
 | |
|                            'native:clip': geoprocessingToolsMenu,
 | |
|                            'qgis:difference': geoprocessingToolsMenu,
 | |
|                            'qgis:dissolve': geoprocessingToolsMenu,
 | |
|                            'qgis:eliminateselectedpolygons': geoprocessingToolsMenu})
 | |
| geometryToolsMenu = vectorMenu + "/" + Processing.tr('G&eometry Tools')
 | |
| defaultMenuEntries.update({'qgis:checkvalidity': geometryToolsMenu,
 | |
|                            'qgis:exportaddgeometrycolumns': geometryToolsMenu,
 | |
|                            'qgis:centroids': geometryToolsMenu,
 | |
|                            'qgis:delaunaytriangulation': geometryToolsMenu,
 | |
|                            'qgis:voronoipolygons': geometryToolsMenu,
 | |
|                            'qgis:simplifygeometries': geometryToolsMenu,
 | |
|                            'qgis:densifygeometries': geometryToolsMenu,
 | |
|                            'qgis:multiparttosingleparts': geometryToolsMenu,
 | |
|                            'qgis:singlepartstomultipart': geometryToolsMenu,
 | |
|                            'qgis:polygonstolines': geometryToolsMenu,
 | |
|                            'qgis:linestopolygons': geometryToolsMenu,
 | |
|                            'qgis:extractnodes': geometryToolsMenu})
 | |
| managementToolsMenu = vectorMenu + "/" + Processing.tr('&Data Management Tools')
 | |
| defaultMenuEntries.update({'qgis:definecurrentprojection': managementToolsMenu,
 | |
|                            'qgis:joinattributesbylocation': managementToolsMenu,
 | |
|                            'qgis:splitvectorlayer': managementToolsMenu,
 | |
|                            'qgis:mergevectorlayers': managementToolsMenu,
 | |
|                            'qgis:createspatialindex': managementToolsMenu})
 | |
| 
 | |
| rasterMenu = Processing.tr('&Raster')
 | |
| projectionsMenu = rasterMenu + "/" + Processing.tr('Projections')
 | |
| defaultMenuEntries.update({'gdal:warpreproject': projectionsMenu,
 | |
|                            'gdal:assignprojection': projectionsMenu,
 | |
|                            'gdal:extractprojection': projectionsMenu})
 | |
| conversionMenu = rasterMenu + "/" + Processing.tr('Conversion')
 | |
| defaultMenuEntries.update({'gdal:rasterize': conversionMenu,
 | |
|                            'gdal:rasterize_over': conversionMenu,
 | |
|                            'gdal:polygonize': conversionMenu,
 | |
|                            'gdal:translate': conversionMenu,
 | |
|                            'gdal:rgbtopct': conversionMenu,
 | |
|                            'gdal:pcttorgb': conversionMenu})
 | |
| extractionMenu = rasterMenu + "/" + Processing.tr('Extraction')
 | |
| defaultMenuEntries.update({'gdal:contour': extractionMenu,
 | |
|                            'gdal:cliprasterbyextent': extractionMenu,
 | |
|                            'gdal:cliprasterbymasklayer': extractionMenu})
 | |
| analysisMenu = rasterMenu + "/" + Processing.tr('Analysis')
 | |
| defaultMenuEntries.update({'gdal:sieve': analysisMenu,
 | |
|                            'gdal:nearblack': analysisMenu,
 | |
|                            'gdal:fillnodata': analysisMenu,
 | |
|                            'gdal:proximity': analysisMenu,
 | |
|                            'gdal:griddatametrics': analysisMenu,
 | |
|                            'gdal:gridaverage': analysisMenu,
 | |
|                            'gdal:gridinvdist': analysisMenu,
 | |
|                            'gdal:gridnearestneighbor': analysisMenu,
 | |
|                            'gdal:aspect': analysisMenu,
 | |
|                            'gdal:hillshade': analysisMenu,
 | |
|                            'gdal:roughness': analysisMenu,
 | |
|                            'gdal:slope': analysisMenu,
 | |
|                            'gdal:tpi': analysisMenu,
 | |
|                            'gdal:tri': analysisMenu})
 | |
| miscMenu = rasterMenu + "/" + Processing.tr('Miscellaneous')
 | |
| defaultMenuEntries.update({'gdal:buildvirtualraster': miscMenu,
 | |
|                            'gdal:merge': miscMenu,
 | |
|                            'gdal:rasterinfo': miscMenu,
 | |
|                            'gdal:overviews': miscMenu,
 | |
|                            'gdal:tileindex': miscMenu})
 | |
| 
 | |
| 
 | |
| def initializeMenus():
 | |
|     for provider in QgsApplication.processingRegistry().providers():
 | |
|         for alg in provider.algorithms():
 | |
|             d = defaultMenuEntries.get(alg.id(), "")
 | |
|             setting = Setting(menusSettingsGroup, "MENU_" + alg.id(),
 | |
|                               "Menu path", d)
 | |
|             ProcessingConfig.addSetting(setting)
 | |
|             setting = Setting(menusSettingsGroup, "BUTTON_" + alg.id(),
 | |
|                               "Add button", False)
 | |
|             ProcessingConfig.addSetting(setting)
 | |
|             setting = Setting(menusSettingsGroup, "ICON_" + alg.id(),
 | |
|                               "Icon", "", valuetype=Setting.FILE)
 | |
|             ProcessingConfig.addSetting(setting)
 | |
| 
 | |
|     ProcessingConfig.readSettings()
 | |
| 
 | |
| 
 | |
| def updateMenus():
 | |
|     removeMenus()
 | |
|     QCoreApplication.processEvents()
 | |
|     createMenus()
 | |
| 
 | |
| 
 | |
| def createMenus():
 | |
|     for alg in QgsApplication.processingRegistry().algorithms():
 | |
|         menuPath = ProcessingConfig.getSetting("MENU_" + alg.id())
 | |
|         addButton = ProcessingConfig.getSetting("BUTTON_" + alg.id())
 | |
|         icon = ProcessingConfig.getSetting("ICON_" + alg.id())
 | |
|         if icon and os.path.exists(icon):
 | |
|             icon = QIcon(icon)
 | |
|         else:
 | |
|             icon = None
 | |
|         if menuPath:
 | |
|             paths = menuPath.split("/")
 | |
|             addAlgorithmEntry(alg, paths[0], paths[-1], addButton=addButton, icon=icon)
 | |
| 
 | |
| 
 | |
| def removeMenus():
 | |
|     for alg in QgsApplication.processingRegistry().algorithms():
 | |
|         menuPath = ProcessingConfig.getSetting("MENU_" + alg.id())
 | |
|         if menuPath:
 | |
|             paths = menuPath.split("/")
 | |
|             removeAlgorithmEntry(alg, paths[0], paths[-1])
 | |
| 
 | |
| 
 | |
| def addAlgorithmEntry(alg, menuName, submenuName, actionText=None, icon=None, addButton=False):
 | |
|     action = QAction(icon or alg.icon(), actionText or alg.displayName(), iface.mainWindow())
 | |
|     action.triggered.connect(lambda: _executeAlgorithm(alg))
 | |
|     action.setObjectName("mProcessingUserMenu_%s" % alg.id())
 | |
| 
 | |
|     if menuName:
 | |
|         menu = getMenu(menuName, iface.mainWindow().menuBar())
 | |
|         submenu = getMenu(submenuName, menu)
 | |
|         submenu.addAction(action)
 | |
| 
 | |
|     if addButton:
 | |
|         global algorithmsToolbar
 | |
|         if algorithmsToolbar is None:
 | |
|             algorithmsToolbar = iface.addToolBar('ProcessingAlgorithms')
 | |
|         algorithmsToolbar.addAction(action)
 | |
| 
 | |
| 
 | |
| def removeAlgorithmEntry(alg, menuName, submenuName, actionText=None, delButton=True):
 | |
|     if menuName:
 | |
|         menu = getMenu(menuName, iface.mainWindow().menuBar())
 | |
|         subMenu = getMenu(submenuName, menu)
 | |
|         action = findAction(subMenu.actions(), alg, actionText)
 | |
|         if action is not None:
 | |
|             subMenu.removeAction(action)
 | |
| 
 | |
|         if len(subMenu.actions()) == 0:
 | |
|             subMenu.deleteLater()
 | |
| 
 | |
|     if delButton:
 | |
|         global algorithmsToolbar
 | |
|         if algorithmsToolbar is not None:
 | |
|             action = findAction(algorithmsToolbar.actions(), alg, actionText)
 | |
|             if action is not None:
 | |
|                 algorithmsToolbar.removeAction(action)
 | |
| 
 | |
| 
 | |
| def _executeAlgorithm(alg):
 | |
|     ok, message = alg.canExecute()
 | |
|     if not ok:
 | |
|         dlg = MessageDialog()
 | |
|         dlg.setTitle(Processing.tr('Missing dependency'))
 | |
|         dlg.setMessage(
 | |
|             Processing.tr('<h3>Missing dependency. This algorithm cannot '
 | |
|                           'be run :-( </h3>\n{0}').format(message))
 | |
|         dlg.exec_()
 | |
|         return
 | |
| 
 | |
|     if (alg.countVisibleParameters()) > 0:
 | |
|         dlg = alg.createCustomParametersWidget(None)
 | |
|         if not dlg:
 | |
|             dlg = AlgorithmDialog(alg)
 | |
|         canvas = iface.mapCanvas()
 | |
|         prevMapTool = canvas.mapTool()
 | |
|         dlg.show()
 | |
|         dlg.exec_()
 | |
|         # have to manually delete the dialog - otherwise it's owned by the
 | |
|         # iface mainWindow and never deleted
 | |
|         del dlg
 | |
|         if canvas.mapTool() != prevMapTool:
 | |
|             try:
 | |
|                 canvas.mapTool().reset()
 | |
|             except:
 | |
|                 pass
 | |
|             canvas.setMapTool(prevMapTool)
 | |
|     else:
 | |
|         feedback = MessageBarProgress()
 | |
|         context = dataobjects.createContext(feedback)
 | |
|         parameters = {}
 | |
|         ret, results = execute(alg, parameters, context, feedback)
 | |
|         handleAlgorithmResults(alg, context, feedback)
 | |
|         feedback.close()
 | |
| 
 | |
| 
 | |
| def getMenu(name, parent):
 | |
|     menus = [c for c in parent.children() if isinstance(c, QMenu) and c.title() == name]
 | |
|     if menus:
 | |
|         return menus[0]
 | |
|     else:
 | |
|         return parent.addMenu(name)
 | |
| 
 | |
| 
 | |
| def findAction(actions, alg, actionText=None):
 | |
|     for action in actions:
 | |
|         if action.text() in [actionText, alg.displayName(), alg.name()]:
 | |
|             return action
 | |
|     return None
 |