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_()
def setFilterRegExp(self, string): self.invalidateFilter() QSortFilterProxyModel.setFilterRegExp(self, string)