Package node_manager_fkie :: Module launch_files_widget
[frames] | no frames]

Source Code for Module node_manager_fkie.launch_files_widget

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  import os 
 33  #from datetime import datetime 
 34   
 35  from python_qt_binding import QtGui 
 36  from python_qt_binding import QtCore 
 37  from python_qt_binding import loadUi 
 38   
 39  import rospy 
 40   
 41  from .common import package_name#, masteruri_from_ros 
 42  from .detailed_msg_box import WarningMessageBox 
 43  from .launch_list_model import LaunchListModel, LaunchItem 
 44  from .progress_queue import ProgressQueue#, ProgressThread 
 45  from .parameter_dialog import ParameterDialog 
 46   
47 -class LaunchFilesWidget(QtGui.QDockWidget):
48 ''' 49 Launch file browser. 50 ''' 51 52 load_signal = QtCore.Signal(str) 53 ''' load the launch file ''' 54 load_as_default_signal = QtCore.Signal(str, str) 55 ''' load the launch file as default (path, host) ''' 56 edit_signal = QtCore.Signal(list) 57 ''' list of paths to open in an editor ''' 58 transfer_signal = QtCore.Signal(list) 59 ''' list of paths selected for transfer ''' 60
61 - def __init__(self, parent=None):
62 ''' 63 Creates the window, connects the signals and init the class. 64 ''' 65 QtGui.QDockWidget.__init__(self, parent) 66 # initialize parameter 67 self.__current_path = os.path.expanduser('~') 68 # load the UI file 69 ui_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'LaunchFilesDockWidget.ui') 70 loadUi(ui_file, self) 71 # initialize the view for the launch files 72 self.launchlist_model = LaunchListModel() 73 self.launchlist_proxyModel = QtGui.QSortFilterProxyModel(self) 74 self.launchlist_proxyModel.setSourceModel(self.launchlist_model) 75 self.xmlFileView.setModel(self.launchlist_proxyModel) 76 self.xmlFileView.setAlternatingRowColors(True) 77 self.xmlFileView.activated.connect(self.on_launch_selection_activated) 78 self.xmlFileView.setDragDropMode(QtGui.QAbstractItemView.DragOnly) 79 self.xmlFileView.setDragEnabled(True) 80 sm = self.xmlFileView.selectionModel() 81 sm.selectionChanged.connect(self.on_xmlFileView_selection_changed) 82 # self.searchPackageLine.setVisible(False) 83 self.searchPackageLine.textChanged.connect(self.set_package_filter) 84 self.searchPackageLine.focusInEvent = self._searchline_focusInEvent 85 # connect to the button signals 86 self.refreshXmlButton.clicked.connect(self.on_refresh_xml_clicked) 87 self.editXmlButton.clicked.connect(self.on_edit_xml_clicked) 88 self.newXmlButton.clicked.connect(self.on_new_xml_clicked) 89 self.openXmlButton.clicked.connect(self.on_open_xml_clicked) 90 self.transferButton.clicked.connect(self.on_transfer_file_clicked) 91 self.loadXmlButton.clicked.connect(self.on_load_xml_clicked) 92 self.loadXmlAsDefaultButton.clicked.connect(self.on_load_as_default) 93 # creates a default config menu 94 start_menu = QtGui.QMenu(self) 95 self.loadDeafaultAtHostAct = QtGui.QAction("&Load default config on host", self, statusTip="Loads the default config at given host", triggered=self.on_load_as_default_at_host) 96 start_menu.addAction(self.loadDeafaultAtHostAct) 97 self.loadXmlAsDefaultButton.setMenu(start_menu) 98 #initialize the progress queue 99 self.progress_queue = ProgressQueue(self.progressFrame_cfg, self.progressBar_cfg, self.progressCancelButton_cfg)
100
101 - def stop(self):
102 ''' 103 Cancel the executing queued actions. This method must be 104 called at the exit! 105 ''' 106 self.progress_queue.stop()
107
108 - def on_launch_selection_activated(self, activated):
109 ''' 110 Tries to load the launch file, if one was activated. 111 ''' 112 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 113 for item in selected: 114 try: 115 lfile = self.launchlist_model.expandItem(item.name, item.path, item.id) 116 self.searchPackageLine.setText('') 117 if not lfile is None: 118 if item.isLaunchFile(): 119 self.launchlist_model.add2LoadHistory(item.path) 120 key_mod = QtGui.QApplication.keyboardModifiers() 121 if (key_mod & QtCore.Qt.ShiftModifier): 122 self.load_as_default_signal.emit(item.path, None) 123 else: 124 self.load_signal.emit(item.path) 125 elif item.isConfigFile(): 126 self.edit_signal.emit([lfile]) 127 except Exception as e: 128 rospy.logwarn("Error while load launch file %s: %s"%(item, e)) 129 WarningMessageBox(QtGui.QMessageBox.Warning, "Load error", 130 'Error while load launch file:\n%s'%item.name, 131 "%s"%e).exec_()
132 # self.launchlist_model.reloadCurrentPath() 133
134 - def on_xmlFileView_selection_changed(self, selected, deselected):
135 ''' 136 On selection of a launch file, the buttons are enabled otherwise disabled. 137 ''' 138 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 139 for item in selected: 140 islaunch = item.isLaunchFile() 141 isconfig = item.isConfigFile() 142 self.editXmlButton.setEnabled(islaunch or isconfig) 143 self.loadXmlButton.setEnabled(islaunch) 144 self.transferButton.setEnabled(islaunch or isconfig) 145 self.loadXmlAsDefaultButton.setEnabled(islaunch)
146
147 - def set_package_filter(self, text):
148 self.launchlist_proxyModel.setFilterRegExp(QtCore.QRegExp(text, 149 QtCore.Qt.CaseInsensitive, 150 QtCore.QRegExp.Wildcard))
151
152 - def on_refresh_xml_clicked(self):
153 ''' 154 Reload the current path. 155 ''' 156 self.launchlist_model.reloadCurrentPath() 157 self.launchlist_model.reloadPackages() 158 self.editXmlButton.setEnabled(False) 159 self.loadXmlButton.setEnabled(False) 160 self.transferButton.setEnabled(False) 161 self.loadXmlAsDefaultButton.setEnabled(False)
162
163 - def on_edit_xml_clicked(self):
164 ''' 165 Opens an XML editor to edit the launch file. 166 ''' 167 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 168 for item in selected: 169 path = self.launchlist_model.expandItem(item.name, item.path, item.id) 170 if not path is None: 171 self.edit_signal.emit([path])
172
173 - def on_new_xml_clicked(self):
174 ''' 175 Creates a new launch file. 176 ''' 177 # get new file from open dialog, use last path if one exists 178 open_path = self.__current_path 179 if not self.launchlist_model.currentPath is None: 180 open_path = self.launchlist_model.currentPath 181 (fileName, _) = QtGui.QFileDialog.getSaveFileName(self, 182 "New launch file", 183 open_path, 184 "Config files (*.launch *.yaml);;All files (*)") 185 if fileName: 186 try: 187 (pkg, _) = package_name(os.path.dirname(fileName))#_:=pkg_path 188 if pkg is None: 189 WarningMessageBox(QtGui.QMessageBox.Warning, "New File Error", 190 'The new file is not in a ROS package').exec_() 191 return 192 with open(fileName, 'w+') as f: 193 f.write("<launch>\n" 194 " <arg name=\"robot_ns\" default=\"my_robot\"/>\n" 195 " <group ns=\"$(arg robot_ns)\">\n" 196 " <param name=\"tf_prefix\" value=\"$(arg robot_ns)\"/>\n" 197 "\n" 198 " <node pkg=\"my_pkg\" type=\"my_node\" name=\"my_name\" >\n" 199 " <param name=\"capability_group\" value=\"MY_GROUP\"/>\n" 200 " </node>\n" 201 " </group>\n" 202 "</launch>\n" 203 ) 204 self.__current_path = os.path.dirname(fileName) 205 self.launchlist_model.setPath(self.__current_path) 206 self.edit_signal.emit([fileName]) 207 except EnvironmentError as e: 208 WarningMessageBox(QtGui.QMessageBox.Warning, "New File Error", 209 'Error while create a new file', 210 '%s'%e).exec_()
211
212 - def on_open_xml_clicked(self):
213 (fileName, _) = QtGui.QFileDialog.getOpenFileName(self, 214 "Load launch file", 215 self.__current_path, 216 "Config files (*.launch);;All files (*)") 217 if fileName: 218 self.__current_path = os.path.dirname(fileName) 219 self.launchlist_model.add2LoadHistory(fileName) 220 self.load_signal.emit(fileName)
221
222 - def on_transfer_file_clicked(self):
223 ''' 224 Emit the signal to copy the selected file to a remote host. 225 ''' 226 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 227 paths = list() 228 for item in selected: 229 path = self.launchlist_model.expandItem(item.name, item.path, item.id) 230 if not path is None: 231 paths.append(path) 232 if paths: 233 self.transfer_signal.emit(paths)
234
235 - def on_load_xml_clicked(self):
236 ''' 237 Tries to load the selected launch file. The button is only enabled and this 238 method is called, if the button was enabled by on_launch_selection_clicked() 239 ''' 240 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 241 for item in selected: 242 path = self.launchlist_model.expandItem(item.name, item.path, item.id) 243 if not path is None: 244 self.launchlist_model.add2LoadHistory(path) 245 self.load_signal.emit(path)
246
248 ''' 249 Tries to load the selected launch file as default configuration. The button 250 is only enabled and this method is called, if the button was enabled by 251 on_launch_selection_clicked() 252 ''' 253 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 254 for item in selected: 255 path = self.launchlist_model.expandItem(item.name, item.path, item.id) 256 if not path is None: 257 params = {'Host' : ('string', 'localhost') } 258 dia = ParameterDialog(params) 259 dia.setFilterVisible(False) 260 dia.setWindowTitle('Start node on...') 261 dia.resize(350,120) 262 dia.setFocusField('Host') 263 if dia.exec_(): 264 try: 265 params = dia.getKeywords() 266 host = params['Host'] 267 rospy.loginfo("LOAD the launch file on host %s as default: %s"%(host, path)) 268 self.launchlist_model.add2LoadHistory(path) 269 self.load_as_default_signal.emit(path, host) 270 except Exception, e: 271 WarningMessageBox(QtGui.QMessageBox.Warning, "Load default config error", 272 'Error while parse parameter', 273 '%s'%e).exec_()
274 275
276 - def on_load_as_default(self):
277 ''' 278 Tries to load the selected launch file as default configuration. The button 279 is only enabled and this method is called, if the button was enabled by 280 on_launch_selection_clicked() 281 ''' 282 key_mod = QtGui.QApplication.keyboardModifiers() 283 if (key_mod & QtCore.Qt.ShiftModifier): 284 self.loadXmlAsDefaultButton.showMenu() 285 else: 286 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 287 for item in selected: 288 path = self.launchlist_model.expandItem(item.name, item.path, item.id) 289 if not path is None: 290 rospy.loginfo("LOAD the launch file as default: %s", path) 291 self.launchlist_model.add2LoadHistory(path) 292 self.load_as_default_signal.emit(path, None)
293
294 - def _launchItemsFromIndexes(self, indexes, recursive=True):
295 result = [] 296 for index in indexes: 297 if index.column() == 0: 298 model_index = self.launchlist_proxyModel.mapToSource(index) 299 item = self.launchlist_model.itemFromIndex(model_index) 300 if not item is None and isinstance(item, LaunchItem): 301 result.append(item) 302 return result
303
304 - def keyReleaseEvent(self, event):
305 ''' 306 Defines some of shortcuts for navigation/management in launch 307 list view or topics view. 308 ''' 309 key_mod = QtGui.QApplication.keyboardModifiers() 310 if not self.xmlFileView.state() == QtGui.QAbstractItemView.EditingState: 311 # remove history file from list by pressing DEL 312 if event == QtGui.QKeySequence.Delete: 313 selected = self._launchItemsFromIndexes(self.xmlFileView.selectionModel().selectedIndexes(), False) 314 for item in selected: 315 if item.path in self.launchlist_model.load_history: 316 self.launchlist_model.removeFromLoadHistory(item.path) 317 self.launchlist_model.reloadCurrentPath() 318 elif not key_mod and event.key() == QtCore.Qt.Key_F4 and self.editXmlButton.isEnabled(): 319 # open selected launch file in xml editor by F4 320 self.on_edit_xml_clicked() 321 elif event == QtGui.QKeySequence.Find: 322 # set focus to filter box for packages 323 self.searchPackageLine.setFocus(QtCore.Qt.ActiveWindowFocusReason) 324 elif event == QtGui.QKeySequence.Paste: 325 # paste files from clipboard 326 self.launchlist_model.paste_from_clipboard() 327 elif event == QtGui.QKeySequence.Copy: 328 # copy the selected items as file paths into clipboard 329 selected = self.xmlFileView.selectionModel().selectedIndexes() 330 indexes = [] 331 for s in selected: 332 indexes.append(self.launchlist_proxyModel.mapToSource(s)) 333 self.launchlist_model.copy_to_clipboard(indexes) 334 if self.searchPackageLine.hasFocus() and event.key() == QtCore.Qt.Key_Escape: 335 # cancel package filtering on pressing ESC 336 self.launchlist_model.show_packages(False) 337 self.searchPackageLine.setText('') 338 self.xmlFileView.setFocus(QtCore.Qt.ActiveWindowFocusReason) 339 QtGui.QDockWidget.keyReleaseEvent(self, event)
340
341 - def _searchline_focusInEvent(self, event):
342 self.launchlist_model.show_packages(True) 343 QtGui.QLineEdit.focusInEvent(self.searchPackageLine, event)
344