1 #----------------------------------------------------------------------------
3 # Purpose: project model for wx.lib.pydocview
9 # Copyright: (c) 2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
16 import activegrid
.util
.xmlutils
as xmlutils
17 import activegrid
.util
.aglogging
as aglogging
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).
23 from IDE
import ACTIVEGRID_BASE_IDE
25 ACTIVEGRID_BASE_IDE
= False
27 if not ACTIVEGRID_BASE_IDE
:
28 import activegrid
.model
.basedocmgr
as basedocmgr
31 #----------------------------------------------------------------------------
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'
40 #----------------------------------------------------------------------------
42 #----------------------------------------------------------------------------
44 class BaseProject(object):
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"] }
56 self
.__xmlnamespaces
__ = { "ag" : xmlutils.AG_NS_URL }
57 self
.version
= PROJECT_VERSION_050826
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()
67 for file in self
._files
:
68 file._parentProj
= self
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
)
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
91 self
._files
.append(file)
93 self
._files
.append(ProjectFile(self
, filePath
, logicalFolder
, type, name
, getDocCallback
=self
._getDocCallback
))
96 def RemoveFile(self
, file):
97 self
._files
.remove(file)
100 def FindFile(self
, filePath
):
102 for file in self
._files
:
103 if file.filePath
== filePath
:
109 def _GetFilePaths(self
):
110 return [file.filePath
for file in self
._files
]
113 filePaths
= property(_GetFilePaths
)
115 def _GetProjectFiles(self
):
117 projectFiles
= property(_GetProjectFiles
)
120 def _GetLogicalFolders(self
):
122 for file in self
._files
:
123 if file.logicalFolder
and file.logicalFolder
not in folders
:
124 folders
.append(file.logicalFolder
)
128 logicalFolders
= property(_GetLogicalFolders
)
131 def _GetPhysicalFolders(self
):
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
140 physicalFolders
= property(_GetPhysicalFolders
)
143 def _GetHomeDir(self
):
147 return self
._projectDir
150 def _SetHomeDir(self
, parentPath
):
151 self
._homeDir
= parentPath
154 def _IsDefaultHomeDir(self
):
155 return (self
._homeDir
== None)
158 isDefaultHomeDir
= property(_IsDefaultHomeDir
)
161 homeDir
= property(_GetHomeDir
, _SetHomeDir
)
164 def GetRelativeFolders(self
):
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
173 def AbsToRelativePath(self
):
174 for file in self
._files
:
175 file.AbsToRelativePath(self
.homeDir
)
178 def RelativeToAbsPath(self
):
179 for file in self
._files
:
180 file.RelativeToAbsPath(self
.homeDir
)
183 def _SetCache(self
, enable
):
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.
189 This bypasses the IsDocumentModificationDateCorrect call because the modification date check is too costly, it hits the disk and takes too long.
192 if self
._cacheEnabled
== 0:
193 # clear old cache, don't want to accidentally return stale value
194 for file in self
._files
:
197 self
._cacheEnabled
+= 1
199 self
._cacheEnabled
-= 1
204 return (self
._cacheEnabled
> 0)
207 cacheEnabled
= property(_GetCache
, _SetCache
)
210 #----------------------------------------------------------------------------
211 # BaseDocumentMgr methods
212 #----------------------------------------------------------------------------
215 def fullPath(self
, fileName
):
216 fileName
= super(BaseProject
, self
).fullPath(fileName
)
218 if os
.path
.isabs(fileName
):
221 absPath
= os
.path
.join(self
.homeDir
, fileName
)
223 absPath
= os
.path
.abspath(fileName
)
224 return os
.path
.normpath(absPath
)
227 def documentRefFactory(self
, name
, fileType
, filePath
):
228 return ProjectFile(self
, filePath
=self
.fullPath(filePath
), type=fileType
, name
=name
, getDocCallback
=self
._getDocCallback
)
231 def findAllRefs(self
):
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
)
240 xformdir
= self
.homeDir
244 def setRefs(self
, files
):
248 def findRefsByFileType(self
, fileType
):
250 for file in self
._files
:
251 if fileType
== file.type:
252 fileList
.append(file)
256 def GenerateServiceRefPath(self
, wsdlFilePath
):
257 # HACK: temporary solution to getting wsdlag path from wsdl path.
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()
265 wsdlAgFilePath
= os
.path
.splitext(wsdlFilePath
)[0] + ext
266 return wsdlAgFilePath
269 def SetDocCallback(self
, getDocCallback
):
270 self
._getDocCallback
= getDocCallback
271 for file in self
._files
:
272 file._getDocCallback
= getDocCallback
275 if ACTIVEGRID_BASE_IDE
:
276 class Project(BaseProject
):
279 class Project(BaseProject
, basedocmgr
.BaseDocumentMgr
):
283 class ProjectFile(object):
285 __xmlexclude__
= ('_parentProj', '_getDocCallback', '_docCallbackCacheReturnValue', '_docModelCallbackCacheReturnValue', '_doc',)
286 __xmlattributes__
= ["filePath", "logicalFolder", "type", "name"]
287 __xmldefaultnamespace__
= xmlutils
.AG_NS_URL
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
296 self
._getDocCallback
= getDocCallback
297 self
._docCallbackCacheReturnValue
= None
298 self
._docModelCallbackCacheReturnValue
= None
302 def _GetDocumentModel(self
):
303 if (self
._docCallbackCacheReturnValue
304 and (self
._parentProj
.cacheEnabled
or self
._docCallbackCacheReturnValue
.IsDocumentModificationDateCorrect())):
305 return self
._docModelCallbackCacheReturnValue
307 if self
._getDocCallback
:
308 self
._docCallbackCacheReturnValue
, self
._docModelCallbackCacheReturnValue
= self
._getDocCallback
(self
.filePath
)
309 return self
._docModelCallbackCacheReturnValue
314 document
= property(_GetDocumentModel
)
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
323 if self
._getDocCallback
:
324 self
._docCallbackCacheReturnValue
, self
._docModelCallbackCacheReturnValue
= self
._getDocCallback
(self
.filePath
)
325 return self
._docCallbackCacheReturnValue
330 ideDocument
= property(_GetDocument
)
333 def ClearCache(self
):
334 self
._docCallbackCacheReturnValue
= None
335 self
._docModelCallbackCacheReturnValue
= None
338 def _typeEnumeration(self
):
339 return basedocmgr
.FILE_TYPE_LIST
342 def _GetPhysicalFolder(self
):
345 dir = os
.path
.dirname(self
.filePath
)
347 dir = dir.replace(os
.sep
, '/') # require '/' as delimiter
351 physicalFolder
= property(_GetPhysicalFolder
)
354 def GetRelativeFolder(self
, parentPath
):
355 parentPathLen
= len(parentPath
)
359 dir = os
.path
.dirname(self
.filePath
)
360 if dir.startswith(parentPath
+ os
.sep
):
361 dir = "." + dir[parentPathLen
:] # convert to relative path
363 dir = dir.replace(os
.sep
, '/') # always save out with '/' as path separator for cross-platform compatibility.
367 def AbsToRelativePath(self
, parentPath
):
368 """ Used to convert path to relative path for saving (disk format) """
369 parentPathLen
= len(parentPath
)
371 if self
.filePath
.startswith(parentPath
+ os
.sep
):
372 self
.filePath
= "." + self
.filePath
[parentPathLen
:] # convert to relative path
374 self
.filePath
= self
.filePath
.replace(os
.sep
, '/') # always save out with '/' as path separator for cross-platform compatibility.
376 pass # not a decendant of project, use absolute path
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
385 #----------------------------------------------------------------------------
386 # BaseDocumentMgr methods
387 #----------------------------------------------------------------------------
390 # HACK: temporary solution.
392 import wx
.lib
.docview
394 docMgr
= wx
.GetApp().GetDocumentManager()
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()
401 if d
.GetFilename() == self
.filePath
:
406 aglogging
.reportException(e
, stacktrace
=True)
411 def _GetLocalServiceProcessName(self
):
412 # HACK: temporary solution to getting process name from wsdlag file.
415 return doc
.GetModel().processName
420 processName
= property(_GetLocalServiceProcessName
)
423 def _GetStateful(self
):
424 # HACK: temporary solution to getting stateful from wsdlag file.
425 return self
._GetDoc
().GetModel().stateful
428 def _SetStateful(self
, stateful
):
429 # HACK: temporary solution to setting stateful from wsdlag file.
430 self
._GetDoc
().GetModel().stateful
= stateful
433 stateful
= property(_GetStateful
, _SetStateful
)
436 def _GetLocalServiceCodeFile(self
):
437 # HACK: temporary solution to getting class name from wsdlag file.
438 return self
._GetDoc
().GetModel().localServiceCodeFile
441 def _SetLocalServiceCodeFile(self
, codefile
):
442 # HACK: temporary solution to setting class name from wsdlag file.
443 self
._GetDoc
().GetModel().localServiceCodeFile
= codefile
446 localServiceCodeFile
= property(_GetLocalServiceCodeFile
, _SetLocalServiceCodeFile
)
449 def _GetLocalServiceClassName(self
):
450 # HACK: temporary solution to getting class name from wsdlag file.
451 return self
._GetDoc
().GetModel().localServiceClassName
454 def _SetLocalServiceClassName(self
, className
):
455 # HACK: temporary solution to setting class name from wsdlag file.
456 self
._GetDoc
().GetModel().localServiceClassName
= className
459 localServiceClassName
= property(_GetLocalServiceClassName
, _SetLocalServiceClassName
)
462 def getServiceParameter(self
, message
, part
):
463 return self
._GetDoc
().GetModel().getServiceParameter(message
, part
)
466 # only activate this code if we programatically need to access these values
467 ## def _GetRssServiceBaseURL(self):
468 ## return self._GetDoc().GetModel().rssServiceBaseURL
471 ## def _SetRssServiceBaseURL(self, baseURL):
472 ## self._GetDoc().GetModel().rssServiceBaseURL = baseURL
475 ## rssServiceBaseURL = property(_GetRssServiceBaseURL, _SetRssServiceBaseURL)
478 ## def _GetRssServiceRssVersion(self):
479 ## return self._GetDoc().GetModel().rssServiceRssVersion
482 ## def _SetRssServiceRssVersion(self, rssVersion):
483 ## self._GetDoc().GetModel().rssServiceRssVersion = rssVersion
486 ## rssServiceRssVersion = property(_GetRssServiceRssVersion, _SetRssServiceRssVersion)
489 def _GetServiceRefServiceType(self
):
490 # HACK: temporary solution to getting service type from wsdlag file.
494 model
= doc
.GetModel()
495 if hasattr(model
, 'serviceType'):
496 return model
.serviceType
501 def _SetServiceRefServiceType(self
, serviceType
):
502 # HACK: temporary solution to getting service type from wsdlag file.
503 self
._GetDoc
().GetModel().serviceType
= serviceType
506 serviceType
= property(_GetServiceRefServiceType
, _SetServiceRefServiceType
)
509 def getExternalPackage(self
):
510 # HACK: temporary solution to getting custom code filename from wsdlag file.
511 import activegrid
.model
.projectmodel
as projectmodel
515 appInfo
= self
._GetDoc
().GetAppInfo()
517 if appInfo
.language
== None:
518 language
= wx
.ConfigBase_Get().Read(ProjectEditor
.APP_LAST_LANGUAGE
, projectmodel
.LANGUAGE_DEFAULT
)
520 language
= appInfo
.language
522 if language
== projectmodel
.LANGUAGE_PYTHON
:
524 elif language
== projectmodel
.LANGUAGE_PHP
:
526 pyFilename
= self
.name
+ suffix
527 return self
._GetDoc
().GetAppDocMgr().fullPath(pyFilename
)
530 #----------------------------------------------------------------------------
532 #----------------------------------------------------------------------------
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"]
543 self
.version
= PROJECT_VERSION_050730
547 def initialize(self
):
548 """ Required method for xmlmarshaller """
552 def upgradeVersion(self
):
553 currModel
= Project()
554 for file in self
._files
:
555 currModel
._files
.append(ProjectFile(currModel
, file))
559 #----------------------------------------------------------------------------
560 # XML Marshalling Methods
561 #----------------------------------------------------------------------------
563 if ACTIVEGRID_BASE_IDE
:
564 KNOWNTYPES
= {"ag:project" : Project, "ag:file" : ProjectFile}
566 KNOWNTYPES
= {"ag:project" : Project
, "ag:file" : ProjectFile
,
567 "ag:appInfo" : AppInfo
.AppInfo
,
568 "ag:deploymentDataSource" : AppInfo
.DeploymentDataSource
,
569 "ag:dataSourceBinding" : AppInfo
.DataSourceBinding
}
571 def load(fileObject
):
572 version
= xmlutils
.getAgVersion(fileObject
.name
)
573 # most current versions on top
574 if version
== PROJECT_VERSION_050826
:
576 project
= xmlutils
.load(fileObject
.name
, knownTypes
=KNOWNTYPES
, knownNamespaces
=xmlutils
.KNOWN_NAMESPACES
, createGenerics
=True)
577 elif version
== PROJECT_VERSION_050730
:
579 project
= xmlutils
.load(fileObject
.name
, knownTypes
={"project" : Project_10}
, createGenerics
=True)
580 project
= project
.upgradeVersion()
582 # assume it is old version without version number
584 project
= xmlutils
.load(fileObject
.name
, knownTypes
={"project" : Project_10}
, createGenerics
=True)
586 project
= project
.upgradeVersion()
588 print "Project, unknown version:", version
592 project
._projectDir
= os
.path
.dirname(fileObject
.name
)
593 project
.RelativeToAbsPath()
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
608 xmlutils
.save(fileObject
.name
, project
, prettyPrint
=True, knownTypes
=KNOWNTYPES
, knownNamespaces
=xmlutils
.KNOWN_NAMESPACES
)
610 if productionDeployment
:
611 project
.homeDir
= savedHomeDir
613 project
.RelativeToAbsPath() # swap it back to absolute path