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

Source Code for Module node_manager_fkie.launch_list_model

  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   
 33  import os 
 34  import sys 
 35   
 36  from PySide import QtCore 
 37  from PySide import QtGui 
 38   
 39  import node_manager_fkie as nm 
 40  from launch_config import LaunchConfig 
 41   
42 -class LaunchListModel(QtCore.QAbstractListModel):
43 ''' 44 The model to manage the files with launch files. 45 ''' 46 47 NOT_FOUND = -1 48 NOTHING = 0 49 RECENT_FILE = 1 50 LAUNCH_FILE = 2 51 FOLDER = 3 52 PACKAGE = 4 53 STACK = 5 54 55 RECENT_LENGTH = 5 56
57 - def __init__(self):
58 ''' 59 Creates a new list model. Loads the required icons. 60 ''' 61 QtCore.QAbstractListModel.__init__(self) 62 self.icons = {LaunchListModel.FOLDER : QtGui.QIcon(":/icons/crystal_clear_folder.png"), 63 LaunchListModel.STACK : QtGui.QIcon(":/icons/crystal_clear_stack.png"), 64 LaunchListModel.PACKAGE : QtGui.QIcon(":/icons/crystal_clear_package.png"), 65 LaunchListModel.LAUNCH_FILE : QtGui.QIcon(":/icons/crystal_clear_launch_file.png"), 66 LaunchListModel.RECENT_FILE : QtGui.QIcon(":/icons/crystal_clear_launch_file_recent.png")} 67 self.items = [] 68 self.currentPath = None 69 self.load_history = self._getLoadHistory() 70 self.root_paths = [os.path.normpath(p) for p in os.getenv("ROS_PACKAGE_PATH").split(':')] 71 self._setNewList(self._moveUp(None))
72
73 - def _getRootItems(self):
74 result = list(self.load_history) 75 result[len(result):] = self.root_paths 76 return result
77 78 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 79 #%%%%%%%%%%%%% Overloaded methods %%%%%%%% 80 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 81
82 - def rowCount(self, parent=QtCore.QModelIndex()):
83 ''' 84 Tell the view how many rows we have present in our data. 85 @param parent: parent of the list 86 @type parent: L{QtCore.QModelIndex} 87 ''' 88 return len(self.items)
89
90 - def data(self, index, role=QtCore.Qt.DisplayRole):
91 ''' 92 The view asks us for all sorts of information about our data... 93 @param index: parent of the list 94 @type index: L{QtCore.QModelIndex} 95 @param role: the art of the data 96 @type role: L{QtCore.Qt.DisplayRole} 97 @see: U{http://www.pyside.org/docs/pyside-1.0.1/PySide/QtCore/Qt.html} 98 ''' 99 if role == QtCore.Qt.DisplayRole: 100 # return the displayed item name 101 pathItem, path, pathId = self.items[index.row()] 102 if pathId == LaunchListModel.RECENT_FILE: 103 return ''.join([pathItem, ' [', str(LaunchConfig.packageName(os.path.dirname(path))[0]), ']']).decode(sys.getfilesystemencoding()) 104 else: 105 return pathItem 106 elif role == QtCore.Qt.ToolTipRole: 107 # return the tooltip of the item 108 pathItem, path, pathId = self.items[index.row()] 109 return path 110 elif role == QtCore.Qt.DecorationRole: 111 # return the showed icon 112 pathItem, path, pathId = self.items[index.row()] 113 114 if pathId > LaunchListModel.NOTHING and self.icons.has_key(pathId): 115 return self.icons[pathId] 116 return None 117 else: 118 # We don't care about anything else, so return None 119 return None
120
121 - def flags(self, index):
122 ''' 123 Make the only selectable 124 @param index: parent of the list 125 @type index: L{QtCore.QModelIndex} 126 @return: Flag or the requestet item 127 @rtype: L{PySide.QtCore.Qt.ItemFlag} 128 @see: U{http://www.pyside.org/docs/pyside-1.0.1/PySide/QtCore/Qt.html} 129 ''' 130 return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
131 132 133 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 134 #%%%%%%%%%%%%% External usage %%%%%%%% 135 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 136
137 - def reloadCurrentPath(self):
138 ''' 139 Reloads the current path. 140 ''' 141 if self.currentPath is None: 142 self._setNewList(self._moveUp(self.currentPath)) 143 else: 144 self._setNewList(self._moveDown(self.currentPath))
145
146 - def isLaunchFile(self, row):
147 ''' 148 Tests for the given row whether it is a launch file or not. 149 @return: C{True} if it is a launch file 150 @rtype: C{boolean} 151 ''' 152 if row >= 0 and row < len(self.items): 153 pathItem, path, pathId = self.items[row] 154 return not path is None and os.path.isfile(path) and path.endswith('.launch') 155 return False
156
157 - def getFilePath(self, item):
158 ''' 159 Returns for the given item the file path if this is a file. Otherwise the 160 folder will be expanded and None will be returned. 161 @param item: the list item 162 @type item: C{str} 163 @return: path of the launch file or None 164 @rtype: C{str} or C{None} 165 ''' 166 for pathItem, path, id in self.items: 167 if item == pathItem: 168 if item == '..': 169 root_path, items = self._moveUp(os.path.dirname(path)) 170 elif os.path.isfile(path): 171 return path 172 else: 173 root_path, items = self._moveDown(path) 174 self._setNewList((root_path, items)) 175 return None
176 177
178 - def setPath(self, path):
179 ''' 180 Shows the new path in the launch configuration view. Only if the new path 181 is in ros package paths 182 @param path: new path 183 @type path: C{str} 184 ''' 185 if self._is_in_ros_packages(path): 186 self._setNewList(self._moveDown(path))
187
188 - def add2LoadHistory(self, file):
189 try: 190 self.load_history.remove(file) 191 except: 192 pass 193 self.load_history.append(file) 194 if len(self.load_history) > self.RECENT_LENGTH: 195 self.load_history.pop(0) 196 self._storeLoadHistory(self.load_history)
197 198 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 199 #%%%%%%%%%%%%% Functionality %%%%%%%% 200 #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 201
202 - def _setNewList(self, (root_path, items)):
203 ''' 204 Sets the list to the given path and insert the items. If the root path is not 205 None the additional item '..' to go up will be inserted. The items parameter 206 is a tupel with three values (the displayed name, the path of the item, the id 207 of the item). 208 @see: L{LaunchListModel._addPathToList()} 209 @param root_path: the root directory 210 @type root_path: C{str} 211 @param items: the list with characterized items 212 @type items: C{[(item, path, id)]} 213 ''' 214 self.beginRemoveRows(QtCore.QModelIndex(), 0, len(self.items)) 215 del self.items[:] 216 self.endRemoveRows() 217 # add new items 218 if not root_path is None: 219 self._addPathToList('..', root_path, LaunchListModel.NOTHING) 220 for item_name, item_path, item_id in items: 221 self._addPathToList(item_name, item_path, item_id) 222 self.currentPath = root_path
223
224 - def _is_in_ros_packages(self, path):
225 ''' 226 Test whether the given path is in ROS_PACKAGE_PATH. 227 @return: C{True}, if the path is in the ROS_PACKAGE_PATH 228 @rtype: C{boolean} 229 ''' 230 for p in self.root_paths: 231 if path.startswith(p): 232 return True 233 return False
234
235 - def _addPathToList(self, item, path, path_id):
236 ''' 237 Inserts the given item in the list model. 238 @param item: the displayed name 239 @type item: C{str} 240 @param path: the path of the item 241 @type path: C{str} 242 @param path_id: the id of the item, which represents whether it is a file, package or stack. 243 @type path_id: C{constants of LaunchListModel} 244 ''' 245 if item is None or path is None or path_id == LaunchListModel.NOT_FOUND: 246 return False 247 if (path_id != LaunchListModel.NOT_FOUND): 248 # add sorted a new entry 249 for index, (i, p, id) in enumerate(self.items): 250 launch_file_cmp = (path_id == LaunchListModel.RECENT_FILE and id == LaunchListModel.LAUNCH_FILE and i > item) 251 if launch_file_cmp or (id == path_id and i > item): 252 self.beginInsertRows(QtCore.QModelIndex(), index, index) 253 self.items.insert(index, (item, path, path_id)) 254 self.endInsertRows() 255 return True 256 self.beginInsertRows(QtCore.QModelIndex(), len(self.items), len(self.items)) 257 self.items.append((item, path, path_id)) 258 self.endInsertRows() 259 return True 260 return False
261
262 - def _identifyPath(self, path):
263 ''' 264 Determines the id of the given path 265 @return: the id represents whether it is a file, package or stack 266 @rtype: C{constants of LaunchListModel} 267 ''' 268 if os.path.basename(path)[0] != '.': 269 if path in self.load_history: 270 return LaunchListModel.RECENT_FILE 271 elif os.path.isfile(path): 272 if (path.endswith('.launch')): 273 return LaunchListModel.LAUNCH_FILE 274 elif os.path.isdir(path): 275 fileList = os.listdir(path) 276 if self._containsLaunches(path): 277 if 'stack.xml' in fileList: 278 return LaunchListModel.STACK 279 elif 'manifest.xml' in fileList: 280 return LaunchListModel.PACKAGE 281 else: 282 return LaunchListModel.FOLDER 283 return LaunchListModel.NOT_FOUND
284
285 - def _containsLaunches(self, path):
286 ''' 287 Moves recursively down in the path tree and searches for a launch file. If 288 one is found True will be returned. 289 @return: C{True} if the path contains a launch file. 290 @rtype: C{boolean} 291 ''' 292 fileList = os.listdir(path) 293 for file in fileList: 294 if os.path.isfile(''.join([path, '/', file])) and file.endswith('.launch'): 295 return True 296 for file in fileList: 297 if os.path.isdir(''.join([path, '/', file])): 298 if self._containsLaunches(''.join([path, '/', file])): 299 return True 300 return False
301 302
303 - def _moveDown(self, path):
304 ''' 305 Moves recursively down in the path tree until the current path contains a 306 launch file. 307 @return: tupel of (root_path, items) 308 @rtype: C{tupel of (root_path, items)} 309 @see: L{LaunchListModel._setNewList()} 310 ''' 311 result_list = [] 312 dirlist = os.listdir(path) 313 for file in dirlist: 314 item = os.path.normpath(''.join([path, '/', file])) 315 pathItem = os.path.basename(item) 316 pathId = self._identifyPath(item) 317 if (pathId != LaunchListModel.NOT_FOUND): 318 result_list.append((pathItem, item, pathId)) 319 if len(result_list) == 1 and not os.path.isfile(result_list[0][1]): 320 return self._moveDown(result_list[0][1]) 321 return path, result_list
322
323 - def _moveUp(self, path):
324 ''' 325 Moves recursively up in the path tree until the current path contains a 326 launch file or the root path defined by ROS_PACKAGES_PATH is reached. 327 @return: tupel of (root_path, items) 328 @rtype: C{tupel of (root_path, items)} 329 @see: L{LaunchListModel._setNewList()} 330 ''' 331 result_list = [] 332 if path is None or not self._is_in_ros_packages(path): 333 dirlist = self._getRootItems() 334 path = None 335 else: 336 dirlist = os.listdir(path) 337 for file in dirlist: 338 item = os.path.normpath(''.join([path, '/', file])) if not path is None else file 339 pathItem = os.path.basename(item) 340 pathId = self._identifyPath(item) 341 if (pathId != LaunchListModel.NOT_FOUND): 342 result_list.append((pathItem, item, pathId)) 343 if not path is None and len(result_list) == 1 and not os.path.isfile(result_list[0][1]): 344 return self._moveUp(os.path.dirname(path)) 345 else: 346 self.currentPath = None 347 return path, result_list
348
349 - def _getLoadHistory(self):
350 ''' 351 Read the history of the recently loaded files from the file stored in ROS_HOME path. 352 @return: the list with file names 353 @rtype: C{[str]} 354 ''' 355 result = list() 356 historyFile = ''.join([nm.CFG_PATH, 'launch.history']) 357 if os.path.isfile(historyFile): 358 with open(historyFile, 'r') as f: 359 line = f.readline() 360 while line: 361 if line: 362 result.append(line.strip()) 363 line = f.readline() 364 f.closed 365 return result
366
367 - def _storeLoadHistory(self, files):
368 ''' 369 Saves the list of recently loaded files to history. The existing history will be replaced! 370 @param files: the list with filenames 371 @type files: C{[str]} 372 ''' 373 if not os.path.isdir(nm.CFG_PATH): 374 os.makedirs(nm.CFG_PATH) 375 with open(''.join([nm.CFG_PATH, 'launch.history']), 'w') as f: 376 for files in files: 377 f.write(''.join([files, '\n'])) 378 f.closed
379