1
# --------------------------------------------------------------------------- #
2
# PersistentControls Library wxPython IMPLEMENTATION
4
# Inspired by the wxWidgets implementation by Vadim Zeitlin.
6
# License: wxWidgets license
10
# Andrea Gavana, @ 16 Nov 2009
11
# Latest Revision: 28 Jan 2011, 15.00 GMT
13
# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
16
# andrea.gavana@gmail.com
19
# Or, Obviously, To The wxPython Mailing List!!!
22
# --------------------------------------------------------------------------- #
25
This module contains the definitions of `PersistentObject` and `PersistenceManager` objects.
35
from persist_handlers import FindHandler
37
from persist_constants import BAD_DEFAULT_NAMES, CONFIG_PATH_SEPARATOR
38
from persist_constants import PM_DEFAULT_STYLE
40
# ----------------------------------------------------------------------------------- #
42
class PersistentObject(object):
44
PersistentObject: ABC for anything persistent.
46
This is the base class for persistent object adapters.
47
wxPython persistence framework is non-intrusive, i.e. can work with the
48
classes which have no relationship to nor knowledge of it. To allow this,
49
an intermediate persistence adapter is used: this is just a simple object
50
which provides the methods used by L{PersistenceManager} to save and restore
51
the object properties and implements them using the concrete class methods.
53
You may derive your own classes from L{PersistentObject} to implement persistence
54
support for your common classes, see :ref:`persistent-windows` in the
58
def __init__(self, window, persistenceHandler=None):
60
Default class constructor.
62
:param `window`: an instance of `wx.Window`;
63
:param `persistenceHandler`: if not ``None``, this should a custom handler derived
64
from L{persist_handlers.AbstractHandler}.
67
self._name = window.GetName()
69
if not self._name.strip():
70
raise Exception("Persistent windows should be named! (class=%s)"%window.__class__)
72
klass = window.__class__
73
if issubclass(klass, wx.GenericDirCtrl):
74
self._window = window.GetTreeCtrl()
75
elif issubclass(klass, wx.gizmos.EditableListBox):
76
self._window = window.GetListCtrl()
80
if persistenceHandler is not None:
81
self._persistentHandler = persistenceHandler(self)
83
self._persistentHandler = FindHandler(self)
85
if self._name in BAD_DEFAULT_NAMES:
86
warnings.warn("Window names should not be defaulted! (class=%s, name=%s)"%(window.__class__, window.GetName()))
91
Returns the string uniquely identifying the window we're associated with
92
among all the other objects of the same type.
94
:note: This method is used together with L{GetKind} to construct the unique
95
full name of the object in e.g. a configuration file.
102
""" Returns the actual associated window. """
109
Returns the string uniquely identifying the objects supported by this adapter.
111
:note: This method is called from L{SaveValue} and L{RestoreValue} and normally
112
returns some short (but not too cryptic) strings, e.g. "Checkbox".
115
return self._persistentHandler.GetKind()
120
Saves the corresponding window settings.
122
:note: This method shouldn't be used directly as it doesn't respect the
123
global L{PersistenceManager.DisableSaving} settings, use L{PersistenceManager}
124
methods with the same name instead.
127
self._persistentHandler.Save()
132
Restores the corresponding window settings.
134
:note: This method shouldn't be used directly as it doesn't respect the
135
global L{PersistenceManager.DisableRestoring} settings, use L{PersistenceManager}
136
methods with the same name instead.
139
self._persistentHandler.Restore()
142
def SaveValue(self, name, value):
144
Save the specified value using the given name.
146
:param `name`: the name of the value in the configuration file.
147
:param `value`: the value to save.
149
:returns: ``True`` if the value was saved or ``False`` if an error occurred.
152
return PersistenceManager.Get().SaveValue(self, name, value)
155
def RestoreValue(self, name):
157
Restore the value saved by L{Save}.
159
:param `name`: the same name as was used by L{Save}.
161
:returns: ``True`` if the value was successfully read or ``False`` if it was not
162
found or an error occurred.
165
return PersistenceManager.Get().RestoreValue(self, name)
167
# ----------------------------------------------------------------------------------- #
169
class PersistenceManager(object):
171
PersistenceManager: global aspects of persistent windows.
173
Provides support for automatically saving and restoring object properties
174
to persistent storage.
176
This class is the central element of wxPython persistence framework, see
177
the :ref:`persistent-overview` in the `__init__.py` file for its overview.
179
This is a singleton class and its unique instance can be retrieved using L{PersistenceManager.Get}
185
Default class constructor.
187
This method should **not** be called directly: you should use the object
188
obtained by L{PersistenceManager.Get} and assign manager styles, custom
189
configuration files and custom configuration handlers using the appropriate
190
methods in this class.
192
Interesting attributes you can set for this class are:
194
- `configFile`: the persistent configuration file for L{PersistenceManager},
195
a custom file name to which `wx.FileConfig` will access to store and
196
retrieve UI settings;
197
- `configKey`: the persistent key name inside the configuration file for
198
L{PersistenceManager};
199
- `customConfigHandler`: the persistent configuration handler for L{PersistenceManager};
200
this attribute is object capable of saving/restoring UI settings. This
201
can be a cPickle object or a ConfigObj one, for example.
202
- `style`: a combination of the following values:
204
======================================== ==================================
205
Flag name Description
206
======================================== ==================================
207
``PM_SAVE_RESTORE_AUI_PERSPECTIVES`` If a toplevel window has an AUI manager associated, the manager will save and restore its AUI perspective
208
``PM_SAVE_RESTORE_TREE_LIST_SELECTIONS`` If set, the manager will save items selections in list and tree controls
209
``PM_DEFAULT_STYLE`` Same as ``PM_SAVE_RESTORE_AUI_PERSPECTIVES``
210
======================================== ==================================
212
:note: UI settings are stored as dictionaries key <=> tuple: the tuple value
213
contains two items. The first is the value *type* (i.e., float, int, bool etc...)
214
while the second is the actual key value.
218
object.__init__(self)
220
# Specifies custom wx.Config object to use (i.e., custom file names)
221
self._configFile = None
223
# Specifies custom key in the wx.Config object to use
224
self._configKey = None
226
# Specifies whether a custom config handler exists, so that we will not use
227
# wx.FileConfig (i.e., ConfigObj, ConfigParser etc...)
228
self._customConfigHandler = None
230
# Specifies the PersistenceManager style
231
self._style = PM_DEFAULT_STYLE
233
# Set these values to True if we should restore/save the settings (it doesn't
234
# make much sense to use this class when both of them are False but setting
235
# one of them to False may make sense in some situations)
237
self._doRestore = True
239
# map with the registered objects as keys and associated
240
# PersistentObjects as values
241
self._persistentObjects = {}
245
""" Accessor to the unique persistence manager object. """
247
if not hasattr(self, "_instance"):
248
self._instance = PersistenceManager()
250
return self._instance
252
Get = classmethod(Get)
256
""" Destructor for the unique persistence manager object. """
258
if hasattr(self, "_instance"):
261
Free = classmethod(Free)
264
def GetManagerStyle(self):
266
Returns the L{PersistenceManager} style.
268
:see: L{SetManagerStyle} for a list of possible styles.
274
def SetManagerStyle(self, style):
276
Sets the L{PersistenceManager} style.
278
:param `style`: a combination of the following values:
280
======================================== ==================================
281
Flag name Description
282
======================================== ==================================
283
``PM_SAVE_RESTORE_AUI_PERSPECTIVES`` If a toplevel window has an AUI manager associated, the manager will save and restore its AUI perspective
284
``PM_SAVE_RESTORE_TREE_LIST_SELECTIONS`` If set, the manager will save items selections in list and tree controls
285
``PM_DEFAULT_STYLE`` Same as ``PM_SAVE_RESTORE_AUI_PERSPECTIVES``.
286
======================================== ==================================
292
def SetPersistenceKey(self, key):
294
Sets the persistent key name inside the configuration file for L{PersistenceManager}.
296
:param `key`: a short meaningful name for your unique preferences key.
298
:note: Calling this method has no influence if you are using your own
299
custom configuration handler (i.e., by using ConfigObj/ConfigParser/cPickle etc...).
302
self._configKey = key
305
def GetPersistenceKey(self):
307
Returns the persistent key name inside the configuration file for L{PersistenceManager}.
309
:note: The return value of this method is not used if you are using your own
310
custom configuration handler (i.e., by using ConfigObj/ConfigParser/cPickle etc...).
313
return self._configKey
316
def SetPersistenceFile(self, fileName):
318
Sets the persistent configuration file for L{PersistenceManager}.
320
:param `fileName`: the file name where to store the persistent options.
322
:note: Calling this method has no influence if you are using your own
323
custom configuration handler (i.e., by using ConfigObj/ConfigParser/cPickle etc...).
326
self._configFile = fileName
329
def GetPersistenceFile(self):
331
Returns the persistent configuration file for L{PersistenceManager}.
333
:note: The return value of this method is not used if you are using your own
334
custom configuration handler (i.e., by using ConfigObj/ConfigParser/cPickle etc...).
337
if self._configFile is not None:
338
persistenceDir, fileName = os.path.split(self._configFile)
339
fileName = self._configFile
341
persistenceDir = self.GetPersistenceDirectory()
342
fileName = "Persistence_Options"
344
fileName = os.path.join(persistenceDir, fileName)
346
if not os.path.exists(persistenceDir):
347
# Create the data folder, it still doesn't exist
348
os.makedirs(persistenceDir)
350
config = wx.FileConfig(localFilename=fileName)
354
def SetConfigurationHandler(self, handler):
356
Sets the persistent configuration handler for L{PersistenceManager}.
358
:param `handler`: an object capable of saving/restoring UI settings. This
359
can be a cPickle object or a ConfigObj one, for example.
361
:note: UI settings are stored as dictionaries key <=> tuple: the tuple value
362
contains two items. The first is the value *type* (i.e., float, int, bool etc...)
363
while the second is the actual key value.
366
self._customConfigHandler = handler
369
def GetConfigurationHandler(self):
371
Returns the persistent configuration handler for L{PersistenceManager}.
374
return self._customConfigHandler
377
def GetPersistenceDirectory(self):
379
Returns a default persistent option directory for L{PersistenceManager}.
381
:note: The return value of this method is not used if you are using your own
382
custom configuration handler (i.e., by using ConfigObj/ConfigParser/cPickle etc...)
383
or if you have specified a custom configuration file to use with `wx.FileConfig`.
386
sp = wx.StandardPaths.Get()
387
return sp.GetUserDataDir()
390
def Find(self, window):
392
Checks if the object is registered and return the associated L{PersistentObject}
393
if it is or ``None`` otherwise.
395
:param `window`: an instance of `wx.Window`.
398
if window.GetName() in self._persistentObjects:
402
def Register(self, window, persistenceHandler=None):
404
Register an object with the manager.
406
:param `window`: an instance of `wx.Window`;
407
:param `persistenceHandler`: if not ``None``, this should a custom handler derived
408
from L{persist_handlers.AbstractHandler}.
410
:note: Note that registering the object doesn't do anything except allowing to call
411
L{Restore} for it later. If you want to register the object and restore its
412
properties, use L{RegisterAndRestore}.
414
:note: The manager takes ownership of the L{PersistentObject} and will delete it when
418
if self.Find(window):
419
raise Exception("Object (class=%s, name=%s) is already registered"%(window.__class__, window.GetName()))
421
name = window.GetName()
422
self._persistentObjects[name] = PersistentObject(window, persistenceHandler)
427
def Unregister(self, window):
429
Unregister the object, this is called by L{PersistentObject} itself so there is
430
usually no need to do it explicitly.
432
:param `window`: an instance of `wx.Window`, which must have been previously
433
registered with L{Register}.
435
:note: For the persistent windows this is done automatically (via L{SaveAndUnregister})
436
when the window is destroyed so you only need to call this function explicitly if you
437
are using custom persistent objects or if you want to prevent the object properties
440
:note: This deletes the associated L{PersistentObject}.
443
if not self.Find(window):
446
name = window.GetName()
447
self._persistentObjects.pop(name)
452
def Save(self, window):
454
Saves the state of an object.
456
:param `window`: an instance of `wx.Window`.
458
:note: This methods does nothing if L{DisableSaving} was called.
464
if not self.Find(window):
467
name = window.GetName()
468
self._persistentObjects[name].Save()
473
def Restore(self, window):
475
Restores the state of an object.
477
:param `window`: an instance of `wx.Window`.
479
:returns: ``True`` if the object properties were restored or ``False`` if nothing
480
was found to restore or the saved settings were invalid.
482
:note: This methods does nothing if L{DisableRestoring} was called.
485
if not self._doRestore:
488
if not self.Find(window):
491
name = window.GetName()
492
self._persistentObjects[name].Restore()
497
def DisableSaving(self):
499
Globally disables saving the persistent properties (enabled by default).
501
:note: By default, saving properties in L{Save} is enabled but the program
502
may wish to disable if, for example, it detects that it is running on a
503
system which shouldn't be modified in any way and so configuration file
504
(or Windows registry) shouldn't be written to.
510
def DisableRestoring(self):
512
Globally disables restoring the persistent properties (enabled by default).
514
:note: By default, restoring properties in L{Restore} is enabled but this
515
function allows to disable it. This is mostly useful for testing.
518
self._doRestore = False
521
def EnableSaving(self):
523
Globally enables saving the persistent properties (enabled by default).
525
:note: By default, saving properties in L{Save} is enabled but the program
526
may wish to disable if, for example, it detects that it is running on a
527
system which shouldn't be modified in any way and so configuration file
528
(or Windows registry) shouldn't be written to.
534
def EnableRestoring(self):
536
Globally enables restoring the persistent properties (enabled by default).
538
:note: By default, restoring properties in L{Restore} is enabled but this
539
function allows to disable it. This is mostly useful for testing.
542
self._doRestore = True
545
def SaveAndUnregister(self, window=None):
547
Combines both L{Save} and L{Unregister} calls.
549
:param `window`: an instance of `wx.Window`. If it is ``None``, all the
550
windows previously registered are saved and then unregistered.
554
for name, obj in self._persistentObjects.items():
555
self.SaveAndUnregister(obj.GetWindow())
560
self.Unregister(window)
563
def RegisterAndRestore(self, window):
565
Combines both L{Register} and L{Restore} calls.
567
:param `window`: an instance of `wx.Window`.
570
return self.Register(window) and self.Restore(window)
573
def GetKey(self, obj, keyName):
575
Returns a correctly formatted key name for the object `obj` and `keyName` parameters.
577
:param `obj`: an instance of L{PersistentObject};
578
:param `keyName`: a string specifying the key name.
582
key = (self._configKey is None and ["Persistence_Options"] or [self._configKey])[0]
584
key += CONFIG_PATH_SEPARATOR + obj.GetKind()
585
key += CONFIG_PATH_SEPARATOR + obj.GetName()
586
key += CONFIG_PATH_SEPARATOR + keyName
591
def SaveValue(self, obj, keyName, value):
593
Method used by the persistent objects to save the data.
595
By default this method simply use `wx.FileConfig` but this behaviour may be
596
overridden by passing a custom configuration handler in the L{PersistenceManager}
599
:param `obj`: an instance of L{PersistentObject};
600
:param `keyName`: a string specifying the key name;
601
:param `value`: the value to store in the configuration file.
605
kind = repr(value.__class__).split("'")[1]
607
if self._customConfigHandler is not None:
608
result = self._customConfigHandler.SaveValue(self.GetKey(obj, keyName), repr((kind, str(value))))
610
config = self.GetPersistenceFile()
611
result = config.Write(self.GetKey(obj, keyName), repr((kind, str(value))))
617
def RestoreValue(self, obj, keyName):
619
Method used by the persistent objects to restore the data.
621
By default this method simply use `wx.FileConfig` but this behaviour may be
622
overridden by passing a custom config handler in the PersistenceManager
625
:param `obj`: an instance of L{PersistentObject};
626
:param `keyName`: a string specifying the key name.
629
if self._customConfigHandler is not None:
630
result = self._customConfigHandler.RestoreValue(self.GetKey(obj, keyName))
632
config = self.GetPersistenceFile()
633
result = config.Read(self.GetKey(obj, keyName))
636
kind, result = eval(result)
637
if kind in ("unicode", "str"):
639
elif kind == "datetime.date":
640
y, m, d = result.split("-")
641
result = datetime.date(int(y), int(m), int(d))