def __init__(self, mainWindow): QWidget.__init__(self, mainWindow) self.__mainWindow = mainWindow #self.__action = action self.sched = scheduler.sched self.vfs = VFS.Get() self.__listFiles = [] self.childSelected = None self.childSelectedLock = QReadWriteLock() self.configure() self.g_display() self.initCallback()
def __init__(self, mainWindow): QWidget.__init__(self, mainWindow) self.__mainWindow = mainWindow #self.__action = action self.sched = scheduler.sched self.vfs = VFS.Get() self.__listFiles = [] self.childSelected = None self.childSelectedLock = QReadWriteLock() self.configure() self.g_display() self.initCallback()
class RWLock(object): def __init__(self): self.lock = QReadWriteLock() @property @contextmanager def readLock(self): self.lock.lockForRead() yield self.lock.unlock() @property @contextmanager def writeLock(self): self.lock.lockForWrite() yield self.lock.unlock()
class SaveThread(QThread): lock = QReadWriteLock() def __init__(self, canvas, colors, activeSymbol, settings, saveFileName, markProjectClean, parent=None): super(SaveThread, self).__init__(parent) self.canvas = canvas self.colors = colors self.activeSymbol = activeSymbol self.settings = settings self.saveFileName = saveFileName self.markProjectClean = markProjectClean def start(self): """ Main start routine of our SaveThread. Simply calls save_project and emits a signal with the results when done. """ with QWriteLocker(SaveThread.lock): (status, errorMsg) = save_project(self.canvas, self.colors, self.activeSymbol, self.settings, self.saveFileName) self.emit(SIGNAL("saving_done"), status, errorMsg, self.saveFileName, self.markProjectClean)
def __init__(self, size = 10000): self.size = size self.fill_pointer = 0 self.ring = [None] * size self.lock = QReadWriteLock()
class LockableRingBuffer (object): """ Ein Ring Buffer mittels einfacher Liste, der Lese- und Schreibzugriffe nicht simultan überwacht. Lesezugriff ist wahlfrei mit buffer[i], Schreibzugriff geht nur über buffer.append(item), welches den Index des gespeicherten Objekts zurückgibt. """ def __init__(self, size = 10000): self.size = size self.fill_pointer = 0 self.ring = [None] * size self.lock = QReadWriteLock() def __getitem__(self, index): self.lock.lockForRead() item = self.ring[index % self.size] self.lock.unlock() return item def __setitem__(self, index, item): self.lock.lockForWrite() self.ring[index % self.size] = item self.lock.unlock() def __len__(self): return self.size def append(self, item): self.lock.lockForWrite() i = self.fill_pointer self.ring[i] = item self.fill_pointer = (i + 1) % self.size self.lock.unlock() return i def reserve(self): self.lock.lockForWrite() i = self.fill_pointer self.fill_pointer = (i + 1) % self.size self.lock.unlock() return i
def __init__(self): self.lock = QReadWriteLock()
class __NodeTree(QWidget): def __init__(self, mainWindow): QWidget.__init__(self, mainWindow) self.__mainWindow = mainWindow #self.__action = action self.sched = scheduler.sched self.vfs = VFS.Get() self.__listFiles = [] self.childSelected = None self.childSelectedLock = QReadWriteLock() self.configure() self.g_display() self.initCallback() def configure(self): self.setObjectName("Browser") self.resize(300, 300) def g_display(self): self.layout = QHBoxLayout(self) # Browser tmp = ["Virtual File System"] self.treeItemModel = TreeItemModel(tmp) self.treeView = TreeView(self, self.__mainWindow, self.treeItemModel) self.layout.addWidget(self.treeView) # Set Model and Resize self.treeView.setModel(self.treeItemModel) self.treeItemModel.addRootVFS() self.treeItemModel.fillAllDirectory(self.treeItemModel.rootItemVFS) self.treeItemModel.reset() self.treeView.resizeAllColumn() self.treeView.setCurrentIndex( self.treeItemModel.createIndex( self.treeItemModel.rootItemVFS.childNumber(), 0, self.treeItemModel.rootItemVFS)) def initCallback(self): self.connect(self, SIGNAL("refreshNodeView"), self.refreshNodeView) self.sched.set_callback("refresh_tree", self.refreshNode) self.vfs.set_callback("refresh_tree", self.refreshNode) def refreshNode(self, node): index = self.treeView.currentIndex() isExpanded = self.treeView.isExpanded(index) item = self.treeItemModel.getItemWithPath(node.absolute()) self.treeItemModel.fillAllDirectory(self.treeItemModel.rootItemVFS) self.treeItemModel.reset() self.emit(SIGNAL("refreshNodeView"), index, isExpanded) self.emit(SIGNAL("reloadNodeView")) def refreshNodeView(self, index, isExpanded): self.treeView.expandAllIndex(index) self.treeView.setCurrentIndex(index) self.treeView.setExpanded(index, isExpanded) def setChild(self, child): if self.childSelectedLock.tryLockForWrite(): self.childSelected = child self.childSelectedLock.unlock() def getChild(self): if self.childSelectedLock.tryLockForRead(): tmp = self.childSelected self.childSelectedLock.unlock() return tmp def addList(self): dockList = DockNodeList(self.__mainWindow, self, len(self.__listFiles)) self.__listFiles.append(dockList) self.__mainWindow.addNewDockWidgetTab(Qt.RightDockWidgetArea, dockList) dockList.initContents(self.treeView.getCurrentItem().node, self.treeView.currentIndex()) return dockList
def __init__(self, debug=False): self.debug = debug self._dict = dict() self._prepare_dir() self._remove_tmps() self._lock = QReadWriteLock()
class __Config(object): def __init__(self, debug=False): self.debug = debug self._dict = dict() self._prepare_dir() self._remove_tmps() self._lock = QReadWriteLock() def __getitem__(self, key): self._lock.lockForRead() r = self._dict[key] self._lock.unlock() return r def __setitem__(self, key, value): self._lock.lockForWrite() self._dict[key] = value self._lock.unlock() def get(self, key, default=None): self._lock.lockForRead() r = self._dict.get(key, default) self._lock.unlock() return r def pop(self, key, default=None): self._lock.lockForWrite() r = self._dict.pop(key, default) self._lock.unlock() return r def __contains__(self, key): self._lock.lockForRead() r = self._dict.__contains__(key) self._lock.unlock() return r def __str__(self): self._lock.lockForRead() s = ''.join([ 'Config(', ', '.join("{0}: {1}".format(k, v) for (k, v) in self._dict), ')']) self._lock.unlock() return s @property def _config_dir(self): # Windows if sys.platform.startswith('win'): if 'LOCALAPPDATA' in os.environ: return os.path.join( os.environ['LOCALAPPDATA'], 'LDOCE5Viewer') else: return os.path.join( os.environ['APPDATA'], 'LDOCE5Viewer') # Mac OS X elif sys.platform.startswith('darwin'): return os.path.expanduser( '~/Library/Application Support/LDOCE5Viewer') # Linux else: base = os.path.join(os.path.expanduser('~'), '.config') # XDG try: import xdg.BaseDirectory base = xdg.BaseDirectory.xdg_config_home except ImportError: if 'XDG_CONFIG_HOME' in os.environ: base = os.environ['XDG_CONFIG_HOME'] return os.path.join(base, 'ldoce5viewer') @property def _data_dir(self): # Windows if sys.platform.startswith('win'): return self._config_dir # Mac OS X elif sys.platform.startswith('darwin'): return self._config_dir # Linux else: base = os.path.join(os.path.expanduser('~'), '.local/share/') # XDG try: import xdg.BaseDirectory base = xdg.BaseDirectory.xdg_data_home except ImportError: if 'XDG_DATA_HOME' in os.environ: base = os.environ['XDG_DATA_HOME'] return os.path.join(base, 'ldoce5viewer') @property def app_name(self): return 'LDOCE5 Viewer' @property def _config_path(self): return os.path.join(self._config_dir, 'config.pickle') @property def filemap_path(self): return os.path.join(self._data_dir, 'filemap.cdb') @property def variations_path(self): return os.path.join(self._data_dir, 'variations.cdb') @property def incremental_path(self): return os.path.join(self._data_dir, 'incremental.db') @property def fulltext_hwdphr_path(self): return os.path.join(self._data_dir, 'fulltext_hp') @property def fulltext_defexa_path(self): return os.path.join(self._data_dir, 'fulltext_de') @property def scan_tmp_path(self): return os.path.join(self._data_dir, 'scan' + self.tmp_suffix) @property def tmp_suffix(self): return '.tmp' def _remove_tmps(self): for name in os.listdir(self._config_dir) + os.listdir(self._data_dir): if name.endswith(self.tmp_suffix): path = os.path.join(self._config_dir, name) try: if os.path.isfile(path): os.remove(path) elif os.path.isdir(path): shutil.rmtree(path) except OSError: pass def _prepare_dir(self): if not os.path.exists(self._config_dir): os.makedirs(self._config_dir) if not os.path.exists(self._data_dir): os.makedirs(self._data_dir) def load(self): self._lock.lockForWrite() try: with open(self._config_path, 'rb') as f: self._dict.clear() try: data = pickle.load(f) except: pass else: self._dict.update(data) except IOError: self._dict.clear() self._lock.unlock() def save(self): self._lock.lockForRead() if sys.platform == 'win32': with open(self._config_path, 'wb') as f: pickle.dump(self._dict, f) else: f = tempfile.NamedTemporaryFile( dir=self._config_dir, delete=False, suffix=self.tmp_suffix) pickle.dump(self._dict, f, protocol=0) f.close() os.rename(f.name, self._config_path) self._lock.unlock()
def __init__(self, argv=[]): # run the initializer of the class inherited from6 super(LabGuiMain, self).__init__() self.settings = QSettings(self) self.settings.setValue("state", self.saveState()) #debug parameter used to run labgui even when there is no instrument #to connect to, used to plot past data or test the code self.DEBUG = True #variable to store the configfile name self.config_file = '' #parse the argument(s) passed inline try: #option c is to provide a name for config file opts, args = getopt.getopt(argv, "c:") #loop through the arguments on the inline command for opt, arg in opts: #user passed configfile if opt == '-c': self.config_file = arg except getopt.GetoptError: logging.error('configuration file : option -c argument missing') #verify if the config file passed by the user is valid and exists if self.config_file: if not exists(self.config_file): logging.error("The config file you provided ('%s') doesn't \ exist, '%s' will be used instead" % (self.config_file, CONFIG_FILE)) self.config_file = CONFIG_FILE else: #check whether the default config file exists or not if exists(CONFIG_FILE) == False: logging.warning("A '%s' file has been generated for you." % (CONFIG_FILE)) logging.warning("Please modify it to change the default \ script, settings and data locations, or to enter debug mode.") # creates a config.txt with basic needs IOTool.create_config_file() #sets default config file name self.config_file = CONFIG_FILE #to make sure the config file is of the right format #ie that the user didn't specify the name of an existing file which #isn't a configuration file config_file_ok = False while not config_file_ok: try: #try to read the DEBUG parameter from the configuration file #as a test of the good formatting of the file self.DEBUG = IOTool.get_debug_setting( config_file_path=self.config_file) #if this didn't generate errors we allow to get out of the loop config_file_ok = True except IOError: logging.error("The config file you provided ('%s') doesn't \ have the right format, '%s' will be used instead" % (self.config_file, CONFIG_FILE)) #check whether the default config file exists or not if exists(CONFIG_FILE) == False: logging.warning("A '%s' file has been generated for you." % (CONFIG_FILE)) logging.warning("Please modify it to change the default \ script, settings and data locations, or to enter debug mode.") # creates a config.txt with basic needs IOTool.create_config_file() #sets default config file name self.config_file = CONFIG_FILE print("Configuration loaded from : %s" % (self.config_file)) if self.DEBUG == True: print("*" * 20) print("Debug mode is set to True") print("*" * 20) self.option_display_debug_state() else: self.option_display_normal_state() #create the central part of the application self.zoneCentrale = QtGui.QMdiArea() self.zoneCentrale.subWindowActivated.connect( self.update_current_window) self.setCentralWidget(self.zoneCentrale) #load the parameter for the GPIB interface setting of the instruments interface = IOTool.get_interface_setting( config_file_path=self.config_file) #test if the parameter is correct if interface not in [Tool.INTF_VISA, Tool.INTF_PROLOGIX]: msg = """The %s variable of the config file '%s' is not correct The only two allowed values are : '%s' and '%s' """ % ( IOTool.GPIB_INTF_ID, IOTool.CONFIG_FILE, Tool.INTF_VISA, Tool.INTF_PROLOGIX) logging.warning(msg) #default setting Tool.INTF_GPIB = Tool.INTF_PROLOGIX else: Tool.INTF_GPIB = interface print("*" * 20) print("The GPIB setting for connecting instruments is %s" % (Tool.INTF_GPIB)) print("*" * 20) # the lock is something for multithreading... not sure if it's important in our application. self.lock = QReadWriteLock() # InstrumentHub is responsible for storing and managing the user # choices about which instrument goes on which port self.instr_hub = Tool.InstrumentHub(parent=self, debug=self.DEBUG) # DataTaker is responsible for taking data from instruments in the # InstrumentHub object self.datataker = DataManagement.DataTaker(self.lock, self.instr_hub) # handle data emitted by datataker (basically stuff it into a shared, # central array) self.connect(self.datataker, SIGNAL("data(PyQt_PyObject)"), self.update_data_array) #a signal to signify the data taking script is over self.connect(self.datataker, SIGNAL("script_finished(bool)"), self.finished_DTT) #the array in which the data will be stored self.data_array = np.array([]) # all actions related to the figure widget (mplZoomWidget.py) are # set up in the actionmanager self.action_manager = mplZoomWidget.ActionManager(self) #this will contain the widget of the latest pdw created upon #connecting the instrument Hub self.actual_pdw = None #this will contain windows settings (labels, checkboxes states, colors) #of the plotdisplaw window which is created when the user click on #the connect button self.plot_window_settings = None #### set up menus and toolbars self.fileMenu = self.menuBar().addMenu("File") self.plotMenu = self.menuBar().addMenu("&Plot") self.instMenu = self.menuBar().addMenu("&Meas/Connect") self.windowMenu = self.menuBar().addMenu("&Window") self.optionMenu = self.menuBar().addMenu("&Options") self.loggingSubMenu = self.optionMenu.addMenu("&Logger output level") self.plotToolbar = self.addToolBar("Plot") self.instToolbar = self.addToolBar("Instruments") # start/stop/pause buttons self.start_DTT_action = QtTools.create_action( self, "Start DTT", slot=self.start_DTT, shortcut=QtGui.QKeySequence("F5"), icon="start", tip="Start script") self.stop_DTT_action = QtTools.create_action( self, "Stop DTT", slot=self.stop_DTT, shortcut=QtGui.QKeySequence("F6"), icon="stop", tip="stop script") self.pause_DTT_action = QtTools.create_action( self, "Pause DTT", slot=self.pause_DTT, shortcut=QtGui.QKeySequence("F7"), icon="pause", tip="pause script") self.pause_DTT_action.setEnabled(False) self.stop_DTT_action.setEnabled(False) self.instToolbar.setObjectName("InstToolBar") self.instToolbar.addAction(self.start_DTT_action) self.instToolbar.addAction(self.pause_DTT_action) self.instToolbar.addAction(self.stop_DTT_action) #this will contain the different widgets in the window self.widgets = {} cur_path = os.path.dirname(__file__) #find the path to the widgets folders widget_path = os.path.join(cur_path, 'LabTools') #these are widgets essential to the interface core_widget_path = os.path.join(widget_path, 'CoreWidgets') #these are widgets which were added by users user_widget_path = os.path.join(widget_path, 'UserWidgets') #this is the legitimate list of core widgets widgets_list = [ o.rstrip('.py') for o in os.listdir(core_widget_path) if o.endswith(".py") and not "__init__" in o ] #this is the legitimate list of user widgets user_widgets_list = [ o.rstrip('.py') for o in os.listdir(user_widget_path) if o.endswith(".py") and not "__init__" in o ] #the user widgets the user would like to run, given in the config file user_widgets = IOTool.get_user_widgets( config_file_path=self.config_file) if user_widgets: for user_widget in user_widgets: #check that the given widget is legitimate if user_widget in user_widgets_list: #add the given widget to the widget list which will be #loaded widgets_list.append(user_widget) else: logging.warning("The user widget '%s' is not found at %s" % (user_widget, user_widget_path)) #add the widgets to the interface for widget in widgets_list: widget_name = widget try: widget_module = import_module("." + widget_name, package=COREWIDGETS_PACKAGE_NAME) except ImportError: widget_module = import_module("." + widget_name, package=USERWIDGETS_PACKAGE_NAME) self.add_widget(widget_module.add_widget_into_main) ###### FILE MENU SETUP ###### self.fileSaveSettingsAction = QtTools.create_action( self, "Save Instrument Settings", slot=self.file_save_settings, shortcut=QtGui.QKeySequence.SaveAs, icon=None, tip="Save the current instrument settings") self.fileLoadSettingsAction = QtTools.create_action( self, "Load Instrument Settings", slot=self.file_load_settings, shortcut=QtGui.QKeySequence.Open, icon=None, tip="Load instrument settings from file") self.fileLoadDataAction = QtTools.create_action( self, "Load Previous Data", slot=self.file_load_data, shortcut=None, icon=None, tip="Load previous data from file") """this is not working I will leave it commented right now""" # self.filePrintAction = QtTools.create_action(self, "&Print Report", slot=self.file_print, shortcut=QtGui.QKeySequence.Print, # icon=None, tip="Print the figure along with relevant information") self.fileSaveCongfigAction = QtTools.create_action( self, "Save current configuration", slot=self.file_save_config, shortcut=None, icon=None, tip="Save the setting file path, \ the script path and the data output path into the config file") self.fileMenu.addAction(self.fileLoadSettingsAction) self.fileMenu.addAction(self.fileSaveSettingsAction) self.fileMenu.addAction(self.fileLoadDataAction) # self.fileMenu.addAction(self.filePrintAction) self.fileMenu.addAction(self.action_manager.saveFigAction) self.fileMenu.addAction(self.fileSaveCongfigAction) ###### PLOT MENU + TOOLBAR SETUP ###### self.plotToolbar.setObjectName("PlotToolBar") for action in self.action_manager.actions: self.plotMenu.addAction(action) self.plotToolbar.addAction(action) self.clearPlotAction = QtTools.create_action( self, "Clear All Plots", slot=self.clear_plot, shortcut=None, icon="clear_plot", tip="Clears the live data arrays") self.removeFitAction = QtTools.create_action( self, "Remove Fit", slot=self.remove_fit, shortcut=None, icon="clear", tip="Reset the fit data to an empty array") self.plotMenu.addAction(self.clearPlotAction) self.plotMenu.addAction(self.removeFitAction) ###### INSTRUMENT MENU SETUP ###### self.read_DTT = QtTools.create_action( self, "Read", slot=self.single_measure_DTT, shortcut=None, icon=None, tip="Take a one shot measure with DTT") self.connect_hub = QtTools.create_action( self, "Connect Instruments", slot=self.connect_instrument_hub, shortcut=QtGui.QKeySequence("Ctrl+I"), icon=None, tip="Refresh the list of selected instruments") self.refresh_ports_list_action = QtTools.create_action( self, "Refresh ports list", slot=self.refresh_ports_list, icon=None, tip="Refresh the list of availiable ports") self.instMenu.addAction(self.start_DTT_action) self.instMenu.addAction(self.read_DTT) self.instMenu.addAction(self.connect_hub) self.instMenu.addAction(self.refresh_ports_list_action) ###### WINDOW MENU SETUP ###### self.add_pdw = QtTools.create_action(self, "Add a Plot", slot=self.create_pdw, shortcut=None, icon=None, tip="Add a recordsweep window") self.add_pqtw = QtTools.create_action(self, "Add a PyQtplot", slot=self.create_pqtw, shortcut=None, icon=None, tip="Add a pyqt window") self.windowMenu.addAction(self.add_pdw) try: import PyQTWindow self.windowMenu.addAction(self.add_pqtw) except: logging.info("pyqtgraph is unable to load, \ the pyqt window option is disabled") ###### OPTION MENU SETUP ###### self.toggle_debug_state = QtTools.create_action( self, "Change debug mode", slot=self.option_change_debug_state, shortcut=None, icon=None, tip="Change the state of the debug mode") # self.toggle_debug_state = QtTools.create_action(self, # "Change debug mode", slot = self.option_change_debug_state, # shortcut = None, icon = None, # tip = "Change the state of the debug mode") self.optionMenu.addAction(self.toggle_debug_state) for log_level in ["DEBUG", "INFO", "WARNING", "ERROR"]: action = QtTools.create_action( self, log_level, slot=self.option_change_log_level, shortcut=None, icon=None, tip="Change the state of the logger to %s" % log_level) self.loggingSubMenu.addAction(action) ############################### #Load the user settings for the instrument connectic and parameters self.default_settings_fname = IOTool.get_settings_name( config_file_path=self.config_file) if not exists(self.default_settings_fname): logging.warning( "The filename '%s' wasn't found, using '%s'" % (self.default_settings_fname, 'settings/default_settings.txt')) self.default_settings_fname = 'settings/default_settings.txt' if os.path.isfile(self.default_settings_fname): self.widgets['CalcWidget'].load_settings( self.default_settings_fname) self.widgets['InstrumentWidget'].load_settings( self.default_settings_fname) # Create the object responsible to display information send by the # datataker self.data_displayer = DataManagement.DataDisplayer(self.datataker) # platform-independent way to restore settings such as toolbar positions, # dock widget configuration and window size from previous session. # this doesn't seem to be working at all on my computer (win7 system) self.settings = QSettings("Gervais Lab", "RecordSweep") try: self.restoreState(self.settings.value("windowState").toByteArray()) self.restoreGeometry(self.settings.value("geometry").toByteArray()) except: logging.info( 'Using default window configuration' ) # no biggie - probably means settings haven't been saved on this machine yet
def __init__(self): QReadWriteLock.__init__(self, QReadWriteLock.Recursive) self.writer = WriteLocker(self) self.reader = ReadLocker(self) self.owner = None
class __NodeTree(QWidget): def __init__(self, mainWindow): QWidget.__init__(self, mainWindow) self.__mainWindow = mainWindow #self.__action = action self.sched = scheduler.sched self.vfs = VFS.Get() self.__listFiles = [] self.childSelected = None self.childSelectedLock = QReadWriteLock() self.configure() self.g_display() self.initCallback() def configure(self): self.setObjectName("Browser") self.resize(300, 300) def g_display(self): self.layout = QHBoxLayout(self) # Browser tmp = ["Virtual File System"] self.treeItemModel = TreeItemModel(tmp) self.treeView = TreeView(self, self.__mainWindow, self.treeItemModel) self.layout.addWidget(self.treeView) # Set Model and Resize self.treeView.setModel(self.treeItemModel) self.treeItemModel.addRootVFS() self.treeItemModel.fillAllDirectory(self.treeItemModel.rootItemVFS) self.treeItemModel.reset() self.treeView.resizeAllColumn() self.treeView.setCurrentIndex(self.treeItemModel.createIndex(self.treeItemModel.rootItemVFS.childNumber(), 0, self.treeItemModel.rootItemVFS)) def initCallback(self): self.connect(self, SIGNAL("refreshNodeView"), self.refreshNodeView) self.sched.set_callback("refresh_tree", self.refreshNode) self.vfs.set_callback("refresh_tree", self.refreshNode) def refreshNode(self, node): index = self.treeView.currentIndex() isExpanded = self.treeView.isExpanded(index) item = self.treeItemModel.getItemWithPath(node.absolute()) self.treeItemModel.fillAllDirectory(self.treeItemModel.rootItemVFS) self.treeItemModel.reset() self.emit(SIGNAL("refreshNodeView"), index, isExpanded) self.emit(SIGNAL("reloadNodeView")) def refreshNodeView(self, index, isExpanded): self.treeView.expandAllIndex(index) self.treeView.setCurrentIndex(index) self.treeView.setExpanded(index, isExpanded) def setChild(self, child): if self.childSelectedLock.tryLockForWrite() : self.childSelected = child self.childSelectedLock.unlock() def getChild(self): if self.childSelectedLock.tryLockForRead(): tmp = self.childSelected self.childSelectedLock.unlock() return tmp def addList(self): dockList = DockNodeList(self.__mainWindow, self, len(self.__listFiles)) self.__listFiles.append(dockList) self.__mainWindow.addNewDockWidgetTab(Qt.RightDockWidgetArea, dockList) dockList.initContents(self.treeView.getCurrentItem().node, self.treeView.currentIndex()) return dockList
def __init__(self, debug=False): self.debug = debug self._dict = dict() self._prepare_dir() self._remove_tmps() self._lock = QReadWriteLock()
class __Config(object): def __init__(self, debug=False): self.debug = debug self._dict = dict() self._prepare_dir() self._remove_tmps() self._lock = QReadWriteLock() def __getitem__(self, key): self._lock.lockForRead() r = self._dict[key] self._lock.unlock() return r def __setitem__(self, key, value): self._lock.lockForWrite() self._dict[key] = value self._lock.unlock() def get(self, key, default=None): self._lock.lockForRead() r = self._dict.get(key, default) self._lock.unlock() return r def pop(self, key, default=None): self._lock.lockForWrite() r = self._dict.pop(key, default) self._lock.unlock() return r def __contains__(self, key): self._lock.lockForRead() r = self._dict.__contains__(key) self._lock.unlock() return r def __str__(self): self._lock.lockForRead() s = ''.join([ 'Config(', ', '.join("{0}: {1}".format(k, v) for (k, v) in self._dict), ')' ]) self._lock.unlock() return s @property def _config_dir(self): # Windows if sys.platform.startswith('win'): if 'LOCALAPPDATA' in os.environ: return os.path.join(os.environ['LOCALAPPDATA'], 'LDOCE5Viewer') else: return os.path.join(os.environ['APPDATA'], 'LDOCE5Viewer') # Mac OS X elif sys.platform.startswith('darwin'): return os.path.expanduser( '~/Library/Application Support/LDOCE5Viewer') # Linux else: base = os.path.join(os.path.expanduser('~'), '.config') # XDG try: import xdg.BaseDirectory base = xdg.BaseDirectory.xdg_config_home except ImportError: if 'XDG_CONFIG_HOME' in os.environ: base = os.environ['XDG_CONFIG_HOME'] return os.path.join(base, 'ldoce5viewer') @property def _data_dir(self): # Windows if sys.platform.startswith('win'): return self._config_dir # Mac OS X elif sys.platform.startswith('darwin'): return self._config_dir # Linux else: base = os.path.join(os.path.expanduser('~'), '.local/share/') # XDG try: import xdg.BaseDirectory base = xdg.BaseDirectory.xdg_data_home except ImportError: if 'XDG_DATA_HOME' in os.environ: base = os.environ['XDG_DATA_HOME'] return os.path.join(base, 'ldoce5viewer') @property def app_name(self): return 'LDOCE5 Viewer' @property def _config_path(self): return os.path.join(self._config_dir, 'config.pickle') @property def filemap_path(self): return os.path.join(self._data_dir, 'filemap.cdb') @property def variations_path(self): return os.path.join(self._data_dir, 'variations.cdb') @property def incremental_path(self): return os.path.join(self._data_dir, 'incremental.db') @property def fulltext_hwdphr_path(self): return os.path.join(self._data_dir, 'fulltext_hp') @property def fulltext_defexa_path(self): return os.path.join(self._data_dir, 'fulltext_de') @property def scan_tmp_path(self): return os.path.join(self._data_dir, 'scan' + self.tmp_suffix) @property def tmp_suffix(self): return '.tmp' def _remove_tmps(self): for name in os.listdir(self._config_dir) + os.listdir(self._data_dir): if name.endswith(self.tmp_suffix): path = os.path.join(self._config_dir, name) try: if os.path.isfile(path): os.remove(path) elif os.path.isdir(path): shutil.rmtree(path) except OSError: pass def _prepare_dir(self): if not os.path.exists(self._config_dir): os.makedirs(self._config_dir) if not os.path.exists(self._data_dir): os.makedirs(self._data_dir) def load(self): self._lock.lockForWrite() try: with open(self._config_path, 'rb') as f: self._dict.clear() try: data = pickle.load(f) except: pass else: self._dict.update(data) except IOError: self._dict.clear() self._lock.unlock() def save(self): self._lock.lockForRead() if sys.platform == 'win32': with open(self._config_path, 'wb') as f: pickle.dump(self._dict, f) else: f = tempfile.NamedTemporaryFile(dir=self._config_dir, delete=False, suffix=self.tmp_suffix) pickle.dump(self._dict, f, protocol=0) f.close() os.rename(f.name, self._config_path) self._lock.unlock()