From 2a4e0c619d7737d0cd99b0cc32d84e93b8aac19c Mon Sep 17 00:00:00 2001
From: A Nilsen <ban@nibio.no>
Date: Fri, 19 Aug 2022 14:25:20 +0000
Subject: [PATCH] Update get_nib.py
---
get_nib.py | 729 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 729 insertions(+)
diff --git a/get_nib.py b/get_nib.py
index 665fe07..dffa002 100644
--- a/get_nib.py
+++ b/get_nib.py
@@ -489,6 +489,735 @@ class getnib:
""" end additional code """
+ # show the dialog
+ self.dlg.show()
+ # Run the dialog event loop
+ result = self.dlg.exec_()
+ # See if OK was pressed
+ if result:
+ # Do something useful here - delete the line containing pass and
+ # substitute with your code.
+ # pass
+ """" Additional code"""
+ selectedLayer = '' # Initialise
+ reset = False
+
+ if self.dlg.checkBox_resetNib.isChecked(): # Empty the Nib-prosjekt group
+ reset = True
+
+ # If checked, use current map canvas as bounding box (= extent of)
+ if self.dlg.radioButton_ucmcbb.isChecked():
+ # Get the extent of current map canvas (coordinates in the project's crs)
+ e = iface.mapCanvas().extent()
+ xmin = e.xMinimum()
+ xmax = e.xMaximum()
+ ymin = e.yMinimum()
+ ymax = e.yMaximum()
+ ok = self.check_bbsize(crs_proj_str, xmin, xmax, ymin, ymax) # Check if bb is small enough
+ # If checked, use the length and height from map canvas sentre point
+ elif self.dlg.radioButton_udbb.isChecked():
+ # Get the extent of current map canvas (coordinates in the project's crs)
+ l = self.dlg.lineEdit_lengthbb.text()
+ h = self.dlg.lineEdit_heightbb.text()
+ if l == "" or h == "":
+ self.iface.messageBar().pushMessage("Error", "Length and/or height are/is missing!", level=Qgis.Critical, duration=3)
+ return # Return from (end) plugin
+ else:
+ # Length and height (in km) requires projected coordinated. Ensures this by converting the coordinates to LAEA
+ e = iface.mapCanvas().extent().center()
+ # Debugging
+ # self.iface.messageBar().pushMessage("Info", "Center x, y: " + str(e.x()) +", "+ str(e.y())+", "+crs_proj_str, level=Qgis.Info, duration=5)
+ # Computes corner coordinates in LAE regardless input crs
+ xmin = e.x() - int(l)*1000/2
+ xmax = e.x() + int(l)*1000/2
+ ymin = e.y() - int(h)*1000/2
+ ymax = e.y() + int(h)*1000/2
+ """ Check length and height of bounding box. Limit is set to 500 km """
+ ok = self.check_bbsize(crs_proj_str, xmin, xmax, ymin, ymax) # Check if bb is small enough
+ else: # a layer or a file is selcted
+ if self.dlg.radioButton_lyr.isChecked(): # layer-option checked
+ lyr_name = self.dlg.comboBox_lyr.currentText() # Get the layer name
+ if lyr_name != "": # If a layer is present/chosen
+ # self.iface.messageBar().pushMessage("Info", "Valgt layer: "+lyr_name, level=Qgis.Info, duration=3)
+ selectedLayer = QgsProject.instance().mapLayersByName(lyr_name)[0] # Get this vector layer
+ # Get the extent of the layer (coordinates in the selected layer's crs)
+ e = selectedLayer.extent()
+ else: # If no file or layer is selcted, throw an error mesage and end plugin
+ self.iface.messageBar().pushMessage("Error", "No layer selected!", level=Qgis.Critical, duration=3)
+ return # Return from (end) plugin
+
+ elif self.dlg.radioButton_file.isChecked(): # file-option checked
+ fname = self.dlg.lineEdit_file.text() # get the text (path and filename)
+ if fname != "":
+ lname = os.path.splitext(os.path.basename(fname))[0] #get only the filename without the extension, will be used as layer name in the Layers panel in QGIS
+ # self.iface.messageBar().pushMessage("Info", "Valgt fil: "+lname, level=Qgis.Info, duration=3)
+ file = r""+fname+"" # Reads the file
+ fLayer = QgsVectorLayer(file, lname, "ogr") # If vector file
+ if not fLayer.isValid(): # If not valid vector laayer
+ fLayer = QgsRasterLayer(file, lname, "gdal") # If raster file
+ if not fLayer.isValid(): # If not valid raster layer either, show error message and end plugin
+ self.iface.messageBar().pushMessage("Error", "Not a valid geo-file: "+ str(lname),level=Qgis.Critical, duration=3)
+ return # Return from (end) plugin
+ QgsProject.instance().addMapLayer(fLayer, True) # Add the layer and show it (True)
+ selectedLayer = QgsProject.instance().mapLayersByName(lname)[0] # Get this layer
+ # Get the extent of the active layer (coordinates in the selected file's crs)
+ e = selectedLayer.extent()
+ else:
+ self.iface.messageBar().pushMessage("Error", "No file selected!", level=Qgis.Critical, duration=3)
+ return # Return from (end) plugin
+ # Hverken layer eller fil er valgt
+ else:
+ self.iface.messageBar().pushMessage("Error", "No extent", level=Qgis.Critical, duration=5)
+
+ # Activate (select) the selected layer in the combobox or in the lineEdit
+ iface.setActiveLayer(selectedLayer)
+ # Zoom to activated layer
+ iface.zoomToActiveLayer()
+
+ # Get selected layer's epsg:code
+ crs_lyr = selectedLayer.crs() # example:
+ crs_lyr_str = crs_lyr.authid() # EPSG:4258
+ try:
+ crs_lyr_int = int(crs_lyr_str[5:]) # 4258
+ except: # In case a non-geo-layer (e.g. csv-file) is selected from the combobox
+ self.iface.messageBar().pushMessage("Error", "Layer is missing crs", level=Qgis.Critical, duration=3)
+ layers = [] # Empty layers to get a fresh start when rerunning the plugin
+ return # Return from (end) plugin
+
+ # Get the extent of the active layer (coordinates in file or layer crs)
+ xmin = e.xMinimum()
+ xmax = e.xMaximum()
+ ymin = e.yMinimum()
+ ymax = e.yMaximum()
+ # coords = "%f,%f;%f,%f;%f,%f;%f,%f" %(xmin,ymin,xmin,ymax,xmax,ymax,xmax,ymin)
+ # self.iface.messageBar().pushMessage("Info", "extent"+str(coords), level=Qgis.Info, duration=3)
+ # If selected file or layer and project have different crs, the layer's
+ # bounding box coordinates must be transformed into the project's crs
+ if crs_lyr_int != crs_proj_int:
+ sourceCrs = QgsCoordinateReferenceSystem(crs_lyr_str)
+ destCrs = QgsCoordinateReferenceSystem(crs_proj_str)
+ transformContext = QgsProject.instance().transformContext()
+ xform = QgsCoordinateTransform(sourceCrs, destCrs, transformContext)
+ # forward transformation: src -> dest
+ pt1 = xform.transform(QgsPointXY(xmin,ymin))
+ pt2 = xform.transform(QgsPointXY(xmax,ymax))
+ xmin = pt1.x()
+ xmax = pt2.x()
+ ymin = pt1.y()
+ ymax = pt2.y()
+ # Check if bb is small enough - input crs and transformed bb coordinates are in project crs
+ ok = self.check_bbsize(crs_proj_str, xmin, xmax, ymin, ymax)
+ else: # Selected file or layer and project have the same crs
+ # Check if bb is small enough - input crs and bb coordinates are in layer crs = project crs
+ ok = self.check_bbsize(crs_lyr_str, xmin, xmax, ymin, ymax)
+
+ if ok: # If bb small enough, get the corner coordinates (to be used in url-request)
+ # Set bounding box corner coordinates as geojson (x1,y1;x2,y2;...)
+ coords = "%f,%f;%f,%f;%f,%f;%f,%f" %(xmin,ymin,xmin,ymax,xmax,ymax,xmax,ymin)
+ else: # If bb too large
+ return # Return from (end) plugin
+
+ # Accessing layers' tree root
+ root = QgsProject.instance().layerTreeRoot()
+
+ # If reset box is checked, group "Nib-prosjekt" is deleted before recreated
+ # and filled with layers
+ if reset: # The reset box is checked
+ group = root.findGroup('Nib-prosjekt') # Find the group
+ root.removeChildNode(group) # Remove the group
+ # Recreate Nib-prosjekt group
+ # Add a layer group to be used for all orthophoto-projects within the active layer's extent
+ if not root.findGroup("Nib-prosjekt"): # If the group don't exist
+ group = root.addGroup('Nib-prosjekt') # add the group and name it "Nib-prosjekt"
+ # group.setExpanded(False) # Collapse the layer group
+
+ # Load Norge i bilder-project based on active layer's bounding box
+ # (geojson-format x1,y1;x2,y2;x3,y3;...)
+ # https://stackoverflow.com/questions/50337388/how-to-use-special-character-%c3%a6-%c3%b8-or-%c3%a5-in-a-urllib-request-urlopen-in-python-3
+ para=parse.quote('{Filter:"ortofototype in (1,2,3,4,8,9,12)",Coordinates:"'+coords+'",InputWKID:'+str(crs_proj_int)+',StopOnCover:false}')
+ js = requests.get('https://tjenester.norgeibilder.no/rest/projectMetadata.ashx?request='+para).json() #liste med aktuelle of-prosjekt på json-format
+ print(js) # {Success:true,ErrorMessage:null,ProjectList:[Sør-Varanger 2019,Sør-Varanger veg 2016,Sør-Varanger 2013,Sør-Varanger 2011],ProjectMetadata:null}
+ nib_liste = js['ProjectList']
+ print('nib_liste =',nib_liste) # nib_liste = ['Sør-Varanger 2019', 'Sør-Varanger veg 2016', 'Sør-Varanger 2013', 'Sør-Varanger 2011']
+ # self.iface.messageBar().pushMessage("Info", "All OF: "+ str(nib_liste),level=Qgis.Info, duration=3)
+
+ nib_liste_years = [] #Initialise
+
+ # Ensured 4 digits in start and end-year. However the years might be wrong. start > end, < 4 digits. Checking this.
+ if self.dlg.radioButton_btwyears.isChecked():
+ # Get the extent of current map canvas (coordinates in the project's crs)
+ start = self.dlg.lineEdit_startyear.text()
+ end = self.dlg.lineEdit_endyear.text()
+ if int(start) <= int(end):
+ if len(start) == 4 and len(end) == 4:
+ # Creates a new list with only the OF-proejcts from between the start- and end-year.
+ years = [str(y) for y in range(int(start),int(end)+1,1)]
+ # We have an original list with all nib-projects (nib_liste)
+ # We make a new list selecting projects from nib_liste from the wanted time period
+ for year in years:
+ for n in (nib_liste):
+ if year in n.split():
+ nib_liste_years.append(n)
+ nib_liste = nib_liste_years
+ else:
+ self.iface.messageBar().pushMessage("Warning", "year must have 4 digits",level=Qgis.Warning, duration=3)
+ return
+ else:
+ self.iface.messageBar().pushMessage("Warning", "end-year must be >= start-year",level=Qgis.Warning, duration=3)
+ return
+
+ lyr = '' # Initiate
+ for nibprosjwms in nib_liste: # Loads WMS (raster layer) for each of-project within the bounding box in question
+ urlWithParams = 'contextualWMSLegend=0&crs=EPSG:'+str(crs_proj_int)+'&dpiMode=7&featureCount=10&format=image/png&layers='+nibprosjwms+'&styles&url=https://wms.geonorge.no/skwms1/wms.nib-prosjekter'
+ rlayer = QgsRasterLayer(urlWithParams, nibprosjwms, 'wms') # Get the raster layer
+ if rlayer.isValid(): # Valid raster layer
+ layers = QgsProject.instance().mapLayersByName(nibprosjwms) # Check if loaded layer already exists
+ if layers:
+ lyr = layers[0]
+ tree_layer = root.findLayer(lyr.id())
+ if tree_layer: # True if layer exists, otherwise False
+ layer_parent = tree_layer.parent()
+ if str(layer_parent.name()) == 'Nib-prosjekt': # If layer exists in group Nib-prosjekt, it will not be added
+ self.iface.messageBar().pushMessage("Info", "WMS layer exists: "+ str(nibprosjwms),level=Qgis.Info, duration=1)
+ continue # Return the control to the beginning of the for loop
+ else: # The layer exists but not in the Nib-prosjekt group
+ QgsProject.instance().addMapLayer(rlayer, False) # Add the raster layer without showing it (False)
+ mygroup = root.findGroup("Nib-prosjekt") # Get the group named "Nib-prosjekt"
+ mygroup.addLayer(rlayer) # Add the layer to this group
+ # Uncheck the raster layer
+ QgsProject.instance().layerTreeRoot().findLayer(rlayer.id()).setItemVisibilityChecked(False)
+ self.iface.messageBar().pushMessage("Success", "WMS reloaded", level=Qgis.Success, duration=3)
+ else: # layer does not exist, thus it will be addedd
+ QgsProject.instance().addMapLayer(rlayer, False) # Add the raster layer without showing it (False)
+ mygroup = root.findGroup("Nib-prosjekt") # Get the group named "Nib-prosjekt"
+ mygroup.addLayer(rlayer) # Add the layer to this group
+ # Uncheck the raster layer
+ QgsProject.instance().layerTreeRoot().findLayer(rlayer.id()).setItemVisibilityChecked(False)
+ self.iface.messageBar().pushMessage("Success", "WMS added in Nib-prosjekt", level=Qgis.Success, duration=3)
+ else: # If not valid raster layer, an error message will appear
+ self.iface.messageBar().pushMessage("Warning", "Can't load: "+ str(nibprosjwms),level=Qgis.Warning, duration=3)
+
+ # Current working directory will be set as destination folder for project lists
+ cwd = os.getcwd() # Get current working directory
+ # self.iface.messageBar().pushMessage("Info", "katalogen er:" +str(cwd), level=Qgis.Info, duration=3)
+
+ if self.dlg.checkBox_sort.isChecked():
+ nib_liste = sorted(nib_liste)
+
+ if self.dlg.checkBox_savelist.isChecked():
+ if self.dlg.radioButton_btwyears.isChecked():
+ for y in years: # years list is created above and contain all years from start to end year
+ # Delete files if existing
+ fn = str(cwd)+"\\OF_"+str(y)+".txt"
+ if os.path.isfile(fn):
+ os.remove(fn)
+ for n in nib_liste: # sort the nib_liste alphabetically
+ for year in years:
+ if year in n.split():
+ if y == year:
+ with open(str(cwd)+'\\OF_'+str(year)+'.txt','a',encoding='utf-8') as f: # a = append to textfile
+ f.write(str(n)+'\n') # write the OF-project for the specific year to the textfile
+ else:
+ # Delete file if existing
+ fn = str(cwd)+"\\OF_all.txt"
+ if os.path.isfile(fn):
+ os.remove(fn)
+ with open(str(cwd)+'\\OF_all.txt','w',encoding='utf-8') as f: # w = write - will overwrite any existing content https://www.w3schools.com/python/python_file_write.asp
+ for n in nib_liste:
+ f.write(str(n)+'\n') # write the all OF-projects to the textfile
+ # Show message
+ self.iface.messageBar().pushMessage("Success", "List with Nib-projects saved to file", level=Qgis.Success, duration=3)
+# -*- coding: utf-8 -*-
+"""
+/***************************************************************************
+ getnib
+ A QGIS plugin
+
+ Plugin "NIB-ortofoto-prosjekt"
+ Hent alle of-prosjekt i et utsnitt fra Norge i bilder (WMS)
+ Utsnittet kan være bounding boksen til
+ - et kartlag i Layers panel
+ - en fil man laster opp
+ - aktuelt map canvas
+
+Ressures brukt:
+ - Plugin Builder for å få riktig oppsett og nødvendige filer
+ - https://www.qgistutorials.com/en/docs/3/building_a_python_plugin.html
+ NB! husk å lage og å kopiere over compile.bat (trengs for å kompilere resources.py slik at f.eks. eget icon skal bli synlig)
+ Se også https://gis.stackexchange.com/questions/136861/getting-layer-by-name-in-pyqgis
+ - https://docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/cheat_sheet.html#
+ - https://docs.qgis.org/3.16/en/docs/pyqgis_developer_cookbook/plugins/index.html
+ - https://norgeibilder.no/dok/webtjenester.pdf for å få tilgang til Metadata og se påkrevd format på input-verdier
+ - installert QGIS plugin "Releod plugin" for å oppdatere endringer gjort i plugin-en
+ - OSGeo4W-installasjon av QGIS med Qt Designer inkludert mtp. utforming av plugin
+ - logo hentet fra https://www.flaticon.com
+ Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
+ -------------------
+ begin : 2021-12-22
+ git sha : $Format:%H$
+ copyright : (C) 2021 by ban, NIBIO
+ email : ban@nibio.no
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+"""
+#Default modules
+from qgis.PyQt.QtCore import QUrl, QSettings, QTranslator, QCoreApplication
+from qgis.PyQt.QtGui import QIcon, QDesktopServices
+from qgis.PyQt.QtWidgets import QAction, QFileDialog, QMessageBox
+
+#Import additional modules
+from qgis.PyQt.QtGui import QRegExpValidator, QIntValidator
+from qgis.PyQt.QtCore import QRegExp
+from qgis.core import QgsProject, Qgis, QgsMessageLog, QgsRasterLayer, QgsVectorLayer, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsPointXY
+from qgis.gui import QgsMapCanvas
+from qgis.utils import iface, showPluginHelp
+from urllib import parse # for å gå gjennom streng
+import requests # https://www.geeksforgeeks.org/response-json-python-requests/ https://realpython.com/python-requests/
+import os # get the current working directory, access to file / path
+import datetime # get the current year
+
+# Initialize Qt resources from file resources.py
+from .resources import *
+# Import the code for the dialog
+from .get_nib_dialog import getnibDialog
+import os.path
+
+
+class getnib:
+ """QGIS Plugin Implementation."""
+
+ def __init__(self, iface):
+ """Constructor.
+
+ :param iface: An interface instance that will be passed to this class
+ which provides the hook by which you can manipulate the QGIS
+ application at run time.
+ :type iface: QgsInterface
+ """
+ # Save reference to the QGIS interface
+ self.iface = iface
+ # initialize plugin directory
+ self.plugin_dir = os.path.dirname(__file__)
+ # initialize locale
+ locale = QSettings().value('locale/userLocale')[0:2]
+ locale_path = os.path.join(
+ self.plugin_dir,
+ 'i18n',
+ 'getnib_{}.qm'.format(locale))
+
+ if os.path.exists(locale_path):
+ self.translator = QTranslator()
+ self.translator.load(locale_path)
+ QCoreApplication.installTranslator(self.translator)
+
+ # Declare instance attributes
+ self.actions = []
+ self.menu = self.tr(u'&NIB of-prosjekt')
+
+ # Check if plugin was started the first time in current QGIS session
+ # Must be set in initGui() to survive plugin reloads
+ self.first_start = None
+
+ # noinspection PyMethodMayBeStatic
+ def tr(self, message):
+ """Get the translation for a string using Qt translation API.
+
+ We implement this ourselves since we do not inherit QObject.
+
+ :param message: String for translation.
+ :type message: str, QString
+
+ :returns: Translated version of message.
+ :rtype: QString
+ """
+ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
+ return QCoreApplication.translate('getnib', message)
+
+
+ def add_action(
+ self,
+ icon_path,
+ text,
+ callback,
+ enabled_flag=True,
+ add_to_menu=True,
+ add_to_toolbar=True,
+ status_tip=None,
+ whats_this=None,
+ parent=None):
+ """Add a toolbar icon to the toolbar.
+
+ :param icon_path: Path to the icon for this action. Can be a resource
+ path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
+ :type icon_path: str
+
+ :param text: Text that should be shown in menu items for this action.
+ :type text: str
+
+ :param callback: Function to be called when the action is triggered.
+ :type callback: function
+
+ :param enabled_flag: A flag indicating if the action should be enabled
+ by default. Defaults to True.
+ :type enabled_flag: bool
+
+ :param add_to_menu: Flag indicating whether the action should also
+ be added to the menu. Defaults to True.
+ :type add_to_menu: bool
+
+ :param add_to_toolbar: Flag indicating whether the action should also
+ be added to the toolbar. Defaults to True.
+ :type add_to_toolbar: bool
+
+ :param status_tip: Optional text to show in a popup when mouse pointer
+ hovers over the action.
+ :type status_tip: str
+
+ :param parent: Parent widget for the new action. Defaults None.
+ :type parent: QWidget
+
+ :param whats_this: Optional text to show in the status bar when the
+ mouse pointer hovers over the action.
+
+ :returns: The action that was created. Note that the action is also
+ added to self.actions list.
+ :rtype: QAction
+ """
+
+ icon = QIcon(icon_path)
+ action = QAction(icon, text, parent)
+ action.triggered.connect(callback)
+ action.setEnabled(enabled_flag)
+
+ if status_tip is not None:
+ action.setStatusTip(status_tip)
+
+ if whats_this is not None:
+ action.setWhatsThis(whats_this)
+
+ if add_to_toolbar:
+ # Adds plugin icon to Plugins toolbar
+ self.iface.addToolBarIcon(action)
+
+ if add_to_menu:
+ self.iface.addPluginToMenu(
+ self.menu,
+ action)
+
+ self.actions.append(action)
+
+ return action
+
+ def initGui(self):
+ """Create the menu entries and toolbar icons inside the QGIS GUI."""
+
+ icon_path = ':/plugins/get_nib/icon.png'
+ self.add_action(
+ icon_path,
+ text=self.tr(u'Hent of-prosjekt'),
+ callback=self.run,
+ parent=self.iface.mainWindow())
+
+ # will be set False in run()
+ self.first_start = True
+
+ def unload(self):
+ """Removes the plugin menu item and icon from QGIS GUI."""
+ for action in self.actions:
+ self.iface.removePluginMenu(
+ self.tr(u'&NIB of-prosjekt'),
+ action)
+ self.iface.removeToolBarIcon(action)
+
+
+ """ Additional methods """
+ def select_input_file(self):
+ """ Får å velge fil som skal tjene som bounding box """
+ filename, _filter = QFileDialog.getOpenFileName(
+ self.dlg, "Select a file ","", 'geo-files (*.shp *.geojson *.gpkg *.gml *.jpg *.tif);; All files (*.*)')
+ self.dlg.lineEdit_file.setText(filename)
+ self.dlg.radioButton_file.setChecked(True) # In case you choose a file directly without first chosing this option
+
+ def show_help(self):
+ """ Display application help to the user. """
+ help_file = 'file:///%s/index.html' % self.plugin_dir
+ # For testing path:
+ # QMessageBox.information(None, 'Help File', help_file)
+ QDesktopServices.openUrl(QUrl(help_file))
+
+ def check_bbsize(self, srid, xmin, xmax, ymin, ymax):
+ """ Check length and height of bounding box. Limit is set to 50 km """
+ sourceCrs = QgsCoordinateReferenceSystem(srid) # Input project or layer crs
+ destCrs = QgsCoordinateReferenceSystem('EPSG:3035') # ETRS89-extended / LAEA Europe
+ transformContext = QgsProject.instance().transformContext()
+ xform = QgsCoordinateTransform(sourceCrs, destCrs, transformContext)
+ # Forward transformation: src -> dest
+ # Computes length and height in LAEA regardless input crs
+ ll = xform.transform(QgsPointXY(xmin,ymin)) # Bounding box's lower left corner
+ ur = xform.transform(QgsPointXY(xmax,ymax)) # Bounding box's upper right corner
+ # Get the maximum height and length of the bounding box (limit is set to 50 km)
+ xdist = (ur.x()-ll.x())/1000 # Get lenght in km (xmax-xmin)
+ ydist = (ur.y()-ll.y())/1000 # Get height in km (ymax-ymin)
+ if xdist > 500 or ydist > 500:
+ self.iface.messageBar().pushMessage("Error", "Height or length of bounding box can't be > 500 km",level=Qgis.Critical, duration=3)
+ ok = False
+ else:
+ ok = True # Bounding box is small enough
+ return ok
+
+ ## Bounding box ##
+
+ # When you change your mind during input (started input of one bb-option and then chnages to another bb-option),
+ # e.g. have entered a length or selected a file, but change your mind and click Use current map canvas insted.
+ # Then length and the file should be wiped out.
+ def notUdbb(self):
+ self.dlg.lineEdit_lengthbb.clear()
+ self.dlg.lineEdit_heightbb.clear()
+ self.dlg.lineEdit_lengthbb.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+ self.dlg.lineEdit_heightbb.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+
+ def notFile(self):
+ self.dlg.lineEdit_file.clear()
+ self.dlg.lineEdit_file.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+
+ # When "Use current map canvas"-option: length, height and file turns white (if you change your mind)
+ def ucmcbbClicked(self):
+ if self.dlg.radioButton_ucmcbb.isChecked():
+ self.notUdbb() # if you change option
+ self.notFile() # if you change option
+
+ # When "User-defined"-option: length turns yellow and is focused
+ def udbbClicked(self):
+ if self.dlg.radioButton_udbb.isChecked():
+ self.notFile() # if you change option
+ self.dlg.lineEdit_lengthbb.setFocus()
+ self.dlg.lineEdit_lengthbb.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : yellow"
+ "}")
+
+ # When length entered: length turns white
+ def lengthbbEdited(self):
+ self.dlg.lineEdit_lengthbb.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+ self.dlg.radioButton_udbb.setChecked(True)
+
+ # When length finished entered: height turns yellow and is focused
+ def lengthbbFinished(self):
+ self.dlg.lineEdit_heightbb.setFocus()
+ self.dlg.lineEdit_heightbb.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : yellow"
+ "}")
+
+ # When height edited: height turns white
+ def heightbbEdited(self):
+ self.dlg.lineEdit_heightbb.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+
+ # When "layer"-option:
+ def lyrClicked(self):
+ if self.dlg.radioButton_lyr.isChecked():
+ self.notUdbb() # if you change option
+ self.notFile() # if you change option
+
+ # When selected lyr is changed
+ def lyrActivated(self):
+ self.dlg.radioButton_lyr.setChecked(True)
+
+ # When "file"-option: file turns yellow and is focused
+ def fileClicked(self):
+ if self.dlg.radioButton_file.isChecked():
+ if self.dlg.lineEdit_file.text() == '':
+ self.dlg.lineEdit_file.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : yellow"
+ "}")
+ self.notUdbb() # if you change option
+
+ # When file selected: file lineedit turns white
+ def fileSelected(self):
+ self.dlg.lineEdit_file.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+
+ ## Years ##
+ # When "All years"-option: start-year turns white (if you change your mind)
+ def allyearsClicked(self):
+ if self.dlg.radioButton_allyears.isChecked():
+ self.dlg.lineEdit_startyear.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+ self.dlg.lineEdit_startyear.clear()
+ self.dlg.lineEdit_endyear.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+ self.dlg.lineEdit_endyear.clear()
+
+ # When "Between years"-option: start-year turns yellow and is focused
+ def btwyearsClicked(self):
+ if self.dlg.radioButton_btwyears.isChecked():
+ self.dlg.lineEdit_startyear.setFocus()
+ self.dlg.lineEdit_startyear.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : yellow"
+ "}")
+
+ # When start-year entered: start-year turns white
+ def startEdited(self):
+ self.dlg.lineEdit_startyear.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+ # Due to "All years"-option is set to default:
+ self.dlg.radioButton_btwyears.setChecked(True) # Check
+
+ # When start-year finished entered: end-year turns yellow and is focused
+ def startFinished(self):
+ self.dlg.lineEdit_endyear.setFocus()
+ self.dlg.lineEdit_endyear.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : yellow"
+ "}")
+
+ # When end-year edited: end-year turns white
+ def endEdited(self):
+ self.dlg.lineEdit_endyear.setStyleSheet("QLineEdit"
+ "{"
+ "background-color : white"
+ "}")
+ """ end additional methods """
+
+
+ def run(self):
+ """Run method that performs all the real work"""
+
+ # Create the dialog with elements (after translation) and keep reference
+ # Only create GUI ONCE in callback, so that it will only load when the plugin is started
+ if self.first_start == True:
+ self.first_start = False
+ self.dlg = getnibDialog()
+ """ Additional code """
+ #connect the select_input_file method to the clicked signal of the push button widget
+ self.dlg.pushButton_file.clicked.connect(self.select_input_file)
+ self.dlg.toolButton_help.clicked.connect(self.show_help)
+
+ self.dlg.radioButton_ucmcbb.toggled.connect(self.ucmcbbClicked) # When current map canvas bb is chosen
+
+ self.dlg.radioButton_udbb.toggled.connect(self.udbbClicked) # When User-defined bb is chosen
+ self.dlg.lineEdit_lengthbb.textEdited.connect(self.lengthbbEdited) # Whenever length is edited
+ self.dlg.lineEdit_lengthbb.editingFinished.connect(self.lengthbbFinished) # When you press ‘Enter’ or length loses focus
+ self.dlg.lineEdit_heightbb.textEdited.connect(self.heightbbEdited) # Whenever height is edited
+
+ self.dlg.radioButton_lyr.toggled.connect(self.lyrClicked) # When lyr bb is chosen
+ self.dlg.comboBox_lyr.activated.connect(self.lyrActivated) # Whenever a lyr item is chosen
+
+ self.dlg.radioButton_file.toggled.connect(self.fileClicked) # When file bb is chosen
+ self.dlg.lineEdit_file.textChanged.connect(self.fileSelected) # Whenever file is selected
+
+ self.dlg.radioButton_allyears.toggled.connect(self.allyearsClicked) # When All years is chosen
+
+ self.dlg.radioButton_btwyears.toggled.connect(self.btwyearsClicked) # When Between years is chosen
+ self.dlg.lineEdit_startyear.textEdited.connect(self.startEdited) # Whenever the start year is edited
+ self.dlg.lineEdit_startyear.editingFinished.connect(self.startFinished) # When you press ‘Enter’ or start loses focus
+ self.dlg.lineEdit_endyear.textEdited.connect(self.endEdited) # Whenever end year is edited
+
+ # As default: Remember user input from previous run
+ """ If this should not be the default, remove comment # from next line """
+ # self.dlg.checkBox_resetNib.setChecked(False) # Unchecked
+
+ # As default: Set map canvas checkbox to checked
+ """ If this should not be the default, comment # next line """
+ self.dlg.radioButton_ucmcbb.setChecked(True) # Checked
+
+ # Clear the contents of the lineEdit_lengthbb from previous runs
+ self.dlg.lineEdit_lengthbb.clear()
+ # Clear the contents of the lineEdit_heightbb from previous runs
+ self.dlg.lineEdit_heightbb.clear()
+ # Clear the contents of the lineEdit_start (year) from previous runs
+ self.dlg.lineEdit_startyear.clear()
+ # Clear the contents of the lineEdit_end (year) from previous runs
+ self.dlg.lineEdit_endyear.clear()
+ # Clear the contents of the lineEdit_file (select file) from previous runs
+ self.dlg.lineEdit_file.clear()
+
+ self.dlg.radioButton_file.setChecked(False) # Unchecked
+
+ # Fetch the currently loaded layers
+ layers = QgsProject.instance().mapLayers()
+ # Clear the contents of the combobox from previous runs
+ self.dlg.comboBox_lyr.clear()
+ # Populate the combobox with names of all the loaded layers
+ layer_list = []
+ unique_lyr = []
+ for layer in layers.values():
+ item = layer.name()
+ layer_list.append(item) # Includes duplicates
+ unique_lyr = list(set(layer_list)) # No duplicates
+ self.dlg.comboBox_lyr.addItems(unique_lyr) # Populate combobox
+ self.dlg.comboBox_lyr.model().sort(0) # Sort layer names (includes filepath) alfabetically
+
+ # Length and height: allowing only 1-500
+ l = self.dlg.lineEdit_lengthbb
+ l.setValidator(QRegExpValidator(QRegExp("[1-9]|[1-9][0-9]|[1-4][0-9][0-9]|500")))
+ h = self.dlg.lineEdit_heightbb
+ h.setValidator(QRegExpValidator(QRegExp("[1-9]|[1-9][0-9]|[1-4][0-9][0-9]|500")))
+
+ # As default: Set all years radiobutton to checked
+ """ If this should not be the default, comment # next line """
+ self.dlg.radioButton_allyears.setChecked(True) # Checked
+
+ # Start- and end-year: must be 1900-current year
+ currentDate = datetime.date.today()
+ cy = currentDate.year # get current year, e.g. 2022 (position 0,1,2,3)
+ # cy = 2042 # used for testing the regexp
+ cy = str(cy) # Convert number to string
+ d3 = cy[2] # Get the third digit (in position 2)
+ d4 = cy[3] # Get the fourth digit (in position 3)
+ # # Debugging
+ # self.iface.messageBar().pushMessage("Info", "To siste sifre i år er: "+d3+', '+d4, level=Qgis.Info, duration=3)
+
+ # Verifying the entered years
+ start = self.dlg.lineEdit_startyear
+ start.setValidator(QRegExpValidator(QRegExp("19[0-9][0-9]|20[0-"+str(int(d3)-1)+"][0-9]|20["+d3+"][0-"+d4+"]")))
+ end = self.dlg.lineEdit_endyear
+ end.setValidator(QRegExpValidator(QRegExp("19[0-9][0-9]|20[0-"+str(int(d3)-1)+"][0-9]|20["+d3+"][0-"+d4+"]")))
+
+ # Get projects epsg-code # e.g.
+ crs_proj_str = iface.mapCanvas().mapSettings().destinationCrs().authid() # EPSG:25832
+ crs_proj_int = int(crs_proj_str[5:]) # 25832
+ epsg_list = [25832, 25833, 25835]
+ if not crs_proj_int in epsg_list:
+ self.iface.messageBar().pushMessage("Error", "Project must be in UTM 32, 33 or 35", level=Qgis.Critical, duration=3)
+ return # Return from (end) plugin
+
+ """ end additional code """
+
+
# show the dialog
self.dlg.show()
# Run the dialog event loop
--
GitLab