Exemplo n.º 1
0
class CreatePluginMenu(QMainWindow, Ui_PluginCreateMenu):

    def __init__(self, gui_api, TabManger, plugin_manager, parent=None):
        super(CreatePluginMenu, self).__init__(parent)
        self.setupUi(self)
        self.dgui = gui_api.gui_data
        self.TabManager = TabManger

        self.gui_api = gui_api

        self.subscriberID = None
        self.targetID = None
        self.blockName = None

        self.plugin_manager = plugin_manager

        self.pluginTree.setDragEnabled(True)
        self.pluginTree.setDropIndicatorShown(True)

        self.setWindowTitle('Available Plugins')

        model = PaPITreeModel()
        model.setHorizontalHeaderLabels(['Name'])

        self.pluginProxyModel = PaPITreeProxyModel(self)
        self.pluginProxyModel.setSourceModel(model)

        regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

        self.pluginTree.setModel(self.pluginProxyModel)
        self.pluginTree.setUniformRowHeights(True)
        self.pluginTree.setSortingEnabled(True)
        self.pluginTree.setStyleSheet(pc.TREE_CSS)

        self.plugin_roots = {}

        self.configuration_inputs = {}

        self.pluginTree.clicked.connect(self.pluginItemChanged)

        self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager)

        self.createButton.clicked.connect(self.show_create_plugin_dialog)
        self.helpButton.clicked.connect(self.help_button_triggered)
        self.finder = ModuleFinder()

        self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field)

        self.pluginSearchText.setFocus(Qt.OtherFocusReason)
        self.helpButton.setText('')
        self.helpButton.setIcon(get16Icon('help.png'))
        self.helpButton.setToolTip('Opens the documentation for the currently selected plugin.')

    def keyPressEvent(self, event):

        if event.key() in [Qt.Key_Right, Qt.Key_Space]:
            index = self.pluginTree.currentIndex()
            self.pluginItemChanged(index)

        if event.key() == Qt.Key_Escape:
            self.close()

        # Use enter/return to bring up the dialog for a selected plugin
        if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter) and self.pluginTree.hasFocus():
           self.show_create_plugin_dialog()

        # if search bar has focus and user pressed enter/return,arrow up/down, change focus to the plugin tree
        if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter or event.key() == Qt.Key_Down \
            or event.key() == Qt.Key_Up) and self.pluginSearchText.hasFocus():
            self.pluginTree.setFocus(Qt.OtherFocusReason)

    def pluginItemChanged(self, index):
        plugin_info = self.pluginTree.model().data(index, Qt.UserRole)

        self.clear()

        self.scrollArea.setDisabled(True)

        if plugin_info is None:
            return

        self.scrollArea.setDisabled(False)

        self.nameEdit.setText(plugin_info.name)
        self.authorEdit.setText(plugin_info.author)
        self.descriptionText.setText(plugin_info.description)
        self.pathEdit.setText(plugin_info.path)

        self.createButton.setEnabled(plugin_info.loadable)

        lines = None
        with open(plugin_info.path + '.py') as f:
            lines = f.readlines()

        found_imports = []

        for line in lines:
            if line.startswith('import'):

                m = re.search('(import)\s+([\w.]*)(\s+as){0,1}',str.strip(line))
                if m is not None:
                    if len(m.groups()) > 2:
                        found_imports.append(m.group(2))

            if line.startswith('from'):
                m = re.search('(from)\s+([\w.]*)(\s+import)',str.strip(line))
                if m is not None:
                    if len(m.groups()) > 2:
                        found_imports.append(m.group(2))
        found_imports.sort()


        for imp in found_imports:
            item = QListWidgetItem(imp)

            spam_loader = importlib.find_loader(imp)
            found = spam_loader is not None
            if not found:
                self.modulesList.addItem(item)
                item.setBackground(QColor(255,0,0,50))

        if not plugin_info.loadable:

            self.modulesList.setEnabled(True)
            self.modulesLabel.setEnabled(True)

    def show_create_plugin_dialog(self):
        index = self.pluginTree.currentIndex()
        plugin_info = self.pluginTree.model().data(index, Qt.UserRole)

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

    def showEvent(self, *args, **kwargs):

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

        for pluginfo in all_pluginfo.values():

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

            plugin_root = self.get_plugin_root(pluginfo.path)
            plugin_root.appendRow(plugin_item)

        for root in sorted(self.plugin_roots.keys()):
            self.pluginTree.model().sourceModel().appendRow(self.plugin_roots[root])
            self.plugin_roots[root].sortChildren(0)

    def help_button_triggered(self):
        index = self.pluginTree.currentIndex()
        plugin_info = self.pluginTree.model().data(index, Qt.UserRole)

        if plugin_info is not None:



            path = plugin_info.path
            plugin_type = path.split('/')[-3]
            suffix = "." + '.'.join(path.split('/')[-2:])
            target_url = pc.PAPI_DOC_URL + pc.PAPI_DOC_PREFIX_PLUGIN + "." + plugin_type.lower() + suffix + ".html"
            QDesktopServices.openUrl(QUrl(target_url, QUrl.TolerantMode))

    def get_plugin_root(self,path):
        parts = path.split('/');
        part = parts[-3]
        name = part
        if part not in self.plugin_roots:

            cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG

            if os.path.isfile(cfg_file):
                config = configparser.ConfigParser()
                config.read(cfg_file)
                if 'Config' in config.sections():
                    if 'name' in config.options('Config'):
                        name = config.get('Config', 'name')

            self.plugin_roots[part] = PaPIRootItem(name)

        return self.plugin_roots[part]

    def changed_search_plugin_text_field(self, value):

        if not len(value):
            value = "*"
            self.pluginTree.collapseAll()
        else:
            value = "*" + value + "*"
            self.pluginTree.expandAll()

        self.pluginProxyModel.sourceModel().mark_visibility_by_name(value)

        # Used to trigger filter action
        regex = QRegExp(value, Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)





    def clear(self):
        self.nameEdit.setText('')
        self.authorEdit.setText('')
        self.descriptionText.setText('')
        self.pathEdit.setText('')
        self.modulesList.clear()
        self.modulesList.setEnabled(False)
        self.modulesLabel.setEnabled(False)

    def closeEvent(self, *args, **kwargs):
        self.plugin_create_dialog.close()
Exemplo n.º 2
0
class CreatePluginMenu(QMainWindow, Ui_PluginCreateMenu):
    """
    This class creates a menu which displays all available plugins.
    This menu is used to create plugin.

    """

    def __init__(self, gui_api, TabManger, plugin_manager, parent=None):
        """
        Constructor of this class.
        'gui_api' is used to access the GUI data storage 'DGUI' and for creating the plugin.
        'TabManager' access to the tab manager is needed because it provides the information about all used tabs.
        'plugin_manager' provides access to the yapsy manager which is used to parse the plugin information.

        :param gui_api:
        :param TabManger:
        :param plugin_manager:
        :param parent:
        :return:
        """
        super(CreatePluginMenu, self).__init__(parent)
        self.setupUi(self)
        self.dgui = gui_api.gui_data
        self.TabManager = TabManger

        self.gui_api = gui_api

        self.subscriberID = None
        self.targetID = None
        self.blockName = None

        self.plugin_manager = plugin_manager

        self.pluginTree.setDragEnabled(True)
        self.pluginTree.setDropIndicatorShown(True)

        self.setWindowTitle('Available Plugins')

        model = PaPITreeModel()
        model.setHorizontalHeaderLabels(['Name'])

        self.pluginProxyModel = PaPITreeProxyModel(self)
        self.pluginProxyModel.setSourceModel(model)

        regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

        self.pluginTree.setModel(self.pluginProxyModel)
        self.pluginTree.setUniformRowHeights(True)
        self.pluginTree.setSortingEnabled(True)
        self.pluginTree.setStyleSheet(pc.TREE_CSS)

        self.plugin_roots = {}

        self.configuration_inputs = {}

        self.pluginTree.clicked.connect(self.plugin_item_changed)

        self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager)

        self.createButton.clicked.connect(self.show_create_plugin_dialog)
        self.helpButton.clicked.connect(self.help_button_triggered)
        self.finder = ModuleFinder()

        self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field)

        self.pluginSearchText.setFocus(Qt.OtherFocusReason)
        self.helpButton.setText('')
        self.helpButton.setIcon(get16Icon('help.png'))
        self.helpButton.setToolTip('Opens the documentation for the currently selected plugin.')

    def keyPressEvent(self, event):
        """
        Default callback function which is called when an arbitrary key was pressed by the user.

        :param event:
        :return:
        """

        if event.key() in [Qt.Key_Right, Qt.Key_Space]:
            index = self.pluginTree.currentIndex()
            self.plugin_item_changed(index)

        if event.key() == Qt.Key_Escape:
            self.close()

        # Use enter/return to bring up the dialog for a selected plugin
        if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter) and self.pluginTree.hasFocus():
            self.show_create_plugin_dialog()

        # if search bar has focus and user pressed enter/return,arrow up/down, change focus to the plugin tree
        if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter or event.key() == Qt.Key_Down \
                    or event.key() == Qt.Key_Up) and self.pluginSearchText.hasFocus():
            self.pluginTree.setFocus(Qt.OtherFocusReason)

    def plugin_item_changed(self, index):
        """
        This function is called when the user selects another plugin in the plugin tree on the left side.
        Every change of plugin updates the displayed plugin information on the right side.

        :param index:
        :return:
        """
        plugin_info = self.pluginTree.model().data(index, Qt.UserRole)

        self.clear()

        self.scrollArea.setDisabled(True)

        if plugin_info is None:
            return

        self.scrollArea.setDisabled(False)

        self.nameEdit.setText(plugin_info.name)
        self.authorEdit.setText(plugin_info.author)
        self.descriptionText.setText(plugin_info.description)
        self.pathEdit.setText(plugin_info.path)

        self.createButton.setEnabled(plugin_info.loadable)

        lines = None
        with open(plugin_info.path + '.py') as f:
            lines = f.readlines()

        found_imports = []

        for line in lines:
            if line.startswith('import'):

                m = re.search('(import)\s+([\w.]*)(\s+as){0,1}', str.strip(line))
                if m is not None:
                    if len(m.groups()) > 2:
                        found_imports.append(m.group(2))

            if line.startswith('from'):
                m = re.search('(from)\s+([\w.]*)(\s+import)', str.strip(line))
                if m is not None:
                    if len(m.groups()) > 2:
                        found_imports.append(m.group(2))
        found_imports.sort()

        for imp in found_imports:
            item = QListWidgetItem(imp)

            spam_loader = importlib.find_loader(imp)
            found = spam_loader is not None
            if not found:
                self.modulesList.addItem(item)
                item.setBackground(QColor(255, 0, 0, 50))

        if not plugin_info.loadable:
            self.modulesList.setEnabled(True)
            self.modulesLabel.setEnabled(True)

    def show_create_plugin_dialog(self):
        """
        This function opens the dialog which is used to create plugin.
        An user opens this dialog by selecting a plugin and clicking on the 'Create Plugin' button.

        :return:
        """

        index = self.pluginTree.currentIndex()
        plugin_info = self.pluginTree.model().data(index, Qt.UserRole)

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

    def showEvent(self, *args, **kwargs):
        """
        This function is called when the dialog was displayed.

        :param args:
        :param kwargs:
        :return:
        """

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

        for plugin_info in all_pluginfo.values():

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

            plugin_root = self.get_plugin_root(plugin_info.path)
            plugin_root.appendRow(plugin_item)

        for root in sorted(self.plugin_roots.keys()):
            self.pluginTree.model().sourceModel().appendRow(self.plugin_roots[root])
            self.plugin_roots[root].sortChildren(0)
        self.pluginTree.expandAll()

    def help_button_triggered(self):
        """
        This function opens the documentation page a plugin in the default web browser.
        An user opens the page by selecting a plugin and clicking on the 'Help' button.

        :return:
        """

        index = self.pluginTree.currentIndex()
        plugin_info = self.pluginTree.model().data(index, Qt.UserRole)

        if plugin_info is not None:
            path = plugin_info.path
            plugin_type = path.split('/')[-3]
            suffix = "." + '.'.join(path.split('/')[-2:])
            target_url = pc.PAPI_DOC_URL + pc.PAPI_DOC_PREFIX_PLUGIN + "." + plugin_type.lower() + suffix + ".html"
            QDesktopServices.openUrl(QUrl(target_url, QUrl.TolerantMode))

    def get_plugin_root(self, path):
        """
        This function returns one of the root-Items of the plugin tree.
        The root-Item is determined by the plugin path.

        :return:
        """

        parts = path.split('/')
        part = parts[-3]
        name = part
        if part not in self.plugin_roots:

            cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG

            if os.path.isfile(cfg_file):
                config = configparser.ConfigParser()
                config.read(cfg_file)
                if 'Config' in config.sections():
                    if 'name' in config.options('Config'):
                        name = config.get('Config', 'name')

            self.plugin_roots[part] = PaPIRootItem(name)

        return self.plugin_roots[part]

    def changed_search_plugin_text_field(self, value):
        """
        This function is triggered by the user. It is called when the text in the search field is changed.
        The plugin-Tree is filtered by `value`

        :param value:
        :return:
        """

        if not len(value):
            value = "*"
            self.pluginTree.collapseAll()
        else:
            value = "*" + value + "*"
            self.pluginTree.expandAll()

        self.pluginProxyModel.sourceModel().mark_visibility_by_name(value)

        # Used to trigger filter action
        regex = QRegExp(value, Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

    def clear(self):
        """
        This function is called to reset all necessary labels and line edits.

        :return:
        """

        self.nameEdit.setText('')
        self.authorEdit.setText('')
        self.descriptionText.setText('')
        self.pathEdit.setText('')
        self.modulesList.clear()
        self.modulesList.setEnabled(False)
        self.modulesLabel.setEnabled(False)

    def closeEvent(self, *args, **kwargs):
        """
        Handles close events for this windows.
        Closing windows will also close the plugin create dialog.

        :param args:
        :param kwargs:
        :return:
        """

        self.plugin_create_dialog.close()
Exemplo n.º 3
0
class OverviewPluginMenu(QMainWindow, Ui_PluginOverviewMenu):
    """
    This class is used to create an extra window which displays all created plugins.
    The information are taken by the corresponding DPlugin-Object of a plugin. By this window a user is also able to
    create and cancel subscriptions.
    """
    def __init__(self, gui_api, tabmanager, parent=None):
        """
        Constructor of this class.
        'gui_api' provides an access to all functions which are needed for the functionality of the GUI.
        'tabmanager' manages the tabs of the gui

        :param gui_api:
        :param tabmanager:
        :param parent:
        :return:
        """

        super(OverviewPluginMenu, self).__init__(parent)
        self.setupUi(self)
        self.dgui = gui_api.gui_data

        self.gui_api = gui_api
        self.TabManager = tabmanager

        self.setWindowTitle("OverviewMenu")

        self.plugin_create_dialog = CreatePluginDialog(self.gui_api,
                                                       self.TabManager)

        # ----------------------------------
        # Build structure of plugin tree
        # ----------------------------------

        self.dpluginModel = DPluginTreeModel()
        self.dpluginModel.setHorizontalHeaderLabels(['Name'])

        self.pluginProxyModel = PaPITreeProxyModel(self)
        self.pluginProxyModel.setSourceModel(self.dpluginModel)
        regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

        self.pluginTree.setModel(self.pluginProxyModel)
        self.pluginTree.setUniformRowHeights(True)

        self.plugin_roots = {}

        # -----------------------------------
        # Build structure of parameter tree
        # -----------------------------------

        self.dparameterModel = DParameterTreeModel()
        self.dparameterModel.setHorizontalHeaderLabels(['Name'])
        self.parameterTree.setModel(self.dparameterModel)
        self.parameterTree.setUniformRowHeights(True)
        self.dparameterModel.dataChanged.connect(
            self.data_changed_parameter_model)

        # -----------------------------------
        # Build structure of block tree
        # -----------------------------------

        self.bModel = DBlockTreeModel(self.showInternalNameCheckBox)
        self.bModel.setHorizontalHeaderLabels(['Name'])
        self.bModel.setColumnCount(2)
        self.blockTree.setModel(self.bModel)
        self.blockTree.setUniformRowHeights(True)
        self.bModel.dataChanged.connect(self.data_changed_block_model)

        self.showInternalNameCheckBox.clicked.connect(
            self.show_internal_name_callback)

        # -----------------------------------
        # Build structure of connection tree
        # -----------------------------------

        self.connectionModel = PaPITreeModel()
        self.connectionModel.setHorizontalHeaderLabels([''])
        self.connectionTree.setHeaderHidden(True)
        self.connectionTree.setModel(self.connectionModel)
        self.connectionTree.setUniformRowHeights(True)

        self.subscribers_root = PaPIRootItem('Subscribers')
        self.connectionModel.appendRow(self.subscribers_root)

        self.subscriptions_root = PaPIRootItem('Subscriptions')
        self.connectionModel.appendRow(self.subscriptions_root)

        # -----------------------------------
        # signal/slots
        # -----------------------------------
        self.playButton.clicked.connect(self.play_button_callback)
        self.pauseButton.clicked.connect(self.pause_button_callback)
        self.stopButton.clicked.connect(self.stop_start_button_callback)
        self.pluginTree.clicked.connect(self.plugin_item_changed)
        self.pluginTree.selectionModel().selectionChanged.connect(
            self.changed_dplugin_tree_selection)

        self.pluginTree.setStyleSheet(pc.TREE_CSS)

        # ----------------------------------
        # Add context menu
        # ----------------------------------
        self.pluginTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.pluginTree.customContextMenuRequested.connect(
            self.open_context_menu_dplugin_tree)

        self.blockTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.blockTree.customContextMenuRequested.connect(
            self.open_context_menu_block_tree)

        self.parameterTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.parameterTree.customContextMenuRequested.connect(
            self.open_context_menu_parameter_tree)

        self.connectionTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connectionTree.customContextMenuRequested.connect(
            self.open_context_menu_connection_tree)

        # ----------------------------------
        # Add Actions
        # ----------------------------------
        self.actionRefresh.triggered.connect(self.refresh_action)
        self.pluginSearchText.textChanged.connect(
            self.changed_search_plugin_text_field)

        self.clear()

        # set focus to the search bar
        self.pluginSearchText.setFocus(Qt.OtherFocusReason)

    def clear(self):
        """
        This function will clear this window.
        It is used to reset all elements in this windows.

        :return:
        """
        self.bModel.clear()
        self.dparameterModel.clear()

        self.subscribers_root.setRowCount(0)
        self.subscriptions_root.setRowCount(0)

        self.unameEdit.setText('')
        self.usedpluginEdit.setText('')
        self.stateEdit.setText('')
        self.typeEdit.setText('')
        self.alivestateEdit.setText('')

        self.bModel.setHorizontalHeaderLabels(['Name'])
        self.dparameterModel.setHorizontalHeaderLabels(['Name', 'Value'])
        self.connectionModel.setHorizontalHeaderLabels([''])

    def plugin_item_changed(self, index):
        """
        Used to display all known information for a DPlugin which is
        accessible in the pluginTree by its index.

        It is called when an user changes the selected plugin in the plugin tree.

        :param index: Current selected index
        :return:
        """

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)
        self.clear()

        if dplugin is None:
            self.pluginWidget.setDisabled(True)
            return
        self.pluginWidget.setDisabled(False)

        # ------------------------------------
        # Get all needed dplugin information
        # ------------------------------------

        self.unameEdit.setText(dplugin.uname)
        self.usedpluginEdit.setText(dplugin.plugin_identifier)
        self.stateEdit.setText(dplugin.state)
        self.typeEdit.setText(dplugin.type)
        self.alivestateEdit.setText(dplugin.alive_state)

        self.pauseButton.setDisabled(False)
        self.playButton.setDisabled(False)
        self.stopButton.setDisabled(False)

        if dplugin.alive_state != PLUGIN_STATE_DEAD:
            if dplugin.state == PLUGIN_STATE_PAUSE:
                self.pauseButton.setDisabled(True)
            if dplugin.state == PLUGIN_STATE_STOPPED:
                self.pauseButton.setDisabled(True)
                self.playButton.setDisabled(True)
                self.stopButton.setText('START')
            if dplugin.state == PLUGIN_STATE_RESUMED:
                self.playButton.setDisabled(True)
            if dplugin.state == PLUGIN_STATE_START_SUCCESFUL:
                self.playButton.setDisabled(True)
                self.stopButton.setText('STOP')

        # ---------------------------
        # Add DBlocks(Also DEvent)
        # ---------------------------

        dblock_ids = dplugin.get_dblocks()

        for dblock_id in dblock_ids:
            dblock = dblock_ids[dblock_id]

            block_item = DBlockTreeItem(dblock)
            self.bModel.appendRow(block_item)

            # -------------------------
            # Add Signals of this DBlock
            # -------------------------

            for signal in dblock.get_signals():
                if signal.uname not in [pc.CORE_TIME_SIGNAL]:
                    signal_item = DSignalTreeItem(
                        signal, self.showInternalNameCheckBox)

                    block_item.appendRow(signal_item)

            block_item.sortChildren(0)

            # ----------------------------------
            # Add Subscribers of this DBlock
            # ----------------------------------

            subscriber_ids = dblock.get_subscribers()

            for subscriber_id in subscriber_ids:
                # Other plugin
                subscriber = self.dgui.get_dplugin_by_id(subscriber_id)

                if dplugin.id in subscriber.get_subscribtions():

                    for dblock_sub_id in subscriber.get_subscribtions()[
                            dplugin.id]:

                        subscriber_item = DPluginTreeItem(subscriber)
                        #                self.subscriberModel.appendRow(subscriber_item)
                        self.subscribers_root.appendRow(subscriber_item)

                        subscription = subscriber.get_subscribtions()[
                            dplugin.id][dblock_sub_id]

                        block_item = DBlockTreeItem(dblock)

                        subscriber_item.appendRow(block_item)

                        subscription_item = PaPITreeItem(
                            subscription, "Signals")
                        block_item.appendRow(subscription_item)
                        for signal_uname in sorted(subscription.get_signals()):
                            if signal_uname not in [pc.CORE_TIME_SIGNAL]:
                                signal_item = PaPITreeItem(
                                    signal_uname, signal_uname)

                                subscription_item.appendRow(signal_item)

        # -------------------------
        # Add all Subscriptions
        # for this plugin
        # -------------------------

        dplugin_sub_ids = dplugin.get_subscribtions()

        for dplugin_sub_id in dplugin_sub_ids:

            dblock_names = dplugin_sub_ids[dplugin_sub_id]

            dplugin_sub = self.gui_api.gui_data.get_dplugin_by_id(
                dplugin_sub_id)
            dplugin_sub_item = DPluginTreeItem(dplugin_sub)
            #self.subscriptionModel.appendRow(dplugin_sub_item)
            self.subscriptions_root.appendRow(dplugin_sub_item)

            for dblock_name in dblock_names:

                dblock_sub = dplugin_sub.get_dblock_by_name(dblock_name)
                dblock_sub_item = DBlockTreeItem(dblock_sub)
                dplugin_sub_item.appendRow(dblock_sub_item)

                subscription = dblock_names[dblock_name]

                subscription_item = PaPITreeItem(subscription, "Signals")

                dblock_sub_item.appendRow(subscription_item)

                for signal_uname in sorted(subscription.get_signals()):
                    if signal_uname not in [pc.CORE_TIME_SIGNAL]:
                        signal_item = PaPITreeItem(signal_uname, signal_uname)

                        subscription_item.appendRow(signal_item)

        # --------------------------
        # Add DParameters
        # --------------------------

        dparameter_names = dplugin.get_parameters()
        for dparameter_name in sorted(dparameter_names):
            dparameter = dparameter_names[dparameter_name]
            dparameter_item = DParameterTreeItem(dparameter)
            self.dparameterModel.appendRow(dparameter_item)
            self.parameterTree.resizeColumnToContents(0)
            self.parameterTree.resizeColumnToContents(1)

        self.blockTree.expandAll()
        self.parameterTree.expandAll()
        self.connectionTree.expandAll()

        # http://srinikom.github.io/pyside-docs/PySide/QtGui/QAbstractItemView.html \
        # #PySide.QtGui.PySide.QtGui.QAbstractItemView.SelectionMode
        self.blockTree.setSelectionMode(QAbstractItemView.ExtendedSelection)

        # Sort Models
        self.bModel.sort(0)

    def plugin_item_refresh(self, index):
        """
        This function is called when it's known that the dplugin object, which describes the selected plugin, was changed.

        :param index:
        :return:
        """
        self.parameterTree.viewport().update()
        self.blockTree.viewport().update()
        self.connectionTree.viewport().update()

    def open_context_menu_dplugin_tree(self, position):
        """
        This callback function is called to create a context menu for the dplugin tree.
        It is triggered by use

        :param position:
        :return:
        """
        index = self.pluginTree.indexAt(position)

        if index.parent().isValid() is False:
            return None

        if index.isValid() is False:
            return None

        if self.pluginTree.isIndexHidden(index):
            return

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)

        menu = QMenu('Menu')

        submenu = QMenu('Action')
        menu.addMenu(submenu)
        action = QAction('Remove plugin', self)
        submenu.addAction(action)

        action.triggered.connect(
            lambda ignore, p=dplugin.id: self.gui_api.do_delete_plugin(p))

        action = QAction('Copy plugin', self)
        submenu.addAction(action)

        action.triggered.connect(
            lambda ignore, p=dplugin: self.show_create_plugin_dialog(p))

        actionCollapsAll = QAction('Collapse all', self)
        actionCollapsAll.triggered.connect(self.pluginTree.collapseAll)

        actionExpandAll = QAction('Expand all', self)
        actionExpandAll.triggered.connect(self.pluginTree.expandAll)

        menu.addAction(actionCollapsAll)
        menu.addAction(actionExpandAll)

        menu.exec_(self.pluginTree.viewport().mapToGlobal(position))

    def open_context_menu_block_tree(self, position):
        """
        This callback function is called to create a context menu
        for the block tree

        :param position:
        :return:
        """

        index = self.blockTree.indexAt(position)

        if index.isValid() is False:
            return None

        if self.blockTree.isIndexHidden(index):
            return

        item = self.blockTree.model().data(index, Qt.UserRole)

        if isinstance(item, DPlugin) or isinstance(item, DBlock):
            return

        index_sel = self.pluginTree.currentIndex()
        dplugin_sel = self.pluginTree.model().data(index_sel, Qt.UserRole)

        if dplugin_sel is not None:

            sub_menu = QMenu('Add Subscription')
            dplugin_ids = self.dgui.get_all_plugins()

            for dplugin_id in dplugin_ids:
                dplugin = dplugin_ids[dplugin_id]

                if dplugin_sel.id != dplugin_id:
                    action = QAction(self.tr(dplugin.uname), self)
                    sub_menu.addAction(action)
                    action.triggered.connect(lambda ignore, p=dplugin.uname:
                                             self.add_subscription_action(p))

            menu = QMenu()
            menu.addMenu(sub_menu)

            menu.exec_(self.blockTree.viewport().mapToGlobal(position))

    def open_context_menu_connection_tree(self, position):
        """
        This callback function is called to create a context menu
        for the subscriper tree

        :param position:
        :return:
        """
        index = self.connectionTree.indexAt(position)

        if index.isValid() is False:
            return None

        if self.connectionTree.isIndexHidden(index):
            return None

        if index.parent().isValid() is False:
            return None

        parIndex = index
        subscriberPart = False
        subscriptionPart = False
        signals = []
        isSignal = False

        while True:
            object = self.connectionTree.model().data(parIndex, Qt.DisplayRole)

            if "Subscribers" in object:
                subscriberPart = True
            if "Subscriptions" in object:
                subscriptionPart = True

            if (subscriptionPart or subscriberPart):
                break

            parIndex = parIndex.parent()

            if parIndex.isValid() is False:
                return

        if not (subscriptionPart or subscriberPart):
            return None

        if isinstance(self.connectionTree.model().data(index, Qt.UserRole),
                      DSubscription):
            return

        if isinstance(self.connectionTree.model().data(index, Qt.UserRole),
                      DPlugin):
            return

        # ----------------------------------
        # Open no context menu for signals
        # ----------------------------------

        if isinstance(self.connectionTree.model().data(index, Qt.UserRole),
                      str):
            isSignal = True
        else:
            isSignal = False

        # ----------------------------------
        # Get necessary objects for this subscription/subscriber
        # ----------------------------------

        if isSignal:
            dblock = self.connectionTree.model().data(index.parent().parent(),
                                                      Qt.UserRole)
            dplugin = self.connectionTree.model().data(
                index.parent().parent().parent(), Qt.UserRole)
            signal_uname = self.connectionTree.model().data(index, Qt.UserRole)
            signals.append(signal_uname)
        else:
            dblock = self.connectionTree.model().data(index, Qt.UserRole)
            dplugin = self.connectionTree.model().data(index.parent(),
                                                       Qt.UserRole)

        if subscriberPart:
            action = QAction('Remove Subscriber', self)
            action.triggered.connect(lambda ignore, p=dblock, m=dplugin: self.
                                     remove_subscriber_action(m, p))

        if subscriptionPart:
            action = QAction('Remove Subscription', self)
            action.triggered.connect(
                lambda ignore, p=dblock, m=dplugin, s=signals: self.
                cancel_subscription_action(m, p, s))

        actionCollapsAll = QAction('Collapse all', self)
        actionCollapsAll.triggered.connect(self.connectionTree.collapseAll)

        actionExpandAll = QAction('Expand all', self)
        actionExpandAll.triggered.connect(self.connectionTree.expandAll)

        menu = QMenu('Remove')
        menu.addAction(action)
        menu.addAction(actionCollapsAll)
        menu.addAction(actionExpandAll)
        menu.exec_(self.connectionTree.viewport().mapToGlobal(position))

    def open_context_menu_parameter_tree(self, position):
        """
        This callback function is called to create a context menu
        for the parameter tree

        :param position:
        :return:
        """

        index = self.parameterTree.indexAt(position)

        if index.isValid() is False:
            return None

        if self.parameterTree.isIndexHidden(index):
            return

        index_sibling = index.sibling(index.row(), index.column() - 1)

        if index_sibling.isValid():
            index = index_sibling

        dparameter = self.parameterTree.model().data(index, Qt.UserRole)
        dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(),
                                               Qt.UserRole)

        sub_menu = QMenu('Control by')

        dplugin_ids = self.dgui.get_all_plugins()

        for dplugin_id in dplugin_ids:
            dplugin_pcp = dplugin_ids[dplugin_id]

            if len(dplugin_pcp.get_devent()) > 0:
                # action = QAction(self.tr(dplugin.uname), self)
                # sub_menu.addAction(action)
                pcp_menu = QMenu(self.tr(dplugin_pcp.uname), sub_menu)
                sub_menu.addMenu(pcp_menu)

                dblock_pcp_ids = dplugin_pcp.get_dblocks()

                for dblock_pcp_id in dblock_pcp_ids:
                    dblock_pcp = dblock_pcp_ids[dblock_pcp_id]

                    count = len(dblock_pcp.get_subscribers())

                    action = QAction(
                        self.tr(dblock_pcp.name) + ' (' + str(count) + ')',
                        pcp_menu)
                    pcp_menu.addAction(action)

                    action.triggered.connect(
                        lambda ignore, p1=dplugin, p2=dparameter, p3=
                        dplugin_pcp, p4=dblock_pcp: self.
                        add_pcp_subscription_action(p1, p2, p3, p4))

        menu = QMenu()
        menu.addMenu(sub_menu)

        menu.exec_(self.parameterTree.viewport().mapToGlobal(position))

    def add_pcp_subscription_action(self, dplugin: DPlugin,
                                    dparameter: DParameter,
                                    dplugin_pcp: DPlugin, dblock_pcp: DBlock):
        """
        This function is used to create a subscription for a process control plugin.

        :param dplugin: Subscriber of a pcp plugin
        :param dparameter: Parameter of the subscriber which should be controlled by the pcp plugin.
        :param dplugin_pcp: The pcp plugin
        :param dblock_pcp: Block of the pcp plugin which is used to control the subscriber's parameter.
        :return:
        """
        self.gui_api.do_subscribe(dplugin.id, dplugin_pcp.id, dblock_pcp.name,
                                  [], dparameter.name)

    def add_subscription_action(self, dplugin_uname):
        """
        Used to add subscription for a specific dplugin

        :param dplugin_uname: Add Subscription for this DPlugin
        :return:
        """

        signals = []

        dplugin = self.gui_api.gui_data.get_dplugin_by_uname(dplugin_uname)

        indexes = self.blockTree.selectedIndexes()

        for index in indexes:
            if index.isValid():
                signal = self.blockTree.model().data(index, Qt.UserRole)
                signals.append(signal.uname)

        index_dblock = index.parent()

        dblock = self.blockTree.model().data(index_dblock, Qt.UserRole)

        index = self.pluginTree.currentIndex()

        dplugin_source = self.pluginTree.model().data(index, Qt.UserRole)

        self.gui_api.do_subscribe(dplugin.id, dplugin_source.id, dblock.name,
                                  signals)

        #self.blockTree.scrollTo(indexes[-1])

    def remove_subscriber_action(self, subscriber: DPlugin, dblock: DBlock):
        """
        Used to remove a subscriber of the dplugin selected in the DPlugin tree.

        :param subscriber: Subscriber which is effected
        :param dblock: DBlock which should be unsubscribed by Subscriber
        :return:
        """
        index = self.pluginTree.currentIndex()
        source = self.pluginTree.model().data(index, Qt.UserRole)
        self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname,
                                          dblock.name, [])

    def refresh_action(self, new_dplugin: DPlugin = None):
        """
        Used to refresh the overview menu view.

        :param new_dplugin: New dplugin which should be added in self.dpluginTreev.
        :return:
        """

        # -----------------------------------------
        # case: no DPlugin was added or removed
        #       e.g. parameter was changed
        # -----------------------------------------

        index = self.pluginTree.currentIndex()

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)

        if dplugin is not None:

            if dplugin.state == PLUGIN_STATE_DELETE:
                self.pluginWidget.setDisabled(True)
                self.clear()
            else:
                self.pluginWidget.setEnabled(True)
                self.plugin_item_refresh(index)

        # -----------------------------------------
        # case: remove already deleted plugins
        # -----------------------------------------
        key_copy = self.plugin_roots.copy().keys()
        for root in key_copy:

            self.plugin_roots[root].clean()

            if not self.plugin_roots[root].rowCount():
                self.dpluginModel.remove_item(self.plugin_roots[root])
                del self.plugin_roots[root]

        self.subscribers_root.clean()
        self.subscriptions_root.clean()

        #        self.subscribersTree

        # -----------------------------------------
        # case: a DPlugin was added
        # -----------------------------------------

        if new_dplugin is not None:
            plugin_item = DPluginTreeItem(new_dplugin)
            plugin_root = self.get_plugin_root(new_dplugin.path)

            if not plugin_root.hasItem(new_dplugin):
                plugin_root.appendRow(plugin_item)

            if plugin_root not in self.dpluginModel.findItems(
                    "", Qt.MatchContains):
                self.dpluginModel.appendRow(plugin_root)

    def cancel_subscription_action(self, source: DPlugin, dblock: DBlock,
                                   signals: []):
        """
        Action called to cancel a subscription of the current selected dplugin.

        :param source:
        :param dblock:
        :return:
        """
        index = self.pluginTree.currentIndex()
        subscriber = self.pluginTree.model().data(index, Qt.UserRole)
        self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname,
                                          dblock.name, signals)

    def showEvent(self, *args, **kwargs):
        """
        ShowEvent of this class.

        :param args:
        :param kwargs:
        :return:
        """
        dplugin_ids = self.dgui.get_all_plugins()

        for dplugin_id in dplugin_ids:
            dplugin = dplugin_ids[dplugin_id]
            # ------------------------------
            # Sort DPluginItem in TreeWidget
            # ------------------------------
            plugin_item = DPluginTreeItem(dplugin)

            plugin_root = self.get_plugin_root(dplugin.path)
            plugin_root.appendRow(plugin_item)

        for root in sorted(self.plugin_roots.keys()):
            self.pluginTree.model().sourceModel().appendRow(
                self.plugin_roots[root])
            self.plugin_roots[root].sortChildren(0)

        self.pluginTree.expandAll()

    def play_button_callback(self):
        """
        Callback function for the play button.

        :return:
        """
        index = self.pluginTree.currentIndex()
        item = self.pluginTree.model().data(index, Qt.UserRole)
        if item is not None:
            self.gui_api.do_resume_plugin_by_id(item.id)
            self.playButton.setDisabled(True)
            self.pauseButton.setDisabled(False)
            self.stopButton.setDisabled(False)

    def pause_button_callback(self):
        """
        Function pause_button_callback

        :return:
        """
        index = self.pluginTree.currentIndex()
        item = self.pluginTree.model().data(index, Qt.UserRole)
        if item is not None:
            self.pauseButton.setDisabled(True)
            self.playButton.setDisabled(False)
            self.gui_api.do_pause_plugin_by_id(item.id)

    def stop_start_button_callback(self):
        """
        Function stop_start_button_callback

        :return:
        """
        index = self.pluginTree.currentIndex()
        item = self.pluginTree.model().data(index, Qt.UserRole)
        if item is not None:
            if self.stopButton.text() == 'STOP':
                self.gui_api.do_stopReset_pluign(item.id)
                self.stopButton.setText('START')
                self.pauseButton.setDisabled(True)
                self.playButton.setDisabled(True)
                self.stopButton.setDisabled(False)

            else:
                self.gui_api.do_start_plugin(item.id)
                self.stopButton.setText('STOP')
                self.pauseButton.setDisabled(False)
                self.playButton.setDisabled(False)
                self.stopButton.setDisabled(False)

    def show_internal_name_callback(self):
        """
        Callback function for 'showInternalNameCheckBox'

        :return:
        """
        self.plugin_item_changed(self.pluginTree.currentIndex())

    def data_changed_parameter_model(self, index, n):
        """
        This function is called when a dparameter value is changed by editing the 'value'-column.

        :param index: Index of current changed dparameter
        :param n: None
        :return:
        """

        dparameter = self.parameterTree.model().data(index, Qt.UserRole)
        index = self.pluginTree.currentIndex()

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)

        self.gui_api.do_set_parameter(dplugin.id, dparameter.name,
                                      dparameter.value)

    def data_changed_block_model(self, index, n):
        """
        This function is called when a dblock child, a disgnal, is changed.

        :param index: Index of current changed dsignal object
        :param n: None
        :return:
        """

        dsignal = self.blockTree.model().data(index, Qt.UserRole)
        dblock = self.blockTree.model().data(index.parent(), Qt.UserRole)

        dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(),
                                               Qt.UserRole)

        self.gui_api.do_edit_plugin_uname(dplugin.uname, dblock,
                                          {"edit": dsignal})

    def get_plugin_root(self, path):
        parts = path.split('/')
        part = parts[-3]
        name = part
        if part not in self.plugin_roots:

            cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG

            if os.path.isfile(cfg_file):
                config = configparser.ConfigParser()
                config.read(cfg_file)
                if 'Config' in config.sections():
                    if 'name' in config.options('Config'):
                        name = config.get('Config', 'name')

            self.plugin_roots[part] = PaPIRootItem(name)

        return self.plugin_roots[part]

    def changed_search_plugin_text_field(self, value):
        if not len(value):
            value = "*"
            self.pluginTree.collapseAll()
        else:
            value = "*" + value + "*"
            self.pluginTree.expandAll()

        self.pluginProxyModel.sourceModel().mark_visibility_by_name(value)

        # Used to trigger filter action
        regex = QRegExp(value, Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

    def show_create_plugin_dialog(self, dplugin):

        if dplugin.type == PLUGIN_VIP_IDENTIFIER:
            dplugin.startup_config = dplugin.plugin.pl_get_current_config()

        self.plugin_create_dialog.set_dplugin(
            dplugin, dplugin.plugin._get_startup_configuration(), dplugin.type)
        self.plugin_create_dialog.show()

    def keyPressEvent(self, event):
        """
        Used to handle key events for this gui element.

        :param event: KeyEvent
        :return:
        """
        if event.key() == Qt.Key_Escape:
            self.close()

        if self.pluginTree.hasFocus() and \
                        event.key() in [Qt.Key_Return, Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right]:
            self.plugin_item_changed(self.pluginTree.currentIndex())

        # if search bar has focus and user pressed enter/return,arrow up/down, change focus to the plugin tree
        if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter or event.key() == Qt.Key_Down \
            or event.key() == Qt.Key_Up) and self.pluginSearchText.hasFocus():
            self.pluginTree.setFocus(Qt.OtherFocusReason)

    def changed_dplugin_tree_selection(self, new_selection, old_selection):
        pass
Exemplo n.º 4
0
class OverviewPluginMenu(QMainWindow, Ui_PluginOverviewMenu):
    """
    This class is used to create an extra window which displays all created plugins.
    The information are taken by the corresponding DPlugin-Object of a plugin. By this window a user is also able to
    create and cancel subscriptions.
    """

    def __init__(self, gui_api, tabmanager, parent=None):
        """
        Constructor of this class.
        'gui_api' provides an access to all functions which are needed for the functionality of the GUI.
        'tabmanager' manages the tabs of the gui

        :param gui_api:
        :param tabmanager:
        :param parent:
        :return:
        """

        super(OverviewPluginMenu, self).__init__(parent)
        self.setupUi(self)
        self.dgui = gui_api.gui_data

        self.gui_api = gui_api
        self.TabManager = tabmanager;

        self.setWindowTitle("OverviewMenu")

        self.plugin_create_dialog = CreatePluginDialog(self.gui_api, self.TabManager)

        # ----------------------------------
        # Build structure of plugin tree
        # ----------------------------------

        self.dpluginModel = DPluginTreeModel()
        self.dpluginModel.setHorizontalHeaderLabels(['Name'])

        self.pluginProxyModel = PaPITreeProxyModel(self)
        self.pluginProxyModel.setSourceModel(self.dpluginModel)
        regex = QRegExp("*", Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

        self.pluginTree.setModel(self.pluginProxyModel)
        self.pluginTree.setUniformRowHeights(True)

        self.plugin_roots = {}

        # -----------------------------------
        # Build structure of parameter tree
        # -----------------------------------

        self.dparameterModel = DParameterTreeModel()
        self.dparameterModel.setHorizontalHeaderLabels(['Name'])
        self.parameterTree.setModel(self.dparameterModel)
        self.parameterTree.setUniformRowHeights(True)
        self.dparameterModel.dataChanged.connect(self.data_changed_parameter_model)

        # -----------------------------------
        # Build structure of block tree
        # -----------------------------------

        self.bModel = DBlockTreeModel(self.showInternalNameCheckBox)
        self.bModel.setHorizontalHeaderLabels(['Name'])
        self.bModel.setColumnCount(2)
        self.blockTree.setModel(self.bModel)
        self.blockTree.setUniformRowHeights(True)
        self.bModel.dataChanged.connect(self.data_changed_block_model)

        self.showInternalNameCheckBox.clicked.connect(self.show_internal_name_callback)

        # -----------------------------------
        # Build structure of connection tree
        # -----------------------------------

        self.connectionModel = PaPITreeModel()
        self.connectionModel.setHorizontalHeaderLabels([''])
        self.connectionTree.setHeaderHidden(True)
        self.connectionTree.setModel(self.connectionModel)
        self.connectionTree.setUniformRowHeights(True)

        self.subscribers_root = PaPIRootItem('Subscribers')
        self.connectionModel.appendRow(self.subscribers_root)

        self.subscriptions_root = PaPIRootItem('Subscriptions')
        self.connectionModel.appendRow(self.subscriptions_root)

        # -----------------------------------
        # signal/slots
        # -----------------------------------
        self.playButton.clicked.connect(self.play_button_callback)
        self.pauseButton.clicked.connect(self.pause_button_callback)
        self.stopButton.clicked.connect(self.stop_start_button_callback)
        self.pluginTree.clicked.connect(self.plugin_item_changed)
        self.pluginTree.selectionModel().selectionChanged.connect(self.changed_dplugin_tree_selection)

        self.pluginTree.setStyleSheet(pc.TREE_CSS)

        # ----------------------------------
        # Add context menu
        # ----------------------------------
        self.pluginTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.pluginTree.customContextMenuRequested.connect(self.open_context_menu_dplugin_tree)

        self.blockTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.blockTree.customContextMenuRequested.connect(self.open_context_menu_block_tree)

        self.parameterTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.parameterTree.customContextMenuRequested.connect(self.open_context_menu_parameter_tree)

        self.connectionTree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connectionTree.customContextMenuRequested.connect(self.open_context_menu_connection_tree)

        # ----------------------------------
        # Add Actions
        # ----------------------------------
        self.actionRefresh.triggered.connect(self.refresh_action)
        self.pluginSearchText.textChanged.connect(self.changed_search_plugin_text_field)

        self.clear()

        # set focus to the search bar
        self.pluginSearchText.setFocus(Qt.OtherFocusReason)


    def clear(self):
        """
        This function will clear this window.
        It is used to reset all elements in this windows.

        :return:
        """
        self.bModel.clear()
        self.dparameterModel.clear()

        self.subscribers_root.setRowCount(0)
        self.subscriptions_root.setRowCount(0)

        self.unameEdit.setText('')
        self.usedpluginEdit.setText('')
        self.stateEdit.setText('')
        self.typeEdit.setText('')
        self.alivestateEdit.setText('')

        self.bModel.setHorizontalHeaderLabels(['Name'])
        self.dparameterModel.setHorizontalHeaderLabels(['Name', 'Value'])
        self.connectionModel.setHorizontalHeaderLabels([''])

    def plugin_item_changed(self, index):
        """
        Used to display all known information for a DPlugin which is
        accessible in the pluginTree by its index.

        It is called when an user changes the selected plugin in the plugin tree.

        :param index: Current selected index
        :return:
        """

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)
        self.clear()

        if dplugin is None:
            self.pluginWidget.setDisabled(True)
            return
        self.pluginWidget.setDisabled(False)

        # ------------------------------------
        # Get all needed dplugin information
        # ------------------------------------

        self.unameEdit.setText(dplugin.uname)
        self.usedpluginEdit.setText(dplugin.plugin_identifier)
        self.stateEdit.setText(dplugin.state)
        self.typeEdit.setText(dplugin.type)
        self.alivestateEdit.setText(dplugin.alive_state)

        self.pauseButton.setDisabled(False)
        self.playButton.setDisabled(False)
        self.stopButton.setDisabled(False)

        if dplugin.alive_state != PLUGIN_STATE_DEAD:
            if dplugin.state == PLUGIN_STATE_PAUSE:
                self.pauseButton.setDisabled(True)
            if dplugin.state == PLUGIN_STATE_STOPPED:
                self.pauseButton.setDisabled(True)
                self.playButton.setDisabled(True)
                self.stopButton.setText('START')
            if dplugin.state == PLUGIN_STATE_RESUMED:
                self.playButton.setDisabled(True)
            if dplugin.state == PLUGIN_STATE_START_SUCCESFUL:
                self.playButton.setDisabled(True)
                self.stopButton.setText('STOP')

        # ---------------------------
        # Add DBlocks(Also DEvent)
        # ---------------------------

        dblock_ids = dplugin.get_dblocks()

        for dblock_id in dblock_ids:
            dblock = dblock_ids[dblock_id]

            block_item = DBlockTreeItem(dblock)
            self.bModel.appendRow(block_item)

            # -------------------------
            # Add Signals of this DBlock
            # -------------------------

            for signal in dblock.get_signals():
                if signal.uname not in [pc.CORE_TIME_SIGNAL]:
                    signal_item = DSignalTreeItem(signal, self.showInternalNameCheckBox)

                    block_item.appendRow(signal_item)

            block_item.sortChildren(0)

            # ----------------------------------
            # Add Subscribers of this DBlock
            # ----------------------------------

            subscriber_ids = dblock.get_subscribers()

            for subscriber_id in subscriber_ids:
                # Other plugin
                subscriber = self.dgui.get_dplugin_by_id(subscriber_id)

                if dplugin.id in subscriber.get_subscribtions():

                    for dblock_sub_id in subscriber.get_subscribtions()[dplugin.id]:


                        subscriber_item = DPluginTreeItem(subscriber)
                        #                self.subscriberModel.appendRow(subscriber_item)
                        self.subscribers_root.appendRow(subscriber_item)

                        subscription = subscriber.get_subscribtions()[dplugin.id][dblock_sub_id]

                        block_item = DBlockTreeItem(dblock)

                        subscriber_item.appendRow(block_item)

                        subscription_item = PaPITreeItem(subscription, "Signals")
                        block_item.appendRow(subscription_item)
                        for signal_uname in sorted(subscription.get_signals()):
                            if signal_uname not in [pc.CORE_TIME_SIGNAL]:
                                signal_item = PaPITreeItem(signal_uname, signal_uname)

                                subscription_item.appendRow(signal_item)


        # -------------------------
        # Add all Subscriptions
        # for this plugin
        # -------------------------

        dplugin_sub_ids = dplugin.get_subscribtions()

        for dplugin_sub_id in dplugin_sub_ids:


            dblock_names = dplugin_sub_ids[dplugin_sub_id]

            dplugin_sub = self.gui_api.gui_data.get_dplugin_by_id(dplugin_sub_id)
            dplugin_sub_item = DPluginTreeItem(dplugin_sub)
            #self.subscriptionModel.appendRow(dplugin_sub_item)
            self.subscriptions_root.appendRow(dplugin_sub_item)

            for dblock_name in dblock_names:

                dblock_sub = dplugin_sub.get_dblock_by_name(dblock_name)
                dblock_sub_item = DBlockTreeItem(dblock_sub)
                dplugin_sub_item.appendRow(dblock_sub_item)

                subscription = dblock_names[dblock_name]

                subscription_item = PaPITreeItem(subscription, "Signals")

                dblock_sub_item.appendRow(subscription_item)

                for signal_uname in sorted(subscription.get_signals()):
                    if signal_uname not in [pc.CORE_TIME_SIGNAL]:
                        signal_item = PaPITreeItem(signal_uname, signal_uname)

                        subscription_item.appendRow(signal_item)

        # --------------------------
        # Add DParameters
        # --------------------------

        dparameter_names = dplugin.get_parameters()
        for dparameter_name in sorted(dparameter_names):
            dparameter = dparameter_names[dparameter_name]
            dparameter_item = DParameterTreeItem(dparameter)
            self.dparameterModel.appendRow(dparameter_item)
            self.parameterTree.resizeColumnToContents(0)
            self.parameterTree.resizeColumnToContents(1)

        self.blockTree.expandAll()
        self.parameterTree.expandAll()
        self.connectionTree.expandAll()

        # http://srinikom.github.io/pyside-docs/PySide/QtGui/QAbstractItemView.html \
        # #PySide.QtGui.PySide.QtGui.QAbstractItemView.SelectionMode
        self.blockTree.setSelectionMode(QAbstractItemView.ExtendedSelection)

        # Sort Models
        self.bModel.sort(0)

    def plugin_item_refresh(self, index):
        """
        This function is called when it's known that the dplugin object, which describes the selected plugin, was changed.

        :param index:
        :return:
        """
        self.parameterTree.viewport().update()
        self.blockTree.viewport().update()
        self.connectionTree.viewport().update()

    def open_context_menu_dplugin_tree(self, position):
        """
        This callback function is called to create a context menu for the dplugin tree.
        It is triggered by use

        :param position:
        :return:
        """
        index = self.pluginTree.indexAt(position)

        if index.parent().isValid() is False:
            return None

        if index.isValid() is False:
            return None

        if self.pluginTree.isIndexHidden(index):
            return

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)

        menu = QMenu('Menu')

        submenu = QMenu('Action')
        menu.addMenu(submenu)
        action = QAction('Remove plugin', self)
        submenu.addAction(action)

        action.triggered.connect(lambda ignore, p=dplugin.id: self.gui_api.do_delete_plugin(p))

        action = QAction('Copy plugin', self)
        submenu.addAction(action)

        action.triggered.connect(lambda ignore, p=dplugin: self.show_create_plugin_dialog(p))

        actionCollapsAll = QAction('Collapse all',self)
        actionCollapsAll.triggered.connect(self.pluginTree.collapseAll)

        actionExpandAll = QAction('Expand all',self)
        actionExpandAll.triggered.connect(self.pluginTree.expandAll)

        menu.addAction(actionCollapsAll)
        menu.addAction(actionExpandAll)

        menu.exec_(self.pluginTree.viewport().mapToGlobal(position))

    def open_context_menu_block_tree(self, position):
        """
        This callback function is called to create a context menu
        for the block tree

        :param position:
        :return:
        """

        index = self.blockTree.indexAt(position)

        if index.isValid() is False:
            return None

        if self.blockTree.isIndexHidden(index):
            return

        item = self.blockTree.model().data(index, Qt.UserRole)

        if isinstance(item, DPlugin) or isinstance(item, DBlock):
            return

        index_sel = self.pluginTree.currentIndex()
        dplugin_sel = self.pluginTree.model().data(index_sel, Qt.UserRole)

        if dplugin_sel is not None:

            sub_menu = QMenu('Add Subscription')
            dplugin_ids = self.dgui.get_all_plugins()

            for dplugin_id in dplugin_ids:
                dplugin = dplugin_ids[dplugin_id]

                if dplugin_sel.id != dplugin_id:
                    action = QAction(self.tr(dplugin.uname), self)
                    sub_menu.addAction(action)
                    action.triggered.connect(lambda ignore, p=dplugin.uname: self.add_subscription_action(p))

            menu = QMenu()
            menu.addMenu(sub_menu)

            menu.exec_(self.blockTree.viewport().mapToGlobal(position))

    def open_context_menu_connection_tree(self, position):
        """
        This callback function is called to create a context menu
        for the subscriper tree

        :param position:
        :return:
        """
        index = self.connectionTree.indexAt(position)

        if index.isValid() is False:
            return None

        if self.connectionTree.isIndexHidden(index):
            return None

        if index.parent().isValid() is False:
            return None

        parIndex = index
        subscriberPart = False
        subscriptionPart = False
        signals = []
        isSignal = False

        while True:
            object = self.connectionTree.model().data(parIndex, Qt.DisplayRole)

            if "Subscribers" in object:
                subscriberPart = True
            if "Subscriptions" in object:
                subscriptionPart = True

            if ( subscriptionPart or subscriberPart ):
                break

            parIndex = parIndex.parent()

            if parIndex.isValid() is False:
                return

        if not (subscriptionPart or subscriberPart):
            return None

        if isinstance(self.connectionTree.model().data(index, Qt.UserRole), DSubscription):
            return

        if isinstance(self.connectionTree.model().data(index, Qt.UserRole), DPlugin):
            return

        # ----------------------------------
        # Open no context menu for signals
        # ----------------------------------

        if isinstance(self.connectionTree.model().data(index, Qt.UserRole), str):
            isSignal = True
        else:
            isSignal = False



        # ----------------------------------
        # Get necessary objects for this subscription/subscriber
        # ----------------------------------

        if isSignal:
            dblock = self.connectionTree.model().data(index.parent().parent(), Qt.UserRole)
            dplugin = self.connectionTree.model().data(index.parent().parent().parent(), Qt.UserRole)
            signal_uname = self.connectionTree.model().data(index, Qt.UserRole)
            signals.append(signal_uname)
        else:
            dblock = self.connectionTree.model().data(index, Qt.UserRole)
            dplugin = self.connectionTree.model().data(index.parent(), Qt.UserRole)

        if subscriberPart:
            action = QAction('Remove Subscriber', self)
            action.triggered.connect(lambda ignore, p=dblock, m=dplugin: self.remove_subscriber_action(m, p))

        if subscriptionPart:
            action = QAction('Remove Subscription', self)
            action.triggered.connect(lambda ignore, p=dblock, m=dplugin, s=signals: self.cancel_subscription_action(m, p, s))

        actionCollapsAll = QAction('Collapse all',self)
        actionCollapsAll.triggered.connect(self.connectionTree.collapseAll)

        actionExpandAll = QAction('Expand all',self)
        actionExpandAll.triggered.connect(self.connectionTree.expandAll)

        menu = QMenu('Remove')
        menu.addAction(action)
        menu.addAction(actionCollapsAll)
        menu.addAction(actionExpandAll)
        menu.exec_(self.connectionTree.viewport().mapToGlobal(position))

    def open_context_menu_parameter_tree(self, position):
        """
        This callback function is called to create a context menu
        for the parameter tree

        :param position:
        :return:
        """

        index = self.parameterTree.indexAt(position)

        if index.isValid() is False:
            return None

        if self.parameterTree.isIndexHidden(index):
            return

        index_sibling = index.sibling(index.row(), index.column()-1)

        if index_sibling.isValid():
            index = index_sibling

        dparameter = self.parameterTree.model().data(index, Qt.UserRole)
        dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(), Qt.UserRole)

        sub_menu = QMenu('Control by')

        dplugin_ids = self.dgui.get_all_plugins()

        for dplugin_id in dplugin_ids:
            dplugin_pcp = dplugin_ids[dplugin_id]

            if len(dplugin_pcp.get_devent()) > 0:
                # action = QAction(self.tr(dplugin.uname), self)
                # sub_menu.addAction(action)
                pcp_menu = QMenu(self.tr(dplugin_pcp.uname), sub_menu)
                sub_menu.addMenu(pcp_menu)

                dblock_pcp_ids = dplugin_pcp.get_dblocks()

                for dblock_pcp_id in dblock_pcp_ids:
                    dblock_pcp = dblock_pcp_ids[dblock_pcp_id]

                    count = len(dblock_pcp.get_subscribers())

                    action = QAction(self.tr(dblock_pcp.name)+' ('+str(count)+')', pcp_menu)
                    pcp_menu.addAction(action)

                    action.triggered.connect(lambda ignore, p1=dplugin, p2=dparameter, p3=dplugin_pcp, p4=dblock_pcp:
                                             self.add_pcp_subscription_action(p1, p2, p3, p4))

        menu = QMenu()
        menu.addMenu(sub_menu)

        menu.exec_(self.parameterTree.viewport().mapToGlobal(position))

    def add_pcp_subscription_action(self, dplugin: DPlugin, dparameter: DParameter, dplugin_pcp: DPlugin,
                                    dblock_pcp: DBlock):
        """
        This function is used to create a subscription for a process control plugin.

        :param dplugin: Subscriber of a pcp plugin
        :param dparameter: Parameter of the subscriber which should be controlled by the pcp plugin.
        :param dplugin_pcp: The pcp plugin
        :param dblock_pcp: Block of the pcp plugin which is used to control the subscriber's parameter.
        :return:
        """
        self.gui_api.do_subscribe(dplugin.id, dplugin_pcp.id, dblock_pcp.name, [], dparameter.name)


    def add_subscription_action(self, dplugin_uname):
        """
        Used to add subscription for a specific dplugin

        :param dplugin_uname: Add Subscription for this DPlugin
        :return:
        """

        signals = []

        dplugin = self.gui_api.gui_data.get_dplugin_by_uname(dplugin_uname)

        indexes = self.blockTree.selectedIndexes()


        for index in indexes:
            if index.isValid():
                signal = self.blockTree.model().data(index, Qt.UserRole)
                signals.append(signal.uname)

        index_dblock = index.parent()

        dblock = self.blockTree.model().data(index_dblock, Qt.UserRole)

        index = self.pluginTree.currentIndex()

        dplugin_source = self.pluginTree.model().data(index, Qt.UserRole)


        self.gui_api.do_subscribe(dplugin.id, dplugin_source.id, dblock.name, signals)

        #self.blockTree.scrollTo(indexes[-1])

    def remove_subscriber_action(self, subscriber: DPlugin, dblock: DBlock):
        """
        Used to remove a subscriber of the dplugin selected in the DPlugin tree.

        :param subscriber: Subscriber which is effected
        :param dblock: DBlock which should be unsubscribed by Subscriber
        :return:
        """
        index = self.pluginTree.currentIndex()
        source = self.pluginTree.model().data(index, Qt.UserRole)
        self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname, dblock.name, [])

    def refresh_action(self, new_dplugin: DPlugin=None):
        """
        Used to refresh the overview menu view.

        :param new_dplugin: New dplugin which should be added in self.dpluginTreev.
        :return:
        """

        # -----------------------------------------
        # case: no DPlugin was added or removed
        #       e.g. parameter was changed
        # -----------------------------------------

        index = self.pluginTree.currentIndex()

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)

        if dplugin is not None:

            if dplugin.state == PLUGIN_STATE_DELETE:
                self.pluginWidget.setDisabled(True)
                self.clear()
            else:
                self.pluginWidget.setEnabled(True)
                self.plugin_item_refresh(index)

        # -----------------------------------------
        # case: remove already deleted plugins
        # -----------------------------------------
        key_copy = self.plugin_roots.copy().keys()
        for root in key_copy:

            self.plugin_roots[root].clean()

            if not self.plugin_roots[root].rowCount():
                self.dpluginModel.remove_item(self.plugin_roots[root])
                del self.plugin_roots[root]

        self.subscribers_root.clean()
        self.subscriptions_root.clean()

        #        self.subscribersTree

        # -----------------------------------------
        # case: a DPlugin was added
        # -----------------------------------------

        if new_dplugin is not None:
            plugin_item = DPluginTreeItem(new_dplugin)
            plugin_root = self.get_plugin_root(new_dplugin.path)

            if not plugin_root.hasItem(new_dplugin):
                plugin_root.appendRow(plugin_item)

            if plugin_root not in self.dpluginModel.findItems("", Qt.MatchContains):
                self.dpluginModel.appendRow(plugin_root)


    def cancel_subscription_action(self, source: DPlugin, dblock: DBlock, signals: []):
        """
        Action called to cancel a subscription of the current selected dplugin.

        :param source:
        :param dblock:
        :return:
        """
        index = self.pluginTree.currentIndex()
        subscriber = self.pluginTree.model().data(index, Qt.UserRole)
        self.gui_api.do_unsubscribe_uname(subscriber.uname, source.uname, dblock.name, signals)

    def showEvent(self, *args, **kwargs):
        """
        ShowEvent of this class.

        :param args:
        :param kwargs:
        :return:
        """
        dplugin_ids = self.dgui.get_all_plugins()

        for dplugin_id in dplugin_ids:
            dplugin = dplugin_ids[dplugin_id]
            # ------------------------------
            # Sort DPluginItem in TreeWidget
            # ------------------------------
            plugin_item = DPluginTreeItem(dplugin)

            plugin_root = self.get_plugin_root(dplugin.path)
            plugin_root.appendRow(plugin_item)

        for root in sorted(self.plugin_roots.keys()):
            self.pluginTree.model().sourceModel().appendRow(self.plugin_roots[root])
            self.plugin_roots[root].sortChildren(0)

        self.pluginTree.expandAll()

    def play_button_callback(self):
        """
        Callback function for the play button.

        :return:
        """
        index = self.pluginTree.currentIndex()
        item = self.pluginTree.model().data(index, Qt.UserRole)
        if item is not None:
            self.gui_api.do_resume_plugin_by_id(item.id)
            self.playButton.setDisabled(True)
            self.pauseButton.setDisabled(False)
            self.stopButton.setDisabled(False)

    def pause_button_callback(self):
        """
        Function pause_button_callback

        :return:
        """
        index = self.pluginTree.currentIndex()
        item = self.pluginTree.model().data(index, Qt.UserRole)
        if item is not None:
            self.pauseButton.setDisabled(True)
            self.playButton.setDisabled(False)
            self.gui_api.do_pause_plugin_by_id(item.id)

    def stop_start_button_callback(self):
        """
        Function stop_start_button_callback

        :return:
        """
        index = self.pluginTree.currentIndex()
        item = self.pluginTree.model().data(index, Qt.UserRole)
        if item is not None:
            if self.stopButton.text() == 'STOP':
                self.gui_api.do_stopReset_pluign(item.id)
                self.stopButton.setText('START')
                self.pauseButton.setDisabled(True)
                self.playButton.setDisabled(True)
                self.stopButton.setDisabled(False)

            else:
                self.gui_api.do_start_plugin(item.id)
                self.stopButton.setText('STOP')
                self.pauseButton.setDisabled(False)
                self.playButton.setDisabled(False)
                self.stopButton.setDisabled(False)

    def show_internal_name_callback(self):
        """
        Callback function for 'showInternalNameCheckBox'

        :return:
        """
        self.plugin_item_changed(self.pluginTree.currentIndex())

    def data_changed_parameter_model(self, index, n):
        """
        This function is called when a dparameter value is changed by editing the 'value'-column.

        :param index: Index of current changed dparameter
        :param n: None
        :return:
        """

        dparameter = self.parameterTree.model().data(index, Qt.UserRole)
        index = self.pluginTree.currentIndex()

        dplugin = self.pluginTree.model().data(index, Qt.UserRole)

        self.gui_api.do_set_parameter(dplugin.id, dparameter.name, dparameter.value)

    def data_changed_block_model(self, index, n):
        """
        This function is called when a dblock child, a disgnal, is changed.

        :param index: Index of current changed dsignal object
        :param n: None
        :return:
        """

        dsignal = self.blockTree.model().data(index, Qt.UserRole)
        dblock  = self.blockTree.model().data(index.parent(), Qt.UserRole)

        dplugin = self.pluginTree.model().data(self.pluginTree.currentIndex(), Qt.UserRole)

        self.gui_api.do_edit_plugin_uname(dplugin.uname, dblock, {"edit" : dsignal})

    def get_plugin_root(self,path):
        parts = path.split('/');
        part = parts[-3]
        name = part
        if part not in self.plugin_roots:

            cfg_file = str.join("/", parts[0:-2]) + "/" + pc.GUI_PLUGIN_CONFIG



            if os.path.isfile(cfg_file):
                config = configparser.ConfigParser()
                config.read(cfg_file)
                if 'Config' in config.sections():
                    if 'name' in config.options('Config'):
                        name = config.get('Config', 'name')

            self.plugin_roots[part] = PaPIRootItem(name)

        return self.plugin_roots[part]

    def changed_search_plugin_text_field(self, value):
        if not len(value):
            value = "*"
            self.pluginTree.collapseAll()
        else:
            value = "*" + value + "*"
            self.pluginTree.expandAll()

        self.pluginProxyModel.sourceModel().mark_visibility_by_name(value)

        # Used to trigger filter action
        regex = QRegExp(value, Qt.CaseInsensitive, QRegExp.Wildcard)
        self.pluginProxyModel.setFilterRegExp(regex)

    def show_create_plugin_dialog(self, dplugin):

        if dplugin.type == PLUGIN_VIP_IDENTIFIER:
            dplugin.startup_config = dplugin.plugin.pl_get_current_config()

        self.plugin_create_dialog.set_dplugin(dplugin, dplugin.plugin._get_startup_configuration(), dplugin.type)
        self.plugin_create_dialog.show()

    def keyPressEvent(self, event):
        """
        Used to handle key events for this gui element.

        :param event: KeyEvent
        :return:
        """
        if event.key() == Qt.Key_Escape:
            self.close()

        if self.pluginTree.hasFocus() and \
                        event.key() in [Qt.Key_Return, Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right]:
            self.plugin_item_changed(self.pluginTree.currentIndex())

        # if search bar has focus and user pressed enter/return,arrow up/down, change focus to the plugin tree
        if (event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter or event.key() == Qt.Key_Down \
            or event.key() == Qt.Key_Up) and self.pluginSearchText.hasFocus():
            self.pluginTree.setFocus(Qt.OtherFocusReason)

    def changed_dplugin_tree_selection(self, new_selection, old_selection):
        pass