예제 #1
0
    def __init__(self):
        """
        Used to initialize this object. An empty dictionary of DPlugin is created

        :return:
        """
        self.__DPlugins = {}

        self.__newid = 0
        self.log = ConsoleLog(2, "DCore: ")
예제 #2
0
 def __init__(self,
              gui_data,
              core_queue,
              gui_id,
              get_gui_config_function=None,
              set_gui_config_function=None,
              TabManager=None,
              plugin_manager=None):
     super(Gui_api, self).__init__()
     self.gui_id = gui_id
     self.gui_data = gui_data
     self.core_queue = core_queue
     self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL,
                           GUI_PROCESS_CONSOLE_IDENTIFIER)
     self.get_gui_config_function = get_gui_config_function
     self.set_gui_config_function = set_gui_config_function
     self.tabManager = TabManager
     self.pluginManager = plugin_manager
예제 #3
0
파일: DCore.py 프로젝트: dani-l/PaPI
    def __init__(self):
        """
        Used to initialize this object. An empty dictionary of DPlugin is created

        :return:
        """
        self.__DPlugins = {}

        self.__newid = 0
        self.log = ConsoleLog(2, "DCore: ")
예제 #4
0
파일: gui_api.py 프로젝트: TUB-Control/PaPI
 def __init__(self, gui_data, core_queue, gui_id, get_gui_config_function = None, set_gui_config_function = None, TabManager = None, plugin_manager = None):
     super(Gui_api, self).__init__()
     self.gui_id = gui_id
     self.gui_data = gui_data
     self.core_queue = core_queue
     self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL, GUI_PROCESS_CONSOLE_IDENTIFIER)
     self.get_gui_config_function = get_gui_config_function
     self.set_gui_config_function = set_gui_config_function
     self.tabManager = TabManager
     self.pluginManager = plugin_manager
예제 #5
0
    def __init__(self, gui_data, core_queue, gui_id, gui_queue, TabManager,
                 plugin_manager):
        """
        Init for eventProcessing

        :param gui_data:    Data object for all the plugin data
        :type gui_data: DGui
        :param core_queue:  multiprocessing queue for process interaction with core process
        :type core_queue: multiprocessing.Queue
        :param gui_id: id of gui process
        :type gui_id: int
        :param gui_queue:  multiprocessing queue for process interaction with gui process
        :type gui_queue: multiprocessing.Queue
        :return:
        """
        super(GuiEventProcessing, self).__init__()
        self.gui_data = gui_data
        self.core_queue = core_queue
        self.gui_id = gui_id
        self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.plugin_manager = plugin_manager
        self.log.lvl = 0

        self.gui_queue = gui_queue
        self.TabManger = TabManager
        # switch case for event processing
        self.process_event = {
            'new_data': self.process_new_data_event,
            'close_programm': self.process_close_program_event,
            'check_alive_status': self.process_check_alive_status,
            'create_plugin': self.process_create_plugin,
            'update_meta': self.process_update_meta,
            'plugin_closed': self.process_plugin_closed,
            'set_parameter': self.process_set_parameter,
            'pause_plugin': self.process_pause_plugin,
            'resume_plugin': self.process_resume_plugin,
            'stop_plugin': self.process_stop_plugin,
            'start_plugin': self.process_restart_plugin,
            'parameter_info': self.process_parameter_info
        }
예제 #6
0
    def __init__(self, gui_data, core_queue, gui_id, gui_queue, TabManager, plugin_manager):
        """
        Init for eventProcessing

        :param gui_data:    Data object for all the plugin data
        :type gui_data: DGui
        :param core_queue:  multiprocessing queue for process interaction with core process
        :type core_queue: multiprocessing.Queue
        :param gui_id: id of gui process
        :type gui_id: int
        :param gui_queue:  multiprocessing queue for process interaction with gui process
        :type gui_queue: multiprocessing.Queue
        :return:
        """
        super(GuiEventProcessing, self).__init__()
        self.gui_data = gui_data
        self.core_queue = core_queue
        self.gui_id = gui_id
        self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL, GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.plugin_manager = plugin_manager
        self.log.lvl = 0

        self.gui_queue = gui_queue
        self.TabManger = TabManager
        # switch case for event processing
        self.process_event = {'new_data': self.process_new_data_event,
                              'close_programm': self.process_close_program_event,
                              'check_alive_status': self.process_check_alive_status,
                              'create_plugin': self.process_create_plugin,
                              'update_meta': self.process_update_meta,
                              'plugin_closed': self.process_plugin_closed,
                              'set_parameter': self.process_set_parameter,
                              'pause_plugin': self.process_pause_plugin,
                              'resume_plugin': self.process_resume_plugin,
                              'stop_plugin': self.process_stop_plugin,
                              'start_plugin': self.process_restart_plugin,
                              'parameter_info': self.process_parameter_info
        }
예제 #7
0
class GuiEventProcessing(QtCore.QObject):
    """
    This class will do all the event handling for a GUI process. It should be created and initialized with database and
    queues.
    To get all the functionality, one should link the callback functions (slots) for the needed signals.

    """
    added_dplugin = QtCore.pyqtSignal(DPlugin)
    removed_dplugin = QtCore.pyqtSignal(DPlugin)
    dgui_changed = QtCore.pyqtSignal()
    plugin_died = QtCore.pyqtSignal(DPlugin, Exception, str)

    def __init__(self, gui_data, core_queue, gui_id, gui_queue, TabManager, plugin_manager):
        """
        Init for eventProcessing

        :param gui_data:    Data object for all the plugin data
        :type gui_data: DGui
        :param core_queue:  multiprocessing queue for process interaction with core process
        :type core_queue: multiprocessing.Queue
        :param gui_id: id of gui process
        :type gui_id: int
        :param gui_queue:  multiprocessing queue for process interaction with gui process
        :type gui_queue: multiprocessing.Queue
        :return:
        """
        super(GuiEventProcessing, self).__init__()
        self.gui_data = gui_data
        self.core_queue = core_queue
        self.gui_id = gui_id
        self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL, GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.plugin_manager = plugin_manager
        self.log.lvl = 0

        self.gui_queue = gui_queue
        self.TabManger = TabManager
        # switch case for event processing
        self.process_event = {'new_data': self.process_new_data_event,
                              'close_programm': self.process_close_program_event,
                              'check_alive_status': self.process_check_alive_status,
                              'create_plugin': self.process_create_plugin,
                              'update_meta': self.process_update_meta,
                              'plugin_closed': self.process_plugin_closed,
                              'set_parameter': self.process_set_parameter,
                              'pause_plugin': self.process_pause_plugin,
                              'resume_plugin': self.process_resume_plugin,
                              'stop_plugin': self.process_stop_plugin,
                              'start_plugin': self.process_restart_plugin,
                              'parameter_info': self.process_parameter_info
        }

    def gui_working(self, close_mock, workingTimer):
        """
         Event processing loop of gui. Build to get called every 40ms after a run through.
         Will process all events of the queue at the time of call.
         Procedure was built this way, so that the processing of an event is not covered by the try/except structure.

         :type event: PapiEventBase
         :type dplugin: DPlugin
        """
        # event flag, true for first loop iteration to enter loop
        isEvent = True
        # event object, if there is an event
        event = None
        while (isEvent):
            # look at queue and try to get a new element
            try:
                event = self.gui_queue.get_nowait()
                # if there is a new element, event flag remains true
                isEvent = True
            except:
                # there was no new element, so event flag is set to false
                isEvent = False


            # check if there was a new element to process it
            if isEvent:
                # get the event operation
                op = event.get_event_operation()
                # debug out
                self.log.printText(2, 'Event: ' + op)
                # process this event
                if op == 'test_close':
                    close_mock()
                else:
                    self.process_event[op](event)
        # after the loop ended, which means that there are no more new events, a new timer will be created to start
        # this method again in a specific time

        workingTimer.start(GUI_WOKRING_INTERVAL)
        #QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_working(close_mock))

    def process_new_data_event(self, event):
        """
        Core sent a new data event to gui. Gui now needs to find the destination plugin and call its execute function
        with the new data.

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # debug print
        self.log.printText(2, 'new data event')
        # get list of destination IDs
        dID_list = event.get_destinatioID()
        # get optional data of event
        opt = event.get_optional_parameter()
        # iterate over destination list
        for dID in dID_list:
            # get destination plugin from DGUI
            dplugin = self.gui_data.get_dplugin_by_id(dID)
            # check if it exists
            if dplugin != None:
                # it exists, so call its execute function, but just if it is not paused ( no data delivery when paused )
                if dplugin.state != PLUGIN_STATE_PAUSE and dplugin.state != PLUGIN_STATE_STOPPED:
                    # check if new_data is a parameter or new raw data
                    try:
                        if opt.is_parameter is False:
                            dplugin.plugin.cb_execute(
                                Data=dplugin.plugin._demux(opt.data_source_id, opt.block_name, opt.data),
                                block_name=opt.block_name, plugin_uname=event.source_plugin_uname)
                        else:
                            dplugin.plugin._set_parameter_internal(opt.parameter_alias, opt.data)
                    except Exception as E:
                        tb = traceback.format_exc()

                        self.plugin_died.emit(dplugin, E, tb)

            else:
                # plugin does not exist in DGUI
                self.log.printText(1, 'new_data, Plugin with id  ' + str(dID) + '  does not exist in DGui')

    def process_plugin_closed(self, event):
        """
        Processes plugin_closed event.
        Gui now knows, that a plugin was closed by core and needs to update its DGui data base

        :param event:
        :type event: PapiEventBase
        :return:
        """
        opt = event.get_optional_parameter()

        dplugin = self.gui_data.get_dplugin_by_id(opt.plugin_id)
        if dplugin is not None:
            if dplugin.own_process is False:
                try:
                    dplugin.plugin.cb_quit()
                except Exception as E:
                    tb = traceback.format_exc()
                    self.plugin_died.emit(dplugin, E, tb)

        if self.gui_data.rm_dplugin(opt.plugin_id) == ERROR.NO_ERROR:
            self.log.printText(1, 'plugin_closed, Plugin with id: ' + str(opt.plugin_id) + ' was removed in GUI')
            self.dgui_changed.emit()
            self.removed_dplugin.emit(dplugin)
        else:
            self.log.printText(1, 'plugin_closed, Plugin with id: ' + str(opt.plugin_id) + ' was NOT removed in GUI')

    def process_stop_plugin(self, event):
        """
        Processes plugin_stop events.
        Quit plugin, emit DPlugin was removed -> necessary signal for the GUI.

        :param event:
        :return:
        """
        id = event.get_destinatioID()
        dplugin = self.gui_data.get_dplugin_by_id(id)
        if dplugin is not None:
            try:
                dplugin.plugin.cb_quit()
                dplugin.state = PLUGIN_STATE_STOPPED
                self.removed_dplugin.emit(dplugin)
                self.dgui_changed.emit()
            except Exception as E:
                tb = traceback.format_exc()
                self.plugin_died.emit(dplugin, E, tb)

    def process_restart_plugin(self, event):
        """
        Processes plugin_start event.
        Used to (re-)start a plugin after the plugin was stopped. Emit DPlugin was added -> necessary signal for the GUI.

        :param event:
        :return:
        """
        id = event.get_destinatioID()
        dplugin = self.gui_data.get_dplugin_by_id(id)
        if dplugin is not None:
            try:
                if dplugin.plugin._starting_sequence(dplugin.plugin.pl_get_current_config()) is True:
                    dplugin.state = PLUGIN_STATE_START_SUCCESFUL
                    self.added_dplugin.emit(dplugin)
                else:
                    dplugin.state = PLUGIN_STATE_START_FAILED
            except Exception as E:
                tb = traceback.format_exc()
                self.plugin_died.emit(dplugin, E, tb)

            self.dgui_changed.emit()


    def process_create_plugin(self, event):
        """
        Processes the create Plugin event. This event got sent by core to GUI.
        Gui now needs to add a new plugin to DGUI and decide whether it is a plugin running in the GUI process or not.

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # get optional data: the plugin id, identifier and uname
        opt = event.get_optional_parameter()
        id = opt.plugin_id
        plugin_identifier = opt.plugin_identifier
        uname = opt.plugin_uname
        # config for passsing additional information to the plugin at the moment of creation
        config = opt.plugin_config

        # debug print
        self.log.printText(2,
                           'create_plugin, Try to create plugin with Name  ' + plugin_identifier + " and UName " + uname)

        # get the plugin object from yapsy manager
        plugin_orginal = self.plugin_manager.getPluginByName(plugin_identifier)

        # check for existance
        if plugin_orginal is None:
            # plugin with given identifier does not exist
            self.log.printText(1,
                               'create_plugin, Plugin with Name  ' + plugin_identifier + '  does not exist in file system')
            # end function
            return -1

        # plugin seems to exist, so get the path of the plugin file
        imp_path = plugin_orginal.path + ".py"
        # build a loader object for this plugin
        module_name = plugin_orginal.name.lower()

        spec = importlib.util.find_spec(module_name)
        #Module was not yet loaded
        if spec is None:
            loader = importlib.machinery.SourceFileLoader(module_name, imp_path)
            current_modul = loader.load_module()
            #Add path to sys path otherwise importlib.import_module will not find the module
            sys_path = "/".join(plugin_orginal.path.split('/')[0:-1])
            sys.path.append(sys_path)
        else:
            #Import module
            current_modul = importlib.import_module(module_name)

        # build the plugin class name for usage
        class_name = plugin_orginal.name[:1].upper() + plugin_orginal.name[1:]
        # get the plugin class of the source code loaded and init class as a new object
        plugin = getattr(current_modul, class_name)()
        # get default startup configuration for merge with user defined startup_configuration
        start_config = plugin._get_startup_configuration()
        config = dict(list(start_config.items()) + list(config.items()))

        # check if plugin in ViP (includes pcp) or something which is not running in the gui process
        if plugin._get_type() == PLUGIN_VIP_IDENTIFIER:
            # plugin in running in gui process
            # add a new dplugin object to DGui and set its type and uname
            dplugin = self.gui_data.add_plugin(None, None, False, self.gui_queue, plugin, id)
            dplugin.uname = uname
            dplugin.type = opt.plugin_type
            dplugin.plugin_identifier = plugin_identifier
            dplugin.startup_config = config
            dplugin.path = plugin_orginal.path
            # call the init function of plugin and set queues and id
            api = Plugin_api(self.gui_data, self.core_queue, self.gui_id, uname + ' API:', tabManager=self.TabManger)

            # call the plugin developers init function with config
            try:
                dplugin.plugin._init_plugin(self.core_queue, self.gui_queue, dplugin.id, api,
                                           dpluginInfo=dplugin.get_meta(),TabManger=self.TabManger)
                if dplugin.plugin._starting_sequence(copy.deepcopy(config)) is True:
                    # start succcessfull
                    self.core_queue.put(Event.status.StartSuccessfull(dplugin.id, 0, None))
                else:
                    self.core_queue.put(Event.status.StartFailed(dplugin.id, 0, None))

                # first set meta to plugin (meta infos in plugin)
                if dplugin.state not in [PLUGIN_STATE_STOPPED]:
                    dplugin.plugin._update_plugin_meta(dplugin.get_meta())

            except Exception as E:
                dplugin.state = PLUGIN_STATE_STOPPED
                tb = traceback.format_exc()
                self.plugin_died.emit(dplugin, E, tb)



            # debug print
            self.log.printText(1, 'create_plugin, Plugin with name  ' + str(uname) + '  was started as ViP')
        else:
            # plugin will not be running in gui process, so we just need to add information to DGui
            # so add a new dplugin to DGUI and set name und type
            dplugin = self.gui_data.add_plugin(None, None, True, None, plugin, id)
            dplugin.plugin_identifier = plugin_identifier
            dplugin.uname = uname
            dplugin.startup_config = opt.plugin_config
            dplugin.type = opt.plugin_type
            dplugin.path = plugin_orginal.path
            # debug print
            self.log.printText(1, 'create_plugin, Plugin with name  ' + str(uname) + '  was added as non ViP')

        self.added_dplugin.emit(dplugin)
        self.dgui_changed.emit()

    def process_close_program_event(self, event):
        """
        Processes close programm event.
        Nothing important happens.

         :param event: event to process
         :type event: PapiEventBase
         :type dplugin: DPlugin
        """
        self.log.printText(1, 'event: close_progam was received but there is no action for it')
        pass

    def process_check_alive_status(self, event):
        """
        Gui received check_alive request form core, so gui will respond to it

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # send event from GUI to Core
        event = Event.status.Alive(1,0,None)
        self.core_queue.put(event)

    def process_update_meta(self, event):
        """
        Core sent new meta information of an existing plugin. This function will update DGui with these information

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # get information of event
        # TODO: pl_id should not be in the origin parameter
        opt = event.get_optional_parameter()
        pl_id = event.get_originID()

        # get plugin of which new meta should be updated
        dplugin = self.gui_data.get_dplugin_by_id(pl_id)
        # check if it exists
        if dplugin is not None:
            # plugin exists, so update its meta information
            dplugin.update_meta(opt.plugin_object)
            # check if plugin runs in gui to update its copy of meta informations
            if dplugin.own_process is False:
                if dplugin.state not in [PLUGIN_STATE_STOPPED]:
                    # try:
                        dplugin.plugin._update_plugin_meta(dplugin.get_meta())
                    # except Exception as E:
                    #     dplugin.state = PLUGIN_STATE_STOPPED
                    #     tb = traceback.format_exc()
                    #     self.plugin_died.emit(dplugin, E, tb)

            self.dgui_changed.emit()
        else:
            # plugin does not exist
            self.log.printText(1, 'update_meta, Plugin with id  ' + str(pl_id) + '  does not exist')

    def process_update_parameter(self, event):
        print('Just update')

    def process_set_parameter(self, event):
        """
        Processes set_parameter event.
        Used to handle parameter sets by the gui or other plugins.

        :param event:
        :return:
        """
        # debug print
        self.log.printText(2, 'set parameter event')

        dID = event.get_destinatioID()
        # get optional data of event
        opt = event.get_optional_parameter()

        if isinstance(event, Event.instruction.UpdateParameter):
            return

        # get destination plugin from DGUI
        dplugin = self.gui_data.get_dplugin_by_id(dID)
        # check if it exists
        if dplugin is not None:
            # it exists, so call its execute function
            dplugin.plugin._set_parameter_internal(opt.parameter_alias, opt.data)
        else:
            # plugin does not exist in DGUI
            self.log.printText(1, 'set_parameter, Plugin with id  ' + str(dID) + '  does not exist in DGui')

    def process_pause_plugin(self, event):
        """
        Core sent event to pause a plugin in GUI, so call the pause function of this plugin

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        pl_id = event.get_destinatioID()

        dplugin = self.gui_data.get_dplugin_by_id(pl_id)
        if dplugin is not None:
            dplugin.plugin.cb_pause()

    def process_resume_plugin(self, event):
        """
        Core sent event to resume a plugin in GUI, so call the resume function of this plugin

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        pl_id = event.get_destinatioID()

        dplugin = self.gui_data.get_dplugin_by_id(pl_id)
        if dplugin is not None:
            dplugin.plugin.cb_resume()

    def process_parameter_info(self, event):
        """

        :param event:
        :return:
        """
        pl_id = event.get_destinatioID()

        dplugin = self.gui_data.get_dplugin_by_id(pl_id)

        if dplugin is not None:
            dplugin.plugin.cb_new_parameter_info(event.dparameter_object)
예제 #8
0
class Gui_api(QtCore.QObject):
    error_occured = QtCore.pyqtSignal(str, str, str)

    def __init__(self,
                 gui_data,
                 core_queue,
                 gui_id,
                 get_gui_config_function=None,
                 set_gui_config_function=None,
                 TabManager=None,
                 plugin_manager=None):
        super(Gui_api, self).__init__()
        self.gui_id = gui_id
        self.gui_data = gui_data
        self.core_queue = core_queue
        self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.get_gui_config_function = get_gui_config_function
        self.set_gui_config_function = set_gui_config_function
        self.tabManager = TabManager
        self.pluginManager = plugin_manager

    def do_create_plugin(self,
                         plugin_identifier,
                         uname,
                         config={},
                         autostart=True):
        """
        Something like a callback function for gui triggered events e.a. when a user wants to create a new plugin.

        :param plugin_identifier: plugin to create
        :type plugin_identifier: basestring
        :param uname: uniqe name to set for new plugin
        :type uname: basestring
        :param config: additional configuration for creation
        :type config:
        :return:
        """
        # create new optional Data for event
        opt = DOptionalData()
        # set important information
        # plugin to create
        opt.plugin_identifier = plugin_identifier
        # uname to create plugin with
        opt.plugin_uname = uname
        # additional config
        opt.plugin_config = config
        opt.autostart = autostart

        # check if plugin with uname already exists
        allPlugins = self.gui_data.get_all_plugins()
        for pluginID in allPlugins:
            plugin = allPlugins[pluginID]
            if plugin.uname == uname:
                return False

        # create event object and sent it to core
        event = Event.instruction.CreatePlugin(self.gui_id, 0, opt)
        self.core_queue.put(event)

    def do_delete_plugin(self, id):
        """
        Delete plugin with given id.

        :param id: Plugin id to delete
        :type id: int
        :return:
        """
        event = Event.instruction.StopPlugin(self.gui_id, id, None)

        self.core_queue.put(event)

    def do_delete_plugin_uname(self, uname):
        """
        Delete plugin with given uname.

        :param uname: Plugin uname to delete
        :type uname: basestring
        :return:
        """
        event = Event.instruction.StopPluginByUname(self.gui_id, uname)
        self.core_queue.put(event)

    def do_edit_plugin(self, pl_id, eObject, changeRequest):
        """
        Edit plugin with given plugin id. Specify attribute of plugin by eObject which should
        be edited e.g. DBlock.
        Specify action by changeRequest e.g. {'edit' : DSignal}.
        Currently only possible to change a DSignal for a given dplugin and dblock.

        :param pl_id: Plugin id to delete
        :type pl_id: int
        :return:
        """
        event = Event.data.EditDPlugin(self.gui_id, pl_id, eObject,
                                       changeRequest)

        self.core_queue.put(event)

    def do_edit_plugin_uname(self, uname, eObject, changeRequest):
        """
        Edit plugin with given plugin uname. Specify attribute of plugin by eObject which should
        be edited e.g. DBlock.
        Specify action by changeRequest e.g. {'edit' : DSignal}.
        Currently only possible to change a DSignal for a given dplugin and dblock.

        :param uname:
        :param eObject:
        :param changeRequest:
        :return:
        """
        event = Event.data.EditDPluginByUname(self.gui_id, uname, eObject,
                                              changeRequest)

        self.core_queue.put(event)

    def do_stopReset_pluign(self, id):
        """
        Stop and reset plugin with given id without deleting it.

        :param id: Plugin id to stopReset
        :type id: int
        :return:
        """
        event = Event.instruction.StopPlugin(self.gui_id,
                                             id,
                                             None,
                                             delete=False)
        self.core_queue.put(event)

    def do_stopReset_plugin_uname(self, uname):
        """
        Stop and reset plugin with given uname without deleting it.

        :param uname: Plugin uname to stop
        :type uname: basestring
        :return:
        """
        pl_id = self.do_get_plugin_id_from_uname(uname)

        if pl_id is not None:
            self.do_stopReset_pluign(pl_id)
        else:
            self.log.printText(
                1, " Do stopReset plugin with uname " + uname + ' failed')
            return ERROR.NOT_EXISTING

    def do_start_plugin(self, id):
        """
        Start plugin with given id.

        :param id: Plugin id to start
        :type id: int
        :return:
        """
        event = Event.instruction.StartPlugin(self.gui_id, id, None)
        self.core_queue.put(event)

    def do_start_plugin_uname(self, uname):
        """
        Start plugin with given uname.

        :param uname: Plugin uname to start
        :type uname: basestring
        :return:
        """
        pl_id = self.do_get_plugin_id_from_uname(uname)

        if pl_id is not None:
            self.do_start_plugin(pl_id)
        else:
            self.log.printText(
                1, " Do start_plugin with uname " + uname + ' failed')
            return ERROR.NOT_EXISTING

    def do_subscribe(self,
                     subscriber_id,
                     source_id,
                     block_name,
                     signals=None,
                     sub_alias=None):
        """
        Something like a callback function for gui triggered events.
        In this case, user wants one plugin to subscribe another

        :param subscriber_id: Plugin id of plugin which should get the data
        :type subscriber_id: int
        :param source_id: plugin uname of plugin that should send the data
        :type source_id: int
        :param block_name: name of block to subscribe
        :type block_name: basestring
        :return:
        """
        # build optional data object and add id and block name to it
        opt = DOptionalData()
        opt.source_ID = source_id
        opt.block_name = block_name
        opt.signals = signals
        opt.subscription_alias = sub_alias
        # send event with subscriber id as the origin to CORE
        event = Event.instruction.Subscribe(subscriber_id, 0, opt)
        self.core_queue.put(event)

    def do_subscribe_uname(self,
                           subscriber_uname,
                           source_uname,
                           block_name,
                           signals=None,
                           sub_alias=None):
        """
        Something like a callback function for gui triggered events.
        In this case, user wants one plugin to subscribe another

        :param subscriber_uname:  Plugin uname of plugin which should get the data
        :type subscriber_uname: basestring
        :param source_uname: plugin uname of plugin that should send the data
        :type source_uname: basestring
        :param block_name: name of block to subscribe
        :type block_name: basestring
        :return:
        """
        event = Event.instruction.SubscribeByUname(self.gui_id,
                                                   0,
                                                   subscriber_uname,
                                                   source_uname,
                                                   block_name,
                                                   signals=signals,
                                                   sub_alias=sub_alias)
        self.core_queue.put(event)

    def do_unsubscribe(self,
                       subscriber_id,
                       source_id,
                       block_name,
                       signal_index=None):
        """
        Something like a callback function for gui triggered events.
        User wants one plugin to do not get any more data from another plugin

        :param subscriber_id: plugin id which wants to lose a data source
        :type subscriber_id: int
        :param source_id: plugin id of data source
        :type source_id: int
        :param block_name: name of block to unsubscribe
        :type block_name: basestring
        :return:
        """
        # create optional data with source id and block_name
        opt = DOptionalData()
        opt.source_ID = source_id
        opt.block_name = block_name
        opt.signals = signal_index
        # sent event to Core with origin subscriber_id
        event = Event.instruction.Unsubscribe(subscriber_id, 0, opt)
        self.core_queue.put(event)

    def do_unsubscribe_uname(self,
                             subscriber_uname,
                             source_uname,
                             block_name,
                             signal_index=None):
        """
        Something like a callback function for gui triggered events.
        User wants one plugin to do not get any more data from another plugin

        :param subscriber_uname: plugin uname which wants to lose a data source
        :type subscriber_uname: basestring
        :param source_uname: plugin uname of data source
        :type source_uname: basestring
        :param block_name: name of block to unsubscribe
        :type block_name: basestring
        :return:
        """
        subscriber_id = self.do_get_plugin_id_from_uname(subscriber_uname)
        if subscriber_id is None:
            # plugin with uname does not exist
            self.log.printText(1, 'do_unsubscribe, sub uname worng')
            return -1

        source_id = self.do_get_plugin_id_from_uname(source_uname)
        if source_id is None:
            # plugin with uname does not exist
            self.log.printText(1, 'do_unsubscribe, target uname wrong')
            return -1

        # call do_subscribe with ids to subscribe
        self.do_unsubscribe(subscriber_id, source_id, block_name, signal_index)

    def do_set_parameter(self,
                         plugin_id,
                         parameter_name,
                         value,
                         only_db_update=False):
        """
        Something like a callback function for gui triggered events.
        User wants to change a parameter of a plugin

        :param plugin_id: id of plugin which owns the parameter
        :type plugin_id: int
        :param parameter_name: name of parameter to change
        :type parameter_name: basestring
        :param value: new parameter value to set
        :type value:
        :param only_db_update: do_set_parameter of the target plugin will not be called. Updates only the internal database.
        :type boolean:
        """
        # get plugin from DGUI
        dplug = self.gui_data.get_dplugin_by_id(plugin_id)
        # check for existance
        if dplug is not None:
            # it exists
            # get its parameter list
            parameters = dplug.get_parameters()
            # check if there are any parameter
            if parameters is not None:
                # there is a parameter list
                # get the parameter with parameter_name
                if parameter_name in parameters:
                    p = parameters[parameter_name]
                    # check if this specific parameter exists
                    if p is not None:
                        # parameter with name parameter_name exists

                        # build an event to send this information to Core
                        opt = DOptionalData()
                        opt.data = value
                        opt.is_parameter = True
                        opt.parameter_alias = parameter_name
                        opt.block_name = None
                        if only_db_update:
                            e = Event.instruction.UpdateParameter(
                                self.gui_id, dplug.id, opt)
                        else:
                            e = Event.instruction.SetParameter(
                                self.gui_id, dplug.id, opt)
                        self.core_queue.put(e)

    def do_set_parameter_uname(self, plugin_uname, parameter_name, value):
        """
        Something like a callback function for gui triggered events.
        User wants to change a parameter of a plugin
        :param plugin_uname: name of plugin which owns the parameter

        :type plugin_uname: basestring
        :param parameter_name: name of parameter to change
        :type parameter_name: basestring
        :param value: new parameter value to set
        :type value:
        """
        # id = self.do_get_plugin_id_from_uname(plugin_uname)
        # if id is not None:
        #     self.do_set_parameter(id, parameter_name, value)
        #     print(parameter_name, value)
        opt = DOptionalData()
        opt.data = value
        opt.is_parameter = True
        opt.parameter_alias = parameter_name
        opt.block_name = None
        e = Event.instruction.SetParameterByUname(self.gui_id, plugin_uname,
                                                  opt)
        self.core_queue.put(e)

    def do_pause_plugin_by_id(self, plugin_id):
        """
        Something like a callback function for gui triggered events.
        User wants to pause a plugin, so this method will send an event to core.

        :param plugin_id: id of plugin to pause
        :type plugin_id: int
        """
        if self.gui_data.get_dplugin_by_id(plugin_id) is not None:
            opt = DOptionalData()
            event = Event.instruction.PausePlugin(self.gui_id, plugin_id, opt)
            self.core_queue.put(event)
            return 1
        else:
            return -1

    def do_pause_plugin_by_uname(self, plugin_uname):
        """
        Something like a callback function for gui triggered events.
        User wants to pause a plugin, so this method will send an event to core.

        :param plugin_uname: uname of plugin to pause
        :type plugin_uname: basestring
        """
        plugin_id = self.do_get_plugin_id_from_uname(plugin_uname)
        if plugin_id is not None:
            return self.do_pause_plugin_by_id(plugin_id)
        else:
            # plugin with uname does not exist
            self.log.printText(1, 'do_pause, plugin uname worng')
            return -1

    def do_resume_plugin_by_id(self, plugin_id):
        """
        Something like a callback function for gui triggered events.
        User wants to pause a plugin, so this method will send an event to core.

        :param plugin_id: id of plugin to pause
        :type plugin_id: int
        """
        if self.gui_data.get_dplugin_by_id(plugin_id) is not None:
            opt = DOptionalData()
            event = Event.instruction.ResumePlugin(self.gui_id, plugin_id, opt)
            self.core_queue.put(event)
            return 1
        else:
            return -1

    def do_resume_plugin_by_uname(self, plugin_uname):
        """
        Something like a callback function for gui triggered events.
        User wants to resume a plugin, so this method will send an event to core.

        :param plugin_uname: uname of plugin to resume
        :type plugin_uname: basestring
        """
        plugin_id = self.do_get_plugin_id_from_uname(plugin_uname)
        if plugin_id is not None:
            return self.do_resume_plugin_by_id(plugin_id)
        else:
            # plugin with uname does not exist
            self.log.printText(1, 'do_resume, plugin uname worng')
            return -1

    def do_get_plugin_id_from_uname(self, uname):
        """
        Returns the plugin id of the plugin with unique name uname

        :param uname: uname of plugin
        :type uname: basestring
        :return: None: plugin with uname does not exist, id: id of plugin
        """
        dplugin = self.gui_data.get_dplugin_by_uname(uname)
        # check for existance
        if dplugin is not None:
            # it does exist, so get its id
            return dplugin.id
        else:
            return None

    def do_close_program(self):
        """
        Tell core to close papi. Core will respond and will close all open plugins.
        GUI will close all VIP Plugins due to calling their quit function
        """

        plugins = self.gui_data.get_all_plugins()
        for dplugin_id in plugins:
            dplugin = plugins[dplugin_id]
            if dplugin.type == PLUGIN_VIP_IDENTIFIER:
                try:
                    dplugin.plugin.cb_quit()
                except Exception as E:
                    tb = traceback.format_exc()
                    self.plugin_died.emit(dplugin, E, tb)

        opt = DOptionalData()
        opt.reason = 'User clicked close Button'
        event = Event.instruction.CloseProgram(self.gui_id, 0, opt)
        self.core_queue.put(event)

    def do_set_tab_active_by_name(self, tabName):
        self.tabManager.set_tab_active_by_name(tabName)

    def do_open_new_tabs_with_names_in_order(self, tabNames=None):
        for name in tabNames:
            self.tabManager.add_tab(name)

    def do_load_xml(self, path):
        if path is None or not os.path.isfile(path):
            return False

        tree = ET.parse(path)
        root = tree.getroot()

        if root.tag == 'PaPI':
            self.do_load_xml_reloaded(root)
        else:
            self.do_load_xml_v1(root)

    def do_load_xml_reloaded(self, root):
        """
        Function to load a xml config to papi and apply the configuration.

        :param path: path to xml file to load.
        :type path: basestring
        :return:
        """

        gui_config = {}
        plugins_to_start = []
        parameters_to_change = []
        signals_to_change = []
        subs_to_make = []

        try:
            for root_element in root:
                ##########################
                # Read gui configuration #
                ##########################
                if root_element.tag == 'Configuration':
                    for property in root_element:
                        gui_config[property.tag] = {}
                        for attr in property:
                            if len(attr) == 0:
                                gui_config[property.tag][attr.tag] = attr.text
                            else:
                                gui_config[property.tag][attr.tag] = {}
                                for val in attr:
                                    gui_config[property.tag][attr.tag][
                                        val.tag] = val.text

                if root_element.tag == 'Plugins':
                    #############################
                    # Read plugin configuration #
                    #############################
                    for plugin_xml in root_element:
                        plObj = {}
                        plObj['uname'] = self.change_uname_to_uniqe(
                            plugin_xml.attrib['uname'])
                        plObj['identifier'] = plugin_xml.find(
                            'Identifier').text
                        config_xml = plugin_xml.find('StartConfig')
                        config_hash = {}
                        for parameter_xml in config_xml.findall('Parameter'):
                            para_name = parameter_xml.attrib['Name']
                            config_hash[para_name] = {}
                            for detail_xml in parameter_xml:
                                detail_name = detail_xml.tag
                                config_hash[para_name][
                                    detail_name] = detail_xml.text

                        plObj['cfg'] = config_hash

                        plugins_to_start.append(plObj)

                        # --------------------------------
                        # Load PreviousParameters
                        # --------------------------------

                        prev_parameters_xml = plugin_xml.find(
                            'PreviousParameters')
                        if prev_parameters_xml is not None:
                            for prev_parameter_xml in prev_parameters_xml.findall(
                                    'Parameter'):
                                para_name = prev_parameter_xml.attrib['Name']
                                para_value = prev_parameter_xml.text
                                # pl_uname_new = self.change_uname_to_uniqe(pl_uname)
                                # TODO validate NO FLOAT in parameter
                                parameters_to_change.append(
                                    [plObj['uname'], para_name, para_value])

                        # --------------------------------
                        # Load DBlocks due to signals name
                        # --------------------------------

                        dblocks_xml = plugin_xml.find('DBlocks')
                        if dblocks_xml is not None:
                            for dblock_xml in dblocks_xml:
                                dblock_name = dblock_xml.attrib['Name']
                                dsignals_xml = dblock_xml.findall('DSignal')
                                for dsignal_xml in dsignals_xml:
                                    dsignal_uname = dsignal_xml.attrib['uname']
                                    dsignal_dname = dsignal_xml.find(
                                        'dname').text
                                    signals_to_change.append([
                                        plObj['uname'], dblock_name,
                                        dsignal_uname, dsignal_dname
                                    ])

                if root_element.tag == 'Subscriptions':
                    for sub_xml in root_element:

                        #TODO: Ask stefan: Why this line?
                        #dest  = self.change_uname_to_uniqe(sub_xml.find('Destination').text)

                        dest = sub_xml.find('Destination').text
                        for source in sub_xml:
                            if source.tag == 'Source':
                                sourceName = source.attrib[
                                    'uname']  #self.change_uname_to_uniqe(source.attrib['uname'])
                                for block_xml in source:
                                    blockName = block_xml.attrib['name']
                                    alias = block_xml.find('Alias').text
                                    signals_xml = block_xml.find('Signals')

                                    signals = []
                                    for sig_xml in signals_xml:
                                        signals.append(sig_xml.text)

                                    subs_to_make.append({
                                        'dest': dest,
                                        'source': sourceName,
                                        'block': blockName,
                                        'alias': alias,
                                        'signals': signals
                                    })

            self.set_gui_config_function(gui_config)

        except Exception as E:
            tb = traceback.format_exc()
            self.error_occured.emit("Error: Config Loader", "Not loadable", tb)

        # -----------------------------------------------
        # Check: Are there unloadable plugins?
        # -----------------------------------------------

        unloadable_plugins = []
        for pl in plugins_to_start:
            plugin_info = self.pluginManager.getPluginByName(pl['identifier'])

            if plugin_info is None:
                if pl['identifier'] not in unloadable_plugins:
                    unloadable_plugins.append(pl['identifier'])

        if not len(unloadable_plugins):
            for pl in plugins_to_start:
                self.do_create_plugin(pl['identifier'], pl['uname'], pl['cfg'])

            self.config_loader_subs_reloaded(plugins_to_start, subs_to_make,
                                             parameters_to_change,
                                             signals_to_change)
        else:
            self.error_occured.emit(
                "Error: Loading Plugins", "Can't use: " +
                str(unloadable_plugins) + "\nConfiguration will not be used.",
                None)

    def config_loader_subs_reloaded(self, pl_to_start, subs_to_make,
                                    parameters_to_change, signals_to_change):
        """
        Function for callback when timer finished to apply
            subscriptions and parameter changed of config.

        :param pl_to_start: list of plugins to start
        :type pl_to_start: list
        :param subs_to_make:  list of subscriptions to make
        :type subs_to_make: list
        :param parameters_to_change: parameter changes to apply
        :type parameters_to_change: list
        :param signals_to_change: signal name changes to apply
        :type signals_to_change: list
        :return:
        """

        for sub in subs_to_make:
            self.do_subscribe_uname(sub['dest'], sub['source'], sub['block'],
                                    sub['signals'], sub['alias'])

        for para in parameters_to_change:
            self.do_set_parameter_uname(para[0], para[1], para[2])

        for sig in signals_to_change:
            plugin_uname = sig[0]
            dblock_name = sig[1]
            dsignal_uname = sig[2]
            dsignal_dname = sig[3]

            self.do_edit_plugin_uname(
                plugin_uname, DBlock(dblock_name),
                {'edit': DSignal(dsignal_uname, dsignal_dname)})

    def do_load_xml_v1(self, root):
        """
        Function to load a xml config to papi and apply the configuration.

        :param path: path to xml file to load.
        :type path: basestring
        :return:
        """

        plugins_to_start = []
        subs_to_make = []
        parameters_to_change = []
        signals_to_change = []

        try:
            for plugin_xml in root:
                ##########################
                # Read gui configuration #
                ##########################
                if plugin_xml.tag == 'guiConfig':
                    cfg = {}
                    for property in plugin_xml:
                        cfg[property.tag] = {}
                        for attr in property:
                            cfg[property.tag][attr.tag] = {}
                            for value in attr:
                                cfg[property.tag][attr.tag][
                                    value.tag] = value.text

                    self.set_gui_config_function(cfg)

                #############################
                # Read plugin configuration #
                #############################
                if plugin_xml.tag == 'Plugin':
                    pl_uname = plugin_xml.attrib['uname']
                    identifier = plugin_xml.find('Identifier').text
                    config_xml = plugin_xml.find('StartConfig')
                    config_hash = {}
                    for parameter_xml in config_xml.findall('Parameter'):
                        para_name = parameter_xml.attrib['Name']
                        config_hash[para_name] = {}
                        for detail_xml in parameter_xml:
                            detail_name = detail_xml.tag
                            config_hash[para_name][
                                detail_name] = detail_xml.text

                    pl_uname_new = self.change_uname_to_uniqe(pl_uname)

                    plugins_to_start.append(
                        [identifier, pl_uname_new, config_hash])

                    # --------------------------------
                    # Load Subscriptions
                    # --------------------------------

                    subs_xml = plugin_xml.find('Subscriptions')
                    if subs_xml is not None:
                        for sub_xml in subs_xml.findall('Subscription'):
                            data_source = sub_xml.find('data_source').text
                            for block_xml in sub_xml.findall('block'):
                                block_name = block_xml.attrib['Name']
                                signals = []
                                for sig_xml in block_xml.findall('Signal'):
                                    signals.append(str(sig_xml.text))
                                alias_xml = block_xml.find('alias')
                                alias = alias_xml.text
                                pl_uname_new = self.change_uname_to_uniqe(
                                    pl_uname)
                                data_source_new = data_source  #self.change_uname_to_uniqe(data_source)
                                subs_to_make.append([
                                    pl_uname_new, data_source_new, block_name,
                                    signals, alias
                                ])

                    # --------------------------------
                    # Load PreviousParameters
                    # --------------------------------

                    prev_parameters_xml = plugin_xml.find('PreviousParameters')
                    if prev_parameters_xml is not None:
                        for prev_parameter_xml in prev_parameters_xml.findall(
                                'Parameter'):
                            para_name = prev_parameter_xml.attrib['Name']
                            para_value = prev_parameter_xml.text
                            pl_uname_new = self.change_uname_to_uniqe(pl_uname)
                            # TODO validate NO FLOAT in parameter
                            parameters_to_change.append(
                                [pl_uname_new, para_name, para_value])

                    # --------------------------------
                    # Load DBlocks due to signals name
                    # --------------------------------

                    dblocks_xml = plugin_xml.find('DBlocks')
                    if dblocks_xml is not None:
                        for dblock_xml in dblocks_xml:
                            dblock_name = dblock_xml.attrib['Name']
                            dsignals_xml = dblock_xml.findall('DSignal')
                            for dsignal_xml in dsignals_xml:
                                dsignal_uname = dsignal_xml.attrib['uname']
                                dsignal_dname = dsignal_xml.find('dname').text
                                signals_to_change.append([
                                    pl_uname, dblock_name, dsignal_uname,
                                    dsignal_dname
                                ])
        except Exception as E:
            tb = traceback.format_exc()
            self.error_occured.emit("Error: Config Loader", "Not loadable", tb)

        # -----------------------------------------------
        # Check: Are there unloadable plugins?
        # -----------------------------------------------

        unloadable_plugins = []
        for pl in plugins_to_start:
            plugin_info = self.pluginManager.getPluginByName(pl[0])

            if plugin_info is None:
                if pl[0] not in unloadable_plugins:
                    unloadable_plugins.append(pl[0])

        if not len(unloadable_plugins):
            for pl in plugins_to_start:
                # 0: ident, 1: uname, 2: config

                self.do_create_plugin(pl[0], pl[1], pl[2])

            # QtCore.QTimer.singleShot(CONFIG_LOADER_SUBSCRIBE_DELAY, \
            #                         lambda: self.config_loader_subs(plugins_to_start, subs_to_make, \
            #                                                         parameters_to_change, signals_to_change))
            self.config_loader_subs(plugins_to_start, subs_to_make,
                                    parameters_to_change, signals_to_change)
        else:
            self.error_occured.emit(
                "Error: Loading Plugins", "Can't use: " +
                str(unloadable_plugins) + "\nConfiguration will not be used.",
                None)

    def change_uname_to_uniqe(self, uname):
        """
        Function will search for unames and add an indentifier to it to make it unique in case of existence

        :param uname: uname to make unique
        :type uname: basestring
        :return: uname
        """
        i = 1
        while self.gui_data.get_dplugin_by_uname(uname) is not None:
            i = i + 1
            if i == 2:
                uname = uname + 'X' + str(i)
            else:
                uname = uname[:-1] + str(i)
        return uname

    def config_loader_subs(self, pl_to_start, subs_to_make,
                           parameters_to_change, signals_to_change):
        """
        Function for callback when timer finished to apply
            subscriptions and parameter changed of config.

        :param pl_to_start: list of plugins to start
        :type pl_to_start: list
        :param subs_to_make:  list of subscriptions to make
        :type subs_to_make: list
        :param parameters_to_change: parameter changes to apply
        :type parameters_to_change: list
        :param signals_to_change: signal name changes to apply
        :type signals_to_change: list
        :return:
        """

        for sub in subs_to_make:
            self.do_subscribe_uname(sub[0], sub[1], sub[2], sub[3], sub[4])

        for para in parameters_to_change:
            self.do_set_parameter_uname(para[0], para[1], para[2])

        for sig in signals_to_change:
            plugin_uname = sig[0]
            dblock_name = sig[1]
            dsignal_uname = sig[2]
            dsignal_dname = sig[3]

            self.do_edit_plugin_uname(
                plugin_uname, DBlock(dblock_name),
                {'edit': DSignal(dsignal_uname, dsignal_dname)})

    def do_save_xml_config_reloaded(self,
                                    path,
                                    plToSave=[],
                                    sToSave=[],
                                    saveUserSettings=False):
        """

        :param path:
        :param plToSave:
        :param sToSave:
        :return:
        """

        subscriptionsToSave = {}
        # check for xml extension in path, add .xml if missing
        if path[-4:] != '.xml':
            path += '.xml'

        try:
            root = ET.Element(CONFIG_ROOT_ELEMENT_NAME_RELOADED)
            root.set(
                'Date',
                datetime.datetime.fromtimestamp(
                    time.time()).strftime('%Y-%m-%d %H:%M:%S'))
            root.set('PaPI_version', CORE_PAPI_VERSION)

            ##########################
            # Save gui configuration #
            ##########################
            gui_cfg = self.get_gui_config_function(
                save_user_settings=saveUserSettings)
            gui_cfg_xml = ET.SubElement(root, 'Configuration')

            for cfg_item in gui_cfg:
                item_xml = ET.SubElement(gui_cfg_xml, cfg_item)
                item = gui_cfg[cfg_item]
                for attr_name in item:
                    attr_xml = ET.SubElement(item_xml, attr_name)
                    values = item[attr_name]

                    # check if there is another dict level to explore
                    # if true: exlplore the dict
                    # if false: save the value of values in the parent xml node
                    if isinstance(values, dict):
                        for val in values:
                            value_xml = ET.SubElement(attr_xml, val)
                            value_xml.text = values[val]
                    else:
                        attr_xml.text = values

            # ---------------------------------------
            # save information of plugins
            # for the next start
            # ---------------------------------------
            plugins_xml = ET.SubElement(root, 'Plugins')

            plugins = self.gui_data.get_all_plugins()
            for dplugin_id in plugins:
                dplugin = plugins[dplugin_id]

                # check if this plugin should be saved to XML
                if dplugin.uname in plToSave:
                    if dplugin.type == PLUGIN_VIP_IDENTIFIER:
                        dplugin.startup_config = dplugin.plugin.pl_get_current_config(
                        )

                    pl_xml = ET.SubElement(plugins_xml, 'Plugin')
                    pl_xml.set('uname', dplugin.uname)

                    identifier_xml = ET.SubElement(pl_xml, 'Identifier')
                    identifier_xml.text = dplugin.plugin_identifier

                    # ---------------------------------------
                    # Save all current config as startup config
                    # for the next start
                    # ---------------------------------------

                    cfg_xml = ET.SubElement(pl_xml, 'StartConfig')
                    for parameter in dplugin.startup_config:
                        para_xml = ET.SubElement(cfg_xml, 'Parameter')
                        para_xml.set('Name', parameter)
                        for detail in dplugin.startup_config[parameter]:
                            if detail not in CONFIG_SAVE_CFG_BLACKLIST:
                                detail_xml = ET.SubElement(para_xml, detail)
                                detail_xml.text = dplugin.startup_config[
                                    parameter][detail]

                    # ---------------------------------------
                    # Save all current values for all
                    # parameter
                    # ---------------------------------------

                    last_paras_xml = ET.SubElement(pl_xml,
                                                   'PreviousParameters')
                    allparas = dplugin.get_parameters()
                    for para_key in allparas:
                        para = allparas[para_key]
                        last_para_xml = ET.SubElement(last_paras_xml,
                                                      'Parameter')
                        last_para_xml.set('Name', para_key)
                        last_para_xml.text = str(para.value)

                    # ---------------------------------------
                    # Save all current values for all
                    # signals of all dblocks
                    # ---------------------------------------

                    dblocks_xml = ET.SubElement(pl_xml, 'DBlocks')

                    alldblock_names = dplugin.get_dblocks()

                    for dblock_name in alldblock_names:
                        dblock = alldblock_names[dblock_name]
                        dblock_xml = ET.SubElement(dblocks_xml, 'DBlock')
                        dblock_xml.set('Name', dblock.name)

                        alldsignals = dblock.get_signals()

                        for dsignal in alldsignals:
                            if dsignal.uname != CORE_TIME_SIGNAL:
                                dsignal_xml = ET.SubElement(
                                    dblock_xml, 'DSignal')
                                dsignal_xml.set('uname', dsignal.uname)

                                dname_xml = ET.SubElement(dsignal_xml, 'dname')
                                dname_xml.text = dsignal.dname

                # ---------------------------------------
                # Build temporary subscription objects
                # to remember the subs of all plugins
                # including plugins that are not saved
                # excluding plugins we do not want the subs saved of
                # ---------------------------------------
                if dplugin.uname in sToSave:
                    subsOfPl = {}
                    subs = dplugin.get_subscribtions()
                    for sub in subs:
                        sourcePL = self.gui_data.get_dplugin_by_id(sub).uname
                        subsOfPl[sourcePL] = {}
                        for block in subs[sub]:
                            subsOfPl[sourcePL][block] = {}
                            dsubscription = subs[sub][block]
                            subsOfPl[sourcePL][block][
                                'alias'] = dsubscription.alias

                            signals = []
                            for s in dsubscription.get_signals():
                                signals.append(str(s))

                            subsOfPl[sourcePL][block]['signals'] = signals

                    if len(subsOfPl) != 0:
                        subscriptionsToSave[dplugin.uname] = subsOfPl

            # ---------------------------------------
            # save subs to xml
            #
            # ---------------------------------------
            subs_xml = ET.SubElement(root, 'Subscriptions')
            for dest in subscriptionsToSave:
                sub_xml = ET.SubElement(subs_xml, 'Subscription')

                # Destination of data
                dest_xml = ET.SubElement(sub_xml, 'Destination')
                dest_xml.text = dest

                for source in subscriptionsToSave[dest]:
                    # Source of Data
                    source_xml = ET.SubElement(sub_xml, 'Source')
                    source_xml.set('uname', source)

                    for block in subscriptionsToSave[dest][source]:
                        block_xml = ET.SubElement(source_xml, 'Block')
                        block_xml.set('name', block)

                        alias_xml = ET.SubElement(block_xml, 'Alias')
                        alias_xml.text = subscriptionsToSave[dest][source][
                            block]['alias']

                        signal_xml = ET.SubElement(block_xml, 'Signals')
                        for sig in subscriptionsToSave[dest][source][block][
                                'signals']:
                            if sig != CORE_TIME_SIGNAL:
                                sig_xml = ET.SubElement(signal_xml, 'Signal')
                                sig_xml.text = sig

            # do transformation for readability and save xml tree to file
            self.indent(root)
            tree = ET.ElementTree(root)
            tree.write(path)

        except Exception as E:
            tb = traceback.format_exc()
            self.error_occured.emit("Error: Config Loader",
                                    "Not saveable: " + path, tb)

    def do_save_xml_config(self, path):
        """
        This function will save papis current state to a xml file provided by path.

        :param path: path to save xml to.
        :type path: basestring
        :return:
        """
        raise Exception('do_save_xml_config_reloaded must be used')

    def do_save_json_config_reloaded(self, path, plToSave=[], sToSave=[]):
        if path[-5:] != '.json':
            path += '.json'

        json_config = {}
        to_create = {}
        to_control = {}
        to_sub = {}
        plugins = self.gui_data.get_all_plugins()

        for dplugin_id in plugins:
            dplugin = plugins[dplugin_id]

            # check if this plugin should be saved to XML
            if dplugin.uname in plToSave:
                if dplugin.type == PLUGIN_VIP_IDENTIFIER:
                    dplugin.startup_config = dplugin.plugin.pl_get_current_config(
                    )

                to_create[dplugin.uname] = {}

                to_create[dplugin.uname]["identifier"] = {
                    'value': dplugin.plugin_identifier
                }
                plugin_config = {}
                for config in dplugin.startup_config:
                    for value in dplugin.startup_config[config]:
                        if value == 'value':
                            plugin_config[config] = {
                                'value': dplugin.startup_config[config][value]
                            }

                to_create[dplugin.uname]["config"] = plugin_config

            if dplugin.uname in sToSave:
                subsOfPl = {}
                subs = dplugin.get_subscribtions()

                for sub in subs:
                    sourcePL = self.gui_data.get_dplugin_by_id(sub).uname

                    subsOfPl[sourcePL] = {}
                    for block in subs[sub]:

                        subsOfPl[sourcePL][block] = {}
                        dsubscription = subs[sub][block]
                        subsOfPl[sourcePL]['alias'] = dsubscription.alias
                        print(sourcePL)
                        print(block)
                        if dsubscription.alias is not None:
                            if sourcePL not in to_control:
                                to_control[sourcePL] = {}
                            to_control[sourcePL][block] = {
                                'parameter': dsubscription.alias
                            }
                        else:

                            signals = []
                            for s in dsubscription.get_signals():
                                signals.append(str(s))

                            to_sub[dplugin.uname] = {}
                            to_sub[dplugin.uname]['signals'] = signals
                            to_sub[dplugin.uname]['block'] = block
                            to_sub[dplugin.uname]['plugin'] = sourcePL

        if len(to_create):
            json_config["ToCreate"] = to_create
        if len(to_control):
            json_config["ToControl"] = to_control
        if len(to_sub):
            json_config["ToSub"] = to_sub

        papi_config = {"PaPIConfig": json_config}

        try:
            with open(path, 'w') as outfile:
                json.dump(papi_config, outfile, indent='    ')

        except:
            pass

    def indent(self, elem, level=0):
        """
        Function which will apply a nice looking indentiation to xml structure before save. Better readability.
        copied from http://effbot.org/zone/element-lib.htm#prettyprint 06.10.2014 15:53

        :param elem:
        :param level:
        :return:
        """
        i = "\n" + level * "  "
        if len(elem):
            if not elem.text or not elem.text.strip():
                elem.text = i + "  "
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
            for elem in elem:
                self.indent(elem, level + 1)
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
        else:
            if level and (not elem.tail or not elem.tail.strip()):
                elem.tail = i

    def do_reset_papi(self):
        """
        APi call to reset PaPI.
        Reset in this case means to delete all plugins cleanly and keep PaPI running.
        Will free all unames.
        Is using the do_delete_plugin api call and the delete plugin mechanism

        :return: ERROR CODE
        """

        all_plugins = self.gui_data.get_all_plugins()
        if all_plugins is not None:
            for plugin_key in all_plugins:
                plugin = all_plugins[plugin_key]
                self.do_delete_plugin(plugin.id)

    def do_test_name_to_be_unique(self, name):
        """
        Will check if a given name would be a valid, unique name for a plugin.
        :param name: name to check

        :type name: basestring
        :return: True or False
        """
        reg = QtCore.QRegExp('\S[^_][^\W_]+')
        if reg.exactMatch(name):
            if self.gui_data.get_dplugin_by_uname(name) is None:
                return True
            else:
                return False
        else:
            return False

    def do_change_string_to_be_uname(self, name):
        """
        This method will take a string and convert him according to some rules to be an uname

        :param name: name to convert to unmae
        :type name: basestring
        :return: name converted to uname
        """
        uname = name

        # TODO: get more inteligence here!

        forbidden = ['_', ',', '.', '`', ' ']
        for c in forbidden:
            uname = uname.replace(c, 'X')
        return uname
예제 #9
0
파일: DCore.py 프로젝트: dani-l/PaPI
class DCore():
    """
    DCore contains and manages the internal data structure
    """
    def __init__(self):
        """
        Used to initialize this object. An empty dictionary of DPlugin is created

        :return:
        """
        self.__DPlugins = {}

        self.__newid = 0
        self.log = ConsoleLog(2, "DCore: ")

    def create_id(self):
        """
        Creates and returns unique IDs

        :returns: unique ID
        :rtype: int
        """
        #self.__newid += 1
        self.__newid = DObject.create_unique_id()
        return self.__newid
#        return uuid.uuid4().int >> 64

    def add_plugin(self, process, pid, own_process, queue, plugin, id):
        """
        Add plugin with necessary information.

        :param process: Plugin is running in this process
        :param pid: Process ID of the process in which the plugin is running
        :param queue: Event queue needed for events which should be received by this plugin
        :param plugin: Plugin object
        :param plugin_id: ID of this plugin
        :param id: ID for the new DPlugin
        :return: Returns the data object DPlugin
        :rtype: DPlugin
        """

        d_pl = DPlugin()

        d_pl.process = process
        d_pl.pid = pid
        d_pl.queue = queue
        d_pl.plugin = plugin
        d_pl.id = id
        d_pl.own_process = own_process

        self.__DPlugins[id] = d_pl

        return d_pl

    def rm_dplugin(self, dplugin_id):
        """
        Removes DPlugin with dplugin_id

        :param dplugin_id:
        :return:
        :rtype: bool
        """

        if dplugin_id in self.__DPlugins:
            self.__DPlugins[dplugin_id].state = 'deleted'

            self.rm_all_subscribers(dplugin_id)
            self.unsubscribe_all(dplugin_id)

            del self.__DPlugins[dplugin_id]

            return ERROR.NO_ERROR
        else:
            return ERROR.UNKNOWN_ERROR

    def get_dplugins_count(self):
        """
        Returns count of known plugins in this data structure

        :return:
        :rtype: int
        """

        return len(self.__DPlugins.keys())

    def get_dplugin_by_id(self, plugin_id):
        """
        Returns DPlugin object by ID

        :param plugin_id: ID of an DPlugin object
        :return DPlugin:
        :rtype: DPlugin
        """

        if plugin_id in self.__DPlugins:
            return self.__DPlugins[plugin_id]
        else:
            return None


    def get_dplugin_by_uname(self, plugin_uname):
        """
        Returns DPlugin object by uname

        :param plugin_name: uname of an DPlugin object
        :return DPlugin:
        :rtype: DPlugin
        """

        for plugin_id in self.__DPlugins:
            d_pl = self.__DPlugins[plugin_id]

            if d_pl.uname == plugin_uname:
                return d_pl

        return None

    def get_all_plugins(self):
        """
        Returns a dictionary of all known dplugins

        :return:
        :rtype: {}
        """

        return self.__DPlugins

    def subscribe(self, subscriber_id, target_id, dblock_name):
        """
        Used to create a subscription.

        :param subscriber_id: DPlugin which likes to subscribes dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for subscribtion
        :return:
        """

        #Get Subscriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            self.log.printText(1, "Found no Subscriber with ID " + subscriber_id)
            return None

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            self.log.printText(1, "Found no Target with ID " + str(target_id))
            return None

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            self.log.printText(1, "Target " + target.uname + " has no DBlock " + dblock_name)

            return None

        #Create relation between DPlugin and DBlock

        dsubscription = subscriber.subscribe(dblock)

        if dsubscription is None:
            self.log.printText(1, "Subscriber " + str(subscriber_id) + " has already subscribed " + dblock_name)
            return None

        if dblock.add_subscribers(subscriber) is False:
            self.log.printText(1, "DBlock " + dblock_name + " was already subscribed by Subscriber" + subscriber_id)
            return None

        return dsubscription

    def unsubscribe(self, subscriber_id, target_id, dblock_name):
        """
        Used to remove a subscription.

        :param subscriber_id: DPlugin which likes to unsubscribes dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for unsubscribtion
        :return:
        :rtype boolean:
        """

        #Get Susbcriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            return False

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            return False

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            return False

        #Destroy relation between DPlugin and DBlock
        if subscriber.unsubscribe(dblock) is False:
            self.log.printText(1, "Subscriber " + str(subscriber_id) + " has already unsubscribed " + dblock_name)
            return False

        if dblock.rm_subscriber(subscriber) is False:
            self.log.printText(1, "DBlock " + dblock_name + " was already unsubscribed by Subscriber" + subscriber_id)
            return False

        return True

    def unsubscribe_all(self, dplugin_id):
        """
        This function is used to cancel all subscription of the DPlugin with the dplugin_id.

        :param dplugin_id: dplugin identifed by dplugin_id whose subscription should be canceled.
        :return:
        """

        dplugin = self.get_dplugin_by_id(dplugin_id)

        # copy subscription for iteration and deletion
        subscribtion_ids = copy.deepcopy( dplugin.get_subscribtions() )

        #Iterate over all DPlugins, which own a subscribed DBlock
        for sub_id in subscribtion_ids:
            sub = self.get_dplugin_by_id(sub_id)

            dblock_names = subscribtion_ids[sub_id]

            for dblock_name in dblock_names:

                dblock = sub.get_dblock_by_name(dblock_name)

                dblock.rm_subscriber(dplugin)

                dplugin.unsubscribe(dblock)

        if 0 == len(dplugin.get_subscribtions()):
            return True
        else:
            return False

    def rm_all_subscribers(self, dplugin_id):
        """
        This function is used to remove all subscribers of all DBlocks, which are hold by the DPlugin with the dplugin_id.

        :param dplugin_id: dplugin identifed by dplugin_id whose subscribers should be removed.
        :return:
        """

        dplugin = self.get_dplugin_by_id(dplugin_id)

        dblock_names = dplugin.get_dblocks()

        for dblock_name in dblock_names:

            dblock = dplugin.get_dblock_by_name(dblock_name)

            copy_dplugin_ids = copy.deepcopy(dblock.get_subscribers())

            for dplugin_id in copy_dplugin_ids:

                subscriber = self.get_dplugin_by_id(dplugin_id)

                subscriber.unsubscribe(dblock)
                dblock.rm_subscriber(subscriber)

        # if len(dplugin.get_dblocks()) == 0:
        #     return True
        # else:
        #     return False


    def rm_all_subscribers_of_a_dblock(self, dplugin_id, dblock_name):
        dplugin = self.get_dplugin_by_id(dplugin_id)
        if dplugin is not None:
            dblock = dplugin.get_dblock_by_name(dblock_name)
            if dblock is not None:
                dplugin_ids = copy.deepcopy(dblock.get_subscribers())
                for dplugin_id in dplugin_ids:

                    subscriber = self.get_dplugin_by_id(dplugin_id)

                    subscriber.unsubscribe(dblock)
                    dblock.rm_subscriber(subscriber)


    def subscribe_signals(self, subscriber_id, target_id, dblock_name, signals):
        """
        This function is used to subscribe a bunch of signals.

        :param subscriber_id: DPlugin which likes to subscribes signals of the chosen  dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for subscribtion
        :param signals: List of signals which are needed to be added
        :return:
        """

        #Get Susbcriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            self.log.printText(1, "Found no Subscriber with ID " + subscriber_id)
            return None

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            self.log.printText(1, "Found no Target with ID " + str(target_id))
            return None

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            self.log.printText(1, "Target " + target.uname + " has no DBlock " + dblock_name)

            return None

        return subscriber.subscribe_signals(dblock, signals)


    def unsubscribe_signals(self, subscriber_id, target_id, dblock_name, signals):
        """
        This function is used to unubscribe a bunch of signals.

        :param subscriber_id: DPlugin which likes to unsubscribes signals of the chosen dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for subscribtion
        :param signals: List of signals which are needed to be added
        :return:
        """

        #Get Susbcriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            self.log.printText(1, "Found no Subscriber with ID " + subscriber_id)
            return False

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            self.log.printText(1, "Found no Target with ID " + str(target_id))
            return False

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            self.log.printText(1, " Target " + target.uname + " has no DBlock " + dblock_name)

            return False

        subscription = subscriber.unsubscribe_signals(dblock, signals)

        if subscription is None:
            self.log.printText(1, " Subscription for target " + target.uname + " and DBlock " + dblock_name + " is None")
            return False

        if len(subscription.get_signals()) == 1:
            return self.unsubscribe(subscriber_id, target_id, dblock_name)

        return True
예제 #10
0
    def init_gui_graphic(self):
        """
        Called to set mandatory variables, create child dialogs and actions.
        This function is called once within the constructor.

        :return:
        """

        self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE)
        # set GUI size
        self.setGeometry(self.geometry().x(),
                         self.geometry().y(), pc.GUI_DEFAULT_WIDTH,
                         pc.GUI_DEFAULT_HEIGHT)

        self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              pc.GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.log.printText(
            1, pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: ' +
            str(os.getpid()))

        self.last_config = pc.PAPI_LAST_CFG_PATH

        self.in_run_mode = False

        # -------------------------------------
        # Create menues
        # -------------------------------------
        self.plugin_create_dialog = CreatePluginDialog(
            self.gui_management.gui_api, self.TabManager)

        # -------------------------------------
        # Create actions
        # -------------------------------------
        _translate = QtCore.QCoreApplication.translate

        self.action_load_config.triggered.connect(self.triggered_load_config)
        self.action_load_config.setShortcut(_translate("DefaultMain",
                                                       "Ctrl+L"))

        self.action_save_config.triggered.connect(self.triggered_save_config)
        self.action_save_config.setShortcut(_translate("DefaultMain",
                                                       "Ctrl+S"))

        self.action_open_overview_menu.triggered.connect(
            self.triggered_open_overview_menu)
        self.action_open_overview_menu.setShortcut(
            _translate("DefaultMain", "Ctrl+O"))

        self.action_open_create_plugin_menu.triggered.connect(
            self.triggered_open_create_plugin_menu)
        self.action_open_create_plugin_menu.setShortcut(
            _translate("DefaultMain", "Ctrl+N"))

        self.action_reset_papi.triggered.connect(self.triggered_reset_papi)
        self.action_reload_config.triggered.connect(
            self.triggered_reload_config)

        self.action_toggle_run_mode.triggered.connect(
            self.triggered_toggle_run_mode)

        self.action_reload_plugin_db.triggered.connect(
            self.triggered_reload_plugin_db)

        self.action_open_papi_doc.triggered.connect(
            self.triggered_open_papi_doc)
        self.action_open_papi_doc.setShortcut(
            _translate("DefaultMain", "Ctrl+H"))

        self.action_open_papi_about.triggered.connect(
            self.triggered_open_papi_about)
        self.action_open_qt_about.triggered.connect(
            self.triggered_open_qt_about)

        self.action_toggle_toolbar.triggered.connect(
            self.triggered_toggle_toolbar)

        self.toolbar.clickedFavouritePlugin.connect(
            self.toolbar_add_fav_plugin)
        self.toolbar.removedFavouritePlugin.connect(
            self.fav_plugin_was_removed)

        self.actionFullscreen.triggered.connect(
            self.triggered_toggle_fullscreen)

        self.init_set_icons()
예제 #11
0
파일: main.py 프로젝트: dani-l/PaPI
class GUI(QMainWindow, Ui_DefaultMain):
    """
    Used to create the qt based PaPI gui.

    """
    def __init__(self, core_queue = None, gui_queue= None, gui_id = None, gui_data = None, is_parent = False, parent=None):
        """
        Init function

        :param core_queue: Queue used to send papi events to Core
        :param gui_queue: GUI queue which contains papi events for the gui
        :param gui_id: Unique ID for this gui
        :param gui_data: Contains all data for the current session
        :param parent: parent element
        :return:
        """
        super(GUI, self).__init__(parent)
        self.is_parent = is_parent

        self.setupUi(self)

        # Create a data structure for gui if it is missing
        # -------------------------------------------------- #
        if not isinstance(gui_data, DGui):
            self.gui_data = DGui()
        else:
            self.gui_data = gui_data


        # check if gui should be the parent process or core is the parent
        # start core if gui is parent
        # -------------------------------------------------- #
        self.core_process = None
        if is_parent:
            core_queue_ref = Queue()
            gui_queue_ref = Queue()
            gui_id_ref = 1
            self.core_process = Process(target = run_core_in_own_process,
                                        args=(gui_queue_ref,core_queue_ref, gui_id_ref ))
            self.core_process.start()
        else:
            if core_queue is None:
                raise Exception('Gui started with wrong arguments')
            if gui_queue is None:
                raise Exception('Gui started with wrong arguments')
            if not isinstance(gui_id, str):
                raise Exception('Gui started with wrong arguments')

            core_queue_ref = core_queue
            gui_queue_ref = gui_queue
            gui_id_ref = gui_id


        # Create the Tab Manager and the gui management unit #
        # connect some signals of management to gui          #
        # -------------------------------------------------- #
        self.TabManager = PapiTabManger(tabWigdet=self.widgetTabs, centralWidget=self.centralwidget)

        self.gui_management = GuiManagement(core_queue_ref,
                                    gui_queue_ref,
                                    gui_id_ref,
                                    self.TabManager,
                                    self.get_gui_config,
                                    self.set_gui_config)

        self.TabManager.gui_api = self.gui_management.gui_api
        self.TabManager.dGui    = self.gui_management.gui_data

        self.gui_management.gui_event_processing.added_dplugin.connect(self.add_dplugin)
        self.gui_management.gui_event_processing.removed_dplugin.connect(self.remove_dplugin)
        self.gui_management.gui_event_processing.dgui_changed.connect(self.changed_dgui)
        self.gui_management.gui_event_processing.plugin_died.connect(self.plugin_died)

        self.gui_management.gui_api.error_occured.connect(self.error_occured)

        # initialize the graphic of the gui
        # -------------------------------------------------- #
        self.gui_graphic_init()

        signal.signal(signal.SIGINT, lambda a,b: self.signal_handler(a,b))

        # List for keys that are active
        self.keysActiveList = [];


    def signal_handler(self,signal, frame):
        """
        This handler will be called, when CTRL+C is used in the console
        It will react to SIGINT Signal
        As an reaction it will close the gui by first telling the core to close and then closing the gui
        :return:
        """
        self.gui_management.gui_api.do_close_program()
        sys.exit(0)


    def gui_graphic_init(self):
        self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE)
        # set GUI size
        self.setGeometry(self.geometry().x(),self.geometry().y(), pc.GUI_DEFAULT_WIDTH, pc.GUI_DEFAULT_HEIGHT)

        self.count = 0

        self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL, pc.GUI_PROCESS_CONSOLE_IDENTIFIER)

        self.log.printText(1,pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: '+str(os.getpid()))

        self.last_config = pc.PAPI_LAST_CFG_PATH

        self.in_run_mode = False


        # -------------------------------------
        # Create placeholder
        # -------------------------------------
        self.overview_menu = None
        self.create_plugin_menu = None
        self.plugin_create_dialog = None

        # -------------------------------------
        # Create menues
        # -------------------------------------
        self.plugin_create_dialog = CreatePluginDialog(self.gui_management.gui_api, self.TabManager)


        # -------------------------------------
        # Create callback functions for buttons
        # -------------------------------------
        #self.loadButton.clicked.connect(self.load_triggered)
        #self.saveButton.clicked.connect(self.save_triggered)

        # -------------------------------------
        # Create actions
        # -------------------------------------
        _translate = QtCore.QCoreApplication.translate

        self.actionLoad.triggered.connect(self.triggered_load)
        self.actionLoad.setShortcut(_translate("DefaultMain","Ctrl+L"))



        self.actionSave.triggered.connect(self.triggered_save)
        self.actionSave.setShortcut(_translate("DefaultMain","Ctrl+S"))

        self.actionOverview.triggered.connect(self.triggered_show_overview_menu)
        self.actionOverview.setShortcut(_translate("DefaultMain","Ctrl+O"))

        self.actionCreate.triggered.connect(self.triggered_show_create_plugin_menu)
        self.actionCreate.setShortcut(_translate("DefaultMain","Ctrl+N"))

        self.actionResetPaPI.triggered.connect(self.triggered_reset_papi)
        self.actionReloadConfig.triggered.connect(self.triggered_reload_config)

        self.actionRunMode.triggered.connect(self.toggle_run_mode)

        self.actionReload_Plugin_DB.triggered.connect(self.triggered_reload_plugin_db)

        self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki)

        self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc)
        self.actionPaPI_Doc.setShortcut(_translate("DefaultMain","Ctrl+H"))

        self.actionAbout.triggered.connect(self.triggered_papi_about)
        self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt)

        self.actionToolbar.triggered.connect(self.triggered_show_toolbar)

        #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent
        #self.toolBar.dropEvent = self.toolbarDropEvent

        self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin)
        self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved)

        self.set_icons()

    def addFavPlugin(self, fav_plugin):
        plugin_manager = self.gui_management.plugin_manager;

        plugin_manager.locatePlugins()

        candidates = plugin_manager.getPluginCandidates()
        all_pluginfo = {c[2].path:c[2] for c in candidates}
        loadable_pluginfo = {p.path:p for p in plugin_manager.getAllPlugins()}

        for plugin_info in all_pluginfo.values():
            if plugin_info.name == fav_plugin:

                if plugin_info.path in loadable_pluginfo.keys():
                    plugin_info = loadable_pluginfo[plugin_info.path]
                    plugin_info.loadable = True
                else:
                    plugin_info.loadable = False

                self.toolbarAddFavPlugin(plugin_info)

    def favPluginWasRemoved(self):
        self.gui_management.gui_api.do_save_xml_config_reloaded(
            pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True)

    def set_icons(self):
        # -------------------------------------
        # Create Icons for buttons
        # -------------------------------------
        load_icon = get32Icon('folder')
        save_icon = get32Icon('file_save_as')
        # -------------------------------------
        # Set Icons for buttons
        # -------------------------------------
        #self.loadButton.setIconSize(QSize(32, 32))
        #self.loadButton.setIcon(load_icon)

        #self.saveButton.setIconSize(QSize(32, 32))
        #self.saveButton.setIcon(save_icon)

        # -------------------------------------
        # Create Icons for actions
        # -------------------------------------
        load_icon = get16Icon('folder')
        save_icon = get16Icon('file_save_as')
        exit_icon = get16Icon('cancel')
        overview_icon = get16Icon('tree_list')
        create_icon = get16Icon('application_add')
        reload_icon = get16Icon('arrow_rotate_clockwise')
        help_icon = get16Icon('help')
        info_icon = get16Icon('information')
        refresh_icon = get16Icon('arrow_refresh')
        delete_icon = get16Icon('delete')
        view_icon = get16Icon('reviewing_pane')

        # -------------------------------------
        # Set Icons for actions
        # -------------------------------------
        self.actionLoad.setIcon(load_icon)
        self.actionSave.setIcon(save_icon)
        self.actionExit.setIcon(exit_icon)
        self.actionOverview.setIcon(overview_icon)
        self.actionCreate.setIcon(create_icon)
        self.actionReload_Plugin_DB.setIcon(reload_icon)
        self.actionReloadConfig.setIcon(reload_icon)
        self.actionPaPI_Wiki.setIcon(help_icon)
        self.actionPaPI_Doc.setIcon(help_icon)
        self.actionAbout.setIcon(info_icon)
        self.actionAbout_Qt.setIcon(info_icon)
        self.actionAbout_PySide.setIcon(info_icon)
        self.actionResetPaPI.setIcon(delete_icon)
        self.actionRunMode.setIcon(view_icon)

        # -------------------------------------
        # Set Icons visible in menu
        # -------------------------------------
        self.actionLoad.setIconVisibleInMenu(True)
        self.actionSave.setIconVisibleInMenu(True)
        self.actionExit.setIconVisibleInMenu(True)
        self.actionOverview.setIconVisibleInMenu(True)
        self.actionCreate.setIconVisibleInMenu(True)
        self.actionReload_Plugin_DB.setIconVisibleInMenu(True)
        self.actionReloadConfig.setIconVisibleInMenu(True)
        self.actionPaPI_Wiki.setIconVisibleInMenu(True)
        self.actionPaPI_Doc.setIconVisibleInMenu(True)
        self.actionAbout.setIconVisibleInMenu(True)
        self.actionAbout_Qt.setIconVisibleInMenu(True)
        self.actionAbout_PySide.setIconVisibleInMenu(True)
        self.actionResetPaPI.setIconVisibleInMenu(True)
        self.actionRunMode.setIconVisibleInMenu(True)

    def get_gui_config(self, saveUserSettings=False):

        actTab = {}
        actTab['Active'] = str(self.TabManager.get_currently_active_tab())

        tabs = {}
        tab_dict = self.TabManager.get_tabs_by_uname()
        for tab in tab_dict:
            tabOb = tab_dict[tab]
            tabs[tab]= {}
            tabs[tab]['Background'] = tabOb.background
            tabs[tab]['Position'] = str(self.TabManager.getTabPosition_by_name(tab))

        size = {}

        size['X']= str(self.size().width())

        size['Y']= str(self.size().height())


        cfg = {}
        cfg['ActiveTab'] = actTab
        cfg['Tabs'] = tabs
        cfg['Size'] = size

        # ----------------------
        # Set favourite plugins
        # ----------------------
        if saveUserSettings:
            favourites = {}
            actions = self.toolBar.actions()
            for i in range(len(actions)):
                action = actions[i]
                if isinstance(action, PaPIFavAction):
                    favourites[action.text()] = {}
                    favourites[action.text()]['position'] = str(i)

            cfg['Favourites'] = favourites

        return cfg

    def set_gui_config(self, cfg):
        #print(cfg)
        # #################
        # # Cfgs for Tabs #
        # #################
        # if 'tabs' in cfg:
        #     tabList = {}
        #     for tab in cfg['tabs']:
        #         # Tab Name
        #         name = tab
        #
        #         # Tab details
        #         tabDetails = cfg['tabs'][tab]
        #
        #         # check for background
        #         if 'background' in tabDetails:
        #             bg = tabDetails['background']
        #             if bg != 'default':
        #                 self.TabManager.set_background_for_tab_with_name(name,bg)
        #         else:
        #             bg = None
        #
        #         # check for position
        #         if 'position' in tabDetails:
        #             pos = int(tabDetails['position'])
        #         else:
        #             if len(list(tabList.keys())) > 1:
        #                 pos = max(list(tabList.keys()))+1
        #             else:
        #                 pos = 0
        #
        #         tabList[pos] = [name, bg]
        #
        #     # sort tabs acoriding to positions
        #     keys = list(tabList.keys())
        #     keys.sort()
        #     for position in keys:
        #         name = tabList[position][0]
        #         bg = tabList[position][1]
        #         tabOb = self.TabManager.add_tab(name)
        #         self.TabManager.set_background_for_tab_with_name(name,bg)
        #
        # if 'activeTab' in cfg:
        #     if 'value' in cfg['activeTab']['active']:
        #         self.TabManager.set_tab_active_by_index(int( cfg['activeTab']['active']['value'] ))
        #
        #################
        # windows size: #
        #################
        if 'Size' in cfg:
            w = int(cfg['Size']['X'])
            h = int(cfg['Size']['Y'])
            self.resize_gui_window(w,h)

        # ------------------------
        # Restore favourite icons
        # ------------------------
        if 'Favourites' in cfg:
            sorted_positions = {}

            for plugin in cfg['Favourites']:
                sorted_positions[int(cfg['Favourites'][plugin]['position'])] = plugin

            for position in sorted(sorted_positions.keys()):
                plugin = sorted_positions[position]
                self.addFavPlugin(plugin)

        # -----------------------
        # Restore Tabs
        # -----------------------
        if 'Tabs' in cfg:
            for tabName in cfg['Tabs']:
                tab = cfg['Tabs'][tabName]
                self.TabManager.add_tab(tabName)
                if 'Background' in tab:
                    self.TabManager.set_background_for_tab_with_name(tabName, tab['Background'])

                


    def triggered_reload_plugin_db(self):
        """
        This Callback function will reload the plugin list of the plugin manager

        :return:
        """
        self.gui_management.plugin_manager.collectPlugins()

    def run(self):
        """


        :return:
        """
        # create a timer and set interval for processing events with working loop

        #QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_event_processing.gui_working(self.closeEvent))
        self.workingTimer = QtCore.QTimer(self)
        self.workingTimer.timeout.connect(lambda: self.gui_management.gui_event_processing.gui_working(self.closeEvent, self.workingTimer))
        self.workingTimer.start(pc.GUI_WOKRING_INTERVAL)




    def triggered_show_create_plugin_menu(self):
        """


        :return:
        """
        self.create_plugin_menu = CreatePluginMenu(self.gui_management.gui_api,
                                                   self.TabManager,
                                                   self.gui_management.plugin_manager )

        self.create_plugin_menu.show()

    def triggered_show_overview_menu(self):
        """
        Used to show the overview menu.

        :return:
        """
        self.overview_menu = OverviewPluginMenu(self.gui_management.gui_api, self.gui_management.tab_manager)
        self.overview_menu.show()

    def triggered_show_toolbar(self):
        """
        Used to hide and unhide the toolbar
        :return:
        """

        self.toolBar.setHidden(not self.toolBar.isHidden())

        self.actionToolbar.setChecked(not self.toolBar.isHidden())

    def triggered_load(self):
        """
        Used to start the 'load config' dialog.

        :return:
        """
        fileNames = ''

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter( self.tr("PaPI-Cfg (*.xml)"))
        dialog.setDirectory(pc.CONFIG_DEFAULT_DIRECTORY)
        dialog.setWindowTitle("Load Configuration")

        if dialog.exec_():
            fileNames = dialog.selectedFiles()

        if len(fileNames):
            if fileNames[0] != '':
                self.last_config = fileNames[0]
                self.load_config(fileNames[0])

    def load_config(self, file_name):
        self.gui_management.gui_api.do_load_xml(file_name)

    def triggered_save(self):
        """
        Used to start the 'save config' dialog.

        :return:
        """
        fileNames = ''

        dialog = PaPIConfigSaveDialog(self, self.gui_management.gui_api)

        dialog.fill_with()

        if dialog.exec_():
            fileNames = dialog.selectedFiles()

        plugin_list, subscription_list = dialog.get_create_lists()

        if len(fileNames):



            if fileNames[0] != '':
                if "json" in dialog.selectedNameFilter():
                    self.gui_management.gui_api.do_save_json_config_reloaded(fileNames[0], plToSave=plugin_list, sToSave=subscription_list)

                if "xml" in dialog.selectedNameFilter():
                    self.gui_management.gui_api.do_save_xml_config_reloaded(fileNames[0], plToSave=plugin_list, sToSave=subscription_list)

    def closeEvent(self, *args, **kwargs):
        """
        Handle close event.
        Saves current session as 'papi/last_active_papi.xml'
        Closes all opened windows.

        :param args:
        :param kwargs:
        :return:
        """
        try:
            self.gui_management.gui_api.do_save_xml_config('papi/last_active_papi.xml')
        except Exception as E:
            tb = traceback.format_exc()

        self.gui_management.gui_api.do_close_program()
        if self.create_plugin_menu is not None:
            self.create_plugin_menu.close()

        if self.overview_menu is not None:
            self.overview_menu.close()

        self.close()

    def add_dplugin(self, dplugin):
        """
        Callback function called by 'DPlugin added signal'
        Used to add a DPlugin SubWindow on the GUI if possible.

        :param dplugin:
        :return:
        """
        if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER:

            # sub_window_ori = dplugin.plugin.get_sub_window()
            #
            # dplugin.plugin.set_window_for_internal_usage(PaPIMDISubWindow())
            # dplugin.plugin.pl_set_widget_for_internal_usage(sub_window_ori.widget())

            sub_window = dplugin.plugin._get_sub_window()

            config = dplugin.startup_config
            tab_name = config['tab']['value']
            if tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]
            else:
                self.log.printText(1,'add dplugin: no tab with tab_id of dplugin')
                area = self.TabManager.add_tab(tab_name)

            area.addSubWindow(sub_window)

            isMaximized = config['maximized']['value'] == '1'


            size_re = re.compile(r'([0-9]+)')

            pos = config['position']['value']
            window_pos = size_re.findall(pos)
            sub_window.move(int(window_pos[0]), int(window_pos[1]))

            if not isMaximized:
                sub_window.show()
            else:
                sub_window.showMaximized()

            # see http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum

            sub_window.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint | Qt.WindowTitleHint )

        if self.overview_menu is not None:
            self.overview_menu.refresh_action(dplugin)

    def remove_dplugin(self, dplugin):
        """
        Callback function called by 'DPlugin removed signal'
        Used to removed a DPlugin SubWindow from the GUI if possible.

        :param dplugin:
        :return:
        """
        if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER:
            config = dplugin.plugin.pl_get_current_config()
            tab_name = config['tab']['value']
            if tab_name in self.TabManager.get_tabs_by_uname():
                tabOb = self.TabManager.get_tabs_by_uname()[tab_name]
                tabOb.removeSubWindow(dplugin.plugin._get_sub_window())
                if tabOb.closeIfempty is True:
                    if len(tabOb.subWindowList()) == 0:
                        if isinstance(tabOb, TabObject):
                            self.TabManager.closeTab_by_name(tabOb.name)
                        else:
                            self.TabManager.remove_window(tabOb)


    def changed_dgui(self):
        if self.overview_menu is not None:
            self.overview_menu.refresh_action()

    def plugin_died(self, dplugin, e, msg):
        dplugin.state = pc.PLUGIN_STATE_STOPPED

        self.gui_management.gui_api.do_stopReset_plugin_uname(dplugin.uname)

        errMsg = QtGui.QMessageBox(self)
        errMsg.setFixedWidth(650)

        # layout = errMsg.layout();
        # spacer = QtGui.QSpacerItem(1000, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        # layout.addItem(spacer, layout.rowCount(), 0,1, layout.columnCount())

        errMsg.setIcon(QtGui.QMessageBox.Critical)
        errMsg.setSizeGripEnabled(True)
        errMsg.setWindowTitle("Plugin: " + dplugin.uname + " // " + str(e))
        errMsg.setText("Error in plugin" + dplugin.uname + " // " + str(e))
        errMsg.setDetailedText(str(msg))
        errMsg.setWindowModality(Qt.NonModal)
        errMsg.show()

    def error_occured(self, title, msg, detailed_msg):

        errMsg = QtGui.QMessageBox(self)
        errMsg.setFixedWidth(650)

        errMsg.setWindowTitle(title)
        errMsg.setText(str(msg))
        errMsg.setDetailedText(str(detailed_msg))
        errMsg.setWindowModality(Qt.NonModal)
        errMsg.show()

    def toggle_run_mode(self):
        if self.in_run_mode is False:
            # hide toolbar
            self.toolBar.setHidden(True)
            self.actionToolbar.setChecked(False)
            # disable context menu of tabmanger
            self.TabManager.disableContextMenus()

            # lock subwindows in tabs
            for tabName in self.TabManager.tab_dict_uname:
                tabObject = self.TabManager.tab_dict_uname[tabName]

                for subWindow in tabObject.subWindowList():
                    subWindow.disableInteraction()
            self.in_run_mode = True
        else:
            # show toolbar
            self.toolBar.setHidden(False)
            self.actionToolbar.setChecked(True)
            # disable context menu of tabmanger
            self.TabManager.enableContextMenus()

            # unlock subwindows in tabs
            for tabName in self.TabManager.tab_dict_uname:
                tabObject = self.TabManager.tab_dict_uname[tabName]

                for subWindow in tabObject.subWindowList():
                    subWindow.enableInteraction()
            self.in_run_mode = False

    def toogle_lock(self):
        raise Exception("PLEASE REPORT THIS BUG!!")
        if self.in_run_mode:
            for tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]

                windowsList = area.subWindowList()

                for window in windowsList:

                    #window.setAttribute(Qt.WA_NoBackground)

                    #window.setAttribute(Qt.WA_NoSystemBackground)
                    #window.setAttribute(Qt.WA_TranslucentBackground)
                    #window.set_movable(False)
                    window.setMouseTracking(False)
                    window.setWindowFlags(~Qt.WindowMinMaxButtonsHint & (Qt.CustomizeWindowHint | Qt.WindowTitleHint))

        if not self.in_run_mode:
            for tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]

                windowsList = area.subWindowList()

                for window in windowsList:
                    #window.set_movable(True)
                    window.setMouseTracking(True)
                    window.setWindowFlags(Qt.CustomizeWindowHint | Qt.WindowMinMaxButtonsHint | Qt.WindowTitleHint )

    def keyPressEvent(self, event):
        if event.key() not in self.keysActiveList:
            self.keysActiveList.append(event.key())

        if  QtCore.Qt.Key_Escape in self.keysActiveList:
            if self.in_run_mode:
                self.toggle_run_mode()

        if QtCore.Qt.Key_D in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.gui_management.tab_manager.select_next_tab()
            self.keysActiveList.remove(QtCore.Qt.Key_D)
            #self.keysActiveList.remove(QtCore.Qt.Key_Control)

        if QtCore.Qt.Key_A in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.gui_management.tab_manager.select_prev_tab()
            self.keysActiveList.remove(QtCore.Qt.Key_A)
            #self.keysActiveList.remove(QtCore.Qt.Key_Control)


    def keyReleaseEvent(self, event):
        if event.key() in self.keysActiveList:
            self.keysActiveList.remove(event.key())


    def resize_gui_window(self, w, h):
        self.setGeometry(self.geometry().x(),self.geometry().y(),w,h)


    def triggered_reload_config(self):
        """
        This function is used to reset PaPI and to reload the last loaded configuration file.
        :return:
        """
        if self.last_config is not None:
            self.triggered_reset_papi()
            QtCore.QTimer.singleShot(pc.GUI_WAIT_TILL_RELOAD, lambda: self.gui_management.gui_api.do_load_xml(self.last_config))

    def triggered_reset_papi(self):
        """
        This function is called to reset PaPI. That means all subscriptions were canceled and all plugins were removed.
        :return:
        """
        h = pc.GUI_DEFAULT_HEIGHT
        w = pc.GUI_DEFAULT_WIDTH
        self.setGeometry(self.geometry().x(),self.geometry().y(),w,h)

        self.TabManager.set_all_tabs_to_close_when_empty(True)
        self.TabManager.close_all_empty_tabs()

        self.gui_management.gui_api.do_reset_papi()



    def triggered_papi_wiki(self):
        QDesktopServices.openUrl(QUrl(pc.PAPI_WIKI_URL, QUrl.TolerantMode))

    def triggered_papi_doc(self):
        QDesktopServices.openUrl(QUrl(pc.PAPI_DOC_URL, QUrl.TolerantMode))

    def triggered_papi_about(self):
        QMessageBox.about(self, pc.PAPI_ABOUT_TITLE, pc.PAPI_ABOUT_TEXT)

    def triggered_papi_about_qt(self):
        QMessageBox.aboutQt(self)

    def toolbarAddFavPlugin(self, plugin_info):

        l = len(plugin_info.name)
        path = plugin_info.path[:-l]
        path += 'box.png'
        px = QPixmap(path)

        icon = QIcon(px)

        for action in self.toolBar.actions():
            if action.text() == plugin_info.name:
                return

        plugin_action = PaPIFavAction(icon, plugin_info.name, self)
        plugin_action.triggered.connect(lambda ignore, p1=plugin_info : self.show_create_plugin_dialog(p1))

        self.toolBar.addAction(plugin_action)

        self.gui_management.gui_api.do_save_xml_config_reloaded(
            pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True)

    def show_create_plugin_dialog(self, plugin_info):
        if plugin_info is not None:
            if plugin_info.loadable:
                self.plugin_create_dialog.set_plugin(plugin_info)
                self.plugin_create_dialog.show()

    def dropEvent(self, event:QDropEvent):
        source = event.source()
예제 #12
0
class DCore():
    """
    DCore contains and manages the internal data structure
    """
    def __init__(self):
        """
        Used to initialize this object. An empty dictionary of DPlugin is created

        :return:
        """
        self.__DPlugins = {}

        self.__newid = 0
        self.log = ConsoleLog(2, "DCore: ")

    def create_id(self):
        """
        Creates and returns unique IDs

        :returns: unique ID
        :rtype: int
        """
        #self.__newid += 1
        self.__newid = DObject.create_unique_id()
        return self.__newid
#        return uuid.uuid4().int >> 64

    def add_plugin(self, process, pid, own_process, queue, plugin, id):
        """
        Add plugin with necessary information.

        :param process: Plugin is running in this process
        :param pid: Process ID of the process in which the plugin is running
        :param queue: Event queue needed for events which should be received by this plugin
        :param plugin: Plugin object
        :param plugin_id: ID of this plugin
        :param id: ID for the new DPlugin
        :return: Returns the data object DPlugin
        :rtype: DPlugin
        """

        d_pl = DPlugin()

        d_pl.process = process
        d_pl.pid = pid
        d_pl.queue = queue
        d_pl.plugin = plugin
        d_pl.id = id
        d_pl.own_process = own_process

        self.__DPlugins[id] = d_pl

        return d_pl

    def rm_dplugin(self, dplugin_id):
        """
        Removes DPlugin with dplugin_id

        :param dplugin_id:
        :return:
        :rtype: bool
        """

        if dplugin_id in self.__DPlugins:
            self.__DPlugins[dplugin_id].state = 'deleted'

            self.rm_all_subscribers(dplugin_id)
            self.unsubscribe_all(dplugin_id)

            del self.__DPlugins[dplugin_id]

            return ERROR.NO_ERROR
        else:
            return ERROR.UNKNOWN_ERROR

    def get_dplugins_count(self):
        """
        Returns count of known plugins in this data structure

        :return:
        :rtype: int
        """

        return len(self.__DPlugins.keys())

    def get_dplugin_by_id(self, plugin_id):
        """
        Returns DPlugin object by ID

        :param plugin_id: ID of an DPlugin object
        :return DPlugin:
        :rtype: DPlugin
        """

        if plugin_id in self.__DPlugins:
            return self.__DPlugins[plugin_id]
        else:
            return None

    def get_dplugin_by_uname(self, plugin_uname):
        """
        Returns DPlugin object by uname

        :param plugin_name: uname of an DPlugin object
        :return DPlugin:
        :rtype: DPlugin
        """

        for plugin_id in self.__DPlugins:
            d_pl = self.__DPlugins[plugin_id]

            if d_pl.uname == plugin_uname:
                return d_pl

        return None

    def get_all_plugins(self):
        """
        Returns a dictionary of all known dplugins

        :return:
        :rtype: {}
        """

        return self.__DPlugins

    def subscribe(self, subscriber_id, target_id, dblock_name):
        """
        Used to create a subscription.

        :param subscriber_id: DPlugin which likes to subscribes dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for subscribtion
        :return:
        """

        #Get Subscriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            self.log.printText(1,
                               "Found no Subscriber with ID " + subscriber_id)
            return None

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            self.log.printText(1, "Found no Target with ID " + str(target_id))
            return None

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            self.log.printText(
                1, "Target " + target.uname + " has no DBlock " + dblock_name)

            return None

        #Create relation between DPlugin and DBlock

        dsubscription = subscriber.subscribe(dblock)

        if dsubscription is None:
            self.log.printText(
                1, "Subscriber " + str(subscriber_id) +
                " has already subscribed " + dblock_name)
            return None

        if dblock.add_subscribers(subscriber) is False:
            self.log.printText(
                1, "DBlock " + dblock_name +
                " was already subscribed by Subscriber" + subscriber_id)
            return None

        return dsubscription

    def unsubscribe(self, subscriber_id, target_id, dblock_name):
        """
        Used to remove a subscription.

        :param subscriber_id: DPlugin which likes to unsubscribes dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for unsubscribtion
        :return:
        :rtype boolean:
        """

        #Get Susbcriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            return False

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            return False

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            return False

        #Destroy relation between DPlugin and DBlock
        if subscriber.unsubscribe(dblock) is False:
            self.log.printText(
                1, "Subscriber " + str(subscriber_id) +
                " has already unsubscribed " + dblock_name)
            return False

        if dblock.rm_subscriber(subscriber) is False:
            self.log.printText(
                1, "DBlock " + dblock_name +
                " was already unsubscribed by Subscriber" + subscriber_id)
            return False

        return True

    def unsubscribe_all(self, dplugin_id):
        """
        This function is used to cancel all subscription of the DPlugin with the dplugin_id.

        :param dplugin_id: dplugin identifed by dplugin_id whose subscription should be canceled.
        :return:
        """

        dplugin = self.get_dplugin_by_id(dplugin_id)

        # copy subscription for iteration and deletion
        subscribtion_ids = copy.deepcopy(dplugin.get_subscribtions())

        #Iterate over all DPlugins, which own a subscribed DBlock
        for sub_id in subscribtion_ids:
            sub = self.get_dplugin_by_id(sub_id)

            dblock_names = subscribtion_ids[sub_id]

            for dblock_name in dblock_names:

                dblock = sub.get_dblock_by_name(dblock_name)

                dblock.rm_subscriber(dplugin)

                dplugin.unsubscribe(dblock)

        if 0 == len(dplugin.get_subscribtions()):
            return True
        else:
            return False

    def rm_all_subscribers(self, dplugin_id):
        """
        This function is used to remove all subscribers of all DBlocks, which are hold by the DPlugin with the dplugin_id.

        :param dplugin_id: dplugin identifed by dplugin_id whose subscribers should be removed.
        :return:
        """

        dplugin = self.get_dplugin_by_id(dplugin_id)

        dblock_names = dplugin.get_dblocks()

        for dblock_name in dblock_names:

            dblock = dplugin.get_dblock_by_name(dblock_name)

            copy_dplugin_ids = copy.deepcopy(dblock.get_subscribers())

            for dplugin_id in copy_dplugin_ids:

                subscriber = self.get_dplugin_by_id(dplugin_id)

                subscriber.unsubscribe(dblock)
                dblock.rm_subscriber(subscriber)

        # if len(dplugin.get_dblocks()) == 0:
        #     return True
        # else:
        #     return False

    def rm_all_subscribers_of_a_dblock(self, dplugin_id, dblock_name):
        dplugin = self.get_dplugin_by_id(dplugin_id)
        if dplugin is not None:
            dblock = dplugin.get_dblock_by_name(dblock_name)
            if dblock is not None:
                dplugin_ids = copy.deepcopy(dblock.get_subscribers())
                for dplugin_id in dplugin_ids:

                    subscriber = self.get_dplugin_by_id(dplugin_id)

                    subscriber.unsubscribe(dblock)
                    dblock.rm_subscriber(subscriber)

    def subscribe_signals(self, subscriber_id, target_id, dblock_name,
                          signals):
        """
        This function is used to subscribe a bunch of signals.

        :param subscriber_id: DPlugin which likes to subscribes signals of the chosen  dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for subscribtion
        :param signals: List of signals which are needed to be added
        :return:
        """

        #Get Susbcriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            self.log.printText(1,
                               "Found no Subscriber with ID " + subscriber_id)
            return None

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            self.log.printText(1, "Found no Target with ID " + str(target_id))
            return None

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            self.log.printText(
                1, "Target " + target.uname + " has no DBlock " + dblock_name)

            return None

        return subscriber.subscribe_signals(dblock, signals)

    def unsubscribe_signals(self, subscriber_id, target_id, dblock_name,
                            signals):
        """
        This function is used to unubscribe a bunch of signals.

        :param subscriber_id: DPlugin which likes to unsubscribes signals of the chosen dblock
        :param target_id: DPlugin which contains the dblock for subscribtion
        :param dblock_name: DBlock identified by its unique name for subscribtion
        :param signals: List of signals which are needed to be added
        :return:
        """

        #Get Susbcriber DPlugin
        subscriber = self.get_dplugin_by_id(subscriber_id)

        if subscriber is None:
            self.log.printText(1,
                               "Found no Subscriber with ID " + subscriber_id)
            return False

        #Get Target DPlugin
        target = self.get_dplugin_by_id(target_id)

        if target is None:
            self.log.printText(1, "Found no Target with ID " + str(target_id))
            return False

        dblock = target.get_dblock_by_name(dblock_name)

        if dblock is None:
            self.log.printText(
                1, " Target " + target.uname + " has no DBlock " + dblock_name)

            return False

        subscription = subscriber.unsubscribe_signals(dblock, signals)

        if subscription is None:
            self.log.printText(
                1, " Subscription for target " + target.uname +
                " and DBlock " + dblock_name + " is None")
            return False

        if len(subscription.get_signals()) == 1:
            return self.unsubscribe(subscriber_id, target_id, dblock_name)

        return True
예제 #13
0
    def gui_graphic_init(self):
        self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE)
        # set GUI size
        self.setGeometry(self.geometry().x(),
                         self.geometry().y(), pc.GUI_DEFAULT_WIDTH,
                         pc.GUI_DEFAULT_HEIGHT)

        self.count = 0

        self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              pc.GUI_PROCESS_CONSOLE_IDENTIFIER)

        self.log.printText(
            1, pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: ' +
            str(os.getpid()))

        self.last_config = pc.PAPI_LAST_CFG_PATH

        self.in_run_mode = False

        # -------------------------------------
        # Create placeholder
        # -------------------------------------
        self.overview_menu = None
        self.create_plugin_menu = None
        self.plugin_create_dialog = None

        # -------------------------------------
        # Create menues
        # -------------------------------------
        self.plugin_create_dialog = CreatePluginDialog(
            self.gui_management.gui_api, self.TabManager)

        # -------------------------------------
        # Create callback functions for buttons
        # -------------------------------------
        #self.loadButton.clicked.connect(self.load_triggered)
        #self.saveButton.clicked.connect(self.save_triggered)

        # -------------------------------------
        # Create actions
        # -------------------------------------
        _translate = QtCore.QCoreApplication.translate

        self.actionLoad.triggered.connect(self.triggered_load)
        self.actionLoad.setShortcut(_translate("DefaultMain", "Ctrl+L"))

        self.actionSave.triggered.connect(self.triggered_save)
        self.actionSave.setShortcut(_translate("DefaultMain", "Ctrl+S"))

        self.actionOverview.triggered.connect(
            self.triggered_show_overview_menu)
        self.actionOverview.setShortcut(_translate("DefaultMain", "Ctrl+O"))

        self.actionCreate.triggered.connect(
            self.triggered_show_create_plugin_menu)
        self.actionCreate.setShortcut(_translate("DefaultMain", "Ctrl+N"))

        self.actionResetPaPI.triggered.connect(self.triggered_reset_papi)
        self.actionReloadConfig.triggered.connect(self.triggered_reload_config)

        self.actionRunMode.triggered.connect(self.toggle_run_mode)

        self.actionReload_Plugin_DB.triggered.connect(
            self.triggered_reload_plugin_db)

        self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki)

        self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc)
        self.actionPaPI_Doc.setShortcut(_translate("DefaultMain", "Ctrl+H"))

        self.actionAbout.triggered.connect(self.triggered_papi_about)
        self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt)

        self.actionToolbar.triggered.connect(self.triggered_show_toolbar)

        #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent
        #self.toolBar.dropEvent = self.toolbarDropEvent

        self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin)
        self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved)

        self.set_icons()
예제 #14
0
class GUI(QMainWindow, Ui_DefaultMain):
    """
    Used to create the qt based PaPI gui.

    """
    def __init__(self,
                 core_queue=None,
                 gui_queue=None,
                 gui_id=None,
                 gui_data=None,
                 is_parent=False,
                 parent=None):
        """
        Init function

        :param core_queue: Queue used to send papi events to Core
        :param gui_queue: GUI queue which contains papi events for the gui
        :param gui_id: Unique ID for this gui
        :param gui_data: Contains all data for the current session
        :param parent: parent element
        :return:
        """
        super(GUI, self).__init__(parent)
        self.is_parent = is_parent

        self.setupUi(self)

        # Create a data structure for gui if it is missing
        # -------------------------------------------------- #
        if not isinstance(gui_data, DGui):
            self.gui_data = DGui()
        else:
            self.gui_data = gui_data

        # check if gui should be the parent process or core is the parent
        # start core if gui is parent
        # -------------------------------------------------- #
        self.core_process = None
        if is_parent:
            core_queue_ref = Queue()
            gui_queue_ref = Queue()
            gui_id_ref = 1
            self.core_process = Process(target=run_core_in_own_process,
                                        args=(gui_queue_ref, core_queue_ref,
                                              gui_id_ref))
            self.core_process.start()
        else:
            if core_queue is None:
                raise Exception('Gui started with wrong arguments')
            if gui_queue is None:
                raise Exception('Gui started with wrong arguments')
            if not isinstance(gui_id, str):
                raise Exception('Gui started with wrong arguments')

            core_queue_ref = core_queue
            gui_queue_ref = gui_queue
            gui_id_ref = gui_id

        # Create the Tab Manager and the gui management unit #
        # connect some signals of management to gui          #
        # -------------------------------------------------- #
        self.TabManager = PapiTabManger(tabWigdet=self.widgetTabs,
                                        centralWidget=self.centralwidget)

        self.gui_management = GuiManagement(core_queue_ref, gui_queue_ref,
                                            gui_id_ref, self.TabManager,
                                            self.get_gui_config,
                                            self.set_gui_config)

        self.TabManager.gui_api = self.gui_management.gui_api
        self.TabManager.dGui = self.gui_management.gui_data

        self.gui_management.gui_event_processing.added_dplugin.connect(
            self.add_dplugin)
        self.gui_management.gui_event_processing.removed_dplugin.connect(
            self.remove_dplugin)
        self.gui_management.gui_event_processing.dgui_changed.connect(
            self.changed_dgui)
        self.gui_management.gui_event_processing.plugin_died.connect(
            self.plugin_died)

        self.gui_management.gui_api.error_occured.connect(self.error_occured)

        # initialize the graphic of the gui
        # -------------------------------------------------- #
        self.gui_graphic_init()

        signal.signal(signal.SIGINT, lambda a, b: self.signal_handler(a, b))

        # List for keys that are active
        self.keysActiveList = []

    def signal_handler(self, signal, frame):
        """
        This handler will be called, when CTRL+C is used in the console
        It will react to SIGINT Signal
        As an reaction it will close the gui by first telling the core to close and then closing the gui
        :return:
        """
        self.gui_management.gui_api.do_close_program()
        sys.exit(0)

    def gui_graphic_init(self):
        self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE)
        # set GUI size
        self.setGeometry(self.geometry().x(),
                         self.geometry().y(), pc.GUI_DEFAULT_WIDTH,
                         pc.GUI_DEFAULT_HEIGHT)

        self.count = 0

        self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              pc.GUI_PROCESS_CONSOLE_IDENTIFIER)

        self.log.printText(
            1, pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: ' +
            str(os.getpid()))

        self.last_config = pc.PAPI_LAST_CFG_PATH

        self.in_run_mode = False

        # -------------------------------------
        # Create placeholder
        # -------------------------------------
        self.overview_menu = None
        self.create_plugin_menu = None
        self.plugin_create_dialog = None

        # -------------------------------------
        # Create menues
        # -------------------------------------
        self.plugin_create_dialog = CreatePluginDialog(
            self.gui_management.gui_api, self.TabManager)

        # -------------------------------------
        # Create callback functions for buttons
        # -------------------------------------
        #self.loadButton.clicked.connect(self.load_triggered)
        #self.saveButton.clicked.connect(self.save_triggered)

        # -------------------------------------
        # Create actions
        # -------------------------------------
        _translate = QtCore.QCoreApplication.translate

        self.actionLoad.triggered.connect(self.triggered_load)
        self.actionLoad.setShortcut(_translate("DefaultMain", "Ctrl+L"))

        self.actionSave.triggered.connect(self.triggered_save)
        self.actionSave.setShortcut(_translate("DefaultMain", "Ctrl+S"))

        self.actionOverview.triggered.connect(
            self.triggered_show_overview_menu)
        self.actionOverview.setShortcut(_translate("DefaultMain", "Ctrl+O"))

        self.actionCreate.triggered.connect(
            self.triggered_show_create_plugin_menu)
        self.actionCreate.setShortcut(_translate("DefaultMain", "Ctrl+N"))

        self.actionResetPaPI.triggered.connect(self.triggered_reset_papi)
        self.actionReloadConfig.triggered.connect(self.triggered_reload_config)

        self.actionRunMode.triggered.connect(self.toggle_run_mode)

        self.actionReload_Plugin_DB.triggered.connect(
            self.triggered_reload_plugin_db)

        self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki)

        self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc)
        self.actionPaPI_Doc.setShortcut(_translate("DefaultMain", "Ctrl+H"))

        self.actionAbout.triggered.connect(self.triggered_papi_about)
        self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt)

        self.actionToolbar.triggered.connect(self.triggered_show_toolbar)

        #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent
        #self.toolBar.dropEvent = self.toolbarDropEvent

        self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin)
        self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved)

        self.set_icons()

    def addFavPlugin(self, fav_plugin):
        plugin_manager = self.gui_management.plugin_manager

        plugin_manager.locatePlugins()

        candidates = plugin_manager.getPluginCandidates()
        all_pluginfo = {c[2].path: c[2] for c in candidates}
        loadable_pluginfo = {p.path: p for p in plugin_manager.getAllPlugins()}

        for plugin_info in all_pluginfo.values():
            if plugin_info.name == fav_plugin:

                if plugin_info.path in loadable_pluginfo.keys():
                    plugin_info = loadable_pluginfo[plugin_info.path]
                    plugin_info.loadable = True
                else:
                    plugin_info.loadable = False

                self.toolbarAddFavPlugin(plugin_info)

    def favPluginWasRemoved(self):
        self.gui_management.gui_api.do_save_xml_config_reloaded(
            pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True)

    def set_icons(self):
        # -------------------------------------
        # Create Icons for buttons
        # -------------------------------------
        load_icon = get32Icon('folder')
        save_icon = get32Icon('file_save_as')
        # -------------------------------------
        # Set Icons for buttons
        # -------------------------------------
        #self.loadButton.setIconSize(QSize(32, 32))
        #self.loadButton.setIcon(load_icon)

        #self.saveButton.setIconSize(QSize(32, 32))
        #self.saveButton.setIcon(save_icon)

        # -------------------------------------
        # Create Icons for actions
        # -------------------------------------
        load_icon = get16Icon('folder')
        save_icon = get16Icon('file_save_as')
        exit_icon = get16Icon('cancel')
        overview_icon = get16Icon('tree_list')
        create_icon = get16Icon('application_add')
        reload_icon = get16Icon('arrow_rotate_clockwise')
        help_icon = get16Icon('help')
        info_icon = get16Icon('information')
        refresh_icon = get16Icon('arrow_refresh')
        delete_icon = get16Icon('delete')
        view_icon = get16Icon('reviewing_pane')

        # -------------------------------------
        # Set Icons for actions
        # -------------------------------------
        self.actionLoad.setIcon(load_icon)
        self.actionSave.setIcon(save_icon)
        self.actionExit.setIcon(exit_icon)
        self.actionOverview.setIcon(overview_icon)
        self.actionCreate.setIcon(create_icon)
        self.actionReload_Plugin_DB.setIcon(reload_icon)
        self.actionReloadConfig.setIcon(reload_icon)
        self.actionPaPI_Wiki.setIcon(help_icon)
        self.actionPaPI_Doc.setIcon(help_icon)
        self.actionAbout.setIcon(info_icon)
        self.actionAbout_Qt.setIcon(info_icon)
        self.actionAbout_PySide.setIcon(info_icon)
        self.actionResetPaPI.setIcon(delete_icon)
        self.actionRunMode.setIcon(view_icon)

        # -------------------------------------
        # Set Icons visible in menu
        # -------------------------------------
        self.actionLoad.setIconVisibleInMenu(True)
        self.actionSave.setIconVisibleInMenu(True)
        self.actionExit.setIconVisibleInMenu(True)
        self.actionOverview.setIconVisibleInMenu(True)
        self.actionCreate.setIconVisibleInMenu(True)
        self.actionReload_Plugin_DB.setIconVisibleInMenu(True)
        self.actionReloadConfig.setIconVisibleInMenu(True)
        self.actionPaPI_Wiki.setIconVisibleInMenu(True)
        self.actionPaPI_Doc.setIconVisibleInMenu(True)
        self.actionAbout.setIconVisibleInMenu(True)
        self.actionAbout_Qt.setIconVisibleInMenu(True)
        self.actionAbout_PySide.setIconVisibleInMenu(True)
        self.actionResetPaPI.setIconVisibleInMenu(True)
        self.actionRunMode.setIconVisibleInMenu(True)

    def get_gui_config(self, saveUserSettings=False):

        actTab = {}
        actTab['Active'] = str(self.TabManager.get_currently_active_tab())

        tabs = {}
        tab_dict = self.TabManager.get_tabs_by_uname()
        for tab in tab_dict:
            tabOb = tab_dict[tab]
            tabs[tab] = {}
            tabs[tab]['Background'] = tabOb.background
            tabs[tab]['Position'] = str(
                self.TabManager.getTabPosition_by_name(tab))

        size = {}

        size['X'] = str(self.size().width())

        size['Y'] = str(self.size().height())

        cfg = {}
        cfg['ActiveTab'] = actTab
        cfg['Tabs'] = tabs
        cfg['Size'] = size

        # ----------------------
        # Set favourite plugins
        # ----------------------
        if saveUserSettings:
            favourites = {}
            actions = self.toolBar.actions()
            for i in range(len(actions)):
                action = actions[i]
                if isinstance(action, PaPIFavAction):
                    favourites[action.text()] = {}
                    favourites[action.text()]['position'] = str(i)

            cfg['Favourites'] = favourites

        return cfg

    def set_gui_config(self, cfg):
        #print(cfg)
        # #################
        # # Cfgs for Tabs #
        # #################
        # if 'tabs' in cfg:
        #     tabList = {}
        #     for tab in cfg['tabs']:
        #         # Tab Name
        #         name = tab
        #
        #         # Tab details
        #         tabDetails = cfg['tabs'][tab]
        #
        #         # check for background
        #         if 'background' in tabDetails:
        #             bg = tabDetails['background']
        #             if bg != 'default':
        #                 self.TabManager.set_background_for_tab_with_name(name,bg)
        #         else:
        #             bg = None
        #
        #         # check for position
        #         if 'position' in tabDetails:
        #             pos = int(tabDetails['position'])
        #         else:
        #             if len(list(tabList.keys())) > 1:
        #                 pos = max(list(tabList.keys()))+1
        #             else:
        #                 pos = 0
        #
        #         tabList[pos] = [name, bg]
        #
        #     # sort tabs acoriding to positions
        #     keys = list(tabList.keys())
        #     keys.sort()
        #     for position in keys:
        #         name = tabList[position][0]
        #         bg = tabList[position][1]
        #         tabOb = self.TabManager.add_tab(name)
        #         self.TabManager.set_background_for_tab_with_name(name,bg)
        #
        # if 'activeTab' in cfg:
        #     if 'value' in cfg['activeTab']['active']:
        #         self.TabManager.set_tab_active_by_index(int( cfg['activeTab']['active']['value'] ))
        #
        #################
        # windows size: #
        #################
        if 'Size' in cfg:
            w = int(cfg['Size']['X'])
            h = int(cfg['Size']['Y'])
            self.resize_gui_window(w, h)

        # ------------------------
        # Restore favourite icons
        # ------------------------
        if 'Favourites' in cfg:
            sorted_positions = {}

            for plugin in cfg['Favourites']:
                sorted_positions[int(
                    cfg['Favourites'][plugin]['position'])] = plugin

            for position in sorted(sorted_positions.keys()):
                plugin = sorted_positions[position]
                self.addFavPlugin(plugin)

        # -----------------------
        # Restore Tabs
        # -----------------------
        if 'Tabs' in cfg:
            for tabName in cfg['Tabs']:
                tab = cfg['Tabs'][tabName]
                self.TabManager.add_tab(tabName)
                if 'Background' in tab:
                    self.TabManager.set_background_for_tab_with_name(
                        tabName, tab['Background'])

    def triggered_reload_plugin_db(self):
        """
        This Callback function will reload the plugin list of the plugin manager

        :return:
        """
        self.gui_management.plugin_manager.collectPlugins()

    def run(self):
        """


        :return:
        """
        # create a timer and set interval for processing events with working loop

        #QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_event_processing.gui_working(self.closeEvent))
        self.workingTimer = QtCore.QTimer(self)
        self.workingTimer.timeout.connect(
            lambda: self.gui_management.gui_event_processing.gui_working(
                self.closeEvent, self.workingTimer))
        self.workingTimer.start(pc.GUI_WOKRING_INTERVAL)

    def triggered_show_create_plugin_menu(self):
        """


        :return:
        """
        self.create_plugin_menu = CreatePluginMenu(
            self.gui_management.gui_api, self.TabManager,
            self.gui_management.plugin_manager)

        self.create_plugin_menu.show()

    def triggered_show_overview_menu(self):
        """
        Used to show the overview menu.

        :return:
        """
        self.overview_menu = OverviewPluginMenu(
            self.gui_management.gui_api, self.gui_management.tab_manager)
        self.overview_menu.show()

    def triggered_show_toolbar(self):
        """
        Used to hide and unhide the toolbar
        :return:
        """

        self.toolBar.setHidden(not self.toolBar.isHidden())

        self.actionToolbar.setChecked(not self.toolBar.isHidden())

    def triggered_load(self):
        """
        Used to start the 'load config' dialog.

        :return:
        """
        fileNames = ''

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter(self.tr("PaPI-Cfg (*.xml)"))
        dialog.setDirectory(pc.CONFIG_DEFAULT_DIRECTORY)
        dialog.setWindowTitle("Load Configuration")

        if dialog.exec_():
            fileNames = dialog.selectedFiles()

        if len(fileNames):
            if fileNames[0] != '':
                self.last_config = fileNames[0]
                self.load_config(fileNames[0])

    def load_config(self, file_name):
        self.gui_management.gui_api.do_load_xml(file_name)

    def triggered_save(self):
        """
        Used to start the 'save config' dialog.

        :return:
        """
        fileNames = ''

        dialog = PaPIConfigSaveDialog(self, self.gui_management.gui_api)

        dialog.fill_with()

        if dialog.exec_():
            fileNames = dialog.selectedFiles()

        plugin_list, subscription_list = dialog.get_create_lists()

        if len(fileNames):

            if fileNames[0] != '':
                if "json" in dialog.selectedNameFilter():
                    self.gui_management.gui_api.do_save_json_config_reloaded(
                        fileNames[0],
                        plToSave=plugin_list,
                        sToSave=subscription_list)

                if "xml" in dialog.selectedNameFilter():
                    self.gui_management.gui_api.do_save_xml_config_reloaded(
                        fileNames[0],
                        plToSave=plugin_list,
                        sToSave=subscription_list)

    def closeEvent(self, *args, **kwargs):
        """
        Handle close event.
        Saves current session as 'papi/last_active_papi.xml'
        Closes all opened windows.

        :param args:
        :param kwargs:
        :return:
        """
        try:
            self.gui_management.gui_api.do_save_xml_config(
                'papi/last_active_papi.xml')
        except Exception as E:
            tb = traceback.format_exc()

        self.gui_management.gui_api.do_close_program()
        if self.create_plugin_menu is not None:
            self.create_plugin_menu.close()

        if self.overview_menu is not None:
            self.overview_menu.close()

        self.close()

    def add_dplugin(self, dplugin):
        """
        Callback function called by 'DPlugin added signal'
        Used to add a DPlugin SubWindow on the GUI if possible.

        :param dplugin:
        :return:
        """
        if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER:

            # sub_window_ori = dplugin.plugin.get_sub_window()
            #
            # dplugin.plugin.set_window_for_internal_usage(PaPIMDISubWindow())
            # dplugin.plugin.pl_set_widget_for_internal_usage(sub_window_ori.widget())

            sub_window = dplugin.plugin._get_sub_window()

            config = dplugin.startup_config
            tab_name = config['tab']['value']
            if tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]
            else:
                self.log.printText(
                    1, 'add dplugin: no tab with tab_id of dplugin')
                area = self.TabManager.add_tab(tab_name)

            area.addSubWindow(sub_window)

            isMaximized = config['maximized']['value'] == '1'

            size_re = re.compile(r'([0-9]+)')

            pos = config['position']['value']
            window_pos = size_re.findall(pos)
            sub_window.move(int(window_pos[0]), int(window_pos[1]))

            if not isMaximized:
                sub_window.show()
            else:
                sub_window.showMaximized()

            # see http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum

            sub_window.setWindowFlags(Qt.CustomizeWindowHint
                                      | Qt.WindowMinMaxButtonsHint
                                      | Qt.WindowTitleHint)

        if self.overview_menu is not None:
            self.overview_menu.refresh_action(dplugin)

    def remove_dplugin(self, dplugin):
        """
        Callback function called by 'DPlugin removed signal'
        Used to removed a DPlugin SubWindow from the GUI if possible.

        :param dplugin:
        :return:
        """
        if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER:
            config = dplugin.plugin.pl_get_current_config()
            tab_name = config['tab']['value']
            if tab_name in self.TabManager.get_tabs_by_uname():
                tabOb = self.TabManager.get_tabs_by_uname()[tab_name]
                tabOb.removeSubWindow(dplugin.plugin._get_sub_window())
                if tabOb.closeIfempty is True:
                    if len(tabOb.subWindowList()) == 0:
                        if isinstance(tabOb, TabObject):
                            self.TabManager.closeTab_by_name(tabOb.name)
                        else:
                            self.TabManager.remove_window(tabOb)

    def changed_dgui(self):
        if self.overview_menu is not None:
            self.overview_menu.refresh_action()

    def plugin_died(self, dplugin, e, msg):
        dplugin.state = pc.PLUGIN_STATE_STOPPED

        self.gui_management.gui_api.do_stopReset_plugin_uname(dplugin.uname)

        errMsg = QtGui.QMessageBox(self)
        errMsg.setFixedWidth(650)

        # layout = errMsg.layout();
        # spacer = QtGui.QSpacerItem(1000, 0, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
        # layout.addItem(spacer, layout.rowCount(), 0,1, layout.columnCount())

        errMsg.setIcon(QtGui.QMessageBox.Critical)
        errMsg.setSizeGripEnabled(True)
        errMsg.setWindowTitle("Plugin: " + dplugin.uname + " // " + str(e))
        errMsg.setText("Error in plugin" + dplugin.uname + " // " + str(e))
        errMsg.setDetailedText(str(msg))
        errMsg.setWindowModality(Qt.NonModal)
        errMsg.show()

    def error_occured(self, title, msg, detailed_msg):

        errMsg = QtGui.QMessageBox(self)
        errMsg.setFixedWidth(650)

        errMsg.setWindowTitle(title)
        errMsg.setText(str(msg))
        errMsg.setDetailedText(str(detailed_msg))
        errMsg.setWindowModality(Qt.NonModal)
        errMsg.show()

    def toggle_run_mode(self):
        if self.in_run_mode is False:
            # hide toolbar
            self.toolBar.setHidden(True)
            self.actionToolbar.setChecked(False)
            # disable context menu of tabmanger
            self.TabManager.disableContextMenus()

            # lock subwindows in tabs
            for tabName in self.TabManager.tab_dict_uname:
                tabObject = self.TabManager.tab_dict_uname[tabName]

                for subWindow in tabObject.subWindowList():
                    subWindow.disableInteraction()
            self.in_run_mode = True
        else:
            # show toolbar
            self.toolBar.setHidden(False)
            self.actionToolbar.setChecked(True)
            # disable context menu of tabmanger
            self.TabManager.enableContextMenus()

            # unlock subwindows in tabs
            for tabName in self.TabManager.tab_dict_uname:
                tabObject = self.TabManager.tab_dict_uname[tabName]

                for subWindow in tabObject.subWindowList():
                    subWindow.enableInteraction()
            self.in_run_mode = False

    def toogle_lock(self):
        raise Exception("PLEASE REPORT THIS BUG!!")
        if self.in_run_mode:
            for tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]

                windowsList = area.subWindowList()

                for window in windowsList:

                    #window.setAttribute(Qt.WA_NoBackground)

                    #window.setAttribute(Qt.WA_NoSystemBackground)
                    #window.setAttribute(Qt.WA_TranslucentBackground)
                    #window.set_movable(False)
                    window.setMouseTracking(False)
                    window.setWindowFlags(~Qt.WindowMinMaxButtonsHint
                                          & (Qt.CustomizeWindowHint
                                             | Qt.WindowTitleHint))

        if not self.in_run_mode:
            for tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]

                windowsList = area.subWindowList()

                for window in windowsList:
                    #window.set_movable(True)
                    window.setMouseTracking(True)
                    window.setWindowFlags(Qt.CustomizeWindowHint
                                          | Qt.WindowMinMaxButtonsHint
                                          | Qt.WindowTitleHint)

    def keyPressEvent(self, event):
        if event.key() not in self.keysActiveList:
            self.keysActiveList.append(event.key())

        if QtCore.Qt.Key_Escape in self.keysActiveList:
            if self.in_run_mode:
                self.toggle_run_mode()

        if QtCore.Qt.Key_D in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.gui_management.tab_manager.select_next_tab()
            self.keysActiveList.remove(QtCore.Qt.Key_D)
            #self.keysActiveList.remove(QtCore.Qt.Key_Control)

        if QtCore.Qt.Key_A in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.gui_management.tab_manager.select_prev_tab()
            self.keysActiveList.remove(QtCore.Qt.Key_A)
            #self.keysActiveList.remove(QtCore.Qt.Key_Control)

    def keyReleaseEvent(self, event):
        if event.key() in self.keysActiveList:
            self.keysActiveList.remove(event.key())

    def resize_gui_window(self, w, h):
        self.setGeometry(self.geometry().x(), self.geometry().y(), w, h)

    def triggered_reload_config(self):
        """
        This function is used to reset PaPI and to reload the last loaded configuration file.
        :return:
        """
        if self.last_config is not None:
            self.triggered_reset_papi()
            QtCore.QTimer.singleShot(
                pc.GUI_WAIT_TILL_RELOAD, lambda: self.gui_management.gui_api.
                do_load_xml(self.last_config))

    def triggered_reset_papi(self):
        """
        This function is called to reset PaPI. That means all subscriptions were canceled and all plugins were removed.
        :return:
        """
        h = pc.GUI_DEFAULT_HEIGHT
        w = pc.GUI_DEFAULT_WIDTH
        self.setGeometry(self.geometry().x(), self.geometry().y(), w, h)

        self.TabManager.set_all_tabs_to_close_when_empty(True)
        self.TabManager.close_all_empty_tabs()

        self.gui_management.gui_api.do_reset_papi()

    def triggered_papi_wiki(self):
        QDesktopServices.openUrl(QUrl(pc.PAPI_WIKI_URL, QUrl.TolerantMode))

    def triggered_papi_doc(self):
        QDesktopServices.openUrl(QUrl(pc.PAPI_DOC_URL, QUrl.TolerantMode))

    def triggered_papi_about(self):
        QMessageBox.about(self, pc.PAPI_ABOUT_TITLE, pc.PAPI_ABOUT_TEXT)

    def triggered_papi_about_qt(self):
        QMessageBox.aboutQt(self)

    def toolbarAddFavPlugin(self, plugin_info):

        l = len(plugin_info.name)
        path = plugin_info.path[:-l]
        path += 'box.png'
        px = QPixmap(path)

        icon = QIcon(px)

        for action in self.toolBar.actions():
            if action.text() == plugin_info.name:
                return

        plugin_action = PaPIFavAction(icon, plugin_info.name, self)
        plugin_action.triggered.connect(
            lambda ignore, p1=plugin_info: self.show_create_plugin_dialog(p1))

        self.toolBar.addAction(plugin_action)

        self.gui_management.gui_api.do_save_xml_config_reloaded(
            pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True)

    def show_create_plugin_dialog(self, plugin_info):
        if plugin_info is not None:
            if plugin_info.loadable:
                self.plugin_create_dialog.set_plugin(plugin_info)
                self.plugin_create_dialog.show()

    def dropEvent(self, event: QDropEvent):
        source = event.source()
예제 #15
0
파일: gui_api.py 프로젝트: TUB-Control/PaPI
class Gui_api(QtCore.QObject):
    error_occured = QtCore.pyqtSignal(str, str, str)

    def __init__(self, gui_data, core_queue, gui_id, get_gui_config_function = None, set_gui_config_function = None, TabManager = None, plugin_manager = None):
        super(Gui_api, self).__init__()
        self.gui_id = gui_id
        self.gui_data = gui_data
        self.core_queue = core_queue
        self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL, GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.get_gui_config_function = get_gui_config_function
        self.set_gui_config_function = set_gui_config_function
        self.tabManager = TabManager
        self.pluginManager = plugin_manager

    def do_create_plugin(self, plugin_identifier, uname, config={}, autostart=True):
        """
        Something like a callback function for gui triggered events e.a. when a user wants to create a new plugin.

        :param plugin_identifier: plugin to create
        :type plugin_identifier: basestring
        :param uname: uniqe name to set for new plugin
        :type uname: basestring
        :param config: additional configuration for creation
        :type config:
        :return:
        """
        # create new optional Data for event
        opt = DOptionalData()
        # set important information
        # plugin to create
        opt.plugin_identifier = plugin_identifier
        # uname to create plugin with
        opt.plugin_uname = uname
        # additional config
        opt.plugin_config = config
        opt.autostart = autostart

        # check if plugin with uname already exists
        allPlugins = self.gui_data.get_all_plugins()
        for pluginID in allPlugins:
            plugin = allPlugins[pluginID]
            if plugin.uname == uname:
                return False

        # create event object and sent it to core
        event = Event.instruction.CreatePlugin(self.gui_id, 0, opt)
        self.core_queue.put(event)

    def do_delete_plugin(self, id):
        """
        Delete plugin with given id.

        :param id: Plugin id to delete
        :type id: int
        :return:
        """
        event = Event.instruction.StopPlugin(self.gui_id, id, None)

        self.core_queue.put(event)

    def do_delete_plugin_uname(self, uname):
        """
        Delete plugin with given uname.

        :param uname: Plugin uname to delete
        :type uname: basestring
        :return:
        """
        event =Event.instruction.StopPluginByUname(self.gui_id, uname)
        self.core_queue.put(event)

    def do_edit_plugin(self, pl_id, eObject, changeRequest):
        """
        Edit plugin with given plugin id. Specify attribute of plugin by eObject which should
        be edited e.g. DBlock.
        Specify action by changeRequest e.g. {'edit' : DSignal}.
        Currently only possible to change a DSignal for a given dplugin and dblock.

        :param pl_id: Plugin id to delete
        :type pl_id: int
        :return:
        """
        event = Event.data.EditDPlugin(self.gui_id, pl_id, eObject, changeRequest)

        self.core_queue.put(event)

    def do_edit_plugin_uname(self, uname, eObject, changeRequest):
        """
        Edit plugin with given plugin uname. Specify attribute of plugin by eObject which should
        be edited e.g. DBlock.
        Specify action by changeRequest e.g. {'edit' : DSignal}.
        Currently only possible to change a DSignal for a given dplugin and dblock.

        :param uname:
        :param eObject:
        :param changeRequest:
        :return:
        """
        event = Event.data.EditDPluginByUname(self.gui_id, uname, eObject, changeRequest)

        self.core_queue.put(event)

    def do_stopReset_pluign(self, id):
        """
        Stop and reset plugin with given id without deleting it.

        :param id: Plugin id to stopReset
        :type id: int
        :return:
        """
        event = Event.instruction.StopPlugin(self.gui_id, id, None, delete=False)
        self.core_queue.put(event)

    def do_stopReset_plugin_uname(self, uname):
        """
        Stop and reset plugin with given uname without deleting it.

        :param uname: Plugin uname to stop
        :type uname: basestring
        :return:
        """
        pl_id = self.do_get_plugin_id_from_uname(uname)

        if pl_id is not None:
            self.do_stopReset_pluign(pl_id)
        else:
            self.log.printText(1, " Do stopReset plugin with uname " + uname + ' failed')
            return ERROR.NOT_EXISTING

    def do_start_plugin(self, id):
        """
        Start plugin with given id.

        :param id: Plugin id to start
        :type id: int
        :return:
        """
        event = Event.instruction.StartPlugin(self.gui_id, id, None)
        self.core_queue.put(event)

    def do_start_plugin_uname(self, uname):
        """
        Start plugin with given uname.

        :param uname: Plugin uname to start
        :type uname: basestring
        :return:
        """
        pl_id = self.do_get_plugin_id_from_uname(uname)

        if pl_id is not None:
            self.do_start_plugin(pl_id)
        else:
            self.log.printText(1, " Do start_plugin with uname " + uname + ' failed')
            return ERROR.NOT_EXISTING

    def do_subscribe(self, subscriber_id, source_id, block_name, signals=None, sub_alias=None):
        """
        Something like a callback function for gui triggered events.
        In this case, user wants one plugin to subscribe another

        :param subscriber_id: Plugin id of plugin which should get the data
        :type subscriber_id: int
        :param source_id: plugin uname of plugin that should send the data
        :type source_id: int
        :param block_name: name of block to subscribe
        :type block_name: basestring
        :return:
        """
        # build optional data object and add id and block name to it
        opt = DOptionalData()
        opt.source_ID = source_id
        opt.block_name = block_name
        opt.signals = signals
        opt.subscription_alias = sub_alias
        # send event with subscriber id as the origin to CORE
        event = Event.instruction.Subscribe(subscriber_id, 0, opt)
        self.core_queue.put(event)

    def do_subscribe_uname(self, subscriber_uname, source_uname, block_name, signals=None, sub_alias=None):
        """
        Something like a callback function for gui triggered events.
        In this case, user wants one plugin to subscribe another

        :param subscriber_uname:  Plugin uname of plugin which should get the data
        :type subscriber_uname: basestring
        :param source_uname: plugin uname of plugin that should send the data
        :type source_uname: basestring
        :param block_name: name of block to subscribe
        :type block_name: basestring
        :return:
        """
        event = Event.instruction.SubscribeByUname(self.gui_id, 0, subscriber_uname, source_uname, block_name,
                                                   signals=signals, sub_alias= sub_alias)
        self.core_queue.put(event)

    def do_unsubscribe(self, subscriber_id, source_id, block_name, signal_index=None):
        """
        Something like a callback function for gui triggered events.
        User wants one plugin to do not get any more data from another plugin

        :param subscriber_id: plugin id which wants to lose a data source
        :type subscriber_id: int
        :param source_id: plugin id of data source
        :type source_id: int
        :param block_name: name of block to unsubscribe
        :type block_name: basestring
        :return:
        """
        # create optional data with source id and block_name
        opt = DOptionalData()
        opt.source_ID = source_id
        opt.block_name = block_name
        opt.signals = signal_index
        # sent event to Core with origin subscriber_id
        event = Event.instruction.Unsubscribe(subscriber_id, 0, opt)
        self.core_queue.put(event)

    def do_unsubscribe_uname(self, subscriber_uname, source_uname, block_name, signal_index=None):
        """
        Something like a callback function for gui triggered events.
        User wants one plugin to do not get any more data from another plugin

        :param subscriber_uname: plugin uname which wants to lose a data source
        :type subscriber_uname: basestring
        :param source_uname: plugin uname of data source
        :type source_uname: basestring
        :param block_name: name of block to unsubscribe
        :type block_name: basestring
        :return:
        """
        subscriber_id = self.do_get_plugin_id_from_uname(subscriber_uname)
        if subscriber_id is None:
            # plugin with uname does not exist
            self.log.printText(1, 'do_unsubscribe, sub uname worng')
            return -1

        source_id = self.do_get_plugin_id_from_uname(source_uname)
        if source_id is None:
            # plugin with uname does not exist
            self.log.printText(1, 'do_unsubscribe, target uname wrong')
            return -1

        # call do_subscribe with ids to subscribe
        self.do_unsubscribe(subscriber_id, source_id, block_name, signal_index)

    def do_set_parameter(self, plugin_id, parameter_name, value, only_db_update = False):
        """
        Something like a callback function for gui triggered events.
        User wants to change a parameter of a plugin

        :param plugin_id: id of plugin which owns the parameter
        :type plugin_id: int
        :param parameter_name: name of parameter to change
        :type parameter_name: basestring
        :param value: new parameter value to set
        :type value:
        :param only_db_update: do_set_parameter of the target plugin will not be called. Updates only the internal database.
        :type boolean:
        """
        # get plugin from DGUI
        dplug = self.gui_data.get_dplugin_by_id(plugin_id)
        # check for existance
        if dplug is not None:
            # it exists
            # get its parameter list
            parameters = dplug.get_parameters()
            # check if there are any parameter
            if parameters is not None:
                # there is a parameter list
                # get the parameter with parameter_name
                if parameter_name in parameters:
                    p = parameters[parameter_name]
                    # check if this specific parameter exists
                    if p is not None:
                        # parameter with name parameter_name exists

                        # build an event to send this information to Core
                        opt = DOptionalData()
                        opt.data = value
                        opt.is_parameter = True
                        opt.parameter_alias = parameter_name
                        opt.block_name = None
                        if only_db_update:
                            e = Event.instruction.UpdateParameter(self.gui_id, dplug.id, opt)
                        else:
                            e = Event.instruction.SetParameter(self.gui_id, dplug.id, opt)
                        self.core_queue.put(e)

    def do_set_parameter_uname(self, plugin_uname, parameter_name, value):
        """
        Something like a callback function for gui triggered events.
        User wants to change a parameter of a plugin
        :param plugin_uname: name of plugin which owns the parameter

        :type plugin_uname: basestring
        :param parameter_name: name of parameter to change
        :type parameter_name: basestring
        :param value: new parameter value to set
        :type value:
        """
        # id = self.do_get_plugin_id_from_uname(plugin_uname)
        # if id is not None:
        #     self.do_set_parameter(id, parameter_name, value)
        #     print(parameter_name, value)
        opt = DOptionalData()
        opt.data = value
        opt.is_parameter = True
        opt.parameter_alias = parameter_name
        opt.block_name = None
        e = Event.instruction.SetParameterByUname(self.gui_id,plugin_uname, opt)
        self.core_queue.put(e)

    def do_pause_plugin_by_id(self, plugin_id):
        """
        Something like a callback function for gui triggered events.
        User wants to pause a plugin, so this method will send an event to core.

        :param plugin_id: id of plugin to pause
        :type plugin_id: int
        """
        if self.gui_data.get_dplugin_by_id(plugin_id) is not None:
            opt = DOptionalData()
            event = Event.instruction.PausePlugin(self.gui_id, plugin_id, opt)
            self.core_queue.put(event)
            return 1
        else:
            return -1

    def do_pause_plugin_by_uname(self, plugin_uname):
        """
        Something like a callback function for gui triggered events.
        User wants to pause a plugin, so this method will send an event to core.

        :param plugin_uname: uname of plugin to pause
        :type plugin_uname: basestring
        """
        plugin_id = self.do_get_plugin_id_from_uname(plugin_uname)
        if plugin_id is not None:
            return self.do_pause_plugin_by_id(plugin_id)
        else:
            # plugin with uname does not exist
            self.log.printText(1, 'do_pause, plugin uname worng')
            return -1

    def do_resume_plugin_by_id(self, plugin_id):
        """
        Something like a callback function for gui triggered events.
        User wants to pause a plugin, so this method will send an event to core.

        :param plugin_id: id of plugin to pause
        :type plugin_id: int
        """
        if self.gui_data.get_dplugin_by_id(plugin_id) is not None:
            opt = DOptionalData()
            event = Event.instruction.ResumePlugin(self.gui_id, plugin_id, opt)
            self.core_queue.put(event)
            return 1
        else:
            return -1

    def do_resume_plugin_by_uname(self, plugin_uname):
        """
        Something like a callback function for gui triggered events.
        User wants to resume a plugin, so this method will send an event to core.

        :param plugin_uname: uname of plugin to resume
        :type plugin_uname: basestring
        """
        plugin_id = self.do_get_plugin_id_from_uname(plugin_uname)
        if plugin_id is not None:
            return self.do_resume_plugin_by_id(plugin_id)
        else:
            # plugin with uname does not exist
            self.log.printText(1, 'do_resume, plugin uname worng')
            return -1

    def do_get_plugin_id_from_uname(self, uname):
        """
        Returns the plugin id of the plugin with unique name uname

        :param uname: uname of plugin
        :type uname: basestring
        :return: None: plugin with uname does not exist, id: id of plugin
        """
        dplugin = self.gui_data.get_dplugin_by_uname(uname)
        # check for existance
        if dplugin is not None:
            # it does exist, so get its id
            return dplugin.id
        else:
            return None

    def do_close_program(self):
        """
        Tell core to close papi. Core will respond and will close all open plugins.
        GUI will close all VIP Plugins due to calling their quit function
        """

        plugins = self.gui_data.get_all_plugins()
        for dplugin_id in plugins:
            dplugin = plugins[dplugin_id]
            if dplugin.type == PLUGIN_VIP_IDENTIFIER:
                try:
                    dplugin.plugin.cb_quit()
                except Exception as E:
                    tb = traceback.format_exc()
                    self.plugin_died.emit(dplugin, E, tb)


        opt = DOptionalData()
        opt.reason = 'User clicked close Button'
        event = Event.instruction.CloseProgram(self.gui_id, 0, opt)
        self.core_queue.put(event)

    def do_set_tab_active_by_name(self, tabName):
        self.tabManager.set_tab_active_by_name(tabName)

    def do_open_new_tabs_with_names_in_order(self, tabNames = None):
        for name in tabNames:
            self.tabManager.add_tab(name)

    def do_load_xml(self, path):
        if path is None or not os.path.isfile(path):
            return False

        tree = ET.parse(path)
        root = tree.getroot()

        if root.tag == 'PaPI':
            self.do_load_xml_reloaded(root)
        else:
            self.do_load_xml_v1(root)

    def do_load_xml_reloaded(self,root):
        """
        Function to load a xml config to papi and apply the configuration.

        :param path: path to xml file to load.
        :type path: basestring
        :return:
        """

        gui_config = {}
        plugins_to_start = []
        parameters_to_change = []
        signals_to_change = []
        subs_to_make = []

        try:
            for root_element in root:
                ##########################
                # Read gui configuration #
                ##########################
                if root_element.tag == 'Configuration':
                    for property in root_element:
                        gui_config[property.tag] = {}
                        for attr in property:
                            if len(attr) == 0:
                                gui_config[property.tag][attr.tag] = attr.text
                            else:
                                gui_config[property.tag][attr.tag] = {}
                                for val in attr:
                                   gui_config[property.tag][attr.tag][val.tag] = val.text



                if root_element.tag == 'Plugins':
                    #############################
                    # Read plugin configuration #
                    #############################
                    for plugin_xml in root_element:
                        plObj = {}
                        plObj['uname'] = self.change_uname_to_uniqe(plugin_xml.attrib['uname'])
                        plObj['identifier'] = plugin_xml.find('Identifier').text
                        config_xml = plugin_xml.find('StartConfig')
                        config_hash = {}
                        for parameter_xml in config_xml.findall('Parameter'):
                            para_name = parameter_xml.attrib['Name']
                            config_hash[para_name] = {}
                            for detail_xml in parameter_xml:
                                detail_name = detail_xml.tag
                                config_hash[para_name][detail_name] = detail_xml.text

                        plObj['cfg'] = config_hash

                        plugins_to_start.append(plObj)

                        # --------------------------------
                        # Load PreviousParameters
                        # --------------------------------

                        prev_parameters_xml = plugin_xml.find('PreviousParameters')
                        if prev_parameters_xml is not None:
                            for prev_parameter_xml in prev_parameters_xml.findall('Parameter'):
                                para_name = prev_parameter_xml.attrib['Name']
                                para_value = prev_parameter_xml.text
                                # pl_uname_new = self.change_uname_to_uniqe(pl_uname)
                                # TODO validate NO FLOAT in parameter
                                parameters_to_change.append([plObj['uname'], para_name, para_value])

                        # --------------------------------
                        # Load DBlocks due to signals name
                        # --------------------------------

                        dblocks_xml = plugin_xml.find('DBlocks')
                        if dblocks_xml is not None:
                            for dblock_xml in dblocks_xml:
                                dblock_name = dblock_xml.attrib['Name']
                                dsignals_xml = dblock_xml.findall('DSignal')
                                for dsignal_xml in dsignals_xml:
                                    dsignal_uname = dsignal_xml.attrib['uname']
                                    dsignal_dname = dsignal_xml.find('dname').text
                                    signals_to_change.append([plObj['uname'], dblock_name, dsignal_uname, dsignal_dname])

                if root_element.tag == 'Subscriptions':
                    for sub_xml in root_element:

                        #TODO: Ask stefan: Why this line?
                        #dest  = self.change_uname_to_uniqe(sub_xml.find('Destination').text)

                        dest  = sub_xml.find('Destination').text
                        for source in sub_xml:
                            if source.tag == 'Source':
                                sourceName =  source.attrib['uname'] #self.change_uname_to_uniqe(source.attrib['uname'])
                                for block_xml in source:
                                    blockName = block_xml.attrib['name']
                                    alias = block_xml.find('Alias').text
                                    signals_xml = block_xml.find('Signals')

                                    signals = []
                                    for sig_xml in signals_xml:
                                        signals.append(sig_xml.text)

                                    subs_to_make.append({'dest':dest, 'source':sourceName, 'block':blockName, 'alias':alias, 'signals':signals})

            self.set_gui_config_function(gui_config)

        except Exception as E:
            tb = traceback.format_exc()
            self.error_occured.emit("Error: Config Loader", "Not loadable", tb)


        # -----------------------------------------------
        # Check: Are there unloadable plugins?
        # -----------------------------------------------

        unloadable_plugins = []
        for pl in plugins_to_start:
            plugin_info = self.pluginManager.getPluginByName(pl['identifier'])

            if plugin_info is None:
                if pl['identifier'] not in unloadable_plugins:
                    unloadable_plugins.append(pl['identifier'])



        if not len(unloadable_plugins):
            for pl in plugins_to_start:
                self.do_create_plugin(pl['identifier'], pl['uname'], pl['cfg'])


            self.config_loader_subs_reloaded(plugins_to_start, subs_to_make, parameters_to_change, signals_to_change)
        else:
            self.error_occured.emit("Error: Loading Plugins", "Can't use: " + str(unloadable_plugins) +
                                    "\nConfiguration will not be used.", None)


    def config_loader_subs_reloaded(self, pl_to_start, subs_to_make, parameters_to_change, signals_to_change):
        """
        Function for callback when timer finished to apply
            subscriptions and parameter changed of config.

        :param pl_to_start: list of plugins to start
        :type pl_to_start: list
        :param subs_to_make:  list of subscriptions to make
        :type subs_to_make: list
        :param parameters_to_change: parameter changes to apply
        :type parameters_to_change: list
        :param signals_to_change: signal name changes to apply
        :type signals_to_change: list
        :return:
        """

        for sub in subs_to_make:
            self.do_subscribe_uname(sub['dest'], sub['source'], sub['block'], sub['signals'], sub['alias'])

        for para in parameters_to_change:
            self.do_set_parameter_uname(para[0], para[1], para[2])

        for sig in signals_to_change:
            plugin_uname = sig[0]
            dblock_name = sig[1]
            dsignal_uname = sig[2]
            dsignal_dname = sig[3]

            self.do_edit_plugin_uname(plugin_uname, DBlock(dblock_name),{'edit': DSignal(dsignal_uname, dsignal_dname)})


    def do_load_xml_v1(self, root):
        """
        Function to load a xml config to papi and apply the configuration.

        :param path: path to xml file to load.
        :type path: basestring
        :return:
        """

        plugins_to_start = []
        subs_to_make = []
        parameters_to_change = []
        signals_to_change = []

        try:
            for plugin_xml in root:
                ##########################
                # Read gui configuration #
                ##########################
                if plugin_xml.tag == 'guiConfig':
                    cfg = {}
                    for property in plugin_xml:
                        cfg[property.tag] =  {}
                        for attr in property:
                            cfg[property.tag][attr.tag] = {}
                            for value in attr:
                                cfg[property.tag][attr.tag][value.tag] = value.text

                    self.set_gui_config_function(cfg)

                #############################
                # Read plugin configuration #
                #############################
                if plugin_xml.tag == 'Plugin':
                    pl_uname = plugin_xml.attrib['uname']
                    identifier = plugin_xml.find('Identifier').text
                    config_xml = plugin_xml.find('StartConfig')
                    config_hash = {}
                    for parameter_xml in config_xml.findall('Parameter'):
                        para_name = parameter_xml.attrib['Name']
                        config_hash[para_name] = {}
                        for detail_xml in parameter_xml:
                            detail_name = detail_xml.tag
                            config_hash[para_name][detail_name] = detail_xml.text

                    pl_uname_new = self.change_uname_to_uniqe(pl_uname)

                    plugins_to_start.append([identifier, pl_uname_new, config_hash])

                    # --------------------------------
                    # Load Subscriptions
                    # --------------------------------

                    subs_xml = plugin_xml.find('Subscriptions')
                    if subs_xml is not None:
                        for sub_xml in subs_xml.findall('Subscription'):
                            data_source = sub_xml.find('data_source').text
                            for block_xml in sub_xml.findall('block'):
                                block_name = block_xml.attrib['Name']
                                signals = []
                                for sig_xml in block_xml.findall('Signal'):
                                    signals.append(str(sig_xml.text))
                                alias_xml = block_xml.find('alias')
                                alias = alias_xml.text
                                pl_uname_new = self.change_uname_to_uniqe(pl_uname)
                                data_source_new = data_source #self.change_uname_to_uniqe(data_source)
                                subs_to_make.append([pl_uname_new, data_source_new, block_name, signals, alias])

                    # --------------------------------
                    # Load PreviousParameters
                    # --------------------------------

                    prev_parameters_xml = plugin_xml.find('PreviousParameters')
                    if prev_parameters_xml is not None:
                        for prev_parameter_xml in prev_parameters_xml.findall('Parameter'):
                            para_name = prev_parameter_xml.attrib['Name']
                            para_value = prev_parameter_xml.text
                            pl_uname_new = self.change_uname_to_uniqe(pl_uname)
                            # TODO validate NO FLOAT in parameter
                            parameters_to_change.append([pl_uname_new, para_name, para_value])

                    # --------------------------------
                    # Load DBlocks due to signals name
                    # --------------------------------

                    dblocks_xml = plugin_xml.find('DBlocks')
                    if dblocks_xml is not None:
                        for dblock_xml in dblocks_xml:
                            dblock_name = dblock_xml.attrib['Name']
                            dsignals_xml = dblock_xml.findall('DSignal')
                            for dsignal_xml in dsignals_xml:
                                dsignal_uname = dsignal_xml.attrib['uname']
                                dsignal_dname = dsignal_xml.find('dname').text
                                signals_to_change.append([pl_uname, dblock_name, dsignal_uname, dsignal_dname])
        except Exception as E:
            tb = traceback.format_exc()
            self.error_occured.emit("Error: Config Loader", "Not loadable", tb)


        # -----------------------------------------------
        # Check: Are there unloadable plugins?
        # -----------------------------------------------

        unloadable_plugins = []
        for pl in plugins_to_start:
            plugin_info = self.pluginManager.getPluginByName(pl[0])

            if plugin_info is None:
                if pl[0] not in unloadable_plugins:
                    unloadable_plugins.append(pl[0])



        if not len(unloadable_plugins):
            for pl in plugins_to_start:
                # 0: ident, 1: uname, 2: config

                self.do_create_plugin(pl[0], pl[1], pl[2])

            # QtCore.QTimer.singleShot(CONFIG_LOADER_SUBSCRIBE_DELAY, \
            #                         lambda: self.config_loader_subs(plugins_to_start, subs_to_make, \
            #                                                         parameters_to_change, signals_to_change))
            self.config_loader_subs(plugins_to_start, subs_to_make, parameters_to_change, signals_to_change)
        else:
            self.error_occured.emit("Error: Loading Plugins", "Can't use: " + str(unloadable_plugins) +
                                    "\nConfiguration will not be used.", None)

    def change_uname_to_uniqe(self, uname):
        """
        Function will search for unames and add an indentifier to it to make it unique in case of existence

        :param uname: uname to make unique
        :type uname: basestring
        :return: uname
        """
        i = 1
        while self.gui_data.get_dplugin_by_uname(uname) is not None:
            i = i + 1
            if i == 2:
                uname = uname + 'X' + str(i)
            else:
                uname = uname[:-1] + str(i)
        return uname

    def config_loader_subs(self, pl_to_start, subs_to_make, parameters_to_change, signals_to_change):
        """
        Function for callback when timer finished to apply
            subscriptions and parameter changed of config.

        :param pl_to_start: list of plugins to start
        :type pl_to_start: list
        :param subs_to_make:  list of subscriptions to make
        :type subs_to_make: list
        :param parameters_to_change: parameter changes to apply
        :type parameters_to_change: list
        :param signals_to_change: signal name changes to apply
        :type signals_to_change: list
        :return:
        """

        for sub in subs_to_make:
            self.do_subscribe_uname(sub[0], sub[1], sub[2], sub[3], sub[4])

        for para in parameters_to_change:
            self.do_set_parameter_uname(para[0], para[1], para[2])

        for sig in signals_to_change:
            plugin_uname = sig[0]
            dblock_name = sig[1]
            dsignal_uname = sig[2]
            dsignal_dname = sig[3]

            self.do_edit_plugin_uname(plugin_uname, DBlock(dblock_name),
                                      {'edit': DSignal(dsignal_uname, dsignal_dname)})

    def do_save_xml_config_reloaded(self,path, plToSave=[], sToSave=[], saveUserSettings=False):
        """

        :param path:
        :param plToSave:
        :param sToSave:
        :return:
        """

        subscriptionsToSave =  {}
        # check for xml extension in path, add .xml if missing
        if path[-4:] != '.xml':
            path += '.xml'

        try:
            root = ET.Element(CONFIG_ROOT_ELEMENT_NAME_RELOADED)
            root.set('Date', datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S'))
            root.set('PaPI_version', CORE_PAPI_VERSION)

            ##########################
            # Save gui configuration #
            ##########################
            gui_cfg = self.get_gui_config_function(save_user_settings=saveUserSettings)
            gui_cfg_xml = ET.SubElement(root, 'Configuration')

            for cfg_item in gui_cfg:
                item_xml = ET.SubElement(gui_cfg_xml,cfg_item)
                item = gui_cfg[cfg_item]
                for attr_name in item:
                    attr_xml = ET.SubElement(item_xml, attr_name)
                    values = item[attr_name]

                    # check if there is another dict level to explore
                    # if true: exlplore the dict
                    # if false: save the value of values in the parent xml node
                    if isinstance(values,dict):
                        for val in values:
                            value_xml = ET.SubElement(attr_xml, val)
                            value_xml.text = values[val]
                    else:
                        attr_xml.text = values

            # ---------------------------------------
            # save information of plugins
            # for the next start
            # ---------------------------------------
            plugins_xml = ET.SubElement(root,'Plugins')

            plugins = self.gui_data.get_all_plugins()
            for dplugin_id in plugins:
                dplugin = plugins[dplugin_id]

                # check if this plugin should be saved to XML
                if dplugin.uname in plToSave:
                    if dplugin.type == PLUGIN_VIP_IDENTIFIER:
                        dplugin.startup_config = dplugin.plugin.pl_get_current_config()

                    pl_xml = ET.SubElement(plugins_xml, 'Plugin')
                    pl_xml.set('uname', dplugin.uname)

                    identifier_xml = ET.SubElement(pl_xml, 'Identifier')
                    identifier_xml.text = dplugin.plugin_identifier

                    # ---------------------------------------
                    # Save all current config as startup config
                    # for the next start
                    # ---------------------------------------

                    cfg_xml = ET.SubElement(pl_xml, 'StartConfig')
                    for parameter in dplugin.startup_config:
                        para_xml = ET.SubElement(cfg_xml, 'Parameter')
                        para_xml.set('Name', parameter)
                        for detail in dplugin.startup_config[parameter]:
                            if detail not in CONFIG_SAVE_CFG_BLACKLIST:
                                detail_xml = ET.SubElement(para_xml, detail)
                                detail_xml.text = dplugin.startup_config[parameter][detail]

                    # ---------------------------------------
                    # Save all current values for all
                    # parameter
                    # ---------------------------------------

                    last_paras_xml = ET.SubElement(pl_xml, 'PreviousParameters')
                    allparas = dplugin.get_parameters()
                    for para_key in allparas:
                        para = allparas[para_key]
                        last_para_xml = ET.SubElement(last_paras_xml, 'Parameter')
                        last_para_xml.set('Name', para_key)
                        last_para_xml.text = str(para.value)

                    # ---------------------------------------
                    # Save all current values for all
                    # signals of all dblocks
                    # ---------------------------------------

                    dblocks_xml = ET.SubElement(pl_xml, 'DBlocks')

                    alldblock_names = dplugin.get_dblocks()

                    for dblock_name in alldblock_names:
                        dblock = alldblock_names[dblock_name]
                        dblock_xml = ET.SubElement(dblocks_xml, 'DBlock')
                        dblock_xml.set('Name', dblock.name)

                        alldsignals = dblock.get_signals()

                        for dsignal in alldsignals:
                            if dsignal.uname != CORE_TIME_SIGNAL:
                                dsignal_xml = ET.SubElement(dblock_xml, 'DSignal')
                                dsignal_xml.set('uname', dsignal.uname)

                                dname_xml = ET.SubElement(dsignal_xml, 'dname')
                                dname_xml.text = dsignal.dname

                # ---------------------------------------
                # Build temporary subscription objects
                # to remember the subs of all plugins
                # including plugins that are not saved
                # excluding plugins we do not want the subs saved of
                # ---------------------------------------
                if dplugin.uname in sToSave:
                    subsOfPl = {}
                    subs = dplugin.get_subscribtions()
                    for sub in subs:
                        sourcePL = self.gui_data.get_dplugin_by_id(sub).uname
                        subsOfPl[sourcePL] = {}
                        for block in subs[sub]:
                            subsOfPl[sourcePL][block] = {}
                            dsubscription = subs[sub][block]
                            subsOfPl[sourcePL][block]['alias'] = dsubscription.alias

                            signals = []
                            for s in dsubscription.get_signals():
                                signals.append( str(s))

                            subsOfPl[sourcePL][block]['signals'] = signals

                    if len(subsOfPl) != 0:
                        subscriptionsToSave[dplugin.uname] = subsOfPl

            # ---------------------------------------
            # save subs to xml
            #
            # ---------------------------------------
            subs_xml = ET.SubElement(root,'Subscriptions')
            for dest in subscriptionsToSave:
                sub_xml = ET.SubElement(subs_xml,'Subscription')

                # Destination of data
                dest_xml = ET.SubElement(sub_xml,'Destination')
                dest_xml.text = dest

                for source in subscriptionsToSave[dest]:
                    # Source of Data
                    source_xml = ET.SubElement(sub_xml,'Source')
                    source_xml.set('uname',source)

                    for block in subscriptionsToSave[dest][source]:
                        block_xml = ET.SubElement(source_xml,'Block')
                        block_xml.set('name',block)

                        alias_xml = ET.SubElement(block_xml,'Alias')
                        alias_xml.text = subscriptionsToSave[dest][source][block]['alias']

                        signal_xml = ET.SubElement(block_xml,'Signals')
                        for sig in subscriptionsToSave[dest][source][block]['signals']:
                            if sig != CORE_TIME_SIGNAL:
                                sig_xml = ET.SubElement(signal_xml,'Signal')
                                sig_xml.text = sig


            # do transformation for readability and save xml tree to file
            self.indent(root)
            tree = ET.ElementTree(root)
            tree.write(path)

        except Exception as E:
            tb = traceback.format_exc()
            self.error_occured.emit("Error: Config Loader", "Not saveable: " + path, tb)

    def do_save_xml_config(self, path):
        """
        This function will save papis current state to a xml file provided by path.

        :param path: path to save xml to.
        :type path: basestring
        :return:
        """
        raise Exception('do_save_xml_config_reloaded must be used')

    def do_save_json_config_reloaded(self, path, plToSave=[], sToSave=[]):
        if path[-5:] != '.json':
            path += '.json'

        json_config = {}
        to_create = {}
        to_control = {}
        to_sub = {}
        plugins = self.gui_data.get_all_plugins()

        for dplugin_id in plugins:
            dplugin = plugins[dplugin_id]

            # check if this plugin should be saved to XML
            if dplugin.uname in plToSave:
                if dplugin.type == PLUGIN_VIP_IDENTIFIER:
                    dplugin.startup_config = dplugin.plugin.pl_get_current_config()

                to_create[dplugin.uname] = {}

                to_create[dplugin.uname]["identifier"] = {'value' : dplugin.plugin_identifier}
                plugin_config = {}
                for config in dplugin.startup_config:
                    for value in dplugin.startup_config[config]:
                        if value == 'value':
                            plugin_config[config] = {'value' : dplugin.startup_config[config][value]}

                to_create[dplugin.uname]["config"] = plugin_config


            if dplugin.uname in sToSave:
                subsOfPl = {}
                subs = dplugin.get_subscribtions()

                for sub in subs:
                    sourcePL = self.gui_data.get_dplugin_by_id(sub).uname

                    subsOfPl[sourcePL] = {}
                    for block in subs[sub]:

                        subsOfPl[sourcePL][block] = {}
                        dsubscription = subs[sub][block]
                        subsOfPl[sourcePL]['alias'] = dsubscription.alias
                        print(sourcePL)
                        print(block)
                        if dsubscription.alias is not None:
                            if sourcePL not in to_control:
                                to_control[sourcePL] = {}
                            to_control[sourcePL][block] = {'parameter' : dsubscription.alias}
                        else:

                            signals = []
                            for s in dsubscription.get_signals():
                                signals.append( str(s))

                            to_sub[dplugin.uname] = {}
                            to_sub[dplugin.uname]['signals'] = signals
                            to_sub[dplugin.uname]['block']   = block
                            to_sub[dplugin.uname]['plugin']  = sourcePL

        if len(to_create):
            json_config["ToCreate"] = to_create;
        if len(to_control):
            json_config["ToControl"] = to_control
        if len(to_sub):
            json_config["ToSub"] = to_sub

        papi_config = {"PaPIConfig" : json_config}


        try:
            with open(path, 'w') as outfile:
                json.dump(papi_config, outfile, indent='    ')

        except:
            pass



    def indent(self, elem, level=0):
        """
        Function which will apply a nice looking indentiation to xml structure before save. Better readability.
        copied from http://effbot.org/zone/element-lib.htm#prettyprint 06.10.2014 15:53

        :param elem:
        :param level:
        :return:
        """
        i = "\n" + level * "  "
        if len(elem):
            if not elem.text or not elem.text.strip():
                elem.text = i + "  "
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
            for elem in elem:
                self.indent(elem, level + 1)
            if not elem.tail or not elem.tail.strip():
                elem.tail = i
        else:
            if level and (not elem.tail or not elem.tail.strip()):
                elem.tail = i

    def do_reset_papi(self):
        """
        APi call to reset PaPI.
        Reset in this case means to delete all plugins cleanly and keep PaPI running.
        Will free all unames.
        Is using the do_delete_plugin api call and the delete plugin mechanism

        :return: ERROR CODE
        """

        all_plugins = self.gui_data.get_all_plugins()
        if all_plugins is not None:
            for plugin_key in all_plugins:
                plugin = all_plugins[plugin_key]
                self.do_delete_plugin(plugin.id)

    def do_test_name_to_be_unique(self, name):
        """
        Will check if a given name would be a valid, unique name for a plugin.
        :param name: name to check

        :type name: basestring
        :return: True or False
        """
        reg = QtCore.QRegExp('\S[^_][^\W_]+')
        if reg.exactMatch(name):
            if self.gui_data.get_dplugin_by_uname(name) is None:
                return True
            else:
                return False
        else:
            return False

    def do_change_string_to_be_uname(self, name):
        """
        This method will take a string and convert him according to some rules to be an uname

        :param name: name to convert to unmae
        :type name: basestring
        :return: name converted to uname
        """
        uname = name

        # TODO: get more inteligence here!

        forbidden = ['_', ',', '.', '`', ' ']
        for c in forbidden:
            uname = uname.replace(c, 'X')
        return uname
예제 #16
0
class GuiEventProcessing(QtCore.QObject):
    """
    This class will do all the event handling for a GUI process. It should be created and initialized with database and
    queues.
    To get all the functionality, one should link the callback functions (slots) for the needed signals.

    """
    added_dplugin = QtCore.pyqtSignal(DPlugin)
    removed_dplugin = QtCore.pyqtSignal(DPlugin)
    dgui_changed = QtCore.pyqtSignal()
    plugin_died = QtCore.pyqtSignal(DPlugin, Exception, str)

    def __init__(self, gui_data, core_queue, gui_id, gui_queue, TabManager,
                 plugin_manager):
        """
        Init for eventProcessing

        :param gui_data:    Data object for all the plugin data
        :type gui_data: DGui
        :param core_queue:  multiprocessing queue for process interaction with core process
        :type core_queue: multiprocessing.Queue
        :param gui_id: id of gui process
        :type gui_id: int
        :param gui_queue:  multiprocessing queue for process interaction with gui process
        :type gui_queue: multiprocessing.Queue
        :return:
        """
        super(GuiEventProcessing, self).__init__()
        self.gui_data = gui_data
        self.core_queue = core_queue
        self.gui_id = gui_id
        self.log = ConsoleLog(GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.plugin_manager = plugin_manager
        self.log.lvl = 0

        self.gui_queue = gui_queue
        self.TabManger = TabManager
        # switch case for event processing
        self.process_event = {
            'new_data': self.process_new_data_event,
            'close_programm': self.process_close_program_event,
            'check_alive_status': self.process_check_alive_status,
            'create_plugin': self.process_create_plugin,
            'update_meta': self.process_update_meta,
            'plugin_closed': self.process_plugin_closed,
            'set_parameter': self.process_set_parameter,
            'pause_plugin': self.process_pause_plugin,
            'resume_plugin': self.process_resume_plugin,
            'stop_plugin': self.process_stop_plugin,
            'start_plugin': self.process_restart_plugin,
            'parameter_info': self.process_parameter_info
        }

    def gui_working(self, close_mock, workingTimer):
        """
         Event processing loop of gui. Build to get called every 40ms after a run through.
         Will process all events of the queue at the time of call.
         Procedure was built this way, so that the processing of an event is not covered by the try/except structure.

         :type event: PapiEventBase
         :type dplugin: DPlugin
        """
        # event flag, true for first loop iteration to enter loop
        isEvent = True
        # event object, if there is an event
        event = None
        while (isEvent):
            # look at queue and try to get a new element
            try:
                event = self.gui_queue.get_nowait()
                # if there is a new element, event flag remains true
                isEvent = True
            except:
                # there was no new element, so event flag is set to false
                isEvent = False

            # check if there was a new element to process it
            if isEvent:
                # get the event operation
                op = event.get_event_operation()
                # debug out
                self.log.printText(2, 'Event: ' + op)
                # process this event
                if op == 'test_close':
                    close_mock()
                else:
                    self.process_event[op](event)
        # after the loop ended, which means that there are no more new events, a new timer will be created to start
        # this method again in a specific time

        workingTimer.start(GUI_WOKRING_INTERVAL)
        #QtCore.QTimer.singleShot(GUI_WOKRING_INTERVAL, lambda: self.gui_working(close_mock))

    def process_new_data_event(self, event):
        """
        Core sent a new data event to gui. Gui now needs to find the destination plugin and call its execute function
        with the new data.

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # debug print
        self.log.printText(2, 'new data event')
        # get list of destination IDs
        dID_list = event.get_destinatioID()
        # get optional data of event
        opt = event.get_optional_parameter()
        # iterate over destination list
        for dID in dID_list:
            # get destination plugin from DGUI
            dplugin = self.gui_data.get_dplugin_by_id(dID)
            # check if it exists
            if dplugin != None:
                # it exists, so call its execute function, but just if it is not paused ( no data delivery when paused )
                if dplugin.state != PLUGIN_STATE_PAUSE and dplugin.state != PLUGIN_STATE_STOPPED:
                    # check if new_data is a parameter or new raw data
                    try:
                        if opt.is_parameter is False:
                            dplugin.plugin.cb_execute(
                                Data=dplugin.plugin._demux(
                                    opt.data_source_id, opt.block_name,
                                    opt.data),
                                block_name=opt.block_name,
                                plugin_uname=event.source_plugin_uname)
                        else:
                            dplugin.plugin._set_parameter_internal(
                                opt.parameter_alias, opt.data)
                    except Exception as E:
                        tb = traceback.format_exc()

                        self.plugin_died.emit(dplugin, E, tb)

            else:
                # plugin does not exist in DGUI
                self.log.printText(
                    1, 'new_data, Plugin with id  ' + str(dID) +
                    '  does not exist in DGui')

    def process_plugin_closed(self, event):
        """
        Processes plugin_closed event.
        Gui now knows, that a plugin was closed by core and needs to update its DGui data base

        :param event:
        :type event: PapiEventBase
        :return:
        """
        opt = event.get_optional_parameter()

        dplugin = self.gui_data.get_dplugin_by_id(opt.plugin_id)
        if dplugin is not None:
            if dplugin.own_process is False:
                try:
                    dplugin.plugin.cb_quit()
                except Exception as E:
                    tb = traceback.format_exc()
                    self.plugin_died.emit(dplugin, E, tb)

        if self.gui_data.rm_dplugin(opt.plugin_id) == ERROR.NO_ERROR:
            self.log.printText(
                1, 'plugin_closed, Plugin with id: ' + str(opt.plugin_id) +
                ' was removed in GUI')
            self.dgui_changed.emit()
            self.removed_dplugin.emit(dplugin)
        else:
            self.log.printText(
                1, 'plugin_closed, Plugin with id: ' + str(opt.plugin_id) +
                ' was NOT removed in GUI')

    def process_stop_plugin(self, event):
        """
        Processes plugin_stop events.
        Quit plugin, emit DPlugin was removed -> necessary signal for the GUI.

        :param event:
        :return:
        """
        id = event.get_destinatioID()
        dplugin = self.gui_data.get_dplugin_by_id(id)
        if dplugin is not None:
            try:
                dplugin.plugin.cb_quit()
                dplugin.state = PLUGIN_STATE_STOPPED
                self.removed_dplugin.emit(dplugin)
                self.dgui_changed.emit()
            except Exception as E:
                tb = traceback.format_exc()
                self.plugin_died.emit(dplugin, E, tb)

    def process_restart_plugin(self, event):
        """
        Processes plugin_start event.
        Used to (re-)start a plugin after the plugin was stopped. Emit DPlugin was added -> necessary signal for the GUI.

        :param event:
        :return:
        """
        id = event.get_destinatioID()
        dplugin = self.gui_data.get_dplugin_by_id(id)
        if dplugin is not None:
            try:
                if dplugin.plugin._starting_sequence(
                        dplugin.plugin.pl_get_current_config()) is True:
                    dplugin.state = PLUGIN_STATE_START_SUCCESFUL
                    self.added_dplugin.emit(dplugin)
                else:
                    dplugin.state = PLUGIN_STATE_START_FAILED
            except Exception as E:
                tb = traceback.format_exc()
                self.plugin_died.emit(dplugin, E, tb)

            self.dgui_changed.emit()

    def process_create_plugin(self, event):
        """
        Processes the create Plugin event. This event got sent by core to GUI.
        Gui now needs to add a new plugin to DGUI and decide whether it is a plugin running in the GUI process or not.

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # get optional data: the plugin id, identifier and uname
        opt = event.get_optional_parameter()
        id = opt.plugin_id
        plugin_identifier = opt.plugin_identifier
        uname = opt.plugin_uname
        # config for passsing additional information to the plugin at the moment of creation
        config = opt.plugin_config

        # debug print
        self.log.printText(
            2, 'create_plugin, Try to create plugin with Name  ' +
            plugin_identifier + " and UName " + uname)

        # get the plugin object from yapsy manager
        plugin_orginal = self.plugin_manager.getPluginByName(plugin_identifier)

        # check for existance
        if plugin_orginal is None:
            # plugin with given identifier does not exist
            self.log.printText(
                1, 'create_plugin, Plugin with Name  ' + plugin_identifier +
                '  does not exist in file system')
            # end function
            return -1

        # plugin seems to exist, so get the path of the plugin file
        imp_path = plugin_orginal.path + ".py"
        # build a loader object for this plugin
        module_name = plugin_orginal.name.lower()

        spec = importlib.util.find_spec(module_name)
        #Module was not yet loaded
        if spec is None:
            loader = importlib.machinery.SourceFileLoader(
                module_name, imp_path)
            current_modul = loader.load_module()
            #Add path to sys path otherwise importlib.import_module will not find the module
            sys_path = "/".join(plugin_orginal.path.split('/')[0:-1])
            sys.path.append(sys_path)
        else:
            #Import module
            current_modul = importlib.import_module(module_name)

        # build the plugin class name for usage
        class_name = plugin_orginal.name[:1].upper() + plugin_orginal.name[1:]
        # get the plugin class of the source code loaded and init class as a new object
        plugin = getattr(current_modul, class_name)()
        # get default startup configuration for merge with user defined startup_configuration
        start_config = plugin._get_startup_configuration()
        config = dict(list(start_config.items()) + list(config.items()))

        # check if plugin in ViP (includes pcp) or something which is not running in the gui process
        if plugin._get_type() == PLUGIN_VIP_IDENTIFIER:
            # plugin in running in gui process
            # add a new dplugin object to DGui and set its type and uname
            dplugin = self.gui_data.add_plugin(None, None, False,
                                               self.gui_queue, plugin, id)
            dplugin.uname = uname
            dplugin.type = opt.plugin_type
            dplugin.plugin_identifier = plugin_identifier
            dplugin.startup_config = config
            dplugin.path = plugin_orginal.path
            # call the init function of plugin and set queues and id
            api = Plugin_api(self.gui_data,
                             self.core_queue,
                             self.gui_id,
                             uname + ' API:',
                             tabManager=self.TabManger)

            # call the plugin developers init function with config
            try:
                dplugin.plugin._init_plugin(self.core_queue,
                                            self.gui_queue,
                                            dplugin.id,
                                            api,
                                            dpluginInfo=dplugin.get_meta(),
                                            TabManger=self.TabManger)
                if dplugin.plugin._starting_sequence(
                        copy.deepcopy(config)) is True:
                    # start succcessfull
                    self.core_queue.put(
                        Event.status.StartSuccessfull(dplugin.id, 0, None))
                else:
                    self.core_queue.put(
                        Event.status.StartFailed(dplugin.id, 0, None))

                # first set meta to plugin (meta infos in plugin)
                if dplugin.state not in [PLUGIN_STATE_STOPPED]:
                    dplugin.plugin._update_plugin_meta(dplugin.get_meta())

            except Exception as E:
                dplugin.state = PLUGIN_STATE_STOPPED
                tb = traceback.format_exc()
                self.plugin_died.emit(dplugin, E, tb)

            # debug print
            self.log.printText(
                1, 'create_plugin, Plugin with name  ' + str(uname) +
                '  was started as ViP')
        else:
            # plugin will not be running in gui process, so we just need to add information to DGui
            # so add a new dplugin to DGUI and set name und type
            dplugin = self.gui_data.add_plugin(None, None, True, None, plugin,
                                               id)
            dplugin.plugin_identifier = plugin_identifier
            dplugin.uname = uname
            dplugin.startup_config = opt.plugin_config
            dplugin.type = opt.plugin_type
            dplugin.path = plugin_orginal.path
            # debug print
            self.log.printText(
                1, 'create_plugin, Plugin with name  ' + str(uname) +
                '  was added as non ViP')

        self.added_dplugin.emit(dplugin)
        self.dgui_changed.emit()

    def process_close_program_event(self, event):
        """
        Processes close programm event.
        Nothing important happens.

         :param event: event to process
         :type event: PapiEventBase
         :type dplugin: DPlugin
        """
        self.log.printText(
            1,
            'event: close_progam was received but there is no action for it')
        pass

    def process_check_alive_status(self, event):
        """
        Gui received check_alive request form core, so gui will respond to it

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # send event from GUI to Core
        event = Event.status.Alive(1, 0, None)
        self.core_queue.put(event)

    def process_update_meta(self, event):
        """
        Core sent new meta information of an existing plugin. This function will update DGui with these information

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        # get information of event
        # TODO: pl_id should not be in the origin parameter
        opt = event.get_optional_parameter()
        pl_id = event.get_originID()

        # get plugin of which new meta should be updated
        dplugin = self.gui_data.get_dplugin_by_id(pl_id)
        # check if it exists
        if dplugin is not None:
            # plugin exists, so update its meta information
            dplugin.update_meta(opt.plugin_object)
            # check if plugin runs in gui to update its copy of meta informations
            if dplugin.own_process is False:
                if dplugin.state not in [PLUGIN_STATE_STOPPED]:
                    # try:
                    dplugin.plugin._update_plugin_meta(dplugin.get_meta())
                # except Exception as E:
                #     dplugin.state = PLUGIN_STATE_STOPPED
                #     tb = traceback.format_exc()
                #     self.plugin_died.emit(dplugin, E, tb)

            self.dgui_changed.emit()
        else:
            # plugin does not exist
            self.log.printText(
                1, 'update_meta, Plugin with id  ' + str(pl_id) +
                '  does not exist')

    def process_update_parameter(self, event):
        print('Just update')

    def process_set_parameter(self, event):
        """
        Processes set_parameter event.
        Used to handle parameter sets by the gui or other plugins.

        :param event:
        :return:
        """
        # debug print
        self.log.printText(2, 'set parameter event')

        dID = event.get_destinatioID()
        # get optional data of event
        opt = event.get_optional_parameter()

        if isinstance(event, Event.instruction.UpdateParameter):
            return

        # get destination plugin from DGUI
        dplugin = self.gui_data.get_dplugin_by_id(dID)
        # check if it exists
        if dplugin is not None:
            # it exists, so call its execute function
            dplugin.plugin._set_parameter_internal(opt.parameter_alias,
                                                   opt.data)
        else:
            # plugin does not exist in DGUI
            self.log.printText(
                1, 'set_parameter, Plugin with id  ' + str(dID) +
                '  does not exist in DGui')

    def process_pause_plugin(self, event):
        """
        Core sent event to pause a plugin in GUI, so call the pause function of this plugin

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        pl_id = event.get_destinatioID()

        dplugin = self.gui_data.get_dplugin_by_id(pl_id)
        if dplugin is not None:
            dplugin.plugin.cb_pause()

    def process_resume_plugin(self, event):
        """
        Core sent event to resume a plugin in GUI, so call the resume function of this plugin

        :param event: event to process
        :type event: PapiEventBase
        :type dplugin: DPlugin
        """
        pl_id = event.get_destinatioID()

        dplugin = self.gui_data.get_dplugin_by_id(pl_id)
        if dplugin is not None:
            dplugin.plugin.cb_resume()

    def process_parameter_info(self, event):
        """

        :param event:
        :return:
        """
        pl_id = event.get_destinatioID()

        dplugin = self.gui_data.get_dplugin_by_id(pl_id)

        if dplugin is not None:
            dplugin.plugin.cb_new_parameter_info(event.dparameter_object)
예제 #17
0
파일: main.py 프로젝트: dani-l/PaPI
    def gui_graphic_init(self):
        self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE)
        # set GUI size
        self.setGeometry(self.geometry().x(),self.geometry().y(), pc.GUI_DEFAULT_WIDTH, pc.GUI_DEFAULT_HEIGHT)

        self.count = 0

        self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL, pc.GUI_PROCESS_CONSOLE_IDENTIFIER)

        self.log.printText(1,pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: '+str(os.getpid()))

        self.last_config = pc.PAPI_LAST_CFG_PATH

        self.in_run_mode = False


        # -------------------------------------
        # Create placeholder
        # -------------------------------------
        self.overview_menu = None
        self.create_plugin_menu = None
        self.plugin_create_dialog = None

        # -------------------------------------
        # Create menues
        # -------------------------------------
        self.plugin_create_dialog = CreatePluginDialog(self.gui_management.gui_api, self.TabManager)


        # -------------------------------------
        # Create callback functions for buttons
        # -------------------------------------
        #self.loadButton.clicked.connect(self.load_triggered)
        #self.saveButton.clicked.connect(self.save_triggered)

        # -------------------------------------
        # Create actions
        # -------------------------------------
        _translate = QtCore.QCoreApplication.translate

        self.actionLoad.triggered.connect(self.triggered_load)
        self.actionLoad.setShortcut(_translate("DefaultMain","Ctrl+L"))



        self.actionSave.triggered.connect(self.triggered_save)
        self.actionSave.setShortcut(_translate("DefaultMain","Ctrl+S"))

        self.actionOverview.triggered.connect(self.triggered_show_overview_menu)
        self.actionOverview.setShortcut(_translate("DefaultMain","Ctrl+O"))

        self.actionCreate.triggered.connect(self.triggered_show_create_plugin_menu)
        self.actionCreate.setShortcut(_translate("DefaultMain","Ctrl+N"))

        self.actionResetPaPI.triggered.connect(self.triggered_reset_papi)
        self.actionReloadConfig.triggered.connect(self.triggered_reload_config)

        self.actionRunMode.triggered.connect(self.toggle_run_mode)

        self.actionReload_Plugin_DB.triggered.connect(self.triggered_reload_plugin_db)

        self.actionPaPI_Wiki.triggered.connect(self.triggered_papi_wiki)

        self.actionPaPI_Doc.triggered.connect(self.triggered_papi_doc)
        self.actionPaPI_Doc.setShortcut(_translate("DefaultMain","Ctrl+H"))

        self.actionAbout.triggered.connect(self.triggered_papi_about)
        self.actionAbout_Qt.triggered.connect(self.triggered_papi_about_qt)

        self.actionToolbar.triggered.connect(self.triggered_show_toolbar)

        #self.toolBar.dragEnterEvent = self.toolbarDragEnterEvent
        #self.toolBar.dropEvent = self.toolbarDropEvent

        self.toolBar.clickedFavouritePlugin.connect(self.toolbarAddFavPlugin)
        self.toolBar.removedFavouritePlugin.connect(self.favPluginWasRemoved)

        self.set_icons()
예제 #18
0
class GUI(QMainWindow, Ui_DefaultMain):
    """
    This class defines the default GUI written by PyQt5.

    """
    def __init__(self,
                 core_queue=None,
                 gui_queue=None,
                 gui_id=None,
                 gui_data=None,
                 is_parent=False,
                 parent=None):
        """
        Constructor of this class. Called to initialize the GUI.

        This constructor is called within an own process which is reliable for the GUI and all graphical plugins.

        :param core_queue: Queue used to send PaPI events to the Core
        :param gui_queue: GUI queue which contains PaPI events for the GUI
        :param gui_id: Unique ID for this gui
        :param gui_data: Contains all data for the current session
        :param parent: parent element
        :return:
        """

        super(GUI, self).__init__(parent)
        self.setupUi(self)
        self.is_parent = is_parent

        # Create a data structure for gui if it is missing
        # -------------------------------------------------- #
        if not isinstance(gui_data, DGui):
            self.gui_data = DGui()
        else:
            self.gui_data = gui_data

        # check if gui should be the parent process or core is the parent
        # start core if gui is parent
        # -------------------------------------------------- #
        self.core_process = None
        if is_parent:
            core_queue_ref = Queue()
            gui_queue_ref = Queue()
            gui_id_ref = 1
            self.core_process = Process(target=run_core_in_own_process,
                                        args=(gui_queue_ref, core_queue_ref,
                                              gui_id_ref))
            self.core_process.start()
        else:
            if core_queue is None:
                raise Exception('Gui started with wrong arguments')
            if gui_queue is None:
                raise Exception('Gui started with wrong arguments')
            if not isinstance(gui_id, str):
                raise Exception('Gui started with wrong arguments')

            core_queue_ref = core_queue
            gui_queue_ref = gui_queue
            gui_id_ref = gui_id

        # Create the Tab Manager and the gui management unit #
        # connect some signals of management to gui          #
        # -------------------------------------------------- #
        self.TabManager = PaPITabManger(tabWigdet=self.widgetTabs,
                                        centralWidget=self.centralwidget)

        self.gui_management = GuiManagement(core_queue_ref, gui_queue_ref,
                                            gui_id_ref, self.TabManager,
                                            self.get_gui_config,
                                            self.set_gui_config)

        self.TabManager.gui_api = self.gui_management.gui_api
        self.TabManager.dGui = self.gui_management.gui_data

        self.gui_management.gui_event_processing.added_dplugin.connect(
            self.add_dplugin)
        self.gui_management.gui_event_processing.removed_dplugin.connect(
            self.remove_dplugin)
        self.gui_management.gui_event_processing.dgui_changed.connect(
            self.triggered_changed_dgui)
        self.gui_management.gui_event_processing.plugin_died.connect(
            self.triggered_plugin_died)

        self.gui_management.gui_api.error_occured.connect(
            self.triggered_error_occurred)

        signal.signal(signal.SIGINT, lambda a, b: self.signal_handler())

        # List for keys that are active
        self.keysActiveList = []

        # -------------------------------------
        # Create placeholder
        # -------------------------------------
        self.overview_menu = None
        self.create_plugin_menu = None
        self.plugin_create_dialog = None

        self.log = None
        self.last_config = None
        self.in_run_mode = None
        self.workingTimer = None

        # initialize the graphic of the gui
        # -------------------------------------------------- #
        self.init_gui_graphic()

    def signal_handler(self):
        """
        This handler will be called, when CTRL+C is used in the console
        It will react to SIGINT Signal
        As an reaction it will close the gui by first telling the core to close and then closing the gui

        :return:
        """

        self.gui_management.gui_api.do_close_program()
        sys.exit(0)

    def init_gui_graphic(self):
        """
        Called to set mandatory variables, create child dialogs and actions.
        This function is called once within the constructor.

        :return:
        """

        self.setWindowTitle(pc.GUI_PAPI_WINDOW_TITLE)
        # set GUI size
        self.setGeometry(self.geometry().x(),
                         self.geometry().y(), pc.GUI_DEFAULT_WIDTH,
                         pc.GUI_DEFAULT_HEIGHT)

        self.log = ConsoleLog(pc.GUI_PROCESS_CONSOLE_LOG_LEVEL,
                              pc.GUI_PROCESS_CONSOLE_IDENTIFIER)
        self.log.printText(
            1, pc.GUI_START_CONSOLE_MESSAGE + ' .. Process id: ' +
            str(os.getpid()))

        self.last_config = pc.PAPI_LAST_CFG_PATH

        self.in_run_mode = False

        # -------------------------------------
        # Create menues
        # -------------------------------------
        self.plugin_create_dialog = CreatePluginDialog(
            self.gui_management.gui_api, self.TabManager)

        # -------------------------------------
        # Create actions
        # -------------------------------------
        _translate = QtCore.QCoreApplication.translate

        self.action_load_config.triggered.connect(self.triggered_load_config)
        self.action_load_config.setShortcut(_translate("DefaultMain",
                                                       "Ctrl+L"))

        self.action_save_config.triggered.connect(self.triggered_save_config)
        self.action_save_config.setShortcut(_translate("DefaultMain",
                                                       "Ctrl+S"))

        self.action_open_overview_menu.triggered.connect(
            self.triggered_open_overview_menu)
        self.action_open_overview_menu.setShortcut(
            _translate("DefaultMain", "Ctrl+O"))

        self.action_open_create_plugin_menu.triggered.connect(
            self.triggered_open_create_plugin_menu)
        self.action_open_create_plugin_menu.setShortcut(
            _translate("DefaultMain", "Ctrl+N"))

        self.action_reset_papi.triggered.connect(self.triggered_reset_papi)
        self.action_reload_config.triggered.connect(
            self.triggered_reload_config)

        self.action_toggle_run_mode.triggered.connect(
            self.triggered_toggle_run_mode)

        self.action_reload_plugin_db.triggered.connect(
            self.triggered_reload_plugin_db)

        self.action_open_papi_doc.triggered.connect(
            self.triggered_open_papi_doc)
        self.action_open_papi_doc.setShortcut(
            _translate("DefaultMain", "Ctrl+H"))

        self.action_open_papi_about.triggered.connect(
            self.triggered_open_papi_about)
        self.action_open_qt_about.triggered.connect(
            self.triggered_open_qt_about)

        self.action_toggle_toolbar.triggered.connect(
            self.triggered_toggle_toolbar)

        self.toolbar.clickedFavouritePlugin.connect(
            self.toolbar_add_fav_plugin)
        self.toolbar.removedFavouritePlugin.connect(
            self.fav_plugin_was_removed)

        self.actionFullscreen.triggered.connect(
            self.triggered_toggle_fullscreen)

        self.init_set_icons()

    def fav_plugin_add(self, plugin_name):
        """
        This function is used to mark an arbitrary plugin as a favourite plugin.
        Favourite plugins are always displayed in the toolbar.

        This function is called by dropping a plugin icon from the create menu on the toolbar.
        It is also called in the initialize phase of the gui for restoring favourite plugin in the configuration file.

        :param plugin_name: Name of the plugin
        :return:
        """

        plugin_manager = self.gui_management.plugin_manager
        plugin_manager.locatePlugins()

        candidates = plugin_manager.getPluginCandidates()
        plugins_info = {c[2].path: c[2] for c in candidates}
        plugins_info_loadable = {
            p.path: p
            for p in plugin_manager.getAllPlugins()
        }

        for plugin_info in plugins_info.values():
            if plugin_info.name == plugin_name:

                if plugin_info.path in plugins_info_loadable.keys():
                    plugin_info = plugins_info_loadable[plugin_info.path]
                    plugin_info.loadable = True
                else:
                    plugin_info.loadable = False

                self.toolbar_add_fav_plugin(plugin_info)

    def fav_plugin_was_removed(self):
        """
        This function is called when a favourite plugin was removed.
        This function is called by using the context menu of the toolbar and using it to remove a plugin.

        :return:
        """

        self.gui_management.gui_api.do_save_xml_config_reloaded(
            pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True)

    def init_set_icons(self):
        """
        This function sets the icon for all actions.
        This function is called once during the initializing of the GUI.

        :return:
        """

        # -------------------------------------
        # Create Icons for actions
        # -------------------------------------
        load_icon = get16Icon('folder')
        save_icon = get16Icon('file_save_as')
        exit_icon = get16Icon('cancel')
        overview_icon = get16Icon('tree_list')
        create_icon = get16Icon('application_add')
        reload_icon = get16Icon('arrow_rotate_clockwise')
        help_icon = get16Icon('help')
        info_icon = get16Icon('information')
        delete_icon = get16Icon('delete')
        view_icon = get16Icon('reviewing_pane')

        # -------------------------------------
        # Set Icons for actions
        # -------------------------------------
        self.action_load_config.setIcon(load_icon)
        self.action_save_config.setIcon(save_icon)
        self.action_exit.setIcon(exit_icon)
        self.action_open_overview_menu.setIcon(overview_icon)
        self.action_open_create_plugin_menu.setIcon(create_icon)
        self.action_reload_plugin_db.setIcon(reload_icon)
        self.action_reload_config.setIcon(reload_icon)
        self.action_open_papi_wiki.setIcon(help_icon)
        self.action_open_papi_doc.setIcon(help_icon)
        self.action_open_papi_about.setIcon(info_icon)
        self.action_open_qt_about.setIcon(info_icon)
        self.actionAbout_PySide.setIcon(info_icon)
        self.action_reset_papi.setIcon(delete_icon)
        #self.action_toggle_run_mode.setIcon(view_icon)

        # -------------------------------------
        # Set Icons visible in menu
        # -------------------------------------
        self.action_load_config.setIconVisibleInMenu(True)
        self.action_save_config.setIconVisibleInMenu(True)
        self.action_exit.setIconVisibleInMenu(True)
        self.action_open_overview_menu.setIconVisibleInMenu(True)
        self.action_open_create_plugin_menu.setIconVisibleInMenu(True)
        self.action_reload_plugin_db.setIconVisibleInMenu(True)
        self.action_reload_config.setIconVisibleInMenu(True)
        self.action_open_papi_wiki.setIconVisibleInMenu(True)
        self.action_open_papi_doc.setIconVisibleInMenu(True)
        self.action_open_papi_about.setIconVisibleInMenu(True)
        self.action_open_qt_about.setIconVisibleInMenu(True)
        self.actionAbout_PySide.setIconVisibleInMenu(True)
        self.action_reset_papi.setIconVisibleInMenu(True)
        #self.action_toggle_run_mode.setIconVisibleInMenu(True)

    def get_gui_config(self, save_user_settings=False):
        """
        Returns a dictionary which describes the current state of the GUI, like e.g. size, background image and postion.

        This function is called when the current configuration is stored.
        This function is also called when a plugin was marked or unmarked as favourite plugin,

        If 'saveUserSettings==True' the dictionary will also contain the current favourite plugins.
        It is not necessary to save user specific settings when a configuration was saved by using the 'save configuration dialog'.

        :param save_user_settings:
        :return:
        """
        current_active_tab = {
            'Active': str(self.TabManager.get_currently_active_tab())
        }

        tabs = {}
        tab_dict = self.TabManager.get_tabs_by_uname()
        for tab in tab_dict:
            tab_config = tab_dict[tab]
            tabs[tab] = {}
            tabs[tab]['Background'] = tab_config.background
            tabs[tab]['Position'] = str(
                self.TabManager.getTabPosition_by_name(tab))

        size = {'X': str(self.size().width()), 'Y': str(self.size().height())}

        cfg = {'ActiveTab': current_active_tab, 'Tabs': tabs, 'Size': size}

        # ----------------------
        # Set favourite plugins
        # ----------------------
        if save_user_settings:
            favourites = {}
            actions = self.toolbar.actions()
            for i in range(len(actions)):
                action = actions[i]
                if isinstance(action, PaPIFavAction):
                    favourites[action.text()] = {}
                    favourites[action.text()]['position'] = str(i)

            cfg['Favourites'] = favourites

        return cfg

    def set_gui_config(self, cfg):
        """
        A configuration as dictionary is loaded by this function.
        This function is called when a configuration was loaded. It restores attributes as size, position and favourite plugins.

        :param cfg:
        :type {};
        :return:
        """

        #################
        # windows size: #
        #################
        if 'Size' in cfg:
            w = int(cfg['Size']['X'])
            h = int(cfg['Size']['Y'])
            self.resize_gui_window(w, h)

        # ------------------------
        # Restore favourite icons
        # ------------------------
        if 'Favourites' in cfg:
            sorted_positions = {}

            for plugin in cfg['Favourites']:
                sorted_positions[int(
                    cfg['Favourites'][plugin]['position'])] = plugin

            for position in sorted(sorted_positions.keys()):
                plugin = sorted_positions[position]
                self.fav_plugin_add(plugin)

        # -----------------------
        # Restore Tabs
        # -----------------------
        if 'Tabs' in cfg:
            for tabName in cfg['Tabs']:
                tab = cfg['Tabs'][tabName]
                self.TabManager.add_tab(tabName)
                if 'Background' in tab:
                    self.TabManager.set_background_for_tab_with_name(
                        tabName, tab['Background'])

    def triggered_reload_plugin_db(self):
        """
        This callback function reloads the list of plugins of the plugin manager.
        This function is triggered by using the action "Reload DB" in the toolbar menu "Plugin".

        :return:
        """
        self.gui_management.plugin_manager.collectPlugins()

    def run(self):
        """
        Creates a timer and sets an interval for processing events with working loop.

        :return:
        """

        self.workingTimer = QtCore.QTimer(self)
        self.workingTimer.timeout.connect(
            lambda: self.gui_management.gui_event_processing.gui_working(
                self.closeEvent, self.workingTimer))
        self.workingTimer.start(pc.GUI_WOKRING_INTERVAL)

    def triggered_open_create_plugin_menu(self):
        """
        Used to open the create plugin menu.
        This function is triggered by using the action "Create" in the toolbar menu "Plugin" or
        by the action "Create" in the toolbar.

        :return:
        """

        self.create_plugin_menu = CreatePluginMenu(
            self.gui_management.gui_api, self.TabManager,
            self.gui_management.plugin_manager)
        self.create_plugin_menu.show()

    def triggered_open_overview_menu(self):
        """
        Used to open the overview menu.
        This function is triggered by using the action "Overview" in the toolbar menu "Plugin" or
        by the action "Overview" in the toolbar.

        :return:
        """
        self.overview_menu = OverviewPluginMenu(
            self.gui_management.gui_api, self.gui_management.tab_manager)
        self.overview_menu.show()

    def triggered_toggle_toolbar(self):
        """
        Used to toogle the vision of the the toolbar
        This function is triggered by using the action "Toolbar" in the toolbar menu "View".

        :return:
        """

        self.toolbar.setHidden(not self.toolbar.isHidden())

        self.action_toggle_toolbar.setChecked(not self.toolbar.isHidden())

    def triggered_toggle_fullscreen(self):
        """

        :return:
        """
        if self.isFullScreen() is False:
            self.toolbar.setHidden(True)
            self.action_toggle_toolbar.setChecked(False)
            self.showFullScreen()
        else:
            self.toolbar.setHidden(False)
            self.action_toggle_toolbar.setChecked(True)
            self.showNormal()

        self.actionFullscreen.setChecked(self.isFullScreen())
        self.actionFullscreen.setChecked(self.isFullScreen())

    def triggered_load_config(self):
        """
        Used to open the 'load config' dialog.
        This function is triggered by using the action "Load" in the toolbar menu "PaPI" or
        by the action "Load" in the toolbar.

        :return:
        """
        file_names = ''

        dialog = QFileDialog(self)
        dialog.setFileMode(QFileDialog.ExistingFile)
        dialog.setNameFilter(self.tr("PaPI-Cfg (*.xml)"))
        dialog.setDirectory(os.path.abspath(pc.CONFIG_DEFAULT_DIRECTORY))
        dialog.setWindowTitle("Load Configuration")

        if dialog.exec_():
            file_names = dialog.selectedFiles()

        if len(file_names):
            if file_names[0] != '':
                self.last_config = file_names[0]
                self.load_config(file_names[0])

    def load_config(self, file_name):
        """
        Called with a PaPI XML Configuration which is determined by file_name,
        This function is called when a configuration file was chosen by the "Load Dialog" and during the initialize phase for loading
        the user specific configuration file.

        :param file_name:
        :return:
        """

        self.gui_management.gui_api.do_load_xml(file_name)

    def triggered_save_config(self):
        """
        Used to start the 'save config' dialog.
        This function is triggered by using the action "Save" in the toolbar menu "PaPI" or
        by the action "Save" in the toolbar.

        :return:
        """

        file_names = ''

        dialog = PaPIConfigSaveDialog(self, self.gui_management.gui_api)

        dialog.fill_with()

        if dialog.exec_():
            file_names = dialog.selectedFiles()

        plugin_list, subscription_list = dialog.get_create_lists()

        if len(file_names):
            if file_names[0] != '':
                if "json" in dialog.selectedNameFilter():
                    self.gui_management.gui_api.do_save_json_config_reloaded(
                        file_names[0],
                        plToSave=plugin_list,
                        sToSave=subscription_list)

                if "xml" in dialog.selectedNameFilter():
                    self.gui_management.gui_api.do_save_xml_config_reloaded(
                        file_names[0],
                        plToSave=plugin_list,
                        sToSave=subscription_list)

    def closeEvent(self, *args, **kwargs):
        """
        Handles close events.
        Saves current session as pc.PAPI_LAST_CFG_PATH
        Closes all opened windows.

        :param args:
        :param kwargs:
        :return:
        """

        try:
            self.gui_management.gui_api.do_save_xml_config_reloaded(
                pc.PAPI_LAST_CFG_PATH)
        except Exception as E:
            tb = traceback.format_exc()

        self.gui_management.gui_api.do_close_program()
        if self.create_plugin_menu is not None:
            self.create_plugin_menu.close()

        if self.overview_menu is not None:
            self.overview_menu.close()

        self.close()

    def add_dplugin(self, dplugin):
        """
        Callback function called by 'DPlugin added signal'
        Used to add a DPlugin SubWindow on the GUI if possible.

        Is called whenever a plugin was created.

        :param dplugin:
        :return:
        """

        if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER:

            sub_window = dplugin.plugin._get_sub_window()

            config = dplugin.startup_config
            tab_name = config['tab']['value']
            if tab_name in self.TabManager.get_tabs_by_uname():
                area = self.TabManager.get_tabs_by_uname()[tab_name]
            else:
                self.log.printText(
                    1, 'add dplugin: no tab with tab_id of dplugin')
                area = self.TabManager.add_tab(tab_name)

            area.addSubWindow(sub_window)

            is_maximized = config['maximized']['value'] == '1'

            size_re = re.compile(r'([0-9]+)')

            pos = config['position']['value']
            window_pos = size_re.findall(pos)
            sub_window.move(int(window_pos[0]), int(window_pos[1]))

            if not is_maximized:
                sub_window.show()
            else:
                sub_window.showMaximized()

            # see http://qt-project.org/doc/qt-4.8/qt.html#WindowType-enum
            sub_window.setWindowFlags(Qt.CustomizeWindowHint
                                      | Qt.WindowMinMaxButtonsHint
                                      | Qt.WindowTitleHint)

            if self.in_run_mode:
                sub_window.disableInteraction()

        if self.overview_menu is not None:
            self.overview_menu.refresh_action(dplugin)

    def remove_dplugin(self, dplugin):
        """
        Callback function called by 'DPlugin removed signal'
        Used to removed a DPlugin SubWindow from the GUI if possible.

        Is called whenever a plugin was removed.

        :param dplugin:
        :return:
        """

        if dplugin.type == pc.PLUGIN_VIP_IDENTIFIER:
            config = dplugin.plugin.pl_get_current_config()
            tab_name = config['tab']['value']
            if tab_name in self.TabManager.get_tabs_by_uname():
                tabOb = self.TabManager.get_tabs_by_uname()[tab_name]
                tabOb.removeSubWindow(dplugin.plugin._get_sub_window())
                if tabOb.closeIfempty is True:
                    if len(tabOb.subWindowList()) == 0:
                        if isinstance(tabOb, TabObject):
                            self.TabManager.closeTab_by_name(tabOb.name)
                        else:
                            self.TabManager.remove_window(tabOb)

    def triggered_changed_dgui(self):
        """
        This is triggered to refresh the overview menu if it is active.
        This is needed to guarantee the consistency between the data structure dgui and the data seen by the user.

        :return:
        """
        if self.overview_menu is not None:
            self.overview_menu.refresh_action()

    def triggered_plugin_died(self, dplugin, e, msg):
        """
        Triggered when a plugin died.

        :param dplugin:
        :param e:
        :param msg:
        :return:
        """

        dplugin.state = pc.PLUGIN_STATE_STOPPED

        self.gui_management.gui_api.do_stopReset_plugin_uname(dplugin.uname)

        err_msg = QtGui.QMessageBox(self)
        err_msg.setFixedWidth(650)

        err_msg.setIcon(QtGui.QMessageBox.Critical)
        err_msg.setSizeGripEnabled(True)
        err_msg.setWindowTitle("Plugin: " + dplugin.uname + " // " + str(e))
        err_msg.setText("Error in plugin" + dplugin.uname + " // " + str(e))
        err_msg.setDetailedText(str(msg))
        err_msg.setWindowModality(Qt.NonModal)
        err_msg.show()

    def triggered_error_occurred(self, title, msg, detailed_msg):
        """
        Triggered when an error occured. Creates an error dialog for the user.
        Title defines the title of the error dialog.
        Msg contains a messages displayed in the dialog.
        Detailed_msg should contain more information about the occured error which is optional displayed.

        :param title:
        :param msg:
        :param detailed_msg:
        :return:
        """

        err_msg = QtGui.QMessageBox(self)
        err_msg.setFixedWidth(650)

        err_msg.setWindowTitle(title)
        err_msg.setText(str(msg))
        err_msg.setDetailedText(str(detailed_msg))
        err_msg.setWindowModality(Qt.NonModal)
        err_msg.show()

    def triggered_toggle_run_mode(self):
        """
        Toggles the run mode, i.e. it changes from active to passive and vice versa.
        This function is triggered by using the action "Toolbar" in the toolbar menu "View".

        :return:
        """

        if self.in_run_mode is False:
            # hide toolbar
            self.toolbar.setHidden(True)
            self.action_toggle_toolbar.setChecked(False)
            # disable context menu of tabmanger
            self.TabManager.disableContextMenus()
            self.TabManager.setTabs_movable_closable(False, False)
            self.action_toggle_run_mode.setChecked(True)
            # lock subwindows in tabs
            for tab_name in self.TabManager.tab_dict_uname:
                tab = self.TabManager.tab_dict_uname[tab_name]

                for sub_window in tab.subWindowList():
                    sub_window.disableInteraction()
            self.in_run_mode = True
            self.menubar.hide()
        else:
            # show toolbar
            self.toolbar.setHidden(False)
            self.action_toggle_toolbar.setChecked(True)
            # disable context menu of tabmanger
            self.TabManager.enableContextMenus()
            self.TabManager.setTabs_movable_closable(True, True)
            self.action_toggle_run_mode.setChecked(False)
            # unlock subwindows in tabs
            for tab_name in self.TabManager.tab_dict_uname:
                tab = self.TabManager.tab_dict_uname[tab_name]

                for sub_window in tab.subWindowList():
                    sub_window.enableInteraction()
            self.in_run_mode = False
            self.menubar.show()

    def keyPressEvent(self, event):
        """
        Default callback function which is called when an any key was pressed by the user.

        :param event:
        :return:
        """

        if event.key() not in self.keysActiveList:
            self.keysActiveList.append(event.key())

        # if QtCore.Qt.Key_Escape in self.keysActiveList:
        # if self.in_run_mode:
        #     self.triggered_toggle_run_mode()
        # if self.isFullScreen():
        #     self.triggered_toggle_fullscreen()

        if QtCore.Qt.Key_D in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.gui_management.tab_manager.select_next_tab()
            self.keysActiveList.remove(QtCore.Qt.Key_D)

        if QtCore.Qt.Key_A in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.gui_management.tab_manager.select_prev_tab()
            self.keysActiveList.remove(QtCore.Qt.Key_A)

        if QtCore.Qt.Key_M in self.keysActiveList and QtCore.Qt.Key_Control in self.keysActiveList:
            self.toggleMenuBarHide()

    def keyReleaseEvent(self, event):
        """
        Default callback function which is called when any key was released by the user.

        :param event:
        :return:
        """

        if event.key() in self.keysActiveList:
            self.keysActiveList.remove(event.key())

    def resize_gui_window(self, w, h):
        """
        Internal function for resizing the window of the GUI.

        :param event:
        :return:
        """

        self.setGeometry(self.geometry().x(), self.geometry().y(), w, h)

    def toggleMenuBarHide(self):
        if not self.menubar.isHidden():
            self.menubar.hide()
        else:
            self.menubar.show()

    def triggered_reload_config(self):
        """
        This function is used to reset PaPI and to reload the last loaded configuration file.

        :return:
        """

        if self.last_config is not None:
            self.triggered_reset_papi()
            QtCore.QTimer.singleShot(
                pc.GUI_WAIT_TILL_RELOAD, lambda: self.gui_management.gui_api.
                do_load_xml(self.last_config))

    def triggered_reset_papi(self):
        """
        This function is called to reset PaPI. That means all subscriptions are canceled and all plugins are removed.
        This function is triggered by using the action "Reset" in the toolbar menu "PaPI" or
        by the action "Reset" in the toolbar.

        :return:
        """

        h = pc.GUI_DEFAULT_HEIGHT
        w = pc.GUI_DEFAULT_WIDTH

        self.setGeometry(self.geometry().x(), self.geometry().y(), w, h)
        self.TabManager.set_all_tabs_to_close_when_empty(True)
        self.TabManager.close_all_empty_tabs()
        self.gui_management.gui_api.do_reset_papi()

    def triggered_open_papi_doc(self):
        """
        Opens the PaPI documentation in the default browser.
        This function is triggered by using the action "PaPI Doc" in the toolbar menu "Help".

        :return:
        """

        QDesktopServices.openUrl(QUrl(pc.PAPI_DOC_URL, QUrl.TolerantMode))

    def triggered_open_papi_about(self):
        """
        Opens a dialog with information about PaPI.
        This function is triggered by using the action "About" in the toolbar menu "Help".

        :return:
        """

        QMessageBox.about(self, pc.PAPI_ABOUT_TITLE, pc.PAPI_ABOUT_TEXT)

    def triggered_open_qt_about(self):
        """
        Opens the default dialog provided by Qt which contains information about Qt.
        This function is triggered by using the action "About Qt" in the toolbar menu "Help".

        :return:
        """

        QMessageBox.aboutQt(self)

    def toolbar_add_fav_plugin(self, plugin_info):
        """
        Adds an plugin described by plugin_info to the toolbar as an action.
        Plugin_info is an object which is created by the plugin manager yapsy to describe a plugin.
        The description contains information like e.g., name and path.

        :param plugin_info:
        :return:
        """

        l = len(plugin_info.name)
        path = plugin_info.path[:-l]
        path += 'box.png'
        px = QPixmap(path)

        icon = QIcon(px)

        for action in self.toolbar.actions():
            if action.text() == plugin_info.name:
                return

        plugin_action = PaPIFavAction(icon, plugin_info.name, self)
        plugin_action.triggered.connect(
            lambda ignore, p1=plugin_info: self.show_create_plugin_dialog(p1))

        self.toolbar.addAction(plugin_action)

        self.gui_management.gui_api.do_save_xml_config_reloaded(
            pc.PAPI_USER_CFG, plToSave=[], sToSave=[], saveUserSettings=True)

    def show_create_plugin_dialog(self, plugin_info):
        """
        Opens the create plugin dialog for a plugin described by plugin_info.
        Plugin_info is an object which is created by the plugin manager yapsy to describe a plugin.
        The description contains information like e.g., name and path.

        This dialog is triggered by clicking on a favourite plugin.

        :param plugin_info:
        :return:
        """

        if plugin_info is not None:
            if plugin_info.loadable:
                self.plugin_create_dialog.set_plugin(plugin_info)
                self.plugin_create_dialog.show()