root/tags/dabo-0.3-2/dApp.py

Revision 702, 14.4 kB (checked in by ed, 4 years ago)

Added a new property named 'Platform' to the Application. It will return either 'Mac', 'Win' or 'GTK'.

Changed the font sizes in the About dialog. What looks good on the Mac looked comically large on Windows.

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