root/tags/dabo-0.3.1/dApp.py

Revision 771, 13.7 kB (checked in by paul, 4 years ago)

Removed dActionList. While it was a good idea at the time, it isn't being
used and it is better to simplify.

Added dabo/ui/dialogs to hold various common dialogs such as About, Find,
Login, etc. Moved dabo/ui/uiwx/dAbout.py to dabo/ui/dialogs/about and
renamed the class 'About' (no d).

  • Property svn:eol-style set to native
Line 
1 """
2     dApp.py : The application object for Dabo.
3
4     This object gets instantiated from the client app's main.py,
5     and lives through the life of the application.
6
7         -- set up an empty data connections object which holds
8         -- connectInfo objects connected to pretty names. If there
9         -- is a file named 'default.cnxml' present, it will import the
10         -- connection definitions contained in that. If no file of that
11         -- name exists, it will import any .cnxml file it finds. If there
12         -- are no such files, it will then revert to the old behavior
13         -- of importing a file in the current directory called
14         -- 'dbConnectionDefs.py', which contains connection
15         -- definitions in python code format instead of XML.
16
17         -- Set up a DB Connection manager, that is basically a dictionary
18         -- of dConnection objects. This allows connections to be shared
19         -- application-wide.
20
21         -- decide which ui to use (wx) and gets that ball rolling
22
23         -- make a system menu bar, based on a combination
24         -- of dabo defaults and user resource files.
25
26         -- ditto for toolbar(s)
27
28         -- look for a mainFrame ui resource file in an expected
29         -- place, otherwise uses default dabo mainFrame, and
30         -- instantiate that.
31
32         -- maintain a forms collection and provide interfaces for
33         -- opening dForms, closing them, and iterating through them.
34
35         -- start the main app event loop.
36
37         -- clean up and exit gracefully
38 """
39 import sys, os, warnings, glob
40 import ConfigParser
41 import dabo, dabo.ui, dabo.db
42 import dabo.ui.dialogs
43 import dabo.common, dSecurityManager
44 from dLocalize import _
45
46 class Collection(list):
47     """
48     Collection : Base class for the various collection
49                     classes used in the app object.
50     """
51
52     def __init__(self):
53         list.__init__(self)
54
55     def add(self, objRef):
56         """
57         Collection.add(objRef)
58             Add the object reference to the collection.
59         """
60         self.append(objRef)
61
62     def remove(self, objRef):
63         """
64         Collection.remove(objRef)
65             Delete the object reference from the collection.
66         """
67         try:
68             index = self.index(objRef)
69         except ValueError:
70             index = None
71         if index is not None:
72             del self[index]
73
74
75 class dApp(dabo.common.dObject):
76     """ dabo.dApp
77
78         The containing object for the entire application.
79         Various UI's will have app objects also, which
80         dabo.App is a wrapper for.
81     """
82     def __init__(self):
83         self._uiAlreadySet = False
84         dabo.dAppRef = self
85         #dApp.doDefault()
86         super(dApp, self).__init__()
87         self._initProperties()
88         # egl: added the option of keeping the main form hidden
89         # initially. The default behavior is for it to be shown, as usual.
90         self.showMainFormOnStart = True
91        
92
93     def setup(self):
94         """ Set up the app - call this before start()."""
95
96         # dabo is going to want to import various things from the Home Directory
97         if self.HomeDirectory not in sys.path:
98             sys.path.append(self.HomeDirectory)
99
100         if not self.getAppInfo("appName"):
101             self.setAppInfo("appName", "Dabo")
102         if not self.getAppInfo("appVersion"):
103             self.setAppInfo("appVersion", dabo.version["version"])
104         if not self.getAppInfo("vendorName"):
105             self.setAppInfo("vendorName", "Dabo")
106
107         self._initDB()
108         self._initUI()
109
110         self.uiApp = dabo.ui.uiApp()
111         self.uiApp.setup(self)
112
113
114     def start(self):
115         """
116         Start the application event loop, which involves
117             wrapping the application object for the ui library
118             being used.
119         """
120         if (not self.SecurityManager or not self.SecurityManager.RequireAppLogin
121             or self.SecurityManager.login()):
122            
123             userName = self.getUserCaption()
124             if userName:
125                 userName = " (%s)" % userName
126             else:
127                 userName = ""
128                
129             self.uiApp.start(self)
130         self.finish()
131
132
133     def finish(self):
134         """
135         The main event loop has exited and the application
136             is about to finish.
137         """
138         self.uiApp.finish()
139         dabo.infoLog.write(_("Application finished."))
140         pass
141
142
143     def getAppInfo(self, item):
144         """ dApp.getAppInfo(self, item) -> value
145
146             Look up the item, and return the value.
147         """
148         try:
149             retVal = self._appInfo[item]
150         except KeyError:
151             retVal = None
152         return retVal
153
154
155     def setAppInfo(self, item, value):
156         """ dApp.getAppInfo(self, item, value) -> None
157
158             Set item to value in the appinfo table.
159         """
160         self._appInfo[item] = value
161
162
163     def getUserSettingKeys(self, spec):
164         """Return a list of all keys underneath <spec>.
165         
166         For example, if spec is "appWizard.dbDefaults", and there are
167         userSettings entries for:
168             appWizard.dbDefaults.pkm.Host
169             appWizard.dbDefaults.pkm.User
170             appWizard.dbDefaults.egl.Host
171             
172         The return value would be ["pkm", "egl"]
173         """
174         configFileName = "%s/.userSettings.ini" % self.HomeDirectory
175
176         cp = ConfigParser.ConfigParser()
177         cp.read(configFileName)
178
179         spec = spec.lower()
180        
181         try:
182             items = cp.items("UserSettings")
183         except ConfigParser.NoSectionError:
184             items = []
185        
186         ret = []   
187         for item in items:
188             wholekey = item[0].lower()
189             if wholekey[:len(spec)] == spec:
190                 key = wholekey[len(spec):].split(".")[0]
191                 if ret.count(key) == 0:
192                     ret.append(key)
193         return ret
194        
195     def getUserSetting(self, item, user="*", system="*"):
196         """ Return the value of the user settings table that
197             corresponds to the item, user, and system id
198             passed. Based on the ctype field in the table,
199             convert the return value into the appropriate
200             type first.
201
202             Types:    I: Int
203                     N: Float
204                     C: String
205                     M: String
206                     D: Date, saved as a string 3-tuple
207                         of integers '(year,month,day)'
208                     T: DateTime, saved as a string
209                         9-tuple of integers '(year,month,
210                         day,hour,minute,second,?,?,?)'
211
212         """
213         configFileName = "%s/.userSettings.ini" % self.HomeDirectory
214
215         cp = ConfigParser.ConfigParser()
216         cp.read(configFileName)
217
218         try:
219             valueType = cp.get("UserSettingsValueTypes", item)
220         except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
221             valueType = "C"
222
223         try:
224             if valueType == "I":
225                 value = cp.getint("UserSettings", item)
226             elif valueType == "N":
227                 value = cp.getfloat("UserSettings", item)
228             elif valueType == "L":
229                 value = cp.getboolean("UserSettings", item)
230             else:
231                 value = cp.get("UserSettings", item)
232         except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
233             value = None
234
235         return value
236
237
238     def setUserSetting(self, item, value):
239         """Persist a value to the user settings file.
240         """
241         # For now, save this info in a plain ini file. Eventually, I'd like
242         # to see this get saved in a persistent dabosettings db table.
243         configFileName = "%s/.userSettings.ini" % self.HomeDirectory
244
245         cp = ConfigParser.ConfigParser()
246         cp.read(configFileName)
247
248         if type(value) in (str, unicode):
249             valueType = "C"
250         elif type(value) == bool:
251             valueType = "L"
252         elif type(value) in (float,):
253             valueType = "N"
254         elif type(value) in (int, long):
255             valueType = "I"
256            
257         if not cp.has_section("UserSettings"):
258             cp.add_section("UserSettings")
259         cp.set("UserSettings", item, str(value))
260
261         if not cp.has_section("UserSettingsValueTypes"):
262             cp.add_section("UserSettingsValueTypes")
263         cp.set("UserSettingsValueTypes", item, valueType)
264
265         configFile = open(configFileName, "w")
266         cp.write(configFile)
267         configFile.close()
268        
269        
270     def getUserCaption(self):
271         """ Return the full name of the currently logged-on user.
272         """
273         if self.SecurityManager:
274             return self.SecurityManager.UserCaption
275         else:
276             return None
277            
278
279     def _initProperties(self):
280         """ Initialize the public properties of the app object. """
281
282         self.uiType   = None    # ("wx", "qt", "curses", "http", etc.)
283         #self.uiModule = None
284
285         # Initialize UI collections
286         self.uiForms = Collection()
287         self.uiMenus = Collection()
288         self.uiToolBars = Collection()
289         self.uiResources = {}
290
291         # Initialize DB collections
292         self.dbConnectionDefs = {}
293
294         self._appInfo = {}
295
296     def _initDB(self):
297         """Set the available connection definitions for use by the app.
298         First look for a file named 'default.cnxml'; if none exists,
299         read in all .cnxml files. If no such XML definition files exist,
300         check for a python code definition file named 'dbConnectionDefs'.
301         """
302         connDefs = {}
303         parser = dabo.common.connParser
304         if os.path.exists("default.cnxml"):
305             connDefs = parser.importConnections("default.cnxml")
306         if not connDefs:
307             # Try importing all .cnxml files
308             cnFiles = glob.glob("*.cnxml")
309             for cn in cnFiles:
310                 cnDefs = parser.importConnections(cn)
311                 connDefs.update(cnDefs)
312         if not connDefs:
313             # No XML definitions present. Try looking for python code
314             # definitions instead.
315             try:
316                 import dbConnectionDefs
317                 connDefs = dbConnectionDefs.getDefs()
318             except:
319                 pass
320        
321         if connDefs:
322             # For each connection definition, add an entry to
323             # self.dbConnectionDefs that contains a key on the
324             # name, and a value of a dConnectInfo object.
325             for k in connDefs.keys():
326                 entry = connDefs[k]
327                 ci = dabo.db.dConnectInfo()
328                 ci.setConnInfo(entry)
329                 self.dbConnectionDefs[k] = ci
330
331             dabo.infoLog.write(_("%s database connection definition(s) loaded.") % (
332                                                 len(self.dbConnectionDefs)))
333
334         else:
335             dabo.infoLog.write(_("No database connection definitions loaded (dbConnectionDefs.py)"))
336
337
338     def _initUI(self):
339         """ Set the user-interface library for the application.
340         
341         Ignored if the UI was already explicitly set by user code.
342         """
343         if self.UI is None and not self._uiAlreadySet:
344             # For now, default to wx, but it should be enhanced to read an
345             # application config file. Actually, that may not be necessary, as the
346             # user's main.py can just set the UI directly now: dApp.UI = "qt".
347             self.UI = "wx"
348         else:
349             # Custom app code or the dabo.ui module already set this: don't touch
350             dabo.infoLog.write(_("User interface already set to '%s', so dApp didn't "
351                 " touch it." % (self.UI,)))
352
353    
354     ########################
355     # This next section simply passes menu events to the UI
356     # layer to be handled there.
357     def onCmdWin(self, evt):
358         self.uiApp.onCmdWin(evt)
359     def onFileExit(self, evt):
360         self.uiApp.onFileExit(evt)
361     def onEditUndo(self, evt):
362         self.uiApp.onEditUndo(evt)
363     def onEditRedo(self, evt):
364         self.uiApp.onEditRedo(evt)
365     def onEditCut(self, evt):
366         self.uiApp.onEditCut(evt)
367     def onEditCopy(self, evt):
368         self.uiApp.onEditCopy(evt)
369     def onEditPaste(self, evt):
370         self.uiApp.onEditPaste(evt)
371     def onEditFind(self, evt):
372         self.uiApp.onEditFind(evt)
373     def onEditFindAgain(self, evt):
374         self.uiApp.onEditFindAgain(evt)
375     def onEditPreferences(self, evt):
376         self.uiApp.onEditPreferences(evt)
377     ############################   
378
379     def onHelpAbout(self, evt):
380         dlg = dabo.ui.dialogs.About(self.MainForm)
381         dlg.show()
382    
383     def _getHomeDirectory(self):
384         try:
385             hd = self._homeDirectory
386         except AttributeError:
387             # Note: sometimes the runtime distros will alter the path so
388             # that the first entry is not a valid directory. Go through the path
389             # and use the first valid directory.
390             hd = None
391             for pth in sys.path:
392                 if os.path.exists(os.path.join(pth, ".")):
393                     hd = pth
394                     break
395             if hd is None:
396                 # punt:
397                 hd = os.getcwd()
398             self._homeDirectory = hd
399            
400         return hd
401        
402     def _setHomeDirectory(self, val):
403         self._homeDirectory = val
404
405                
406     def _getMainForm(self):
407         try:
408             f = self._mainForm
409         except AttributeError:
410             f = None
411             self._mainForm = None
412         return f
413            
414     def _setMainForm(self, val):
415         self._mainForm = val
416
417                
418     def _getMainFormClass(self):
419         try:
420             c = self._mainFormClass
421         except AttributeError:
422             c = dabo.ui.dFormMain
423             self._mainFormClass = c
424         return c
425            
426     def _setMainFormClass(self, val):
427         self._mainFormClass = val
428        
429        
430     def _getSecurityManager(self):
431         try:
432             return self._securityManager
433         except AttributeError:
434             return None
435            
436     def _setSecurityManager(self, value):
437         if isinstance(value, dSecurityManager.dSecurityManager):
438             if self.SecurityManager:
439                 warnings.warn(Warning, _("SecurityManager previously set"))
440             self._securityManager = value
441         else:
442             raise TypeError, _("SecurityManager must descend from dSecurityManager.")
443            
444            
445     def _getUI(self):
446         try:
447             return dabo.ui.getUIType()
448         except AttributeError:
449             return None
450            
451     def _setUI(self, uiType):
452         # Load the appropriate ui module. dabo.ui will now contain
453         # the classes of that library, wx for instance.
454         if self.UI is None:
455             if dabo.ui.loadUI(uiType):
456                 self._uiAlreadySet = True
457                 dabo.infoLog.write(_("User interface set to '%s' by dApp.") % (uiType,))
458             else:
459                 dabo.infoLog.write(_("Tried to set UI to '%s', but it failed." % (uiType,)))
460         else:
461             raise RuntimeError, _("The UI cannot be reset once assigned.")
462
463     def _getPlatform(self):
464         return self.uiApp._getPlatform()
465
466     def _getActiveForm(self):
467         return self.uiApp.ActiveForm
468     def _setActiveForm(self, frm):
469         self.uiApp._setActiveForm(frm)
470
471    
472     ActiveForm = property(_getActiveForm, None, None,
473             "Returns the form that currently has focus, or None.  (dForm)" )
474    
475     HomeDirectory = property(_getHomeDirectory, _setHomeDirectory, None,
476             _("Specifies the home-base directory for the application's program files."))
477        
478     MainForm = property(_getMainForm, _setMainForm, None,
479             _("The object reference to the main form of the application, or None. This gets "
480             "set automatically during application setup, based on the MainFormClass."))
481        
482     MainFormClass = property(_getMainFormClass, _setMainFormClass, None,
483             _("Specifies the class to use to instantiate the main form. Defaults to "
484             "the dFormMain base class. Set to None if you don't want a main form."))
485    
486     Platform = property(_getPlatform, None, None,
487             "Returns one of 'Mac', 'Win' or 'GTK', depending on where we're running  (string)")
488            
489     UI = property(_getUI, _setUI,
490             None, _("Specifies the user interface to load, or None. "
491             "Once set, it cannot be reassigned."))
492    
493     SecurityManager = property(_getSecurityManager, _setSecurityManager,
494             None, _("Specifies the Security Manager, if any. You "
495             "must subclass dSecurityManager, overriding the appropriate hooks "
496             "and properties, and then set dApp.SecurityManager to an instance "
497             "of your subclass. There is no security manager by default - you "
498             "explicitly set this to use Dabo security."))
Note: See TracBrowser for help on using the browser.