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  from python_qt_binding.QtCore import QMimeData, Qt 
 34  try: 
 35      from python_qt_binding.QtGui import QApplication, QInputDialog, QLineEdit, QMessageBox 
 36  except: 
 37      from python_qt_binding.QtWidgets import QApplication, QInputDialog, QLineEdit, QMessageBox 
 38  from python_qt_binding.QtGui import QIcon, QStandardItem, QStandardItemModel 
 39  import os 
 40  import shutil 
 41   
 42  import node_manager_fkie as nm 
 43   
 44  from .common import is_package, package_name 
 45  from .detailed_msg_box import WarningMessageBox 
 46  from .packages_thread import PackagesThread 
47 48 49 -class LaunchItem(QStandardItem):
50 ''' 51 The launch item stored in the launch model. 52 ''' 53 54 ITEM_TYPE = QStandardItem.UserType + 40 55 56 NOT_FOUND = -1 57 NOTHING = 0 58 RECENT_FILE = 1 59 LAUNCH_FILE = 2 60 CFG_FILE = 3 61 FOLDER = 10 62 PACKAGE = 11 63 STACK = 12 64
65 - def __init__(self, name, path, lid, parent=None):
66 ''' 67 Initialize the topic item. 68 @param name: the topic name 69 @type name: C{str} 70 ''' 71 QStandardItem.__init__(self, name) 72 self.parent_item = parent 73 self.name = name 74 self.path = path 75 self.package_name = package_name(os.path.dirname(self.path))[0] 76 self.id = lid 77 if self.id == LaunchItem.FOLDER: 78 self.setIcon(QIcon(":/icons/crystal_clear_folder.png")) 79 elif self.id == LaunchItem.PACKAGE: 80 self.setIcon(QIcon(":/icons/crystal_clear_package.png")) 81 elif self.id == LaunchItem.LAUNCH_FILE: 82 self.setIcon(QIcon(":/icons/crystal_clear_launch_file.png")) 83 elif self.id == LaunchItem.RECENT_FILE: 84 self.setIcon(QIcon(":/icons/crystal_clear_launch_file_recent.png")) 85 elif self.id == LaunchItem.STACK: 86 self.setIcon(QIcon(":/icons/crystal_clear_stack.png"))
87 88 # def __del__(self): 89 # print "delete LAUNCH", self.name 90
91 - def type(self):
92 return LaunchItem.ITEM_TYPE
93
94 - def data(self, role):
95 ''' 96 The view asks us for all sorts of information about our data... 97 @param role: the art of the data 98 @type role: U{QtCore.Qt.DisplayRole<https://srinikom.github.io/pyside-docs/PySide/QtCore/Qt.html>} 99 @see: U{http://www.pyside.org/docs/pyside-1.0.1/PySide/QtCore/Qt.html} 100 ''' 101 if role == Qt.DisplayRole: 102 # return the displayed item name 103 if self.id == LaunchItem.RECENT_FILE: 104 return "%s [%s]" % (self.name, self.package_name) # .decode(sys.getfilesystemencoding()) 105 else: 106 return "%s" % self.name 107 elif role == Qt.ToolTipRole: 108 # return the tooltip of the item 109 result = "%s" % self.path 110 if self.id == LaunchItem.RECENT_FILE: 111 result = "%s\nPress 'Delete' to remove the entry from the history list" % self.path 112 return result 113 # elif role == Qt.DecorationRole: 114 # # return the showed icon 115 # pathItem, path, pathId = self.items[index.row()] 116 # if self.id > LaunchListModel.NOTHING and self.model().icons.has_key(self.id): 117 # return self.model().icons[self.id] 118 # return None 119 elif role == Qt.EditRole: 120 return "%s" % self.name 121 else: 122 # We don't care about anything else, so return default value 123 return QStandardItem.data(self, role)
124
125 - def setData(self, value, role=Qt.EditRole):
126 if role == Qt.EditRole: 127 # rename the file or folder 128 if self.name != value and self.id in [self.RECENT_FILE, self.LAUNCH_FILE, self.CFG_FILE, self.FOLDER]: 129 new_path = os.path.join(os.path.dirname(self.path), value) 130 if not os.path.exists(new_path): 131 os.rename(self.path, new_path) 132 self.name = value 133 self.path = new_path 134 else: 135 WarningMessageBox(QMessageBox.Warning, "Path already exists", 136 "`%s` already exists!" % value, "Complete path: %s" % new_path).exec_() 137 return QStandardItem.setData(self, value, role)
138 139 @classmethod
140 - def getItemList(self, name, path, item_id, root):
141 ''' 142 Creates the list of the items . This list is used for the 143 visualization of topic data as a table row. 144 @param name: the topic name 145 @type name: C{str} 146 @param root: The parent QStandardItem 147 @type root: U{QtGui.QStandardItem<https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>} 148 @return: the list for the representation as a row 149 @rtype: C{[L{LaunchItem} or U{QtGui.QStandardItem<https://srinikom.github.io/pyside-docs/PySide/QtGui/QStandardItem.html>}, ...]} 150 ''' 151 items = [] 152 item = LaunchItem(name, path, item_id, parent=root) 153 items.append(item) 154 return items
155
156 - def isLaunchFile(self):
157 ''' 158 @return: C{True} if it is a launch file 159 @rtype: C{boolean} 160 ''' 161 return self.path is not None and os.path.isfile(self.path) and self.path.endswith('.launch')
162
163 - def isConfigFile(self):
164 ''' 165 @return: C{True} if it is a config file 166 @rtype: C{boolean} 167 ''' 168 return self.id == self.CFG_FILE
169
170 171 -class LaunchListModel(QStandardItemModel):
172 ''' 173 The model to manage the list with launch files. 174 ''' 175 header = [('Name', -1)] 176 '''@ivar: the list with columns C{[(name, width), ...]}''' 177
178 - def __init__(self):
179 ''' 180 Creates a new list model. 181 ''' 182 QStandardItemModel.__init__(self) 183 self.setColumnCount(len(LaunchListModel.header)) 184 self.setHorizontalHeaderLabels([label for label, _width in LaunchListModel.header]) 185 self.pyqt_workaround = dict() # workaround for using with PyQt: store the python object to keep the defined attributes in the TopicItem subclass 186 self.items = [] 187 self.DIR_CACHE = {} 188 self.currentPath = None 189 self.load_history = self._getLoadHistory() 190 self.root_paths = [os.path.normpath(p) for p in os.getenv("ROS_PACKAGE_PATH").split(':')] 191 self._setNewList(self._moveUp(None)) 192 self.__packages = {} 193 self._fill_packages_thread = PackagesThread()
194
195 - def _getRootItems(self):
196 result = list(self.load_history) 197 result.extend(self.root_paths) 198 return result
199
200 - def _fill_packages(self, packages):
201 self.__packages = packages
202 203 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 204 # %%%%%%%%%%%%% Overloaded methods %%%%%%%% 205 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 206
207 - def flags(self, index):
208 ''' 209 @param index: parent of the list 210 @type index: U{QtCore.QModelIndex<https://srinikom.github.io/pyside-docs/PySide/QtCore/QModelIndex.html>} 211 @return: Flag or the requested item 212 @rtype: U{QtCore.Qt.ItemFlag<https://srinikom.github.io/pyside-docs/PySide/QtCore/Qt.html>} 213 @see: U{http://www.pyside.org/docs/pyside-1.0.1/PySide/QtCore/Qt.html} 214 ''' 215 if not index.isValid(): 216 return Qt.NoItemFlags 217 try: 218 item = self.itemFromIndex(index) 219 result = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled 220 if item.id in [LaunchItem.RECENT_FILE, LaunchItem.LAUNCH_FILE, LaunchItem.CFG_FILE, LaunchItem.FOLDER]: 221 result = result | Qt.ItemIsEditable | Qt.ItemIsDragEnabled 222 return result 223 except: 224 return Qt.ItemIsEnabled | Qt.ItemIsSelectable
225 226 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 227 # %%%%%%%%%%%%% Drag operation %%%%%%%% 228 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 229
230 - def mimeTypes(self):
231 return ['text/plain']
232
233 - def mimeData(self, indexes):
234 mimeData = QMimeData() 235 text = '' 236 for index in indexes: 237 if index.isValid(): 238 item = self.itemFromIndex(index) 239 prev = '%s\n' % text if text else '' 240 text = '%sfile://%s' % (prev, item.path) 241 mimeData.setData('text/plain', text) 242 return mimeData
243 244 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 245 # %%%%%%%%%%%%% External usage %%%%%%%% 246 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 247
248 - def reloadPackages(self):
249 ''' 250 Reloads the cached packag list. 251 ''' 252 if not self._fill_packages_thread.isAlive(): 253 self._fill_packages_thread = PackagesThread() 254 self._fill_packages_thread.packages.connect(self._fill_packages) 255 self._fill_packages_thread.start()
256
257 - def reloadCurrentPath(self):
258 ''' 259 Reloads the current path. 260 ''' 261 # clear the cache for package names 262 try: 263 from .common import PACKAGE_CACHE 264 PACKAGE_CACHE.clear() 265 self.DIR_CACHE = {} 266 except: 267 import traceback 268 print traceback.format_exc(2) 269 try: 270 if self.currentPath is None: 271 self._setNewList(self._moveUp(self.currentPath)) 272 else: 273 self._setNewList(self._moveDown(self.currentPath)) 274 except: 275 self._setNewList(self._moveUp(None))
276
277 - def expandItem(self, path_item, path, item_id):
278 ''' 279 Returns for the given item and path the file path if this is a file. Otherwise the 280 folder will be expanded and None will be returned. 281 @param path_item: the list item 282 @type path_item: C{str} 283 @param path: the real path of the item 284 @type path: C{str} 285 @return: path of the launch file or None 286 @rtype: C{str} 287 @raise Exception if no path to given item was found 288 ''' 289 if path_item == '..': 290 goto_path = os.path.dirname(path) 291 key_mod = QApplication.keyboardModifiers() 292 if key_mod & Qt.ControlModifier: 293 goto_path = None 294 root_path, items = self._moveUp(goto_path) 295 elif os.path.isfile(path): 296 return path 297 elif item_id == LaunchItem.RECENT_FILE or item_id == LaunchItem.LAUNCH_FILE: 298 raise Exception("Invalid file path: %s", path) 299 else: 300 key_mod = QApplication.keyboardModifiers() 301 onestep = False 302 if key_mod & Qt.ControlModifier: 303 onestep = True 304 root_path, items = self._moveDown(path, onestep) 305 self._setNewList((root_path, items)) 306 return None
307
308 - def setPath(self, path):
309 ''' 310 Shows the new path in the launch configuration view. Only if the new path 311 is in ros package paths 312 @param path: new path 313 @type path: C{str} 314 ''' 315 # if self._is_in_ros_packages(path): 316 self._setNewList(self._moveDown(path))
317
318 - def add2LoadHistory(self, launch_file):
319 try: 320 self.load_history.remove(launch_file) 321 except: 322 pass 323 self.load_history.append(launch_file) 324 try: 325 while len(self.load_history) > nm.settings().launch_history_length: 326 self.load_history.pop(0) 327 except: 328 pass 329 self._storeLoadHistory(self.load_history)
330 # self.reloadCurrentPath() # todo: keep the item selected in list view after the reload the path 331
332 - def removeFromLoadHistory(self, launch_file):
333 try: 334 self.load_history.remove(launch_file) 335 except: 336 pass 337 self._storeLoadHistory(self.load_history)
338 # self.reloadCurrentPath() # todo: keep the item selected in list view after the reload the path 339
340 - def show_packages(self, show):
341 if show: 342 # clear the cache for package names 343 try: 344 items = [] 345 for package, path in self.__packages.items(): 346 items.append((package, path, LaunchItem.PACKAGE)) 347 self._setNewList((self.currentPath if self.currentPath else '', items)) 348 except: 349 import traceback 350 print traceback.format_exc(2) 351 else: 352 self._setNewList(self._moveUp(self.currentPath))
353
354 - def paste_from_clipboard(self):
355 ''' 356 Copy the file or folder to new position... 357 ''' 358 if QApplication.clipboard().mimeData().hasText() and self.currentPath: 359 text = QApplication.clipboard().mimeData().text() 360 if text.startswith('file://'): 361 path = text.replace('file://', '') 362 basename = os.path.basename(text) 363 ok = True 364 if os.path.exists(os.path.join(self.currentPath, basename)): 365 basename, ok = QInputDialog.getText(None, 'File exists', 'New name (or override):', QLineEdit.Normal, basename) 366 if ok and basename: 367 if os.path.isdir(path): 368 shutil.copytree(path, os.path.join(self.currentPath, basename)) 369 elif os.path.isfile(path): 370 shutil.copy2(path, os.path.join(self.currentPath, basename)) 371 self.reloadCurrentPath()
372
373 - def copy_to_clipboard(self, indexes):
374 ''' 375 Copy the selected path to the clipboard 376 ''' 377 mimeData = QMimeData() 378 text = '' 379 for index in indexes: 380 if index.isValid(): 381 item = self.itemFromIndex(index) 382 prev = '%s\n' % text if text else '' 383 text = '%sfile://%s' % (prev, item.path) 384 mimeData.setData('text/plain', text) 385 QApplication.clipboard().setMimeData(mimeData)
386 387 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 388 # %%%%%%%%%%%%% Functionality %%%%%%%% 389 # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 390
391 - def _setNewList(self, (root_path, items)):
392 ''' 393 Sets the list to the given path and insert the items. If the root path is not 394 None the additional item '..' to go up will be inserted. The items parameter 395 is a tupel with three values (the displayed name, the path of the item, the id 396 of the item). 397 @see: L{LaunchListModel._addPathToList()} 398 @param root_path: the root directory 399 @type root_path: C{str} 400 @param items: the list with characterized items 401 @type items: C{[(item, path, id)]} 402 ''' 403 root = self.invisibleRootItem() 404 while root.rowCount(): 405 root.removeRow(0) 406 self.pyqt_workaround.clear() 407 # add new items 408 if root_path is not None: 409 self._addPathToList('..', root_path, LaunchItem.NOTHING) 410 for item_name, item_path, item_id in items: 411 self._addPathToList(item_name, item_path, item_id) 412 self.currentPath = root_path
413
414 - def _is_in_ros_packages(self, path):
415 ''' 416 Test whether the given path is in ROS_PACKAGE_PATH. 417 @return: C{True}, if the path is in the ROS_PACKAGE_PATH 418 @rtype: C{boolean} 419 ''' 420 # TODO fix for paths with symbolic links 421 for p in self.root_paths: 422 if path.startswith(p): 423 return True 424 return False
425
426 - def _addPathToList(self, item, path, path_id):
427 ''' 428 Inserts the given item in the list model. 429 @param item: the displayed name 430 @type item: C{str} 431 @param path: the path of the item 432 @type path: C{str} 433 @param path_id: the id of the item, which represents whether it is a file, package or stack. 434 @type path_id: C{constants of LaunchListModel} 435 ''' 436 root = self.invisibleRootItem() 437 if item is None or path is None or path_id == LaunchItem.NOT_FOUND: 438 return False 439 if (path_id != LaunchItem.NOT_FOUND): 440 # add sorted a new entry 441 try: 442 for i in range(root.rowCount()): 443 launchItem = root.child(i) 444 launch_file_cmp = (path_id in [LaunchItem.RECENT_FILE, LaunchItem.LAUNCH_FILE] and item < launchItem.name) 445 launch_id_cmp = (launchItem.id > path_id and launchItem.id > LaunchItem.LAUNCH_FILE) 446 launch_name_cmp = (launchItem.id == path_id and item < launchItem.name) 447 if launch_file_cmp or launch_id_cmp or launch_name_cmp: 448 new_item_row = LaunchItem.getItemList(item, path, path_id, root) 449 root.insertRow(i, new_item_row) 450 self.pyqt_workaround[item] = new_item_row[0] # workaround for using with PyQt: store the python object to keep the defined attributes in the TopicItem subclass 451 return True 452 new_item_row = LaunchItem.getItemList(item, path, path_id, root) 453 root.appendRow(new_item_row) 454 self.pyqt_workaround[item] = new_item_row[0] 455 return True 456 except: 457 import traceback 458 print traceback.format_exc(2) 459 return False
460
461 - def _identifyPath(self, path):
462 ''' 463 Determines the id of the given path 464 @return: the id represents whether it is a file, package or stack 465 @rtype: C{constants of LaunchItem} 466 ''' 467 if path in self.DIR_CACHE: 468 if path in self.load_history: 469 return LaunchItem.RECENT_FILE 470 return self.DIR_CACHE[path] 471 if os.path.basename(path)[0] != '.': 472 if path in self.load_history: 473 self.DIR_CACHE[path] = LaunchItem.RECENT_FILE 474 return LaunchItem.RECENT_FILE 475 elif os.path.isfile(path): 476 if (path.endswith('.launch')): 477 self.DIR_CACHE[path] = LaunchItem.LAUNCH_FILE 478 return LaunchItem.LAUNCH_FILE 479 else: 480 for e in nm.settings().launch_view_file_ext: 481 if path.endswith(e): 482 self.DIR_CACHE[path] = LaunchItem.CFG_FILE 483 return LaunchItem.CFG_FILE 484 elif os.path.isdir(path): 485 fileList = os.listdir(path) 486 if self._containsLaunches(path): 487 if 'stack.xml' in fileList: 488 self.DIR_CACHE[path] = LaunchItem.STACK 489 return LaunchItem.STACK 490 elif is_package(fileList): 491 self.DIR_CACHE[path] = LaunchItem.PACKAGE 492 return LaunchItem.PACKAGE 493 else: 494 self.DIR_CACHE[path] = LaunchItem.FOLDER 495 return LaunchItem.FOLDER 496 self.DIR_CACHE[path] = LaunchItem.NOT_FOUND 497 return LaunchItem.NOT_FOUND
498
499 - def _containsLaunches(self, path):
500 ''' 501 Moves recursively down in the path tree and searches for a launch file. If 502 one is found True will be returned. 503 @return: C{True} if the path contains a launch file. 504 @rtype: C{boolean} 505 ''' 506 fileList = os.listdir(path) 507 for cfile in fileList: 508 _, file_extension = os.path.splitext(cfile) 509 if os.path.isfile(os.path.join(path, cfile)) and (cfile.endswith('.launch')) or (file_extension in nm.settings().launch_view_file_ext): 510 return True 511 for cfile in fileList: 512 if os.path.isdir(os.path.join(path, cfile)): 513 if self._containsLaunches(os.path.join(path, cfile)): 514 return True 515 return False
516
517 - def _moveDown(self, path, onestep=False):
518 ''' 519 Moves recursively down in the path tree until the current path contains a 520 launch file. 521 @return: tupel of (root_path, items) 522 @rtype: C{tupel of (root_path, items)} 523 @see: L{LaunchListModel._setNewList()} 524 ''' 525 result_list = [] 526 dirlist = os.listdir(path) 527 for cfile in dirlist: 528 item = os.path.normpath(''.join([path, '/', cfile])) 529 pathItem = os.path.basename(item) 530 if pathItem == 'src': 531 pathItem = '%s (src)' % os.path.basename(os.path.dirname(item)) 532 pathId = self._identifyPath(item) 533 if (pathId != LaunchItem.NOT_FOUND): 534 result_list.append((pathItem, item, pathId)) 535 if len(result_list) == 1 and not os.path.isfile(result_list[0][1]): 536 if not onestep: 537 return self._moveDown(result_list[0][1]) 538 return path, result_list
539
540 - def _moveUp(self, path):
541 ''' 542 Moves recursively up in the path tree until the current path contains a 543 launch file or the root path defined by ROS_PACKAGES_PATH is reached. 544 @return: tupel of (root_path, items) 545 @rtype: C{tupel of (root_path, items)} 546 @see: L{LaunchListModel._setNewList()} 547 ''' 548 result_list = [] 549 if path is None or not self._is_in_ros_packages(path): 550 dirlist = self._getRootItems() 551 path = None 552 else: 553 dirlist = os.listdir(path) 554 for dfile in dirlist: 555 item = os.path.normpath(os.path.join(path, dfile)) if path is not None else dfile 556 pathItem = os.path.basename(item) 557 if pathItem == 'src': 558 pathItem = '%s (src)' % os.path.basename(os.path.dirname(item)) 559 pathId = self._identifyPath(item) 560 if (pathId != LaunchItem.NOT_FOUND): 561 result_list.append((pathItem, item, pathId)) 562 if path is not None and len(result_list) == 1 and not os.path.isfile(result_list[0][1]): 563 return self._moveUp(os.path.dirname(path)) 564 else: 565 self.currentPath = None 566 return path, result_list
567
568 - def _getLoadHistory(self):
569 ''' 570 Read the history of the recently loaded files from the file stored in ROS_HOME path. 571 @return: the list with file names 572 @rtype: C{[str]} 573 ''' 574 result = list() 575 historyFile = nm.settings().qsettings(nm.settings().LAUNCH_HISTORY_FILE) 576 size = historyFile.beginReadArray("launch_history") 577 for i in range(size): 578 historyFile.setArrayIndex(i) 579 if i >= nm.settings().launch_history_length: 580 break 581 launch_file = historyFile.value("file") 582 if os.path.isfile(launch_file): 583 result.append(launch_file) 584 historyFile.endArray() 585 return result
586
587 - def _storeLoadHistory(self, files):
588 ''' 589 Saves the list of recently loaded files to history. The existing history will be replaced! 590 @param files: the list with filenames 591 @type files: C{[str]} 592 ''' 593 historyFile = nm.settings().qsettings(nm.settings().LAUNCH_HISTORY_FILE) 594 historyFile.beginWriteArray("launch_history") 595 for i, launch_file in enumerate(files): 596 historyFile.setArrayIndex(i) 597 historyFile.setValue("file", launch_file) 598 historyFile.endArray()
599