]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/project.py
DocView and ActiveGrid IDE updates from Morgan Hua:
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / project.py
1 #----------------------------------------------------------------------------
2 # Name: project.py
3 # Purpose: project model for wx.lib.pydocview
4 #
5 # Author: Morgan Hua
6 #
7 # Created: 8/25/05
8 # CVS-ID: $Id$
9 # Copyright: (c) 2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13 import copy
14 import os
15 import os.path
16 import activegrid.util.xmlutils as xmlutils
17 import activegrid.util.aglogging as aglogging
18
19 # REVIEW 07-Mar-06 stoens@activegrid.com -- Ideally move the pieces required
20 # to generate the .dpl file out of this module so there's no dependency on wx,
21 # instead of doing this try/catch (IDE drags in wx).
22 try:
23 from IDE import ACTIVEGRID_BASE_IDE
24 except:
25 ACTIVEGRID_BASE_IDE = False
26
27 if not ACTIVEGRID_BASE_IDE:
28 import activegrid.model.basedocmgr as basedocmgr
29 import AppInfo
30
31 #----------------------------------------------------------------------------
32 # Constants
33 #----------------------------------------------------------------------------
34 # Always add new versions, never edit the version number
35 # This allows you to upgrade the file by checking the version number
36 PROJECT_VERSION_050730 = '10'
37 PROJECT_VERSION_050826 = '11'
38
39
40 #----------------------------------------------------------------------------
41 # Classes
42 #----------------------------------------------------------------------------
43
44 class BaseProject(object):
45
46 __xmlname__ = "project"
47 __xmlexclude__ = ('fileName', '_projectDir', '_getDocCallback', '_cacheEnabled')
48 __xmlattributes__ = ("_homeDir", "version")
49 __xmlrename__ = { "_homeDir":"homeDir", "_appInfo":"appInfo" }
50 __xmlflattensequence__ = { "_files":("file",) }
51 __xmldefaultnamespace__ = xmlutils.AG_NS_URL
52 __xmlattrnamespaces__ = { "ag": ["version", "_homeDir"] }
53
54
55 def __init__(self):
56 self.__xmlnamespaces__ = { "ag" : xmlutils.AG_NS_URL }
57 self.version = PROJECT_VERSION_050826
58 self._files = []
59 self._projectDir = None # default for homeDir, set on load
60 self._homeDir = None # user set homeDir for use in calculating relative path
61 self._cacheEnabled = 0
62 if not ACTIVEGRID_BASE_IDE:
63 self._appInfo = AppInfo.AppInfo()
64
65
66 def initialize(self):
67 for file in self._files:
68 file._parentProj = self
69
70
71 def __copy__(self):
72 clone = Project()
73 clone._files = [copy.copy(file) for file in self._files]
74 clone._projectDir = self._projectDir
75 clone._homeDir = self._homeDir
76 if not ACTIVEGRID_BASE_IDE:
77 clone._appInfo = copy.copy(self._appInfo)
78 return clone
79
80
81 def GetAppInfo(self):
82 return self._appInfo
83
84
85 def AddFile(self, filePath=None, logicalFolder=None, type=None, name=None, file=None):
86 """ Usage: self.AddFile(filePath, logicalFolder, type, name) # used for initial generation of object
87 self.AddFile(file=xyzFile) # normally used for redo/undo
88 Add newly created file object using filePath and logicalFolder or given file object
89 """
90 if file:
91 self._files.append(file)
92 else:
93 self._files.append(ProjectFile(self, filePath, logicalFolder, type, name, getDocCallback=self._getDocCallback))
94
95
96 def RemoveFile(self, file):
97 self._files.remove(file)
98
99
100 def FindFile(self, filePath):
101 if filePath:
102 for file in self._files:
103 if file.filePath == filePath:
104 return file
105
106 return None
107
108
109 def _GetFilePaths(self):
110 return [file.filePath for file in self._files]
111
112
113 filePaths = property(_GetFilePaths)
114
115 def _GetProjectFiles(self):
116 return self._files
117 projectFiles = property(_GetProjectFiles)
118
119
120 def _GetLogicalFolders(self):
121 folders = []
122 for file in self._files:
123 if file.logicalFolder and file.logicalFolder not in folders:
124 folders.append(file.logicalFolder)
125 return folders
126
127
128 logicalFolders = property(_GetLogicalFolders)
129
130
131 def _GetPhysicalFolders(self):
132 physicalFolders = []
133 for file in self._files:
134 physicalFolder = file.physicalFolder
135 if physicalFolder and physicalFolder not in physicalFolders:
136 physicalFolders.append(physicalFolder)
137 return physicalFolders
138
139
140 physicalFolders = property(_GetPhysicalFolders)
141
142
143 def _GetHomeDir(self):
144 if self._homeDir:
145 return self._homeDir
146 else:
147 return self._projectDir
148
149
150 def _SetHomeDir(self, parentPath):
151 self._homeDir = parentPath
152
153
154 def _IsDefaultHomeDir(self):
155 return (self._homeDir == None)
156
157
158 isDefaultHomeDir = property(_IsDefaultHomeDir)
159
160
161 homeDir = property(_GetHomeDir, _SetHomeDir)
162
163
164 def GetRelativeFolders(self):
165 relativeFolders = []
166 for file in self._files:
167 relFolder = file.GetRelativeFolder(self.homeDir)
168 if relFolder and relFolder not in relativeFolders:
169 relativeFolders.append(relFolder)
170 return relativeFolders
171
172
173 def AbsToRelativePath(self):
174 for file in self._files:
175 file.AbsToRelativePath(self.homeDir)
176
177
178 def RelativeToAbsPath(self):
179 for file in self._files:
180 file.RelativeToAbsPath(self.homeDir)
181
182
183 def _SetCache(self, enable):
184 """
185 Only turn this on if your operation assumes files on disk won't change.
186 Once your operation is done, turn this back off.
187 Nested enables are allowed, only the last disable will disable the cache.
188
189 This bypasses the IsDocumentModificationDateCorrect call because the modification date check is too costly, it hits the disk and takes too long.
190 """
191 if enable:
192 if self._cacheEnabled == 0:
193 # clear old cache, don't want to accidentally return stale value
194 for file in self._files:
195 file.ClearCache()
196
197 self._cacheEnabled += 1
198 else:
199 self._cacheEnabled -= 1
200
201
202
203 def _GetCache(self):
204 return (self._cacheEnabled > 0)
205
206
207 cacheEnabled = property(_GetCache, _SetCache)
208
209
210 #----------------------------------------------------------------------------
211 # BaseDocumentMgr methods
212 #----------------------------------------------------------------------------
213
214
215 def fullPath(self, fileName):
216 fileName = super(BaseProject, self).fullPath(fileName)
217
218 if os.path.isabs(fileName):
219 absPath = fileName
220 elif self.homeDir:
221 absPath = os.path.join(self.homeDir, fileName)
222 else:
223 absPath = os.path.abspath(fileName)
224 return os.path.normpath(absPath)
225
226
227 def documentRefFactory(self, name, fileType, filePath):
228 return ProjectFile(self, filePath=self.fullPath(filePath), type=fileType, name=name, getDocCallback=self._getDocCallback)
229
230
231 def findAllRefs(self):
232 return self._files
233
234
235 def GetXFormsDirectory(self):
236 forms = self.findRefsByFileType(basedocmgr.FILE_TYPE_XFORM)
237 filePaths = map(lambda form: form.filePath, forms)
238 xformdir = os.path.commonprefix(filePaths)
239 if not xformdir:
240 xformdir = self.homeDir
241 return xformdir
242
243
244 def setRefs(self, files):
245 self._files = files
246
247
248 def findRefsByFileType(self, fileType):
249 fileList = []
250 for file in self._files:
251 if fileType == file.type:
252 fileList.append(file)
253 return fileList
254
255
256 def GenerateServiceRefPath(self, wsdlFilePath):
257 # HACK: temporary solution to getting wsdlag path from wsdl path.
258 import wx
259 from WsdlAgEditor import WsdlAgDocument
260 ext = WsdlAgDocument.WSDL_AG_EXT
261 for template in wx.GetApp().GetDocumentManager().GetTemplates():
262 if template.GetDocumentType() == WsdlAgDocument:
263 ext = template.GetDefaultExtension()
264 break;
265 wsdlAgFilePath = os.path.splitext(wsdlFilePath)[0] + ext
266 return wsdlAgFilePath
267
268
269 def SetDocCallback(self, getDocCallback):
270 self._getDocCallback = getDocCallback
271 for file in self._files:
272 file._getDocCallback = getDocCallback
273
274
275 if ACTIVEGRID_BASE_IDE:
276 class Project(BaseProject):
277 pass
278 else:
279 class Project(BaseProject, basedocmgr.BaseDocumentMgr):
280 pass
281
282
283 class ProjectFile(object):
284 __xmlname__ = "file"
285 __xmlexclude__ = ('_parentProj', '_getDocCallback', '_docCallbackCacheReturnValue', '_docModelCallbackCacheReturnValue', '_doc',)
286 __xmlattributes__ = ["filePath", "logicalFolder", "type", "name"]
287 __xmldefaultnamespace__ = xmlutils.AG_NS_URL
288
289
290 def __init__(self, parent=None, filePath=None, logicalFolder=None, type=None, name=None, getDocCallback=None):
291 self._parentProj = parent
292 self.filePath = filePath
293 self.logicalFolder = logicalFolder
294 self.type = type
295 self.name = name
296 self._getDocCallback = getDocCallback
297 self._docCallbackCacheReturnValue = None
298 self._docModelCallbackCacheReturnValue = None
299 self._doc = None
300
301
302 def _GetDocumentModel(self):
303 if (self._docCallbackCacheReturnValue
304 and (self._parentProj.cacheEnabled or self._docCallbackCacheReturnValue.IsDocumentModificationDateCorrect())):
305 return self._docModelCallbackCacheReturnValue
306
307 if self._getDocCallback:
308 self._docCallbackCacheReturnValue, self._docModelCallbackCacheReturnValue = self._getDocCallback(self.filePath)
309 return self._docModelCallbackCacheReturnValue
310
311 return None
312
313
314 document = property(_GetDocumentModel)
315
316
317 def _GetDocument(self):
318 # Return the IDE document wrapper that corresponds to the runtime document model
319 if (self._docCallbackCacheReturnValue
320 and (self._parentProj.cacheEnabled or self._docCallbackCacheReturnValue.IsDocumentModificationDateCorrect())):
321 return self._docCallbackCacheReturnValue
322
323 if self._getDocCallback:
324 self._docCallbackCacheReturnValue, self._docModelCallbackCacheReturnValue = self._getDocCallback(self.filePath)
325 return self._docCallbackCacheReturnValue
326
327 return None
328
329
330 ideDocument = property(_GetDocument)
331
332
333 def ClearCache(self):
334 self._docCallbackCacheReturnValue = None
335 self._docModelCallbackCacheReturnValue = None
336
337
338 def _typeEnumeration(self):
339 return basedocmgr.FILE_TYPE_LIST
340
341
342 def _GetPhysicalFolder(self):
343 dir = None
344 if self.filePath:
345 dir = os.path.dirname(self.filePath)
346 if os.sep != '/':
347 dir = dir.replace(os.sep, '/') # require '/' as delimiter
348 return dir
349
350
351 physicalFolder = property(_GetPhysicalFolder)
352
353
354 def GetRelativeFolder(self, parentPath):
355 parentPathLen = len(parentPath)
356
357 dir = None
358 if self.filePath:
359 dir = os.path.dirname(self.filePath)
360 if dir.startswith(parentPath + os.sep):
361 dir = "." + dir[parentPathLen:] # convert to relative path
362 if os.sep != '/':
363 dir = dir.replace(os.sep, '/') # always save out with '/' as path separator for cross-platform compatibility.
364 return dir
365
366
367 def AbsToRelativePath(self, parentPath):
368 """ Used to convert path to relative path for saving (disk format) """
369 parentPathLen = len(parentPath)
370
371 if self.filePath.startswith(parentPath + os.sep):
372 self.filePath = "." + self.filePath[parentPathLen:] # convert to relative path
373 if os.sep != '/':
374 self.filePath = self.filePath.replace(os.sep, '/') # always save out with '/' as path separator for cross-platform compatibility.
375 else:
376 pass # not a decendant of project, use absolute path
377
378
379 def RelativeToAbsPath(self, parentPath):
380 """ Used to convert path to absolute path (for any necessary disk access) """
381 if self.filePath.startswith("./"): # relative to project file
382 self.filePath = os.path.normpath(os.path.join(parentPath, self.filePath)) # also converts '/' to os.sep
383
384
385 #----------------------------------------------------------------------------
386 # BaseDocumentMgr methods
387 #----------------------------------------------------------------------------
388
389 def _GetDoc(self):
390 # HACK: temporary solution.
391 import wx
392 import wx.lib.docview
393 if not self._doc:
394 docMgr = wx.GetApp().GetDocumentManager()
395
396 try:
397 doc = docMgr.CreateDocument(self.filePath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
398 if (doc == None): # already open
399 docs = docMgr.GetDocuments()
400 for d in docs:
401 if d.GetFilename() == self.filePath:
402 doc = d
403 break
404 self._doc = doc
405 except Exception,e:
406 aglogging.reportException(e, stacktrace=True)
407
408 return self._doc
409
410
411 def _GetLocalServiceProcessName(self):
412 # HACK: temporary solution to getting process name from wsdlag file.
413 doc = self._GetDoc()
414 if doc:
415 return doc.GetModel().processName
416 else:
417 return None
418
419
420 processName = property(_GetLocalServiceProcessName)
421
422
423 def _GetStateful(self):
424 # HACK: temporary solution to getting stateful from wsdlag file.
425 return self._GetDoc().GetModel().stateful
426
427
428 def _SetStateful(self, stateful):
429 # HACK: temporary solution to setting stateful from wsdlag file.
430 self._GetDoc().GetModel().stateful = stateful
431
432
433 stateful = property(_GetStateful, _SetStateful)
434
435
436 def _GetLocalServiceCodeFile(self):
437 # HACK: temporary solution to getting class name from wsdlag file.
438 return self._GetDoc().GetModel().localServiceCodeFile
439
440
441 def _SetLocalServiceCodeFile(self, codefile):
442 # HACK: temporary solution to setting class name from wsdlag file.
443 self._GetDoc().GetModel().localServiceCodeFile = codefile
444
445
446 localServiceCodeFile = property(_GetLocalServiceCodeFile, _SetLocalServiceCodeFile)
447
448
449 def _GetLocalServiceClassName(self):
450 # HACK: temporary solution to getting class name from wsdlag file.
451 return self._GetDoc().GetModel().localServiceClassName
452
453
454 def _SetLocalServiceClassName(self, className):
455 # HACK: temporary solution to setting class name from wsdlag file.
456 self._GetDoc().GetModel().localServiceClassName = className
457
458
459 localServiceClassName = property(_GetLocalServiceClassName, _SetLocalServiceClassName)
460
461
462 def getServiceParameter(self, message, part):
463 return self._GetDoc().GetModel().getServiceParameter(message, part)
464
465
466 # only activate this code if we programatically need to access these values
467 ## def _GetRssServiceBaseURL(self):
468 ## return self._GetDoc().GetModel().rssServiceBaseURL
469 ##
470 ##
471 ## def _SetRssServiceBaseURL(self, baseURL):
472 ## self._GetDoc().GetModel().rssServiceBaseURL = baseURL
473 ##
474 ##
475 ## rssServiceBaseURL = property(_GetRssServiceBaseURL, _SetRssServiceBaseURL)
476 ##
477 ##
478 ## def _GetRssServiceRssVersion(self):
479 ## return self._GetDoc().GetModel().rssServiceRssVersion
480 ##
481 ##
482 ## def _SetRssServiceRssVersion(self, rssVersion):
483 ## self._GetDoc().GetModel().rssServiceRssVersion = rssVersion
484 ##
485 ##
486 ## rssServiceRssVersion = property(_GetRssServiceRssVersion, _SetRssServiceRssVersion)
487
488
489 def _GetServiceRefServiceType(self):
490 # HACK: temporary solution to getting service type from wsdlag file.
491 doc = self._GetDoc()
492 if not doc:
493 return None
494 model = doc.GetModel()
495 if hasattr(model, 'serviceType'):
496 return model.serviceType
497 else:
498 return None
499
500
501 def _SetServiceRefServiceType(self, serviceType):
502 # HACK: temporary solution to getting service type from wsdlag file.
503 self._GetDoc().GetModel().serviceType = serviceType
504
505
506 serviceType = property(_GetServiceRefServiceType, _SetServiceRefServiceType)
507
508
509 def getExternalPackage(self):
510 # HACK: temporary solution to getting custom code filename from wsdlag file.
511 import activegrid.model.projectmodel as projectmodel
512 import wx
513 import ProjectEditor
514
515 appInfo = self._GetDoc().GetAppInfo()
516
517 if appInfo.language == None:
518 language = wx.ConfigBase_Get().Read(ProjectEditor.APP_LAST_LANGUAGE, projectmodel.LANGUAGE_DEFAULT)
519 else:
520 language = appInfo.language
521
522 if language == projectmodel.LANGUAGE_PYTHON:
523 suffix = ".py"
524 elif language == projectmodel.LANGUAGE_PHP:
525 suffix = ".php"
526 pyFilename = self.name + suffix
527 return self._GetDoc().GetAppDocMgr().fullPath(pyFilename)
528
529
530 #----------------------------------------------------------------------------
531 # Old Classes
532 #----------------------------------------------------------------------------
533
534 class Project_10:
535 """ Version 1.0, kept for upgrading to latest version. Over time, this should be deprecated. """
536 __xmlname__ = "project"
537 __xmlrename__ = { "_files":"files"}
538 __xmlexclude__ = ('fileName',)
539 __xmlattributes__ = ["version"]
540
541
542 def __init__(self):
543 self.version = PROJECT_VERSION_050730
544 self._files = []
545
546
547 def initialize(self):
548 """ Required method for xmlmarshaller """
549 pass
550
551
552 def upgradeVersion(self):
553 currModel = Project()
554 for file in self._files:
555 currModel._files.append(ProjectFile(currModel, file))
556 return currModel
557
558
559 #----------------------------------------------------------------------------
560 # XML Marshalling Methods
561 #----------------------------------------------------------------------------
562
563 if ACTIVEGRID_BASE_IDE:
564 KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile}
565 else:
566 KNOWNTYPES = {"ag:project" : Project, "ag:file" : ProjectFile,
567 "ag:appInfo" : AppInfo.AppInfo,
568 "ag:deploymentDataSource" : AppInfo.DeploymentDataSource,
569 "ag:dataSourceBinding" : AppInfo.DataSourceBinding}
570
571 def load(fileObject):
572 version = xmlutils.getAgVersion(fileObject.name)
573 # most current versions on top
574 if version == PROJECT_VERSION_050826:
575 fileObject.seek(0)
576 project = xmlutils.load(fileObject.name, knownTypes=KNOWNTYPES, knownNamespaces=xmlutils.KNOWN_NAMESPACES, createGenerics=True)
577 elif version == PROJECT_VERSION_050730:
578 fileObject.seek(0)
579 project = xmlutils.load(fileObject.name, knownTypes={"project" : Project_10}, createGenerics=True)
580 project = project.upgradeVersion()
581 else:
582 # assume it is old version without version number
583 fileObject.seek(0)
584 project = xmlutils.load(fileObject.name, knownTypes={"project" : Project_10}, createGenerics=True)
585 if project:
586 project = project.upgradeVersion()
587 else:
588 print "Project, unknown version:", version
589 return None
590
591 if project:
592 project._projectDir = os.path.dirname(fileObject.name)
593 project.RelativeToAbsPath()
594
595 return project
596
597
598 def save(fileObject, project, productionDeployment=False):
599 if not project._projectDir:
600 project._projectDir = os.path.dirname(fileObject.name)
601 project.AbsToRelativePath() # temporarily change it to relative paths for saving
602 savedHomeDir = project.homeDir
603 if productionDeployment:
604 # for deployments, we don't want an abs path in homeDir since that
605 # would tie the app to the current filesystem. So unset it.
606 project.homeDir = None
607
608 xmlutils.save(fileObject.name, project, prettyPrint=True, knownTypes=KNOWNTYPES, knownNamespaces=xmlutils.KNOWN_NAMESPACES)
609
610 if productionDeployment:
611 project.homeDir = savedHomeDir
612
613 project.RelativeToAbsPath() # swap it back to absolute path
614