#!/usr/bin/env python #**************************************************************************** # treestates.py, class to keep track of recent files' meta-data # # Copyright (C) 2004, Jan Hustak # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, Version 2. This program is # distributed in the hope that it will be useful, but WITTHOUT ANY WARRANTY. #***************************************************************************** import globalref from os import stat from qt import QPoint from time import time class TreeStates: """Tracks, loads & saves tree states of recently opened files""" DefaultState = '0:0:0:0' # timestamp:firstVisible:selected:openNodes def __init__(self, fileList): self.treeStates = {} for i in range(len(fileList)): state = globalref.options.strData(self.optionName(i), True) if not state: state = TreeStates.DefaultState self.treeStates[fileList[i]] = state self.currentFile = '' def fileListChanged(self, newList): """Sync tree states with the list of recent files""" newTreeStates = {} self.currentFile = '' for i in range(len(newList)): filePath = newList[i] treeState = self.getStateByFile(filePath) globalref.options.changeData(self.optionName(i), treeState, True) newTreeStates[filePath] = treeState globalref.options.writeChanges() self.treeStates = newTreeStates if newList: self.currentFile = newList[0] def clear(self): """Clear tree states of all recent files""" for i in range(len(self.treeStates)): globalref.options.changeData(self.optionName(i), \ TreeStates.DefaultState, True) globalref.options.writeChanges() self.treeStates = {} def loadCurrent(self, view): """Apply the tree state to the currently open file and update the views""" if not self.currentFile: globalref.updateViewAll() return fileTimestamp = stat(self.currentFile).st_mtime stateTokens = self.getStateByFile(self.currentFile).split(':') if fileTimestamp > int(stateTokens[0]): # file modified externally interimState = str(int(fileTimestamp)) + ':0:0:0' # see DefaultState self.treeStates[self.currentFile] = interimState globalref.options.changeData(self.optionName(0), interimState, True) stateTokens = interimState.split(':') globalref.options.writeChanges() allNodes = globalref.docRef.root.descendantList(True) try: selectedNode = allNodes[int(stateTokens[2])] except IndexError: selectedNode = allNodes[0] globalref.docRef.selection.replace([selectedNode]) self.loadOpenNodes(allNodes, stateTokens[3]) globalref.updateViewAll() try: firstVisibleItem = allNodes[int(stateTokens[1])] view.setContentsPos(0, view.itemPos(firstVisibleItem.viewData)) except (IndexError, AttributeError): pass def saveCurrent(self, view): """Persist the tree state of the currently open file""" if not self.currentFile: return allNodes = globalref.docRef.root.descendantList(True) firstNode = str(allNodes.index(view.itemAt(QPoint(0, 0)).docItemRef)) selectNode = str(allNodes.index(globalref.docRef.selection.currentItem)) openNodes = self.saveOpenNodes(allNodes) state = '%s:%s:%s:%s' % (str(int(time())), firstNode, selectNode, \ openNodes) self.treeStates[self.currentFile] = state globalref.options.changeData(self.optionName(0), state, True) globalref.options.writeChanges() def getStateByFile(self, filePath): """Retrieve the given file's tree state or the default""" try: treeState = self.treeStates[filePath] except KeyError: treeState = TreeStates.DefaultState if not treeState: treeState = TreeStates.DefaultState return treeState def optionName(self, index): return 'TreeState' + `index + 1` def loadOpenNodes(self, allNodes, stateStr): """Set nodes' visibility state according to stateStr""" openNodeIndices = [int(x) for x in stateStr.split(',')] for index in openNodeIndices: try: node = allNodes[index] except IndexError: return # nodes don't exist, posssibly due to file import issues while not node.open and node != allNodes[0]: node.open = True node = node.parent def saveOpenNodes(self, allNodes): """Serialize visible nodes into a string""" openList = [] if not allNodes[0].open: # root closed, return default return '0' for i, node in enumerate(allNodes): if node.open and \ not [child for child in node.childList if child.open] and \ node.allAncestorsOpen(): openList.append(str(i)) return ','.join(openList)