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