Example #1
0
    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)
Example #2
0
    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)
Example #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
Example #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