Пример #1
0
 def invalidateFilter(self):
     """
     Invalidates the filter
     """
     QSortFilterProxyModel.invalidateFilter(self)
     # invalidate cache
     self.filterAcceptsRow.cache_clear()
Пример #2
0
 def invalidateFilter(self):
     """
     Invalidates the filter
     """
     QSortFilterProxyModel.invalidateFilter(self)
     #invalidate cache
     self.filterAcceptsRow.cache_clear()
Пример #3
0
 def __init__(self, parent=None):
     '''
     Creates the window, connects the signals and init the class.
     '''
     QDockWidget.__init__(self, parent)
     # initialize parameter
     self.__current_path = os.path.expanduser('~')
     # load the UI file
     ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                            'LaunchFilesDockWidget.ui')
     loadUi(ui_file,
            self,
            custom_widgets={'EnhancedLineEdit': EnhancedLineEdit})
     self._current_search = ''
     pal = self.palette()
     self._default_color = pal.color(QPalette.Window)
     # initialize the progress queue
     self.progress_queue = ProgressQueue(self.ui_frame_progress_cfg,
                                         self.ui_bar_progress_cfg,
                                         self.ui_button_progress_cancel_cfg,
                                         'Launch File')
     # initialize the view for the launch files
     self.launchlist_model = LaunchListModel(
         progress_queue=self.progress_queue, viewobj=self.ui_file_view)
     self.launchlist_proxy_model = QSortFilterProxyModel(self)
     self.launchlist_proxy_model.setSourceModel(self.launchlist_model)
     self.name_delegate = HTMLDelegate(check_for_ros_names=False,
                                       palette=self.palette())
     self.ui_file_view.setItemDelegateForColumn(0, self.name_delegate)
     self.ui_file_view.setModel(self.launchlist_proxy_model)
     self.ui_file_view.setAlternatingRowColors(True)
     self.ui_file_view.activated.connect(self.on_launch_selection_activated)
     self.ui_file_view.setDragDropMode(QAbstractItemView.DragOnly)
     self.ui_file_view.setDragEnabled(True)
     sm = self.ui_file_view.selectionModel()
     sm.selectionChanged.connect(self.on_ui_file_view_selection_changed)
     self.launchlist_model.pathlist_handled.connect(
         self.on_pathlist_handled)
     self.launchlist_model.error_on_path.connect(self.on_error_on_path)
     self.ui_search_line.refresh_signal.connect(self.set_package_filter)
     self.ui_search_line.stop_signal.connect(self.stop)
     # connect to the button signals
     self.ui_button_reload.clicked.connect(self.on_reload_clicked)
     self.ui_button_edit.clicked.connect(self.on_edit_xml_clicked)
     self.ui_button_new.clicked.connect(self.on_new_xml_clicked)
     self.ui_button_transfer.clicked.connect(self.on_transfer_file_clicked)
     self.ui_button_save_profile.clicked.connect(
         self.on_save_profile_clicked)
     self.ui_button_load.clicked.connect(self.on_load_xml_clicked)
     self._masteruri2name = {}
     self._reload_timer = None
Пример #4
0
 def __init__(self, parent=None):
     '''
     Creates the window, connects the signals and init the class.
     '''
     QDockWidget.__init__(self, parent)
     # initialize parameter
     self.__current_path = os.path.expanduser('~')
     # load the UI file
     ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                            'LaunchFilesDockWidget.ui')
     loadUi(ui_file, self)
     # initialize the view for the launch files
     self.launchlist_model = LaunchListModel()
     self.launchlist_proxyModel = QSortFilterProxyModel(self)
     self.launchlist_proxyModel.setSourceModel(self.launchlist_model)
     self.xmlFileView.setModel(self.launchlist_proxyModel)
     self.xmlFileView.setAlternatingRowColors(True)
     self.xmlFileView.activated.connect(self.on_launch_selection_activated)
     self.xmlFileView.setDragDropMode(QAbstractItemView.DragOnly)
     self.xmlFileView.setDragEnabled(True)
     sm = self.xmlFileView.selectionModel()
     sm.selectionChanged.connect(self.on_xmlFileView_selection_changed)
     #    self.searchPackageLine.setVisible(False)
     self.searchPackageLine.textChanged.connect(self.set_package_filter)
     self.searchPackageLine.focusInEvent = self._searchline_focusInEvent
     # connect to the button signals
     self.refreshXmlButton.clicked.connect(self.on_refresh_xml_clicked)
     self.editXmlButton.clicked.connect(self.on_edit_xml_clicked)
     self.newXmlButton.clicked.connect(self.on_new_xml_clicked)
     self.openXmlButton.clicked.connect(self.on_open_xml_clicked)
     self.transferButton.clicked.connect(self.on_transfer_file_clicked)
     self.loadXmlButton.clicked.connect(self.on_load_xml_clicked)
     self.loadXmlAsDefaultButton.clicked.connect(self.on_load_as_default)
     # creates a default config menu
     start_menu = QMenu(self)
     self.loadDeafaultAtHostAct = QAction(
         "&Load default config on host",
         self,
         statusTip="Loads the default config at given host",
         triggered=self.on_load_as_default_at_host)
     start_menu.addAction(self.loadDeafaultAtHostAct)
     self.loadXmlAsDefaultButton.setMenu(start_menu)
     # initialize the progress queue
     self.progress_queue = ProgressQueue(self.progressFrame_cfg,
                                         self.progressBar_cfg,
                                         self.progressCancelButton_cfg,
                                         'Launch File')
 def __init__(self, parent=None):
     '''
     Creates the window, connects the signals and init the class.
     '''
     QDockWidget.__init__(self, parent)
     # load the UI file
     settings_dock_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'SettingsDockWidget.ui')
     loadUi(settings_dock_file, self)
     # initialize the settings view model
     self.settings_model = SettingsModel()
     self.settings_proxyModel = QSortFilterProxyModel(self)
     self.settings_proxyModel.setSourceModel(self.settings_model)
     self.settingsTreeView.setModel(self.settings_proxyModel)
     self.settingsTreeView.setAlternatingRowColors(True)
     for i, (_, width) in enumerate(SettingsModel.header):
         self.settingsTreeView.setColumnWidth(i, width)
     self.item_delegate = ItemDelegate()
     self.item_delegate.settings_path_changed_signal.connect(self.reload_settings)
     self.settingsTreeView.setItemDelegateForColumn(1, self.item_delegate)
     self.reload_settings()
Пример #6
0
    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # add a filter model to filter matching items
        self.filter_model = QSortFilterProxyModel(self)
        self.filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter_model.setSourceModel(self.model())

        # add a completer, which uses the filter model
        self.completer = QCompleter(self.filter_model, self)
        # always show all (filtered) completions
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # connect signals
        self.lineEdit().textEdited[unicode].connect(self.filter_model.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)
        self.setItems.connect(self.onSetItems)
Пример #7
0
    def filterAcceptsRow(self, source_row, source_parent):
        """
        Tells by analysing the given row if it should be shown or not. This behaviour can be modified via setFilterRegExp
         method so that e.g. only the entries of a specific host can be shown.

        :param source_row: the source row
        :type source_row: int
        :param source_parent: the source of the parent
        :type source_parent: QModelIndex

        :returns: bool
        """
        return QSortFilterProxyModel.filterAcceptsRow(self, source_row, source_parent)
Пример #8
0
    def filterAcceptsRow(self, source_row, source_parent):
        """
        Tells by analysing the given row if it should be shown or not. This behaviour can be modified via setFilterRegExp
         method so that e.g. only the entries of a specific host can be shown.

        :param source_row: the source row
        :type source_row: int
        :param source_parent: the source of the parent
        :type source_parent: QModelIndex

        :returns: bool
        """
        return QSortFilterProxyModel.filterAcceptsRow(self, source_row,
                                                      source_parent)
Пример #9
0
class ExtendedComboBox(QComboBox):
    setItems = Signal(list)

    def __init__(self, parent=None):
        super(ExtendedComboBox, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setEditable(True)

        # add a filter model to filter matching items
        self.filter_model = QSortFilterProxyModel(self)
        self.filter_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.filter_model.setSourceModel(self.model())

        # add a completer, which uses the filter model
        self.completer = QCompleter(self.filter_model, self)
        # always show all (filtered) completions
        self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
        self.setCompleter(self.completer)

        # connect signals
        self.lineEdit().textEdited[unicode].connect(self.filter_model.setFilterFixedString)
        self.completer.activated.connect(self.on_completer_activated)
        self.setItems.connect(self.onSetItems)

    # on selection of an item from the completer, select the corresponding item from combobox
    def on_completer_activated(self, text):
        if text:
            index = self.findText(text)
            self.setCurrentIndex(index)

    # on model change, update the models of the filter and completer as well
    def setModel(self, model):
        super(ExtendedComboBox, self).setModel(model)
        self.filter_model.setSourceModel(model)
        self.completer.setModel(self.filter_model)

    # on model column change, update the model column of the filter and completer as well
    def setModelColumn(self, column):
        self.completer.setCompletionColumn(column)
        self.filter_model.setFilterKeyColumn(column)
        super(ExtendedComboBox, self).setModelColumn(column)

    @Slot(list)
    def onSetItems(self, items):
        self.clear()
        self.addItems(items)
Пример #10
0
 def __init__(self, parent=None):
     '''
     Creates the window, connects the signals and init the class.
     '''
     QDockWidget.__init__(self, parent)
     # load the UI file
     settings_dock_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'SettingsDockWidget.ui')
     loadUi(settings_dock_file, self)
     # initialize the settings view model
     self.settings_model = SettingsModel()
     self.settings_proxyModel = QSortFilterProxyModel(self)
     self.settings_proxyModel.setSourceModel(self.settings_model)
     self.settingsTreeView.setModel(self.settings_proxyModel)
     self.settingsTreeView.setAlternatingRowColors(True)
     for i, (_, width) in enumerate(SettingsModel.header):
         self.settingsTreeView.setColumnWidth(i, width)
     self.item_delegate = ItemDelegate()
     self.item_delegate.settings_path_changed_signal.connect(self.reload_settings)
     self.settingsTreeView.setItemDelegateForColumn(1, self.item_delegate)
     self.reload_settings()
Пример #11
0
    def __init__(self, parent=None):
        '''
        Creates the window, connects the signals and init the class.
        '''
        QDockWidget.__init__(self, parent)
        # initialize parameter
        self.__current_path = os.path.expanduser('~')
        # load the UI file
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'LaunchFilesDockWidget.ui')
        loadUi(ui_file, self)
        # initialize the view for the launch files
        self.launchlist_model = LaunchListModel()
        self.launchlist_proxyModel = QSortFilterProxyModel(self)
        self.launchlist_proxyModel.setSourceModel(self.launchlist_model)
        self.xmlFileView.setModel(self.launchlist_proxyModel)
        self.xmlFileView.setAlternatingRowColors(True)
        self.xmlFileView.activated.connect(self.on_launch_selection_activated)
        self.xmlFileView.setDragDropMode(QAbstractItemView.DragOnly)
        self.xmlFileView.setDragEnabled(True)
        sm = self.xmlFileView.selectionModel()
        sm.selectionChanged.connect(self.on_xmlFileView_selection_changed)
#    self.searchPackageLine.setVisible(False)
        self.searchPackageLine.textChanged.connect(self.set_package_filter)
        self.searchPackageLine.focusInEvent = self._searchline_focusInEvent
        # connect to the button signals
        self.refreshXmlButton.clicked.connect(self.on_refresh_xml_clicked)
        self.editXmlButton.clicked.connect(self.on_edit_xml_clicked)
        self.newXmlButton.clicked.connect(self.on_new_xml_clicked)
        self.openXmlButton.clicked.connect(self.on_open_xml_clicked)
        self.transferButton.clicked.connect(self.on_transfer_file_clicked)
        self.loadXmlButton.clicked.connect(self.on_load_xml_clicked)
        self.loadXmlAsDefaultButton.clicked.connect(self.on_load_as_default)
        # creates a default config menu
        start_menu = QMenu(self)
        self.loadDeafaultAtHostAct = QAction("&Load default config on host", self, statusTip="Loads the default config at given host", triggered=self.on_load_as_default_at_host)
        start_menu.addAction(self.loadDeafaultAtHostAct)
        self.loadXmlAsDefaultButton.setMenu(start_menu)
        # initialize the progress queue
        self.progress_queue = ProgressQueue(self.progressFrame_cfg, self.progressBar_cfg, self.progressCancelButton_cfg)
Пример #12
0
    def filterAcceptsRow(self, source_row, source_parent):
        """
        Tells by analysing the given row if it should be shown or not. This behaviour can be modified via
        setFilterRegExp method so that e.g. only the entries of a specific host can be shown.

        :param source_row: the source of the parent
        :type source_row: int
        :param source_parent: the source of the parent
        :type source_parent: QModelIndex

        :returns: True if the row should be shown
        :rtype: bool
        """
        entries = []
        item = source_parent.internalPointer()
        child = None
        if item is not None:
            if isinstance(item, TreeTopicItem):
                child = item.get_child(source_row, self.sourceModel().parent(
                    source_parent).internalPointer())
            else:
                child = source_parent.internalPointer().get_child(source_row)
            entries = [child.get_type(), child.get_seuid(), child.get_state(), child.get_short_data()]
        else:
            child = self.sourceModel().get_root_item().get_child(source_row)
            entries = [child.get_type(), child.get_seuid(), child.get_state(), child.get_short_data()]

        child_childs = child.get_childs( self.sourceModel().parent(
                    source_parent).internalPointer())

        for i in range(0, len(child_childs)):
            if self.filterAcceptsRow(i, self.sourceModel().index(source_row, 0, source_parent)):
                return True

        correct_type = False
        data = entries[0]

        if data[0] == "h":
            correct_type = True
        elif self.__show_nodes and data[0] == "n":
            correct_type = True
        elif self.__show_connections and data[0] == "c":
            if self.__show_subscribers:
                correct_type = True
            else:
                if child.is_subscriber:
                    correct_type = False
                else:
                    correct_type = True
        elif self.__show_topics is True:
            if data[0] == "t":
                correct_type = True

        if correct_type is False:
            return False

        if self.__hide_debug is True:
            for entry in self.__quiet_names:
                if entries[1].find(entry) is not -1:
                    return False


        # todo: speed this implementation a lot up by not using the model!!!
        if self.__filter_string is not "":
            for i in range(0, len(entries)):
                if self.__filter_string in entries[i]:
                    return QSortFilterProxyModel.filterAcceptsRow(self, source_row, source_parent)
            return False
        return QSortFilterProxyModel.filterAcceptsRow(self, source_row, source_parent)
Пример #13
0
class SettingsWidget(QDockWidget):
    '''
    Settings widget to handle the settings changes. The changes will direct change
    the settings of the GUI.
    '''
    def __init__(self, parent=None):
        '''
        Creates the window, connects the signals and init the class.
        '''
        QDockWidget.__init__(self, parent)
        # load the UI file
        settings_dock_file = os.path.join(
            os.path.dirname(os.path.realpath(__file__)),
            'SettingsDockWidget.ui')
        loadUi(settings_dock_file, self)
        # initialize the settings view model
        self.settings_model = SettingsModel()
        self.settings_proxyModel = QSortFilterProxyModel(self)
        self.settings_proxyModel.setSourceModel(self.settings_model)
        self.settingsTreeView.setModel(self.settings_proxyModel)
        self.settingsTreeView.setAlternatingRowColors(True)
        for i, (_, width) in enumerate(SettingsModel.header):
            self.settingsTreeView.setColumnWidth(i, width)
        self.item_delegate = ItemDelegate()
        self.item_delegate.settings_path_changed_signal.connect(
            self.reload_settings)
        self.settingsTreeView.setItemDelegateForColumn(1, self.item_delegate)
        self.reload_settings()

    def reload_settings(self):
        '''
        Load the current settings data into the model. The settings itself will not
        be loaded.
        '''
        settings = {
            'Default user:'******'value':
                nm.settings().default_user,
                'settings':
                nm.settings(),
                'attrname':
                'default_user',
                'value_default':
                nm.settings().USER_DEFAULT,
                'tooltip':
                '<p>The user used for ssh connection to remote hosts</p>'
            }, ),
            'Launch history length:': ({
                'value':
                nm.settings().launch_history_length,
                'settings':
                nm.settings(),
                'attrname':
                'launch_history_length',
                'value_default':
                nm.settings().LAUNCH_HISTORY_LENGTH,
                'value_min':
                0,
                'value_max':
                25,
                'tooltip':
                '<p>The count of recent '
                'loaded launch files displayed in the root '
                'of the <span style=" font-weight:600;">launch '
                'files</span> view.</p>'
            }, ),
            'Param history length:': ({
                'value':
                nm.settings().param_history_length,
                'settings':
                nm.settings(),
                'attrname':
                'param_history_length',
                'value_default':
                nm.settings().PARAM_HISTORY_LENGTH,
                'value_min':
                0,
                'value_max':
                25,
                'tooltip':
                '<p>The count of parameters stored which '
                'are entered in a parameter dialog (Launch file arguments, '
                'paramter server, publishing to a topic, service call)</p>'
            }, ),
            'Settings path:': ({
                'value': nm.settings().cfg_path,
                'settings': nm.settings(),
                'attrname': 'cfg_path',
                'edit_type': SettingsValueItem.EDIT_TYPE_FOLDER,
                'value_default': nm.settings().CFG_PATH,
                'tooltip': ''
            }, ),
            'Robot icon path:': ({
                'value':
                nm.settings().robots_path,
                'settings':
                nm.settings(),
                'attrname':
                'robots_path',
                'edit_type':
                SettingsValueItem.EDIT_TYPE_FOLDER,
                'value_default':
                nm.settings().ROBOTS_DIR,
                'tooltip':
                '<p>The path to the folder with robot images '
                '(<span style=" font-weight:600;">.png</span>).'
                'The images with robot name will be displayed in the '
                'info bar.</p>'
            }, ),
            'Show files extensions:': ({
                'value':
                ', '.join(nm.settings().launch_view_file_ext),
                'settings':
                nm.settings(),
                'attrname':
                'launch_view_file_ext',
                'value_default':
                ', '.join(nm.settings().LAUNCH_VIEW_EXT),
                'tooltip':
                '<p>Files that are displayed next to Launch '
                'files in the <span style="font-weight:600;">'
                'launch files</span> view</p>'
            }, ),
            'Store window layout:': ({
                'value': nm.settings().store_geometry,
                'settings': nm.settings(),
                'attrname': 'store_geometry',
                'value_default': nm.settings().STORE_GEOMETRY,
                'tooltip': ''
            }, ),
            'Movable dock widgets:': ({
                'value': nm.settings().movable_dock_widgets,
                'settings': nm.settings(),
                'attrname': 'movable_dock_widgets',
                'value_default': nm.settings().MOVABLE_DOCK_WIDGETS,
                'tooltip':
                'On false you can\'t reorganize docking widgets. Needs restart!',
                'need_restart': True
            }, ),
            'Max time difference:': ({
                'value':
                nm.settings().max_timediff,
                'settings':
                nm.settings(),
                'attrname':
                'max_timediff',
                'value_default':
                nm.settings().MAX_TIMEDIFF,
                'value_step':
                0.1,
                'tooltip':
                '<p>Shows a warning if the time difference to '
                'remote host is greater than this value</p>'
            }, ),
            'Autoupdate:': ({
                'value':
                nm.settings().autoupdate,
                'settings':
                nm.settings(),
                'attrname':
                'autoupdate',
                'value_default':
                nm.settings().AUTOUPDATE,
                'tooltip':
                '<p>By default node manager updates the current '
                'state on changes. You can deactivate this behavior to '
                'reduce the network load. If autoupdate is deactivated '
                'you must refresh the state manually.</p>'
            }, ),
            'Start sync with discovery:': ({
                'value':
                nm.settings().start_sync_with_discovery,
                'settings':
                nm.settings(),
                'attrname':
                'start_sync_with_discovery',
                'value_default':
                nm.settings().START_SYNC_WITH_DISCOVERY,
                'tooltip':
                "<p>Sets 'start sync' in 'Start' master discovery "
                "dialog to True, if this option is set to true.</p>"
            }, ),
            'Confirm exit when closing:': ({
                'value':
                nm.settings().confirm_exit_when_closing,
                'settings':
                nm.settings(),
                'attrname':
                'confirm_exit_when_closing',
                'value_default':
                nm.settings().CONFIRM_EXIT_WHEN_CLOSING,
                'tooltip':
                "<p>Shows on closing of node_manager a dialog to stop "
                "all ROS nodes if this option is set to true.</p>"
            }, ),
            'Highlight xml blocks:': ({
                'value':
                nm.settings().highlight_xml_blocks,
                'settings':
                nm.settings(),
                'attrname':
                'highlight_xml_blocks',
                'value_default':
                nm.settings().HIGHLIGHT_XML_BLOCKS,
                'tooltip':
                "<p>Highlights the current selected XML block, while "
                "editing ROS launch file.</p>"
            }, ),
            'Colorize hosts:': ({
                'value':
                nm.settings().colorize_hosts,
                'settings':
                nm.settings(),
                'attrname':
                'colorize_hosts',
                'value_default':
                nm.settings().COLORIZE_HOSTS,
                'tooltip':
                "<p>Determine automatic a default color for each host if True. "
                "Manually setted color will be prefered. You can select the color by "
                "double-click on hostname in description panel. To remove a setted color "
                "delete it manually from $HOME/.ros/node_manager/settings.ini</p>"
            }, ),
            'Check for nodelets at start:': ({
                'value':
                nm.settings().check_for_nodelets_at_start,
                'settings':
                nm.settings(),
                'attrname':
                'check_for_nodelets_at_start',
                'value_default':
                nm.settings().CHECK_FOR_NODELETS_AT_START,
                'tooltip':
                "Test the startlist for nodelet manager and all nodelets. "
                "If one of the nodes is not in the list a dialog is displayed with "
                "proposal to start other nodes, too.</p>"
            }, ),
            'Show noscreen error:': ({
                'value':
                nm.settings().show_noscreen_error,
                'settings':
                nm.settings(),
                'attrname':
                'show_noscreen_error',
                'value_default':
                nm.settings().SHOW_NOSCREEN_ERROR,
                'tooltip':
                "Shows an error if requested screen for a node is not available.</p>"
            }, ),
            'Show domain suffix:': ({
                'value':
                nm.settings().show_domain_suffix,
                'settings':
                nm.settings(),
                'attrname':
                'show_domain_suffix',
                'value_default':
                nm.settings().SHOW_DOMAIN_SUFFIX,
                'tooltip':
                "<p>Shows the domain suffix of the host in the host description"
                " panel and node tree view.</p>"
            }, ),
            'Transpose pub/sub description:': ({
                'value':
                nm.settings().transpose_pub_sub_descr,
                'settings':
                nm.settings(),
                'attrname':
                'transpose_pub_sub_descr',
                'value_default':
                nm.settings().TRANSPOSE_PUB_SUB_DESCR,
                'tooltip':
                "<p>Transpose publisher/subscriber in description dock.</p>"
            }, )
        }
        self.settings_model.init_settings(settings)
        #    self.settingsTreeView.setSortingEnabled(True)
        self.settingsTreeView.sortByColumn(0, Qt.AscendingOrder)
        self.settingsTreeView.expandAll()
Пример #14
0
class LaunchFilesWidget(QDockWidget):
    '''
    Launch file browser.
    '''

    load_signal = Signal(str)
    ''' load the launch file '''
    load_as_default_signal = Signal(str, str)
    ''' load the launch file as default (path, host) '''
    edit_signal = Signal(list)
    ''' list of paths to open in an editor '''
    transfer_signal = Signal(list)
    ''' list of paths selected for transfer '''

    def __init__(self, parent=None):
        '''
        Creates the window, connects the signals and init the class.
        '''
        QDockWidget.__init__(self, parent)
        # initialize parameter
        self.__current_path = os.path.expanduser('~')
        # load the UI file
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'LaunchFilesDockWidget.ui')
        loadUi(ui_file, self)
        # initialize the view for the launch files
        self.launchlist_model = LaunchListModel()
        self.launchlist_proxyModel = QSortFilterProxyModel(self)
        self.launchlist_proxyModel.setSourceModel(self.launchlist_model)
        self.xmlFileView.setModel(self.launchlist_proxyModel)
        self.xmlFileView.setAlternatingRowColors(True)
        self.xmlFileView.activated.connect(self.on_launch_selection_activated)
        self.xmlFileView.setDragDropMode(QAbstractItemView.DragOnly)
        self.xmlFileView.setDragEnabled(True)
        sm = self.xmlFileView.selectionModel()
        sm.selectionChanged.connect(self.on_xmlFileView_selection_changed)
#    self.searchPackageLine.setVisible(False)
        self.searchPackageLine.textChanged.connect(self.set_package_filter)
        self.searchPackageLine.focusInEvent = self._searchline_focusInEvent
        # connect to the button signals
        self.refreshXmlButton.clicked.connect(self.on_refresh_xml_clicked)
        self.editXmlButton.clicked.connect(self.on_edit_xml_clicked)
        self.newXmlButton.clicked.connect(self.on_new_xml_clicked)
        self.openXmlButton.clicked.connect(self.on_open_xml_clicked)
        self.transferButton.clicked.connect(self.on_transfer_file_clicked)
        self.loadXmlButton.clicked.connect(self.on_load_xml_clicked)
        self.loadXmlAsDefaultButton.clicked.connect(self.on_load_as_default)
        # creates a default config menu
        start_menu = QMenu(self)
        self.loadDeafaultAtHostAct = QAction("&Load default config on host", self, statusTip="Loads the default config at given host", triggered=self.on_load_as_default_at_host)
        start_menu.addAction(self.loadDeafaultAtHostAct)
        self.loadXmlAsDefaultButton.setMenu(start_menu)
        # initialize the progress queue
        self.progress_queue = ProgressQueue(self.progressFrame_cfg, self.progressBar_cfg, self.progressCancelButton_cfg)

    def stop(self):
        '''
        Cancel the executing queued actions. This method must be
        called at the exit!
        '''
        self.progress_queue.stop()

    def on_launch_selection_activated(self, activated):
        '''
        Tries to load the launch file, if one was activated.
        '''
        selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False)
        for item in selected:
            try:
                lfile = self.launchlist_model.expandItem(item.name, item.path, item.id)
                self.searchPackageLine.setText('')
                if lfile is not None:
                    if item.isLaunchFile():
                        self.launchlist_model.add2LoadHistory(item.path)
                        key_mod = QApplication.keyboardModifiers()
                        if key_mod & Qt.ShiftModifier:
                            self.load_as_default_signal.emit(item.path, None)
                        elif key_mod & Qt.ControlModifier:
                            self.launchlist_model.setPath(os.path.dirname(item.path))
                        else:
                            self.load_signal.emit(item.path)
                    elif item.isConfigFile():
                        self.edit_signal.emit([lfile])
            except Exception as e:
                rospy.logwarn("Error while load launch file %s: %s" % (item, e))
                WarningMessageBox(QMessageBox.Warning, "Load error",
                                  'Error while load launch file:\n%s' % item.name,
                                  "%s" % e).exec_()
#        self.launchlist_model.reloadCurrentPath()

    def on_xmlFileView_selection_changed(self, selected, deselected):
        '''
        On selection of a launch file, the buttons are enabled otherwise disabled.
        '''
        selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False)
        for item in selected:
            islaunch = item.isLaunchFile()
            isconfig = item.isConfigFile()
            self.editXmlButton.setEnabled(islaunch or isconfig)
            self.loadXmlButton.setEnabled(islaunch)
            self.transferButton.setEnabled(islaunch or isconfig)
            self.loadXmlAsDefaultButton.setEnabled(islaunch)

    def set_package_filter(self, text):
        self.launchlist_proxyModel.setFilterRegExp(QRegExp(text,
                                                           Qt.CaseInsensitive,
                                                           QRegExp.Wildcard))

    def on_refresh_xml_clicked(self):
        '''
        Reload the current path.
        '''
        self.launchlist_model.reloadCurrentPath()
        self.launchlist_model.reloadPackages()
        self.editXmlButton.setEnabled(False)
        self.loadXmlButton.setEnabled(False)
        self.transferButton.setEnabled(False)
        self.loadXmlAsDefaultButton.setEnabled(False)

    def on_edit_xml_clicked(self):
        '''
        Opens an XML editor to edit the launch file.
        '''
        selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False)
        for item in selected:
            path = self.launchlist_model.expandItem(item.name, item.path, item.id)
            if path is not None:
                self.edit_signal.emit([path])

    def on_new_xml_clicked(self):
        '''
        Creates a new launch file.
        '''
        # get new file from open dialog, use last path if one exists
        open_path = self.__current_path
        if self.launchlist_model.currentPath is not None:
            open_path = self.launchlist_model.currentPath
        (fileName, _) = QFileDialog.getSaveFileName(self,
                                                    "New launch file",
                                                    open_path,
                                                    "Config files (*.launch *.yaml);;All files (*)")
        if fileName:
            try:
                (pkg, _) = package_name(os.path.dirname(fileName))  # _:=pkg_path
                if pkg is None:
                    WarningMessageBox(QMessageBox.Warning, "New File Error",
                                      'The new file is not in a ROS package').exec_()
                    return
                with open(fileName, 'w+') as f:
                    f.write("<launch>\n"
                            "  <arg name=\"robot_ns\" default=\"my_robot\"/>\n"
                            "  <group ns=\"$(arg robot_ns)\">\n"
                            "    <param name=\"tf_prefix\" value=\"$(arg robot_ns)\"/>\n"
                            "\n"
                            "    <node pkg=\"my_pkg\" type=\"my_node\" name=\"my_name\" >\n"
                            "      <param name=\"capability_group\" value=\"MY_GROUP\"/>\n"
                            "    </node>\n"
                            "  </group>\n"
                            "</launch>\n"
                            )
                self.__current_path = os.path.dirname(fileName)
                self.launchlist_model.setPath(self.__current_path)
                self.edit_signal.emit([fileName])
            except EnvironmentError as e:
                WarningMessageBox(QMessageBox.Warning, "New File Error",
                                  'Error while create a new file',
                                  '%s' % e).exec_()

    def on_open_xml_clicked(self):
        (fileName, _) = QFileDialog.getOpenFileName(self,
                                                    "Load launch file",
                                                    self.__current_path,
                                                    "Config files (*.launch);;All files (*)")
        if fileName:
            self.__current_path = os.path.dirname(fileName)
            self.launchlist_model.add2LoadHistory(fileName)
            self.load_signal.emit(fileName)

    def on_transfer_file_clicked(self):
        '''
        Emit the signal to copy the selected file to a remote host.
        '''
        selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False)
        paths = list()
        for item in selected:
            path = self.launchlist_model.expandItem(item.name, item.path, item.id)
            if path is not None:
                paths.append(path)
        if paths:
            self.transfer_signal.emit(paths)

    def on_load_xml_clicked(self):
        '''
        Tries to load the selected launch file. The button is only enabled and this
        method is called, if the button was enabled by on_launch_selection_clicked()
        '''
        selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False)
        for item in selected:
            path = self.launchlist_model.expandItem(item.name, item.path, item.id)
            if path is not None:
                self.launchlist_model.add2LoadHistory(path)
                self.load_signal.emit(path)

    def on_load_as_default_at_host(self):
        '''
        Tries to load the selected launch file as default configuration. The button
        is only enabled and this method is called, if the button was enabled by
        on_launch_selection_clicked()
        '''
        selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False)
        for item in selected:
            path = self.launchlist_model.expandItem(item.name, item.path, item.id)
            if path is not None:
                params = {'Host': ('string', 'localhost')}
                dia = ParameterDialog(params)
                dia.setFilterVisible(False)
                dia.setWindowTitle('Start node on...')
                dia.resize(350, 120)
                dia.setFocusField('Host')
                if dia.exec_():
                    try:
                        params = dia.getKeywords()
                        host = params['Host']
                        rospy.loginfo("LOAD the launch file on host %s as default: %s" % (host, path))
                        self.launchlist_model.add2LoadHistory(path)
                        self.load_as_default_signal.emit(path, host)
                    except Exception, e:
                        WarningMessageBox(QMessageBox.Warning, "Load default config error",
                                          'Error while parse parameter',
                                          '%s' % e).exec_()
Пример #15
0
    def filterAcceptsRow(self, source_row, source_parent):
        """
        Tells by analysing the given row if it should be shown or not. This behaviour can be modified via
        setFilterRegExp method so that e.g. only the entries of a specific host can be shown.

        :param source_row: the source of the parent
        :type source_row: int
        :param source_parent: the source of the parent
        :type source_parent: QModelIndex

        :returns: True if the row should be shown
        :rtype: bool
        """
        entries = []
        item = source_parent.internalPointer()
        child = None
        if item is not None:
            if isinstance(item, TreeTopicItem):
                child = item.get_child(
                    source_row,
                    self.sourceModel().parent(source_parent).internalPointer())
            else:
                child = source_parent.internalPointer().get_child(source_row)
            entries = [
                child.get_type(),
                child.get_seuid(),
                child.get_state(),
                child.get_short_data()
            ]
        else:
            child = self.sourceModel().get_root_item().get_child(source_row)
            entries = [
                child.get_type(),
                child.get_seuid(),
                child.get_state(),
                child.get_short_data()
            ]

        child_childs = child.get_childs(
            self.sourceModel().parent(source_parent).internalPointer())

        for i in range(0, len(child_childs)):
            if self.filterAcceptsRow(
                    i,
                    self.sourceModel().index(source_row, 0, source_parent)):
                return True

        correct_type = False
        data = entries[0]

        if data[0] == "h":
            correct_type = True
        elif self.__show_nodes and data[0] == "n":
            correct_type = True
        elif self.__show_connections and data[0] == "c":
            if self.__show_subscribers:
                correct_type = True
            else:
                if child.is_subscriber:
                    correct_type = False
                else:
                    correct_type = True
        elif self.__show_topics is True:
            if data[0] == "t":
                correct_type = True

        if correct_type is False:
            return False

        if self.__hide_debug is True:
            for entry in self.__quiet_names:
                if entries[1].find(entry) is not -1:
                    return False

        # todo: speed this implementation a lot up by not using the model!!!
        if self.__filter_string is not "":
            for i in range(0, len(entries)):
                if self.__filter_string in entries[i]:
                    return QSortFilterProxyModel.filterAcceptsRow(
                        self, source_row, source_parent)
            return False
        return QSortFilterProxyModel.filterAcceptsRow(self, source_row,
                                                      source_parent)
Пример #16
0
class LaunchFilesWidget(QDockWidget):
    '''
    Launch file browser.
    '''

    load_signal = Signal(str, dict, str)
    ''' load the launch file with given arguments (launchfile, args, masteruri)'''
    load_profile_signal = Signal(str)
    ''' load the profile file '''
    edit_signal = Signal(str)
    ''' list of paths to open in an editor '''
    transfer_signal = Signal(list)
    ''' list of tuples of (url, path) selected for transfer '''
    save_profile_signal = Signal(str)
    ''':ivar str save_profile_signa: the signal is emitted, to save profile. (current path selected in launch files)'''
    def __init__(self, parent=None):
        '''
        Creates the window, connects the signals and init the class.
        '''
        QDockWidget.__init__(self, parent)
        # initialize parameter
        self.__current_path = os.path.expanduser('~')
        # load the UI file
        ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                               'ui', 'LaunchFilesDockWidget.ui')
        loadUi(ui_file,
               self,
               custom_widgets={'EnhancedLineEdit': EnhancedLineEdit})
        self.ui_button_progress_cancel_cfg.setIcon(
            nm.settings().icon('crystal_clear_button_close.png'))
        self.ui_button_reload.setIcon(
            nm.settings().icon('oxygen_view_refresh.png'))
        self.ui_button_edit.setIcon(
            nm.settings().icon('crystal_clear_edit_launch.png'))
        self.ui_button_new.setIcon(nm.settings().icon('crystal_clear_add.png'))
        self.ui_button_transfer.setIcon(
            nm.settings().icon('crystal_clear_launch_file_transfer.png'))
        self.ui_button_save_profile.setIcon(
            nm.settings().icon('crystal_clear_profile_new.png'))
        self.ui_button_load.setIcon(
            nm.settings().icon('crystal_clear_launch_file.png'))
        self._current_search = ''
        pal = self.palette()
        self._default_color = pal.color(QPalette.Window)
        # initialize the progress queue
        self.progress_queue = ProgressQueue(self.ui_frame_progress_cfg,
                                            self.ui_bar_progress_cfg,
                                            self.ui_button_progress_cancel_cfg,
                                            'Launch File')
        # initialize the view for the launch files
        self.launchlist_model = LaunchListModel(
            progress_queue=self.progress_queue, viewobj=self.ui_file_view)
        self.launchlist_proxy_model = QSortFilterProxyModel(self)
        self.launchlist_proxy_model.setSourceModel(self.launchlist_model)
        self.name_delegate = HTMLDelegate(check_for_ros_names=False,
                                          palette=self.palette())
        self.ui_file_view.setItemDelegateForColumn(0, self.name_delegate)
        self.ui_file_view.setModel(self.launchlist_proxy_model)
        self.ui_file_view.setAlternatingRowColors(True)
        self.ui_file_view.activated.connect(self.on_launch_selection_activated)
        self.ui_file_view.setDragDropMode(QAbstractItemView.DragOnly)
        self.ui_file_view.setDragEnabled(True)
        sm = self.ui_file_view.selectionModel()
        sm.selectionChanged.connect(self.on_ui_file_view_selection_changed)
        self.launchlist_model.pathlist_handled.connect(
            self.on_pathlist_handled)
        self.launchlist_model.error_on_path.connect(self.on_error_on_path)
        self.ui_search_line.refresh_signal.connect(self.set_package_filter)
        self.ui_search_line.stop_signal.connect(self.stop)
        # connect to the button signals
        self.ui_button_reload.clicked.connect(self.on_reload_clicked)
        self.ui_button_edit.clicked.connect(self.on_edit_xml_clicked)
        #self.ui_button_new.clicked.connect(self.on_new_xml_clicked)
        self.ui_button_transfer.clicked.connect(self.on_transfer_file_clicked)
        self.ui_button_save_profile.clicked.connect(
            self.on_save_profile_clicked)
        self.ui_button_load.clicked.connect(self.on_load_xml_clicked)
        # add menu to create fiel or directory
        self._menu_add = QMenu()
        create_file_action = QAction(
            nm.settings().icon('crystal_clear_launch_file_new.png'),
            "create file",
            self,
            statusTip="",
            triggered=self.on_new_xml_clicked)
        create_dir_action = QAction(
            nm.settings().icon('crystal_clear_folder.png'),
            "create directory",
            self,
            statusTip="",
            triggered=self.on_new_dir_clicked)
        self._menu_add.addAction(create_file_action)
        self._menu_add.addAction(create_dir_action)
        self.ui_button_new.setMenu(self._menu_add)
        self._masteruri2name = {}
        self._reload_timer = None

    def stop(self):
        '''
        Cancel the executing queued actions. This method must be
        called at the exit!
        '''
        self.progress_queue.stop()
        self.ui_search_line.set_process_active(False)
        self._stop_timer_reload()

    def set_current_master(self, masteruri, mastername):
        self.launchlist_model.set_current_master(masteruri, mastername)
        self._masteruri2name[masteruri.rstrip(os.path.sep)] = mastername
        try:
            color = QColor.fromRgb(nm.settings().host_color(
                self._masteruri2name[nmdurl.masteruri(
                    self.launchlist_model.current_path)],
                self._default_color.rgb()))
            self._new_color(color)
        except Exception as _:
            pass
#             import traceback
#             print traceback.format_exc()
#             rospy.logwarn("Error while set color in launch dock: %s" % utf8(err))

    def on_launch_selection_activated(self, activated):
        '''
        Tries to load the launch file, if one was activated.
        '''
        selected = self._pathItemsFromIndexes(
            self.ui_file_view.selectionModel().selectedIndexes(), False)
        for item in selected:
            try:
                self.ui_search_line.set_process_active(True)
                lfile = self.launchlist_model.expand_item(item.path, item.id)
                # self.ui_search_line.setText('')
                if lfile is not None:
                    self.ui_search_line.set_process_active(False)
                    if item.is_launch_file():
                        nm.settings().launch_history_add(item.path)
                        self.load_signal.emit(item.path, {}, None)
                    elif item.is_profile_file():
                        nm.settings().launch_history_add(item.path)
                        self.load_profile_signal.emit(item.path)
                    elif item.is_config_file():
                        self.edit_signal.emit(lfile)
                if self.launchlist_model.current_path:
                    self.setWindowTitle(
                        'Launch @%s' %
                        get_hostname(self.launchlist_model.current_grpc))
                else:
                    self.setWindowTitle('Launch files')
            except Exception as e:
                import traceback
                print(traceback.format_exc())
                rospy.logwarn("Error while load launch file %s: %s" %
                              (item, utf8(e)))
                MessageBox.warning(
                    self, "Load error",
                    'Error while load launch file:\n%s' % item.name,
                    "%s" % utf8(e))
        try:
            color = QColor.fromRgb(nm.settings().host_color(
                self._masteruri2name[nmdurl.masteruri(
                    self.launchlist_model.current_path)],
                self._default_color.rgb()))
            self._new_color(color)
        except Exception as _:
            pass
#             import traceback
#             print traceback.format_exc()
#             rospy.logwarn("Error while set color in launch dock: %s" % utf8(err))

    def _new_color(self, color):
        bg_style_launch_dock = "QWidget#ui_dock_widget_contents { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 %s, stop: 0.7 %s);}" % (
            color.name(), self._default_color.name())
        self.setStyleSheet("%s" % (bg_style_launch_dock))

    def on_pathlist_handled(self, gpath):
        self.ui_search_line.set_process_active(False)
        self.ui_button_new.setEnabled(not self.launchlist_model.is_in_root)
        self._stop_timer_reload()

    def on_error_on_path(self, gpath):
        if gpath == self._current_search or gpath == self.launchlist_model.current_path:
            self.ui_search_line.set_process_active(False)
        if self.launchlist_model.is_in_root:
            self._reload_timer = threading.Timer(
                2.,
                nm.nmd().file.list_path_threaded)
            self._reload_timer.start()

    def _stop_timer_reload(self):
        if self._reload_timer is not None and self._reload_timer.is_alive():
            try:
                self._reload_timer.cancel()
                self._reload_timer = None
            except Exception:
                pass

    def _on_timer_reload_callback(self, event=None):
        nm.nmd().file.list_path_threaded(self.launchlist_model.current_path)
        self._reload_timer = threading.Timer(2.,
                                             nm.nmd().file.list_path_threaded)
        self._reload_timer.start()

    def on_launch_selection_changed(self, selected, deselected):
        print("selection launch changed")

    def load_file(self, path, args={}, masteruri=None):
        '''
        Tries to load the launch file, if one was activated.
        '''
        if path is not None:
            if path.endswith('.launch'):
                self.load_signal.emit(path, args, masteruri)
            elif path.endswith('.nmprofile'):
                self.load_profile_signal.emit(path)

    def on_ui_file_view_selection_changed(self, selected, deselected):
        '''
        On selection of a launch file, the buttons are enabled otherwise disabled.
        '''
        selected = self._pathItemsFromIndexes(
            self.ui_file_view.selectionModel().selectedIndexes(), False)
        for item in selected:
            islaunch = item.is_launch_file()
            isconfig = item.is_config_file()
            isprofile = item.is_profile_file()
            self.ui_button_edit.setEnabled(islaunch or isconfig or isprofile)
            self.ui_button_load.setEnabled(islaunch or isprofile)
            self.ui_button_transfer.setEnabled(islaunch or isconfig)

    def set_package_filter(self, text):
        if text:
            if text.startswith(os.path.sep):
                self._current_search = nmdurl.join(
                    self.launchlist_model.current_grpc, text)
                self.launchlist_model.set_path(text)
            else:
                # search for a package
                self.launchlist_model.show_packages(text)
                self.ui_search_line.set_process_active(False)
        else:
            self.launchlist_model.reload_current_path()

    def on_reload_clicked(self):
        '''
        Clear daemon's cache.
        '''
        self.launchlist_model.reload_current_path(clear_cache=True)

    def on_edit_xml_clicked(self):
        '''
        Opens an XML editor to edit the launch file.
        '''
        selected = self._pathItemsFromIndexes(
            self.ui_file_view.selectionModel().selectedIndexes(), False)
        for item in selected:
            path = self.launchlist_model.expand_item(item.path, item.id)
            if path is not None:
                self.edit_signal.emit(path)

    def on_new_xml_clicked(self):
        '''
        Creates a new launch file.
        '''
        # get new file from open dialog, use last path if one exists
        if not self.launchlist_model.is_in_root:
            items = self.launchlist_model.add_new_item("new.launch",
                                                       PathItem.LAUNCH_FILE)
            if items:
                index = self.launchlist_proxy_model.mapFromSource(
                    self.launchlist_model.index(1, 0))
                self.ui_file_view.selectionModel().select(
                    index, QItemSelectionModel.Select)
                self.ui_file_view.setCurrentIndex(index)
                self.ui_file_view.edit(index)

    def on_new_dir_clicked(self):
        '''
        Creates a new directory.
        '''
        # get new file from open dialog, use last path if one exists
        if not self.launchlist_model.is_in_root:
            items = self.launchlist_model.add_new_item("new", PathItem.FOLDER)
            if items:
                index = self.launchlist_proxy_model.mapFromSource(
                    self.launchlist_model.index(1, 0))
                self.ui_file_view.selectionModel().select(
                    index, QItemSelectionModel.Select)
                self.ui_file_view.setCurrentIndex(index)
                self.ui_file_view.edit(index)

    def on_transfer_file_clicked(self):
        '''
        Emit the signal to copy the selected file to a remote host.
        '''
        selected = self._pathItemsFromIndexes(
            self.ui_file_view.selectionModel().selectedIndexes(), False)
        paths = list()
        for item in selected:
            path = self.launchlist_model.expand_item(item.path, item.id)
            if path is not None:
                paths.append(path)
        if paths:
            self.transfer_signal.emit(paths)

    def on_save_profile_clicked(self):
        # save the profile
        _netloc, path = nmdurl.split(self.launchlist_model.current_path,
                                     with_scheme=True)
        self.save_profile_signal.emit(path)

    def on_load_xml_clicked(self):
        '''
        Tries to load the selected launch file. The button is only enabled and this
        method is called, if the button was enabled by on_launch_selection_clicked()
        '''
        selected = self._pathItemsFromIndexes(
            self.ui_file_view.selectionModel().selectedIndexes(), False)
        for item in selected:
            path = self.launchlist_model.expand_item(item.path, item.id)
            if path is not None:
                nm.settings().launch_history_add(item.path)
                self.load_signal.emit(path, {}, None)

    def _pathItemsFromIndexes(self, indexes, recursive=True):
        result = []
        for index in indexes:
            if index.column() == 0:
                model_index = self.launchlist_proxy_model.mapToSource(index)
                item = self.launchlist_model.itemFromIndex(model_index)
                if item is not None and isinstance(item, PathItem):
                    result.append(item)
        return result

    def keyPressEvent(self, event):
        '''
        Defines some of shortcuts for navigation/management in launch
        list view or topics view.
        '''
        key_mod = QApplication.keyboardModifiers()
        if not self.ui_file_view.state() == QAbstractItemView.EditingState:
            # remove history file from list by pressing DEL
            if event == QKeySequence.Delete or (event.key() == Qt.Key_Delete
                                                and
                                                key_mod & Qt.ShiftModifier):
                selected = self._pathItemsFromIndexes(
                    self.ui_file_view.selectionModel().selectedIndexes(),
                    False)
                for item in selected:
                    if item in nm.settings().launch_history:
                        nm.settings().launch_history_remove(item.path)
                        self.launchlist_model.reload_current_path()
                    elif not self.launchlist_model.is_in_root:
                        if key_mod & Qt.ShiftModifier:
                            rem_uri, rem_path = nmdurl.split(item.path)
                            host = rem_uri.split(':')
                            result = MessageBox.question(
                                self,
                                "Delete Question",
                                "Delete %s\n@ %s" % (rem_path, host[0]),
                                buttons=MessageBox.No | MessageBox.Yes)
                            if result == MessageBox.Yes:
                                try:
                                    nm.nmd().file.delete(item.path)
                                    self.launchlist_model.reload_current_path(
                                        clear_cache=True)
                                except Exception as e:
                                    rospy.logwarn("Error while delete %s: %s" %
                                                  (item.path, utf8(e)))
                                    MessageBox.warning(
                                        self, "Delete error",
                                        'Error while delete:\n%s' % item.name,
                                        "%s" % utf8(e))
                        else:
                            MessageBox.information(
                                self,
                                "Delete Info",
                                "Use Shift+Del to delete files or directories",
                                buttons=MessageBox.Ok)
            elif not key_mod and event.key(
            ) == Qt.Key_F4 and self.ui_button_edit.isEnabled():
                # open selected launch file in xml editor by F4
                self.on_edit_xml_clicked()
            elif event == QKeySequence.Find:
                # set focus to filter box for packages
                self.ui_search_line.setFocus(Qt.ActiveWindowFocusReason)
            elif event == QKeySequence.Paste:
                # paste files from clipboard
                self.launchlist_model.paste_from_clipboard()
            elif event == QKeySequence.Copy:
                # copy the selected items as file paths into clipboard
                selected = self.ui_file_view.selectionModel().selectedIndexes()
                indexes = []
                for s in selected:
                    indexes.append(self.launchlist_proxy_model.mapToSource(s))
                self.launchlist_model.copy_to_clipboard(indexes)
        if self.ui_search_line.hasFocus() and event.key() == Qt.Key_Escape:
            # cancel package filtering on pressing ESC
            self.launchlist_model.reload_current_path()
            self.ui_search_line.setText('')
            self.ui_file_view.setFocus(Qt.ActiveWindowFocusReason)
        QDockWidget.keyReleaseEvent(self, event)
 def __init__(self, parent=None):
     '''
     Creates the window, connects the signals and init the class.
     '''
     QDockWidget.__init__(self, parent)
     # initialize parameter
     self.__current_path = os.path.expanduser('~')
     # load the UI file
     ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                            'ui', 'LaunchFilesDockWidget.ui')
     loadUi(ui_file,
            self,
            custom_widgets={'EnhancedLineEdit': EnhancedLineEdit})
     self.hostLabel.setVisible(False)
     self.ui_button_progress_cancel_cfg.setIcon(
         nm.settings().icon('crystal_clear_button_close.png'))
     self.ui_button_reload.setIcon(
         nm.settings().icon('oxygen_view_refresh.png'))
     self.ui_button_edit.setIcon(
         nm.settings().icon('crystal_clear_edit_launch.png'))
     self.ui_button_new.setIcon(nm.settings().icon('crystal_clear_add.png'))
     self.ui_button_transfer.setIcon(
         nm.settings().icon('crystal_clear_launch_file_transfer.png'))
     self.ui_button_save_profile.setIcon(
         nm.settings().icon('crystal_clear_profile_new.png'))
     self.ui_button_load.setIcon(
         nm.settings().icon('crystal_clear_launch_file.png'))
     self._current_search = ''
     pal = self.palette()
     self._default_color = pal.color(QPalette.Window)
     # initialize the progress queue
     self.progress_queue = ProgressQueue(self.ui_frame_progress_cfg,
                                         self.ui_bar_progress_cfg,
                                         self.ui_button_progress_cancel_cfg,
                                         'Launch File')
     # initialize the view for the launch files
     self.launchlist_model = LaunchListModel(
         progress_queue=self.progress_queue, viewobj=self.ui_file_view)
     self.launchlist_proxy_model = QSortFilterProxyModel(self)
     self.launchlist_proxy_model.setSourceModel(self.launchlist_model)
     self.name_delegate = HTMLDelegate(check_for_ros_names=False,
                                       palette=self.palette())
     self.ui_file_view.setItemDelegateForColumn(0, self.name_delegate)
     self.ui_file_view.setModel(self.launchlist_proxy_model)
     self.ui_file_view.setAlternatingRowColors(True)
     self.ui_file_view.activated.connect(self.on_launch_selection_activated)
     self.ui_file_view.setDragDropMode(QAbstractItemView.DragOnly)
     self.ui_file_view.setDragEnabled(True)
     sm = self.ui_file_view.selectionModel()
     sm.selectionChanged.connect(self.on_ui_file_view_selection_changed)
     self.launchlist_model.pathlist_handled.connect(
         self.on_pathlist_handled)
     self.launchlist_model.error_on_path.connect(self.on_error_on_path)
     self.ui_search_line.refresh_signal.connect(self.set_package_filter)
     self.ui_search_line.stop_signal.connect(self.stop)
     # connect to the button signals
     self.ui_button_reload.clicked.connect(self.on_reload_clicked)
     self.ui_button_edit.clicked.connect(self.on_edit_xml_clicked)
     #self.ui_button_new.clicked.connect(self.on_new_xml_clicked)
     self.ui_button_transfer.clicked.connect(self.on_transfer_file_clicked)
     self.ui_button_save_profile.clicked.connect(
         self.on_save_profile_clicked)
     self.ui_button_load.clicked.connect(self.on_load_xml_clicked)
     # add menu to create fiel or directory
     self._menu_add = QMenu()
     create_file_action = QAction(
         nm.settings().icon('crystal_clear_launch_file_new.png'),
         "create file",
         self,
         statusTip="",
         triggered=self.on_new_xml_clicked)
     create_dir_action = QAction(
         nm.settings().icon('crystal_clear_folder.png'),
         "create directory",
         self,
         statusTip="",
         triggered=self.on_new_dir_clicked)
     self._menu_add.addAction(create_file_action)
     self._menu_add.addAction(create_dir_action)
     self.ui_button_new.setMenu(self._menu_add)
     self._masteruri2name = {}
     self._reload_timer = None
     self._first_path = self.launchlist_model.current_path
Пример #18
0
 def setFilterRegExp(self, string):
     self.invalidateFilter()
     QSortFilterProxyModel.setFilterRegExp(self, string)
Пример #19
0
 def setFilterRegExp(self, string):
     self.invalidateFilter()
     QSortFilterProxyModel.setFilterRegExp(self, string)
Пример #20
0
class SettingsWidget(QDockWidget):
    '''
    Settings widget to handle the settings changes. The changes will direct change
    the settings of the GUI.
    '''

    def __init__(self, parent=None):
        '''
        Creates the window, connects the signals and init the class.
        '''
        QDockWidget.__init__(self, parent)
        # load the UI file
        settings_dock_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'SettingsDockWidget.ui')
        loadUi(settings_dock_file, self)
        # initialize the settings view model
        self.settings_model = SettingsModel()
        self.settings_proxyModel = QSortFilterProxyModel(self)
        self.settings_proxyModel.setSourceModel(self.settings_model)
        self.settingsTreeView.setModel(self.settings_proxyModel)
        self.settingsTreeView.setAlternatingRowColors(True)
        for i, (_, width) in enumerate(SettingsModel.header):
            self.settingsTreeView.setColumnWidth(i, width)
        self.item_delegate = ItemDelegate()
        self.item_delegate.settings_path_changed_signal.connect(self.reload_settings)
        self.settingsTreeView.setItemDelegateForColumn(1, self.item_delegate)
        self.reload_settings()

    def reload_settings(self):
        '''
        Load the current settings data into the model. The settings itself will not
        be loaded.
        '''
        settings = {'Default user:'******'value': nm.settings().default_user,
                                       'settings': nm.settings(),
                                       'attrname': 'default_user',
                                       'value_default': nm.settings().USER_DEFAULT,
                                       'tooltip': '<p>The user used for ssh connection to remote hosts</p>'
                                       },),
                    'Launch history length:': ({'value': nm.settings().launch_history_length,
                                                'settings': nm.settings(),
                                                'attrname': 'launch_history_length',
                                                'value_default': nm.settings().LAUNCH_HISTORY_LENGTH,
                                                'value_min': 0,
                                                'value_max': 25,
                                                'tooltip': '<p>The count of recent '
                                                'loaded launch files displayed in the root '
                                                'of the <span style=" font-weight:600;">launch '
                                                'files</span> view.</p>'
                                                },),
                    'Param history length:': ({'value': nm.settings().param_history_length,
                                               'settings': nm.settings(),
                                               'attrname': 'param_history_length',
                                               'value_default': nm.settings().PARAM_HISTORY_LENGTH,
                                               'value_min': 0,
                                               'value_max': 25,
                                               'tooltip': '<p>The count of parameters stored which '
                                               'are entered in a parameter dialog (Launch file arguments, '
                                               'paramter server, publishing to a topic, service call)</p>'
                                               },),

                    'Settings path:': ({'value': nm.settings().cfg_path,
                                        'settings': nm.settings(),
                                        'attrname': 'cfg_path',
                                        'edit_type': SettingsValueItem.EDIT_TYPE_FOLDER,
                                        'value_default': nm.settings().CFG_PATH,
                                        'tooltip': ''
                                        },),
                    'Robot icon path:': ({'value': nm.settings().robots_path,
                                          'settings': nm.settings(),
                                          'attrname': 'robots_path',
                                          'edit_type': SettingsValueItem.EDIT_TYPE_FOLDER,
                                          'value_default': nm.settings().ROBOTS_DIR,
                                          'tooltip': '<p>The path to the folder with robot images '
                                          '(<span style=" font-weight:600;">.png</span>).'
                                          'The images with robot name will be displayed in the '
                                          'info bar.</p>'
                                          },),
                    'Show files extensions:': ({'value': ', '.join(nm.settings().launch_view_file_ext),
                                                'settings': nm.settings(),
                                                'attrname': 'launch_view_file_ext',
                                                'value_default': ', '.join(nm.settings().LAUNCH_VIEW_EXT),
                                                'tooltip': '<p>Files that are displayed next to Launch '
                                                'files in the <span style="font-weight:600;">'
                                                'launch files</span> view</p>'
                                                },),
                    'Store window layout:': ({'value': nm.settings().store_geometry,
                                              'settings': nm.settings(),
                                              'attrname': 'store_geometry',
                                              'value_default': nm.settings().STORE_GEOMETRY,
                                              'tooltip': ''
                                              },),
                    'Max time difference:': ({'value': nm.settings().max_timediff,
                                              'settings': nm.settings(),
                                              'attrname': 'max_timediff',
                                              'value_default': nm.settings().MAX_TIMEDIFF,
                                              'tooltip': '<p>Shows a warning if the time difference to '
                                              'remote host is greater than this value</p>'
                                              },),
                    'Autoupdate:': ({'value': nm.settings().autoupdate,
                                     'settings': nm.settings(),
                                     'attrname': 'autoupdate',
                                     'value_default': nm.settings().AUTOUPDATE,
                                     'tooltip': '<p>By default node manager updates the current '
                                     'state on changes. You can deactivate this behavior to '
                                     'reduce the network load. If autoupdate is deactivated '
                                     'you must refresh the state manually.</p>'
                                     },),
                    'Start sync with discovery:': ({'value': nm.settings().start_sync_with_discovery,
                                                    'settings': nm.settings(),
                                                    'attrname': 'start_sync_with_discovery',
                                                    'value_default': nm.settings().START_SYNC_WITH_DISCOVERY,
                                                    'tooltip': "<p>Sets 'start sync' in 'Start' master discovery "
                                                    "dialog to True, if this option is set to true.</p>"
                                                    },),
                    'Confirm exit when closing:': ({'value': nm.settings().confirm_exit_when_closing,
                                                    'settings': nm.settings(),
                                                    'attrname': 'confirm_exit_when_closing',
                                                    'value_default': nm.settings().CONFIRM_EXIT_WHEN_CLOSING,
                                                    'tooltip': "<p>Shows on closing of node_manager a dialog to stop "
                                                    "all ROS nodes if this option is set to true.</p>"
                                                    },),
                    'Highlight xml blocks:': ({'value': nm.settings().highlight_xml_blocks,
                                               'settings': nm.settings(),
                                               'attrname': 'highlight_xml_blocks',
                                               'value_default': nm.settings().HIGHLIGHT_XML_BLOCKS,
                                               'tooltip': "<p>Highlights the current selected XML block, while "
                                               "editing ROS launch file.</p>"
                                               },),
                    'Colorize hosts:': ({'value': nm.settings().colorize_hosts,
                                         'settings': nm.settings(),
                                         'attrname': 'colorize_hosts',
                                         'value_default': nm.settings().COLORIZE_HOSTS,
                                         'tooltip': "<p>Determine automatic a default color for each host if True. "
                                         "Manually setted color will be prefered. You can select the color by "
                                         "double-click on hostname in description panel. To remove a setted color "
                                         "delete it manually from $HOME/.ros/node_manager/settings.ini</p>"
                                         },),
                    'Transpose pub/sub description:': ({'value': nm.settings().transpose_pub_sub_descr,
                                                        'settings': nm.settings(),
                                                        'attrname': 'transpose_pub_sub_descr',
                                                        'value_default': nm.settings().TRANSPOSE_PUB_SUB_DESCR,
                                                        'tooltip': "<p>Transpose publisher/subscriber in description dock.</p>"
                                                        },)
                    }
        self.settings_model.init_settings(settings)
#    self.settingsTreeView.setSortingEnabled(True)
        self.settingsTreeView.sortByColumn(0, Qt.AscendingOrder)
        self.settingsTreeView.expandAll()