class OpenTripPlannerPlugin(): """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', 'OpenTripPlannerPlugin_{}.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'&OpenTripPlanner Plugin') # 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('OpenTripPlannerPlugin', 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/otp_plugin/icon.png' self.add_action(icon_path, text=self.tr(u'OpenTripPlanner Plugin'), 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'&OpenTripPlanner Plugin'), action) self.iface.removeToolBarIcon(action) def isochronesStartWorker(self): # method to start the worker thread if not self.gf.isochrones_selectedlayer: # dont execute if no layer is selected QgsMessageLog.logMessage( "Warning! No inputlayer selected. Choose an inputlayer and try again.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " No inputlayer selected. Choose an inputlayer and try again.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return if self.gf.isochrones_selectedlayer.featureCount() == 0: QgsMessageLog.logMessage( "Warning! Inputlayer is empty. Add some features and try again.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " Inputlayer is empty. Add some features and try again.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return isochrones_memorylayer_vl = QgsVectorLayer( "MultiPolygon?crs=epsg:4326", "Isochrones", "memory") # Create temporary polygon layer (output file) self.isochrones_thread = QThread() self.isochrones_worker = OpenTripPlannerPluginIsochronesWorker( self.dlg, self.iface, self.gf, isochrones_memorylayer_vl) # see https://realpython.com/python-pyqt-qthread/#using-qthread-to-prevent-freezing-guis # and https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html self.isochrones_worker.moveToThread( self.isochrones_thread) # move Worker-Class to a thread # Connect signals and slots: self.isochrones_thread.started.connect(self.isochrones_worker.run) self.isochrones_worker.isochrones_finished.connect( self.isochrones_thread.quit) self.isochrones_worker.isochrones_finished.connect( self.isochrones_worker.deleteLater) self.isochrones_thread.finished.connect( self.isochrones_thread.deleteLater) self.isochrones_worker.isochrones_progress.connect( self.isochronesReportProgress) self.isochrones_worker.isochrones_finished.connect( self.isochronesFinished) self.isochrones_thread.start() # finally start the thread # Disable/Enable GUI elements to prevent them from beeing used while worker threads are running and accidentially changing settings during progress self.gf.disableIsochronesGui() self.gf.disableGeneralSettingsGui() self.isochrones_thread.finished.connect( lambda: self.gf.enableIsochronesGui()) self.isochrones_thread.finished.connect( lambda: self.gf.enableGeneralSettingsGui()) def isochronesKillWorker(self): # method to kill/cancel the worker thread # print('pushed cancel') # debugging # see https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html try: # to prevent a Python error when the cancel button has been clicked but no thread is running use try/except self.isochrones_worker.stop( ) # call the stop method in worker class to break the work-loop so we can quit the thread if self.isochrones_thread.isRunning( ): # check if a thread is running # print('pushed cancel, thread is running, trying to cancel') # debugging self.isochrones_thread.requestInterruption() self.isochrones_thread.exit( ) # Tells the thread’s event loop to exit with a return code. self.isochrones_thread.quit( ) # Tells the thread’s event loop to exit with return code 0 (success). Equivalent to calling exit (0). self.isochrones_thread.wait( ) # Blocks the thread until https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html#PySide6.QtCore.PySide6.QtCore.QThread.wait except: self.dlg.Isochrones_ProgressBar.setValue(0) self.dlg.Isochrones_StatusBox.setText('') def isochronesReportProgress( self, progress, status): # method to report the progress to gui self.dlg.Isochrones_ProgressBar.setValue( progress) # set the current progress in progress bar self.dlg.Isochrones_StatusBox.setText(status) def isochronesFinished( self, isochrones_resultlayer, isochrones_state, unique_errors="", runtime="00:00:00 (unknown)" ): # method to interact with gui when thread is finished or canceled QgsProject.instance().addMapLayer( isochrones_resultlayer) # Show resultlayer in project # isochrones_state is indicating different states of the thread/result as integer if unique_errors: self.iface.messageBar().pushMessage( "Warning", " Errors occurred. Check the resultlayer for details. The errors were: " + unique_errors + " - Created dummy geometries at coordinate 0,0 on error features", MESSAGE_CATEGORY, level=Qgis.Warning, duration=12) QgsMessageLog.logMessage( "Errors occurred. Check the resultlayer for details. The errors were: " + unique_errors + " - Created dummy geometries at coordinate 0,0 on error features", MESSAGE_CATEGORY, Qgis.Warning) if isochrones_state == 0: self.iface.messageBar().pushMessage( "Warning", " Run-Method was never executed.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) elif isochrones_state == 1: self.iface.messageBar().pushMessage( "Done!", " Isochrones job finished after " + runtime, MESSAGE_CATEGORY, level=Qgis.Success, duration=6) elif isochrones_state == 2: self.iface.messageBar().pushMessage( "Done!", " Isochrones job canceled after " + runtime, MESSAGE_CATEGORY, level=Qgis.Success, duration=6) elif isochrones_state == 3: self.iface.messageBar().pushMessage( "Warning", " No Isochrones to create - Check your settings and retry.", MESSAGE_CATEGORY, level=Qgis.Warning, duration=6) elif isochrones_state == 99: self.iface.messageBar().pushMessage( "Debugging", " Just having some debugging fun :)", MESSAGE_CATEGORY, level=Qgis.Info, duration=6) else: self.iface.messageBar().pushMessage( "Warning", " Unknown error occurred during execution.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) def aggregated_isochronesStartWorker( self): # method to start the worker thread if not self.gf.aggregated_isochrones_selectedlayer: # dont execute if no layer is selected QgsMessageLog.logMessage( "Warning! No inputlayer selected. Choose an inputlayer and try again.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " No inputlayer selected. Choose an inputlayer and try again.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return if self.gf.aggregated_isochrones_selectedlayer.featureCount() == 0: QgsMessageLog.logMessage( "Warning! Inputlayer is empty. Add some features and try again.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " Inputlayer is empty. Add some features and try again.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return aggregated_isochrones_memorylayer_vl = QgsVectorLayer( "MultiPolygon?crs=epsg:4326", "AggregatedIsochrones", "memory") # Create temporary polygon layer (output file) self.aggregated_isochrones_thread = QThread() self.aggregated_isochrones_worker = OpenTripPlannerPluginAggregatedIsochronesWorker( self.dlg, self.iface, self.gf, aggregated_isochrones_memorylayer_vl) # see https://realpython.com/python-pyqt-qthread/#using-qthread-to-prevent-freezing-guis # and https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html self.aggregated_isochrones_worker.moveToThread( self.aggregated_isochrones_thread) # move Worker-Class to a thread # Connect signals and slots: self.aggregated_isochrones_thread.started.connect( self.aggregated_isochrones_worker.run) self.aggregated_isochrones_worker.aggregated_isochrones_finished.connect( self.aggregated_isochrones_thread.quit) self.aggregated_isochrones_worker.aggregated_isochrones_finished.connect( self.aggregated_isochrones_worker.deleteLater) self.aggregated_isochrones_thread.finished.connect( self.aggregated_isochrones_thread.deleteLater) self.aggregated_isochrones_worker.aggregated_isochrones_progress.connect( self.aggregated_isochronesReportProgress) self.aggregated_isochrones_worker.aggregated_isochrones_finished.connect( self.aggregated_isochronesFinished) self.aggregated_isochrones_thread.start() # finally start the thread # Disable/Enable GUI elements to prevent them from beeing used while worker threads are running and accidentially changing settings during progress self.gf.disableAggregatedIsochronesGui() self.gf.disableGeneralSettingsGui() self.aggregated_isochrones_thread.finished.connect( lambda: self.gf.enableAggregatedIsochronesGui()) self.aggregated_isochrones_thread.finished.connect( lambda: self.gf.enableGeneralSettingsGui()) def aggregated_isochronesKillWorker( self): # method to kill/cancel the worker thread # print('pushed cancel') # debugging # see https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html try: # to prevent a Python error when the cancel button has been clicked but no thread is running use try/except self.aggregated_isochrones_worker.stop( ) # call the stop method in worker class to break the work-loop so we can quit the thread if self.aggregated_isochrones_thread.isRunning( ): # check if a thread is running # print('pushed cancel, thread is running, trying to cancel') # debugging self.aggregated_isochrones_thread.requestInterruption() self.aggregated_isochrones_thread.exit( ) # Tells the thread’s event loop to exit with a return code. self.aggregated_isochrones_thread.quit( ) # Tells the thread’s event loop to exit with return code 0 (success). Equivalent to calling exit (0). self.aggregated_isochrones_thread.wait( ) # Blocks the thread until https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html#PySide6.QtCore.PySide6.QtCore.QThread.wait except: self.dlg.AggregatedIsochrones_ProgressBar.setValue(0) self.dlg.AggregatedIsochrones_StatusBox.setText('') def aggregated_isochronesReportProgress( self, progress, status): # method to report the progress to gui self.dlg.AggregatedIsochrones_ProgressBar.setValue( progress) # set the current progress in progress bar self.dlg.AggregatedIsochrones_StatusBox.setText(status) def aggregated_isochronesFinished( self, aggregated_isochrones_resultlayer, aggregated_isochrones_state, unique_errors="", runtime="00:00:00 (unknown)" ): # method to interact with gui when thread is finished or canceled QgsProject.instance().addMapLayer( aggregated_isochrones_resultlayer) # Show resultlayer in project # aggregated_isochrones_state is indicating different states of the thread/result as integer if unique_errors: self.iface.messageBar().pushMessage( "Warning", " Errors occurred. Check the resultlayer for details. The errors were: " + unique_errors, MESSAGE_CATEGORY, level=Qgis.Warning, duration=12) QgsMessageLog.logMessage( "Errors occurred. Check the resultlayer for details. The errors were: " + unique_errors, MESSAGE_CATEGORY, Qgis.Warning) if aggregated_isochrones_state == 0: self.iface.messageBar().pushMessage( "Warning", " Run-Method was never executed.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) elif aggregated_isochrones_state == 1: self.iface.messageBar().pushMessage( "Done!", " Isochrones job finished after " + runtime, MESSAGE_CATEGORY, level=Qgis.Success, duration=6) elif aggregated_isochrones_state == 2: self.iface.messageBar().pushMessage( "Done!", " Isochrones job canceled after " + runtime, MESSAGE_CATEGORY, level=Qgis.Success, duration=6) elif aggregated_isochrones_state == 3: self.iface.messageBar().pushMessage( "Warning", " No Isochrones to create - Check your settings and retry.", MESSAGE_CATEGORY, level=Qgis.Warning, duration=6) elif aggregated_isochrones_state == 4: self.iface.messageBar().pushMessage( "Warning", " There is something wrong with your DateTime-Settings, check them and try again.", MESSAGE_CATEGORY, level=Qgis.Warning, duration=6) elif aggregated_isochrones_state == 99: self.iface.messageBar().pushMessage( "Debugging", " Just having some debugging fun :)", MESSAGE_CATEGORY, level=Qgis.Info, duration=6) else: self.iface.messageBar().pushMessage( "Warning", " Unknown error occurred during execution.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) def routesStartWorker(self): # method to start the worker thread if not self.gf.routes_selectedlayer_source or not self.gf.routes_selectedlayer_target: QgsMessageLog.logMessage( "Warning! No inputlayer selected. Choose your inputlayers and try again.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " No sourcelayer or no targetlayer selected. Choose your inputlayers and try again.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return if self.gf.routes_selectedlayer_source.fields().count( ) == 0 or self.gf.routes_selectedlayer_target.fields().count() == 0: QgsMessageLog.logMessage( "Warning! Inputlayer has no fields. Script wont work until you add at least one dummy ID-Field.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " Inputlayer has no fields - Add at least a dummy-id field.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return if self.gf.routes_selectedlayer_source.featureCount( ) == 0 or self.gf.routes_selectedlayer_target.featureCount() == 0: QgsMessageLog.logMessage( "Warning! One or both inputlayers are empty. Add some features and try again.", MESSAGE_CATEGORY, Qgis.Critical) self.iface.messageBar().pushMessage( "Warning", " One or both inputlayers are empty. Add some features and try again.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) return routes_memorylayer_vl = QgsVectorLayer( "LineString?crs=epsg:4326", "Routes", "memory") # Create temporary polygon layer (output file) self.routes_thread = QThread() self.routes_worker = OpenTripPlannerPluginRoutesWorker( self.dlg, self.iface, self.gf, routes_memorylayer_vl) # see https://realpython.com/python-pyqt-qthread/#using-qthread-to-prevent-freezing-guis # and https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html self.routes_worker.moveToThread( self.routes_thread) # move Worker-Class to a thread # Connect signals and slots: self.routes_thread.started.connect(self.routes_worker.run) self.routes_worker.routes_finished.connect(self.routes_thread.quit) self.routes_worker.routes_finished.connect( self.routes_worker.deleteLater) self.routes_thread.finished.connect(self.routes_thread.deleteLater) self.routes_worker.routes_progress.connect(self.routesReportProgress) self.routes_worker.routes_finished.connect(self.routesFinished) self.routes_thread.start() # finally start the thread # Disable/Enable GUI elements to prevent them from beeing used while worker threads are running and accidentially changing settings during progress self.gf.disableRoutesGui() self.gf.disableGeneralSettingsGui() self.routes_thread.finished.connect(lambda: self.gf.enableRoutesGui()) self.routes_thread.finished.connect( lambda: self.gf.enableGeneralSettingsGui()) def routesKillWorker(self): # method to kill/cancel the worker thread # print('pushed cancel') # debugging # see https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html try: # to prevent a Python error when the cancel button has been clicked but no thread is running use try/except self.routes_worker.stop( ) # call the stop method in worker class to break the work-loop so we can quit the thread if self.routes_thread.isRunning(): # check if a thread is running # print('pushed cancel, thread is running, trying to cancel') # debugging self.routes_thread.requestInterruption() self.routes_thread.exit( ) # Tells the thread’s event loop to exit with a return code. self.routes_thread.quit( ) # Tells the thread’s event loop to exit with return code 0 (success). Equivalent to calling exit (0). self.routes_thread.wait( ) # Blocks the thread until https://doc.qt.io/qtforpython/PySide6/QtCore/QThread.html#PySide6.QtCore.PySide6.QtCore.QThread.wait except: self.dlg.Routes_ProgressBar.setValue(0) self.dlg.Routes_StatusBox.setText('') def routesReportProgress(self, progress, status): # method to report the progress to gui self.dlg.Routes_ProgressBar.setValue( progress) # set the current progress in progress bar self.dlg.Routes_StatusBox.setText(status) def routesFinished( self, routes_resultlayer, routes_state, unique_errors="", runtime="00:00:00 (unknown)" ): # method to interact with gui when thread is finished or canceled QgsProject.instance().addMapLayer( routes_resultlayer) # Show resultlayer in project # routes_state is indicating different states of the thread/result as integer if unique_errors: self.iface.messageBar().pushMessage( "Warning", " Errors occurred. Check the resultlayer for details. The errors were: " + unique_errors + " - Created dummy geometries at coordinate 0,0 on error features", MESSAGE_CATEGORY, level=Qgis.Warning, duration=12) QgsMessageLog.logMessage( "Errors occurred. Check the resultlayer for details. The errors were: " + unique_errors + " - Created dummy geometries at coordinate 0,0 on error features", MESSAGE_CATEGORY, Qgis.Warning) if routes_state == 0: self.iface.messageBar().pushMessage( "Warning", " Run-Method was never executed.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) elif routes_state == 1: self.iface.messageBar().pushMessage("Done!", " Routes job finished after " + runtime, MESSAGE_CATEGORY, level=Qgis.Success, duration=6) elif routes_state == 2: self.iface.messageBar().pushMessage("Done!", " Routes job canceled after " + runtime, MESSAGE_CATEGORY, level=Qgis.Success, duration=6) elif routes_state == 3: self.iface.messageBar().pushMessage( "Warning", " No Routes to create / no matching attributes - Check your settings and retry.", MESSAGE_CATEGORY, level=Qgis.Warning, duration=6) elif routes_state == 99: self.iface.messageBar().pushMessage( "Debugging", " Just having some debugging fun :)", MESSAGE_CATEGORY, level=Qgis.Info, duration=6) else: self.iface.messageBar().pushMessage( "Warning", " Unknown error occurred during execution.", MESSAGE_CATEGORY, level=Qgis.Critical, duration=6) 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 = OpenTripPlannerPluginDialog() self.gf = OpenTripPlannerPluginGeneralFunctions( self.dlg, self.iface) # Calling maplayer selection on first startup to load layers into QgsMapLayerComboBox and initialize QgsOverrideButton stuff so selections can be done without actually using the QgsMapLayerComboBox (related to currentIndexChanged.connect(self.isochrones_maplayerselection) below) self.gf.routes_maplayerselection() self.gf.isochrones_maplayerselection() self.gf.aggregated_isochrones_maplayerselection() # Execute Main-Functions on Click: Placing them here prevents them from beeing executed multiple times, see https://gis.stackexchange.com/a/137161/107424 self.dlg.Isochrones_RequestIsochrones.clicked.connect( lambda: self.isochronesStartWorker() ) #Call the start worker method self.dlg.Isochrones_Cancel.clicked.connect( lambda: self.isochronesKillWorker()) self.dlg.AggregatedIsochrones_RequestIsochrones.clicked.connect( lambda: self.aggregated_isochronesStartWorker() ) #Call the start worker method self.dlg.AggregatedIsochrones_Cancel.clicked.connect( lambda: self.aggregated_isochronesKillWorker()) self.dlg.Routes_RequestRoutes.clicked.connect( lambda: self.routesStartWorker()) self.dlg.Routes_Cancel.clicked.connect( lambda: self.routesKillWorker()) # Calling Functions on button click self.dlg.GeneralSettings_CheckServerStatus.clicked.connect( self.gf.check_server_status) self.dlg.GeneralSettings_Save.clicked.connect( self.gf.store_general_variables ) #Call store_general_variables function when clicking on save button self.dlg.GeneralSettings_Restore.clicked.connect( self.gf.restore_general_variables) self.dlg.Isochrones_SaveSettings.clicked.connect( self.gf.store_isochrone_variables) self.dlg.Isochrones_RestoreDefaultSettings.clicked.connect( self.gf.restore_isochrone_variables) self.dlg.Isochrones_Now.clicked.connect( self.gf.set_datetime_now_isochrone) self.dlg.AggregatedIsochrones_SaveSettings.clicked.connect( self.gf.store_aggregated_isochrone_variables) self.dlg.AggregatedIsochrones_RestoreDefaultSettings.clicked.connect( self.gf.restore_aggregated_isochrone_variables) self.dlg.AggregatedIsochrones_Now.clicked.connect( self.gf.set_datetime_now_aggregated_isochrone) self.dlg.Routes_SaveSettings.clicked.connect( self.gf.store_route_variables) self.dlg.Routes_RestoreDefaultSettings.clicked.connect( self.gf.restore_route_variables) self.dlg.Routes_Now.clicked.connect(self.gf.set_datetime_now_route) # Calling Functions to update layer stuff when layerselection has changed self.dlg.Isochrones_SelectInputLayer.currentIndexChanged.connect( self.gf.isochrones_maplayerselection ) # Call function isochrones_maplayerselection to update all selection related stuff when selection has been changed self.dlg.AggregatedIsochrones_SelectInputLayer.currentIndexChanged.connect( self.gf.aggregated_isochrones_maplayerselection) self.dlg.Routes_SelectInputLayer_Source.currentIndexChanged.connect( self.gf.routes_maplayerselection) self.dlg.Routes_SelectInputLayer_Target.currentIndexChanged.connect( self.gf.routes_maplayerselection) self.dlg.Routes_SelectInputField_Source.currentIndexChanged.connect( self.gf.routes_maplayerselection) # or "fieldChanged"? self.dlg.Routes_SelectInputField_Target.currentIndexChanged.connect( self.gf.routes_maplayerselection) self.dlg.Routes_DataDefinedLayer_Source.stateChanged.connect( self.gf.routes_maplayerselection) self.dlg.Routes_DataDefinedLayer_Target.stateChanged.connect( self.gf.routes_maplayerselection) # Setting GUI stuff for startup every time the plugin is opened self.dlg.Isochrones_Date.setDateTime( QtCore.QDateTime.currentDateTime() ) # Set Dateselection to today on restart or firststart, only functional if never used save settings, otherwise overwritten by read_route_variables() self.dlg.AggregatedIsochrones_FromDateTime.setDateTime( QtCore.QDateTime.currentDateTime()) self.dlg.AggregatedIsochrones_ToDateTime.setDateTime( QtCore.QDateTime.currentDateTime()) self.dlg.Routes_Date.setDateTime(QtCore.QDateTime.currentDateTime()) self.dlg.Isochrones_ProgressBar.setValue( 0) # Set Progressbar to 0 on restart or first start self.dlg.AggregatedIsochrones_ProgressBar.setValue(0) self.dlg.Routes_ProgressBar.setValue(0) self.dlg.GeneralSettings_ServerStatusResult.setText( "Serverstatus Unknown") self.dlg.GeneralSettings_ServerStatusResult.setStyleSheet( "background-color: white; color: black ") # Functions to execute every time the plugin is opened self.gf.read_general_variables( ) #Run Read-Stored-Variables-Function on every start self.gf.read_isochrone_variables() self.gf.read_aggregated_isochrone_variables() self.gf.read_route_variables() # 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. QgsMessageLog.logMessage( "OpenTripPlanner Plugin is already running! Close it before, if you wish to restart it.", MESSAGE_CATEGORY, Qgis.Warning) self.iface.messageBar().pushMessage( "Error", "OpenTripPlanner Plugin is already running! Close it before, if you wish to restart it.", MESSAGE_CATEGORY, level=Qgis.Warning, duration=6)