Files
wxWidgets/wxPython/samples/ide/activegrid/tool/ProjectEditor.py
2005-12-30 23:02:03 +00:00

3916 lines
163 KiB
Python

#----------------------------------------------------------------------------
# Name: ProjectEditor.py
# Purpose: IDE-style Project Editor for wx.lib.pydocview
#
# Author: Morgan Hua, Peter Yared
#
# Created: 8/15/03
# CVS-ID: $Id$
# Copyright: (c) 2003, 2004, 2005 ActiveGrid, Inc.
# License: wxWindows License
#----------------------------------------------------------------------------
import wx
import wx.lib.docview
import wx.lib.pydocview
import wx.lib.buttons
from wxPython.lib.rcsizer import RowColSizer
import Service
import copy
import os
import os.path
import sets
import sys
import time
import types
import activegrid.util.appdirs as appdirs
import activegrid.util.fileutils as fileutils
import UICommon
import Wizard
import SVNService
import project as projectlib
import ExtensionService
from IDE import ACTIVEGRID_BASE_IDE
if not ACTIVEGRID_BASE_IDE:
import activegrid.server.deployment as deploymentlib
import ProcessModelEditor
import DataModelEditor
import WsdlAgEditor
APP_LAST_LANGUAGE = "LastLanguage"
import activegrid.model.basedocmgr as basedocmgr
import activegrid.model.basemodel as basemodel
import PropertyService
from activegrid.server.toolsupport import GetTemplate
import activegrid.util.xmlutils as xmlutils
import activegrid.util.sysutils as sysutils
from SVNService import SVN_INSTALLED
_ = wx.GetTranslation
if wx.Platform == '__WXMSW__':
_WINDOWS = True
else:
_WINDOWS = False
#----------------------------------------------------------------------------
# Constants
#----------------------------------------------------------------------------
SPACE = 10
HALF_SPACE = 5
PROJECT_EXTENSION = ".agp"
# wxBug: the wxTextCtrl and wxChoice controls on Mac do not correctly size
# themselves with sizers, so we need to add a right border to the sizer to
# get the control to shrink itself to fit in the sizer.
MAC_RIGHT_BORDER = 0
if wx.Platform == "__WXMAC__":
MAC_RIGHT_BORDER = 5
PROJECT_KEY = "/AG_Projects"
PROJECT_DIRECTORY_KEY = "NewProjectDirectory"
NEW_PROJECT_DIRECTORY_DEFAULT = appdirs.documents_folder
#----------------------------------------------------------------------------
# Methods
#----------------------------------------------------------------------------
def getProjectKeyName(projectName, mode):
return "%s/%s/%s" % (PROJECT_KEY, projectName.replace(os.sep, '|'), mode)
def GetDocCallback(filepath):
""" Get the Document used by the IDE and the in-memory document model used by runtime engine """
docMgr = wx.GetApp().GetDocumentManager()
doc = docMgr.CreateDocument(filepath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
if (doc == None): # already open
for d in docMgr.GetDocuments():
if os.path.normcase(d.GetFilename()) == os.path.normcase(filepath):
doc = d
break
else:
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectDocs = projectService.FindProjectByFile(filepath)
if projectDocs:
projectDoc = projectDocs[0]
projectService.AddProjectMapping(doc, projectDoc)
if hasattr(doc, "GetModel"):
projectService.AddProjectMapping(doc.GetModel(), projectDoc)
if doc and doc.GetDocumentTemplate().GetDocumentType() == WsdlAgEditor.WsdlAgDocument:
# get referenced wsdl doc instead
if os.path.isabs(doc.GetModel().filePath): # if absolute path, leave it alone
filepath = doc.GetModel().filePath
else:
filepath = doc.GetAppDocMgr().fullPath(doc.GetModel().filePath) # check relative to project homeDir
if not os.path.isfile(filepath):
filepath = os.path.normpath(os.path.join(os.path.dirname(doc.GetFilename()), doc.GetModel().filePath)) # check relative to wsdlag file
if not os.path.isfile(filepath):
filename = os.sep + os.path.basename(doc.GetModel().filePath) # check to see if in project file
filePaths = findDocumentMgr(doc).filePaths
for fp in filePaths:
if fp.endswith(filename):
filepath = fp
break
doc = docMgr.CreateDocument(filepath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
if (doc == None): # already open
for d in docMgr.GetDocuments():
if os.path.normcase(d.GetFilename()) == os.path.normcase(filepath):
doc = d
break
else:
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectDocs = projectService.FindProjectByFile(filepath)
if projectDocs:
projectDoc = projectDocs[0]
projectService.AddProjectMapping(doc, projectDoc)
if hasattr(doc, "GetModel"):
projectService.AddProjectMapping(doc.GetModel(), projectDoc)
if doc:
docModel = doc.GetModel()
else:
docModel = None
return doc, docModel
def findDocumentMgr(root):
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectDoc = projectService.FindProjectFromMapping(root)
if projectDoc:
return projectDoc.GetModel()
projectDoc = projectService.GetCurrentProject()
if not projectDoc:
return None
if isinstance(root, wx.lib.docview.Document):
filepath = root.GetFilename()
elif hasattr(root, "fileName") and root.fileName:
filepath = root.fileName
else:
filepath = None
if filepath:
if projectDoc.IsFileInProject(filepath):
return projectDoc.GetModel()
projects = []
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
for openDoc in openDocs:
if openDoc == projectDoc:
continue
if(isinstance(openDoc, ProjectDocument)):
if openDoc.IsFileInProject(filepath):
projects.append(openDoc)
if projects:
if len(projects) == 1:
return projects[0].GetModel()
else:
choices = [os.path.basename(project.GetFilename()) for project in projects]
dlg = wx.SingleChoiceDialog(wx.GetApp().GetTopWindow(), _("'%s' found in more than one project.\nWhich project should be used for this operation?") % os.path.basename(filepath), _("Select Project"), choices, wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER|wx.OK|wx.CENTRE)
dlg.CenterOnParent()
projectDoc = None
if dlg.ShowModal() == wx.ID_OK:
i = dlg.GetSelection()
projectDoc = projects[i]
dlg.Destroy()
return projectDoc.GetModel()
return projectDoc.GetModel()
return None
if not ACTIVEGRID_BASE_IDE:
basemodel.findGlobalDocumentMgr = findDocumentMgr
#----------------------------------------------------------------------------
# Classes
#----------------------------------------------------------------------------
class ProjectDocument(wx.lib.docview.Document):
def __init__(self, model=None):
wx.lib.docview.Document.__init__(self)
if model:
self.SetModel(model)
else:
self.SetModel(projectlib.Project()) # initial model used by "File | New... | Project"
self.GetModel().SetDocCallback(GetDocCallback)
self._stageProjectFile = False
def __copy__(self):
model = copy.copy(self.GetModel())
clone = ProjectDocument(model)
clone.SetFilename(self.GetFilename())
return clone
def GetFirstView(self):
""" Bug: workaround. If user tries to open an already open project with main menu "File | Open...", docview.DocManager.OnFileOpen() silently returns None if project is already open.
And to the user, it appears as if nothing has happened. The user expects to see the open project.
This forces the project view to show the correct project.
"""
view = wx.lib.docview.Document.GetFirstView(self)
view.SetProject(self.GetFilename()) # ensure project is displayed in view
return view
def GetModel(self):
return self._projectModel
def SetModel(self, model):
self._projectModel = model
def OnCreate(self, path, flags):
projectService = wx.GetApp().GetService(ProjectService)
view = projectService.GetView()
if view: # view already exists, reuse
# All project documents share the same view.
self.AddView(view)
if view.GetDocument():
# All project documents need to share the same command processor,
# to enable redo/undo of cross project document commands
cmdProcessor = view.GetDocument().GetCommandProcessor()
if cmdProcessor:
self.SetCommandProcessor(cmdProcessor)
else: # generate view
view = self.GetDocumentTemplate().CreateView(self, flags)
projectService.SetView(view)
return view
def LoadObject(self, fileObject):
self.SetModel(projectlib.load(fileObject))
self.GetModel().SetDocCallback(GetDocCallback)
return True
def SaveObject(self, fileObject):
projectlib.save(fileObject, self.GetModel())
return True
def OnOpenDocument(self, filePath):
projectService = wx.GetApp().GetService(ProjectService)
view = projectService.GetView()
if not os.path.exists(filePath):
wx.GetApp().CloseSplash()
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("File Error")
wx.MessageBox(_("Could not find '%s'.") % filePath,
msgTitle,
wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP,
wx.GetApp().GetTopWindow())
return True # if we return False, the Project View is destroyed, Service windows shouldn't be destroyed
fileObject = file(filePath, 'r')
try:
self.LoadObject(fileObject)
except:
wx.GetApp().CloseSplash()
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("File Error")
wx.MessageBox(_("Could not open '%s'. %s") % (wx.lib.docview.FileNameFromPath(filePath), sys.exc_value),
msgTitle,
wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP,
wx.GetApp().GetTopWindow())
return True # if we return False, the Project View is destroyed, Service windows shouldn't be destroyed
self.Modify(False)
self.SetFilename(filePath, True)
view.AddProjectToView(self)
self.SetDocumentModificationDate()
self.UpdateAllViews()
self._savedYet = True
view.Activate()
return True
def AddFile(self, filePath, folderPath=None, type=None, name=None):
if type:
types = [type]
else:
types = None
if name:
names = [name]
else:
names = None
return self.AddFiles([filePath], folderPath, types, names)
def AddFiles(self, filePaths=None, folderPath=None, types=None, names=None, files=None):
# Filter out files that are not already in the project
if filePaths:
newFilePaths = []
oldFilePaths = []
for filePath in filePaths:
if self.GetModel().FindFile(filePath):
oldFilePaths.append(filePath)
else:
newFilePaths.append(filePath)
projectService = wx.GetApp().GetService(ProjectService)
for i, filePath in enumerate(newFilePaths):
if types:
type = types[i]
else:
type = None
if names:
name = names[i]
else:
name = projectService.FindNameDefault(filePath)
if not folderPath:
folder = projectService.FindLogicalViewFolderDefault(filePath)
else:
folder = folderPath
self.GetModel().AddFile(filePath, folder, type, name)
elif files:
newFilePaths = []
oldFilePaths = []
for file in files:
if self.GetModel().FindFile(file.filePath):
oldFilePaths.append(file.filePath)
else:
newFilePaths.append(file.filePath)
self.GetModel().AddFile(file=file)
else:
return False
self.AddNameSpaces(newFilePaths)
self.UpdateAllViews(hint = ("add", self, newFilePaths, oldFilePaths))
if len(newFilePaths):
self.Modify(True)
return True
else:
return False
def RemoveFile(self, filePath):
return self.RemoveFiles([filePath])
def RemoveFiles(self, filePaths=None, files=None):
removedFiles = []
if files:
filePaths = []
for file in files:
filePaths.append(file.filePath)
for filePath in filePaths:
file = self.GetModel().FindFile(filePath)
if file:
self.GetModel().RemoveFile(file)
removedFiles.append(file.filePath)
self.UpdateAllViews(hint = ("remove", self, removedFiles))
if len(removedFiles):
self.Modify(True)
return True
else:
return False
def RenameFile(self, oldFilePath, newFilePath, isProject = False):
try:
if oldFilePath == newFilePath:
return False
# projects don't have to exist yet, so not required to rename old file,
# but files must exist, so we'll try to rename and allow exceptions to occur if can't.
if not isProject or (isProject and os.path.exists(oldFilePath)):
os.rename(oldFilePath, newFilePath)
if isProject:
documents = self.GetDocumentManager().GetDocuments()
for document in documents:
if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFilePath): # If the renamed document is open, update it
document.SetFilename(newFilePath)
document.SetTitle(wx.lib.docview.FileNameFromPath(newFilePath))
document.UpdateAllViews(hint = ("rename", self, oldFilePath, newFilePath))
else:
self.UpdateFilePath(oldFilePath, newFilePath)
documents = self.GetDocumentManager().GetDocuments()
for document in documents:
if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFilePath): # If the renamed document is open, update it
document.SetFilename(newFilePath, notifyViews = True)
document.UpdateAllViews(hint = ("rename", self, oldFilePath, newFilePath))
return True
except OSError, (code, message):
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("File Error")
wx.MessageBox("Could not rename '%s'. '%s'" % (wx.lib.docview.FileNameFromPath(oldFilePath), message),
msgTitle,
wx.OK | wx.ICON_EXCLAMATION,
wx.GetApp().GetTopWindow())
return False
def MoveFile(self, file, newFolderPath):
return self.MoveFiles([file], newFolderPath)
def MoveFiles(self, files, newFolderPath):
filePaths = []
isArray = isinstance(newFolderPath, type([]))
for i in range(len(files)):
if isArray:
files[i].logicalFolder = newFolderPath[i]
else:
files[i].logicalFolder = newFolderPath
filePaths.append(files[i].filePath)
self.UpdateAllViews(hint = ("remove", self, filePaths))
self.UpdateAllViews(hint = ("add", self, filePaths, []))
self.Modify(True)
return True
def UpdateFilePath(self, oldFilePath, newFilePath):
file = self.GetModel().FindFile(oldFilePath)
self.RemoveFile(oldFilePath)
if file:
self.AddFile(newFilePath, file.logicalFolder, file.type, file.name)
else:
self.AddFile(newFilePath)
def RemoveInvalidPaths(self):
"""Makes sure all paths project knows about are valid and point to existing files. Removes and returns list of invalid paths."""
invalidFileRefs = []
fileRefs = self.GetFileRefs()
for fileRef in fileRefs:
if not os.path.exists(fileRef.filePath):
invalidFileRefs.append(fileRef)
for fileRef in invalidFileRefs:
fileRefs.remove(fileRef)
return [fileRef.filePath for fileRef in invalidFileRefs]
def SetStageProjectFile(self):
self._stageProjectFile = True
def ArchiveProject(self, zipdest, tmpdir=None, stagedir=None):
"""Stages the application files in tmpdir, and zips the stagedir, creating a zipfile that has the projectname, in zipdest. Returns path to zipfile. Optionally, pass in stagedir and we assume the app is already staged at stagedir (we don't stage again in that case)."""
if not stagedir:
if not tmpdir:
raise AssertionError("'tmpdir' must be set when not passing 'stagedir' so we know where to stage the app")
stagedir = self.StageProject(tmpdir)
if os.path.exists(zipdest):
raise AssertionError("Cannot archive project, %s already exists" % zipdest)
fileutils.zip(zipdest, stagedir)
return zipdest
def StageProject(self, tmpdir):
""" Copies all files that project knows about into staging location. Files that live outside of the project dir are copied into the root of the stage dir, and their recorded file path is updated. Files that live inside of the project dir keep their relative path. Generates .dpl file into staging dir. Returns path to staging dir."""
projname = self.GetProjectName()
stagedir = os.path.join(tmpdir, projname)
fileutils.remove(stagedir)
os.makedirs(stagedir)
# remove invalid files from project
self.RemoveInvalidPaths()
# required so relative paths are written correctly when .dpl file is
# generated below.
self.SetFilename(os.path.join(stagedir,
os.path.basename(self.GetFilename())))
projectdir = self.GetModel().homeDir
# Validate paths before actually copying, and populate a dict
# with src->dest so copying is easy.
# (fileDict: ProjectFile instance -> dest path (string))
fileDict = self._ValidateFilePaths(projectdir, stagedir)
# copy files to staging dir
self._StageFiles(fileDict)
# it is unfortunate we require this. it would be nice if filepaths
# were only in the project
self._FixWsdlAgFiles(stagedir)
# generate .dpl file
dplfilename = projname + deploymentlib.DEPLOYMENT_EXTENSION
dplfilepath = os.path.join(stagedir, dplfilename)
self.GenerateDeployment(dplfilepath, productionDeployment=True)
if self._stageProjectFile:
# save project so we get the .agp file. not required for deployment
# but convenient if user wants to open the deployment in the IDE
agpfilename = projname + PROJECT_EXTENSION
agpfilepath = os.path.join(stagedir, agpfilename)
f = None
try:
f = open(agpfilepath, "w")
# setting homeDir correctly is required for the "figuring out
# relative paths" logic when saving the project
self.GetModel().homeDir = stagedir
projectlib.save(f, self.GetModel(), productionDeployment=True)
finally:
try:
f.close()
except: pass
return stagedir
def _FixWsdlAgFiles(self, stagedir):
"""For each wsdlag file in the stagedir:
Ensure the referenced wsdl file lives in root of stagedir. This
should be the case if wsdl is part of project (and staging has run).
If it is not at root of stagedir, copy it. Then update path in
wsdlag."""
files = os.listdir(stagedir)
for f in files:
if f.endswith(WsdlAgEditor.WsdlAgDocument.WSDL_AG_EXT):
wsdlagpath = os.path.join(stagedir, f)
fileObject = None
mod = False
try:
fileObject = open(wsdlagpath)
serviceref = WsdlAgEditor.load(fileObject)
if hasattr(serviceref, "filePath") and serviceref.filePath:
mod = self.UpdateServiceRefFilePath(stagedir,serviceref)
finally:
try:
fileObject.close()
except:
pass
# no need to save the file if we did not change anything
if not mod: continue
# write the wsdlag file
fileObject = open(wsdlagpath)
try:
serviceref = WsdlAgEditor.save(fileObject, serviceref)
finally:
try:
fileObject.close()
except:
pass
def UpdateServiceRefFilePath(self, stagedir, serviceref):
"""Returns True if serviceref.filePath has been updated, False otherwise."""
if not os.path.exists(serviceref.filePath):
# should be an error? wrong place to
# validate that referenced file exists
# could print warning
return False
# If the referenced file is in stagedir already, there's nothing to do
if fileutils.hasAncestorDir(serviceref.filePath, stagedir):
return False
# The path points outside of stagedir.
# Check if we already have the referenced wsdl file at root, should be
# the case if the referenced wsdl is part of project
# Copy it if we don't have it
relPath = os.path.basename(serviceref.filePath)
stagepath = os.path.join(stagedir, relPath)
if not os.path.exists(stagepath):
fileutils.copyFile(serviceref.filePath, stagepath)
serviceref.filePath = relPath
return True
def _StageFiles(self, fileDict):
"""Copy files to staging directory, update filePath attr of project's ProjectFile instances."""
# fileDict: ProjectFile instance -> dest path (string)
for fileRef, fileDest in fileDict.items():
fileutils.copyFile(fileRef.filePath, fileDest)
fileRef.filePath = fileDest
def _ValidateFilePaths(self, projectdir, stagedir):
"""If paths validate, returns a dict mapping ProjectFile to destination path. Destination path is the path the file needs to be copied to for staging. If paths don't validate, throws an IOError.
With our current slightly simplistic staging algorithm, staging will not work iff the project has files outside of the projectdir with names (filename without path) that:
- match filenames of files living at the root of the project.
- are same as those of any other file that lives outside of the projectdir.
We have this limitation because we move any file that lives outside of the project dir into the root of the stagedir (== copied project dir). We could make this smarter by either giving files unique names if we detect a collistion, or by creating some directory structure instead of putting all files from outside of the projectdir into the root of the stagedir (== copied projectdir)."""
# ProjectFile instance -> dest path (string)
rtn = {}
projectRootFiles = sets.Set() # live at project root
foreignFiles = sets.Set() # live outside of project
fileRefsToDeploy = self.GetFileRefs()
for fileRef in fileRefsToDeploy:
relPath = fileutils.getRelativePath(fileRef.filePath, projectdir)
filename = os.path.basename(fileRef.filePath)
if not relPath: # file lives outside of project dir...
# do we have another file with the same name already?
if filename in foreignFiles:
raise IOError("More than one file with name \"%s\" lives outside of the project. These files need to have unique names" % filename)
foreignFiles.add(filename)
fileDest = os.path.join(stagedir, filename)
else:
# file lives somewhere within the project dir
fileDest = os.path.join(stagedir, relPath)
if not os.path.dirname(relPath):
projectRootFiles.add(filename)
rtn[fileRef] = fileDest
# make sure we won't collide with a file that lives at root of
# projectdir when moving files into project
for filename in foreignFiles:
if filename in projectRootFiles:
raise IOError("File outside of project, \"%s\", cannot have same name as file at project root" % filename)
# REVIEW stoens@activegrid.com 19-Oct-05 --
# We could also validate that user does not already have a .dpl file
# since we're going to generate one...
return rtn
def RenameFolder(self, oldFolderPath, newFolderPath):
for file in self.GetModel()._files:
if file.logicalFolder == oldFolderPath:
file.logicalFolder = newFolderPath
self.UpdateAllViews(hint = ("rename folder", self, oldFolderPath, newFolderPath))
self.Modify(True)
return True
def GetFiles(self):
return self.GetModel().filePaths
def GetFileRefs(self):
return self.GetModel().findAllRefs()
def SetFileRefs(self, fileRefs):
return self.GetModel().setRefs(fileRefs)
def IsFileInProject(self, filename):
return self.GetModel().FindFile(filename)
def GetAppInfo(self):
return self.GetModel().GetAppInfo()
def GetAppDocMgr(self):
return self.GetModel()
def GetProjectName(self):
return os.path.splitext(os.path.basename(self.GetFilename()))[0]
def GetDeploymentFilepath(self):
projectName = self.GetProjectName()
return os.path.join(self.GetModel().homeDir, projectName + "RunTime_tmp" + deploymentlib.DEPLOYMENT_EXTENSION)
def GenerateDeployment(self, deployFilepath=None, preview=False, productionDeployment=False):
if ACTIVEGRID_BASE_IDE:
return
def FindOpenDoc(filePath):
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
for openDoc in openDocs:
if openDoc.GetFilename() == filePath:
return openDoc
return None
if not deployFilepath:
deployFilepath = self.GetDeploymentFilepath()
deployment = deploymentlib.Deployment(deployFilepath)
defaultFlagsNoView = wx.GetApp().GetDocumentManager().GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW
self.GetAppInfo().CopyToDeployment(deployment)
for file in self.GetModel()._files:
if not file.type:
continue
elif file.type == basedocmgr.FILE_TYPE_SERVICE: # set serviceRefs
doc = wx.GetApp().GetDocumentManager().CreateDocument(file.filePath, flags=defaultFlagsNoView)
if (doc == None): # already open
doc = FindOpenDoc(file.filePath)
if doc:
serviceRef = doc.GetModel()
if serviceRef:
documentRef = copy.copy(serviceRef)
deployment.serviceRefs.append(documentRef)
if not productionDeployment:
# filePath should point to location of wsdl file
# wsdlag filePath points to relative path to wsdl file from wsdlag location
# but deployment needs relative path from deployment location, so here's the conversion
curDir = os.path.dirname(self.GetFilename()) + os.sep
filePath = file.document.fileName
if (filePath == None):
raise Exception("Cannot find file \"%s\"" % file.filePath)
if filePath.startswith(curDir):
filePath = filePath[len(curDir):]
if os.sep != '/':
filePath = filePath.replace(os.sep, "/")
documentRef.filePath = filePath
documentRef.document = file.document
if serviceRef.serviceType == deploymentlib.SERVICE_DATABASE and serviceRef.databaseService:
dataSourceService = wx.GetApp().GetService(DataModelEditor.DataSourceService)
ds = dataSourceService.getDataSource(serviceRef.databaseService.datasourceName)
if ds:
found = False
for d in deployment.dataSources:
if d.name == ds.name:
found = True
break
if not found:
deployment.dataSources.append(ds)
else:
curDir = os.path.dirname(self.GetFilename()) + os.sep
filePath = file.filePath
if filePath.startswith(curDir):
filePath = filePath[len(curDir):]
if os.sep != '/':
filePath = filePath.replace(os.sep, "/")
if file.type == basedocmgr.FILE_TYPE_XFORM:
documentRef = deploymentlib.XFormRef()
deployment.xformRefs.append(documentRef)
elif file.type == basedocmgr.FILE_TYPE_PROCESS:
documentRef = deploymentlib.ProcessRef()
deployment.processRefs.append(documentRef)
elif file.type == basedocmgr.FILE_TYPE_SCHEMA:
# set schemaRefs
documentRef = deploymentlib.SchemaRef()
deployment.schemaRefs.append(documentRef)
# set dataSources
doc = wx.GetApp().GetDocumentManager().CreateDocument(file.filePath, flags=defaultFlagsNoView)
if (doc == None): # already open
doc = FindOpenDoc(file.filePath)
if doc:
dataSourceService = wx.GetApp().GetService(DataModelEditor.DataSourceService)
ds = dataSourceService.getDataSource(doc.GetModel().getDefaultDataSourceName())
if ds:
found = False
for d in deployment.dataSources:
if d.name == ds.name:
found = True
break
if not found:
deployment.dataSources.append(ds)
# set keyServices
keyServices = doc.GetModel().keyServices
for keyService in keyServices:
# add default key service to deployment
if not productionDeployment:
mainModuleDir = sysutils.mainModuleDir
else:
mainModuleDir = sysutils.MAINMODULE_DIR_VAR
wsdlFullPath = os.path.join(mainModuleDir, "..", "wsdl", DataModelEditor.DEFAULT_KEYSERVICE_WSDL_FILENAME)
keyServiceRef = deploymentlib.ServiceRef(filePath=wsdlFullPath)
deployment.serviceRefs.append(keyServiceRef)
keyServiceRef.name = keyService
keyServiceRef.serviceType = deploymentlib.SERVICE_LOCAL
keyServiceRef.localService = deploymentlib.LocalService()
if keyService == DataModelEditor.DEFAULT_KEYSERVICE:
keyServiceRef.filePath = wsdlFullPath
keyServiceRef.localServiceClassName = DataModelEditor.DEFAULT_KEYSERVICE_CLASSNAME
elif file.type == basedocmgr.FILE_TYPE_SKIN:
documentRef = deploymentlib.SkinRef(deployment)
deployment.skinref = documentRef
elif file.type == basedocmgr.FILE_TYPE_IDENTITY:
documentRef = deploymentlib.IdentityRef()
deployment.identityRefs.append(documentRef)
else:
continue
documentRef.name = file.name
documentRef.filePath = filePath
doc = FindOpenDoc(file.filePath)
if doc and hasattr(doc, 'GetModel'):
documentRef.document = doc.GetModel()
if isinstance(documentRef, deploymentlib.XFormRef):
doc.GetModel().linkDeployment(deployment, deployment.loader)
if preview:
deployment.initialize() # used in preview only
if 0: # preview: # setPrototype not working, commented this out
deploymentlib._deploymentCache.setPrototype(deployment.fileName, deployment)
else:
deploymentlib.saveThroughCache(deployment.fileName, deployment)
return deployFilepath
def AddNameSpaces(self, filePaths):
""" Add any new wsdl namespaces to bpel files """
""" Add any new schema namespaces to wsdl files """
if ACTIVEGRID_BASE_IDE:
return
serviceRefs = self.GetAppDocMgr().allServiceRefs # wsdl
processRefs = self.GetAppDocMgr().findRefsByFileType(basedocmgr.FILE_TYPE_PROCESS) # bpel
if processRefs and serviceRefs:
for processRef in processRefs:
processDoc = processRef._GetDoc()
process = processDoc.GetModel()
modified = False
for serviceRef in serviceRefs:
wsdl = serviceRef.document
if (wsdl.fileName in filePaths
or serviceRef.filePath in filePaths):
wsdlLongNS = wsdl.targetNamespace
wsdlShortNS = self.GetAppDocMgr().findShortNS(wsdlLongNS)
if not wsdlShortNS:
wsdlShortNS = xmlutils.genShortNS(process, wsdlLongNS)
xmlutils.addNSAttribute(process, wsdlShortNS, wsdlLongNS)
modified = True
if modified:
processDoc.OnSaveDocument(processDoc.GetFilename())
schemaRefs = self.GetAppDocMgr().findRefsByFileType(basedocmgr.FILE_TYPE_SCHEMA)
if schemaRefs and serviceRefs:
for serviceRef in serviceRefs:
wsdl = serviceRef.document
wsdlDoc = serviceRef.ideDocument
modified = False
for schemaRef in schemaRefs:
schema = schemaRef.document
if schema.fileName in filePaths:
schemaLongNS = schema.targetNamespace
schemaShortNS = self.GetAppDocMgr().findShortNS(schemaLongNS)
if not schemaShortNS:
schemaShortNS = xmlutils.genShortNS(process, schemaLongNS)
xmlutils.addNSAttribute(wsdl, schemaShortNS, schemaLongNS)
modified = True
if modified:
wsdlDoc.OnSaveDocument(wsdlDoc.GetFilename())
class NewProjectWizard(Wizard.BaseWizard):
WIZTITLE = _("New Project Wizard")
def __init__(self, parent):
self._parent = parent
self._fullProjectPath = None
Wizard.BaseWizard.__init__(self, parent, self.WIZTITLE)
self._projectLocationPage = self.CreateProjectLocation(self)
wx.wizard.EVT_WIZARD_PAGE_CHANGING(self, self.GetId(), self.OnWizPageChanging)
def CreateProjectLocation(self,wizard):
page = Wizard.TitledWizardPage(wizard, _("Project File Location"))
page.GetSizer().Add(wx.StaticText(page, -1, _("\nSelect the directory and filename for the project.\n\n")))
self._projectName, self._dirCtrl, sizer, self._fileValidation = UICommon.CreateDirectoryControl(page, fileExtension="agp", appDirDefaultStartDir=True)
page.GetSizer().Add(sizer, 1, flag=wx.EXPAND)
wizard.Layout()
wizard.FitToPage(page)
return page
def RunWizard(self, existingTables = None, existingRelationships = None):
status = wx.wizard.Wizard.RunWizard(self, self._projectLocationPage)
if status:
wx.ConfigBase_Get().Write(PROJECT_DIRECTORY_KEY, self._dirCtrl.GetValue())
docManager = wx.GetApp().GetTopWindow().GetDocumentManager()
if os.path.exists(self._fullProjectPath):
# What if the document is already open and we're overwriting it?
documents = docManager.GetDocuments()
for document in documents:
if os.path.normcase(document.GetFilename()) == os.path.normcase(self._fullProjectPath): # If the renamed document is open, update it
document.DeleteAllViews()
break
os.remove(self._fullProjectPath)
for template in docManager.GetTemplates():
if template.GetDocumentType() == ProjectDocument:
doc = template.CreateDocument(self._fullProjectPath, flags = wx.lib.docview.DOC_NEW)
doc.OnSaveDocument(self._fullProjectPath)
projectService = wx.GetApp().GetService(ProjectService)
view = projectService.GetView()
view.AddProjectToView(doc)
break
self.Destroy()
return status
def OnWizPageChanging(self, event):
if event.GetDirection(): # It's going forwards
if event.GetPage() == self._projectLocationPage:
if not self._fileValidation(noFirstCharDigit=True):
event.Veto()
return
self._fullProjectPath = os.path.join(self._dirCtrl.GetValue(),UICommon.MakeNameEndInExtension(self._projectName.GetValue(), PROJECT_EXTENSION))
def OnShowCreatePages(self):
self.Hide()
import DataModelEditor
requestedPos = self.GetPositionTuple()
projectService = wx.GetApp().GetService(ProjectService)
projectView = projectService.GetView()
wiz = DataModelEditor.ImportExportWizard(projectView.GetFrame(), pos=requestedPos)
if wiz.RunWizard(dontDestroy=True):
self._schemaName.SetValue(wiz.GetSchemaFileName())
wiz.Destroy()
self.Show(True)
class ProjectTemplate(wx.lib.docview.DocTemplate):
def CreateDocument(self, path, flags):
if path:
doc = wx.lib.docview.DocTemplate.CreateDocument(self, path, flags)
if path:
doc.GetModel()._projectDir = os.path.dirname(path)
return doc
else:
wiz = NewProjectWizard(wx.GetApp().GetTopWindow())
wiz.RunWizard()
wiz.Destroy()
return None # never return the doc, otherwise docview will think it is a new file and rename it
class ProjectAddFilesCommand(wx.lib.docview.Command):
def __init__(self, projectDoc, filePaths, folderPath=None, types=None, names=None):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._projectDoc = projectDoc
self._allFilePaths = filePaths
self._folderPath = folderPath
self._types = types
self._names = names
if not self._types:
self._types = []
projectService = wx.GetApp().GetService(ProjectService)
for filePath in self._allFilePaths:
self._types.append(projectService.FindFileTypeDefault(filePath))
# list of files that will really be added
self._newFiles = []
for filePath in self._allFilePaths:
if not projectDoc.GetModel().FindFile(filePath):
self._newFiles.append(filePath)
def GetName(self):
if len(self._allFilePaths) == 1:
return _("Add File %s") % os.path.basename(self._allFilePaths[0])
else:
return _("Add Files")
def Do(self):
return self._projectDoc.AddFiles(self._allFilePaths, self._folderPath, self._types, self._names)
def Undo(self):
return self._projectDoc.RemoveFiles(self._newFiles)
class ProjectRemoveFilesCommand(wx.lib.docview.Command):
def __init__(self, projectDoc, files):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._projectDoc = projectDoc
self._files = files
def GetName(self):
if len(self._files) == 1:
return _("Remove File %s") % os.path.basename(self._files[0].filePath)
else:
return _("Remove Files")
def Do(self):
return self._projectDoc.RemoveFiles(files=self._files)
def Undo(self):
return self._projectDoc.AddFiles(files=self._files)
class ProjectRenameFileCommand(wx.lib.docview.Command):
def __init__(self, projectDoc, oldFilePath, newFilePath, isProject = False):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._projectDoc = projectDoc
self._oldFilePath = oldFilePath
self._newFilePath = newFilePath
self._isProject = isProject
def GetName(self):
return _("Rename File %s to %s") % (os.path.basename(self._oldFilePath), os.path.basename(self._newFilePath))
def Do(self):
return self._projectDoc.RenameFile(self._oldFilePath, self._newFilePath, self._isProject)
def Undo(self):
return self._projectDoc.RenameFile(self._newFilePath, self._oldFilePath, self._isProject)
class ProjectRenameFolderCommand(wx.lib.docview.Command):
def __init__(self, doc, oldFolderPath, newFolderPath):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._doc = doc
self._oldFolderPath = oldFolderPath
self._newFolderPath = newFolderPath
def GetName(self):
return _("Rename Folder %s to %s") % (os.path.basename(self._oldFolderPath), os.path.basename(self._newFolderPath))
def Do(self):
return self._doc.RenameFolder(self._oldFolderPath, self._newFolderPath)
def Undo(self):
return self._doc.RenameFolder(self._newFolderPath, self._oldFolderPath)
class ProjectAddFolderCommand(wx.lib.docview.Command):
def __init__(self, view, doc, folderpath):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._doc = doc
self._view = view
self._folderpath = folderpath
def GetName(self):
return _("Add Folder %s") % (os.path.basename(self._folderpath))
def Do(self):
if self._view.GetDocument() != self._doc:
return True
status = self._view.AddFolder(self._folderpath)
if status:
self._view._treeCtrl.UnselectAll()
item = self._view._treeCtrl.FindFolder(self._folderpath)
self._view._treeCtrl.SelectItem(item)
return status
def Undo(self):
if self._view.GetDocument() != self._doc:
return True
return self._view.DeleteFolder(self._folderpath)
class ProjectRemoveFolderCommand(wx.lib.docview.Command):
def __init__(self, view, doc, folderpath):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._doc = doc
self._view = view
self._folderpath = folderpath
def GetName(self):
return _("Remove Folder %s") % (os.path.basename(self._folderpath))
def Do(self):
if self._view.GetDocument() != self._doc:
return True
return self._view.DeleteFolder(self._folderpath)
def Undo(self):
if self._view.GetDocument() != self._doc:
return True
status = self._view.AddFolder(self._folderpath)
if status:
self._view._treeCtrl.UnselectAll()
item = self._view._treeCtrl.FindFolder(self._folderpath)
self._view._treeCtrl.SelectItem(item)
return status
class ProjectMoveFilesCommand(wx.lib.docview.Command):
def __init__(self, doc, files, folderPath):
wx.lib.docview.Command.__init__(self, canUndo = True)
self._doc = doc
self._files = files
self._newFolderPath = folderPath
self._oldFolderPaths = []
for file in self._files:
self._oldFolderPaths.append(file.logicalFolder)
def GetName(self):
if len(self._files) == 1:
return _("Move File %s") % os.path.basename(self._files[0].filePath)
else:
return _("Move Files")
def Do(self):
return self._doc.MoveFiles(self._files, self._newFolderPath)
def Undo(self):
return self._doc.MoveFiles(self._files, self._oldFolderPaths)
class ProjectTreeCtrl(wx.TreeCtrl):
#----------------------------------------------------------------------------
# Overridden Methods
#----------------------------------------------------------------------------
def __init__(self, parent, id, style):
wx.TreeCtrl.__init__(self, parent, id, style = style)
templates = wx.GetApp().GetDocumentManager().GetTemplates()
iconList = wx.ImageList(16, 16, initialCount = len(templates))
self._iconIndexLookup = []
for template in templates:
icon = template.GetIcon()
if icon:
if icon.GetHeight() != 16 or icon.GetWidth() != 16:
icon.SetHeight(16)
icon.SetWidth(16)
if wx.GetApp().GetDebug():
print "Warning: icon for '%s' isn't 16x16, not crossplatform" % template._docTypeName
iconIndex = iconList.AddIcon(icon)
self._iconIndexLookup.append((template, iconIndex))
icon = getBlankIcon()
if icon.GetHeight() != 16 or icon.GetWidth() != 16:
icon.SetHeight(16)
icon.SetWidth(16)
if wx.GetApp().GetDebug():
print "Warning: getBlankIcon isn't 16x16, not crossplatform"
self._blankIconIndex = iconList.AddIcon(icon)
icon = getFolderClosedIcon()
if icon.GetHeight() != 16 or icon.GetWidth() != 16:
icon.SetHeight(16)
icon.SetWidth(16)
if wx.GetApp().GetDebug():
print "Warning: getFolderIcon isn't 16x16, not crossplatform"
self._folderClosedIconIndex = iconList.AddIcon(icon)
icon = getFolderOpenIcon()
if icon.GetHeight() != 16 or icon.GetWidth() != 16:
icon.SetHeight(16)
icon.SetWidth(16)
if wx.GetApp().GetDebug():
print "Warning: getFolderIcon isn't 16x16, not crossplatform"
self._folderOpenIconIndex = iconList.AddIcon(icon)
self.AssignImageList(iconList)
def OnCompareItems(self, item1, item2):
item1IsFolder = (self.GetPyData(item1) == None)
item2IsFolder = (self.GetPyData(item2) == None)
if (item1IsFolder == item2IsFolder): # if both are folders or both not
return cmp(self.GetItemText(item1).lower(), self.GetItemText(item2).lower())
elif item1IsFolder and not item2IsFolder: # folders sort above non-folders
return -1
elif not item1IsFolder and item2IsFolder: # folders sort above non-folders
return 1
def AppendFolder(self, parent, folderName):
item = wx.TreeCtrl.AppendItem(self, parent, folderName)
self.SetItemImage(item, self._folderClosedIconIndex, wx.TreeItemIcon_Normal)
self.SetItemImage(item, self._folderOpenIconIndex, wx.TreeItemIcon_Expanded)
self.SetPyData(item, None)
return item
def AppendItem(self, parent, filename, file):
item = wx.TreeCtrl.AppendItem(self, parent, filename)
found = False
template = wx.GetApp().GetDocumentManager().FindTemplateForPath(filename)
if template:
for t, iconIndex in self._iconIndexLookup:
if t is template:
self.SetItemImage(item, iconIndex, wx.TreeItemIcon_Normal)
self.SetItemImage(item, iconIndex, wx.TreeItemIcon_Expanded)
## self.SetItemImage(item, iconIndex, wx.TreeItemIcon_Selected)
found = True
break
if not found:
self.SetItemImage(item, self._blankIconIndex, wx.TreeItemIcon_Normal)
self.SetItemImage(item, self._blankIconIndex, wx.TreeItemIcon_Expanded)
## self.SetItemImage(item, self._blankIconIndex, wx.TreeItemIcon_Selected)
self.SetPyData(item, file)
return item
def AddFolder(self, folderPath):
folderItems = []
if folderPath != None:
folderTree = folderPath.split('/')
item = self.GetRootItem()
for folderName in folderTree:
found = False
(child, cookie) = self.GetFirstChild(item)
while child.IsOk():
file = self.GetPyData(child)
if file:
pass
else: # folder
if self.GetItemText(child) == folderName:
item = child
found = True
break
(child, cookie) = self.GetNextChild(item, cookie)
if not found:
item = self.AppendFolder(item, folderName)
folderItems.append(item)
return folderItems
def FindItem(self, filePath, parentItem=None):
if not parentItem:
parentItem = self.GetRootItem()
(child, cookie) = self.GetFirstChild(parentItem)
while child.IsOk():
file = self.GetPyData(child)
if file:
if file.filePath == filePath:
return child
else: # folder
result = self.FindItem(filePath, child) # do recursive call
if result:
return result
(child, cookie) = self.GetNextChild(parentItem, cookie)
return None
def FindFolder(self, folderPath):
if folderPath != None:
folderTree = folderPath.split('/')
item = self.GetRootItem()
for folderName in folderTree:
found = False
(child, cookie) = self.GetFirstChild(item)
while child.IsOk():
file = self.GetPyData(child)
if file:
pass
else: # folder
if self.GetItemText(child) == folderName:
item = child
found = True
break
(child, cookie) = self.GetNextChild(item, cookie)
if found:
return item
return None
def FindClosestFolder(self, x, y):
item, flags = self.HitTest((x,y))
if item:
file = self.GetPyData(item)
if file:
item = self.GetItemParent(item)
return item
return item
return None
class ProjectView(wx.lib.docview.View):
LOGICAL_MODE = "logical"
PHYSICAL_MODE = "physical"
#----------------------------------------------------------------------------
# Overridden methods
#----------------------------------------------------------------------------
def __init__(self, service = None):
wx.lib.docview.View.__init__(self)
# self._service = service # not used, but kept to match other Services
self._projectChoice = None
self._logicalBtn = None
self._physicalBtn = None
self._treeCtrl = None
self._editingSoDontKillFocus = False
self._checkEditMenu = True
self._loading = False # flag to not to try to saving state of folders while it is loading
def GetDocumentManager(self): # Overshadow this since the superclass uses the view._viewDocument attribute directly, which the project editor doesn't use since it hosts multiple docs
return wx.GetApp().GetDocumentManager()
def Destroy(self):
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectService.SetView(None)
wx.lib.docview.View.Destroy(self)
def GetDocument(self):
if not self._projectChoice:
return None
selItem = self._projectChoice.GetSelection()
if selItem == wx.NOT_FOUND:
return None
document = self._projectChoice.GetClientData(selItem)
return document
def Activate(self, activate = True):
if not wx.GetApp().IsMDI():
if activate and not self.IsShown():
self.Show()
if self.IsShown():
wx.lib.docview.View.Activate(self, activate = activate)
if activate and self._treeCtrl:
self._treeCtrl.SetFocus()
def OnCreate(self, doc, flags):
config = wx.ConfigBase_Get()
if wx.GetApp().IsMDI():
self._embeddedWindow = wx.GetApp().GetTopWindow().GetEmbeddedWindow(wx.lib.pydocview.EMBEDDED_WINDOW_TOPLEFT)
self.SetFrame(self._embeddedWindow)
frame = self._embeddedWindow
wx.EVT_SIZE(frame, self.OnSize)
else:
self._embeddedWindow = None
pos = config.ReadInt("ProjectFrameXLoc", -1), config.ReadInt("ProjectFrameYLoc", -1)
# make sure frame is visible
screenWidth = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X)
screenHeight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
if pos[0] < 0 or pos[0] >= screenWidth or pos[1] < 0 or pos[1] >= screenHeight:
pos = wx.DefaultPosition
size = wx.Size(config.ReadInt("ProjectFrameXSize", -1), config.ReadInt("ProjectFrameYSize", -1))
title = _("Projects")
if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI and wx.GetApp().GetAppName():
title = title + " - " + wx.GetApp().GetAppName()
frame = wx.GetApp().CreateDocumentFrame(self, doc, 0, title = title, pos = pos, size = size)
if config.ReadInt("ProjectFrameMaximized", False):
frame.Maximize(True)
panel = wx.Panel(frame, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
butSizer = wx.BoxSizer(wx.HORIZONTAL)
self._projectChoice = wx.Choice(panel, -1)
panel.Bind(wx.EVT_CHOICE, self.OnProjectSelect, self._projectChoice)
w, h = self._projectChoice.GetSize()
self._logicalBtn = wx.lib.buttons.GenBitmapToggleButton(panel, -1, getLogicalModeOffBitmap(), size=(h,h))
self._logicalBtn.SetBitmapSelected(getLogicalModeOnBitmap())
self._logicalBtn.SetToggle(True)
self._logicalBtn.SetToolTipString(_("View Files by Logical Groups"))
panel.Bind(wx.EVT_BUTTON, self.OnSelectMode, self._logicalBtn)
self._physicalBtn = wx.lib.buttons.GenBitmapToggleButton(panel, -1, getPhysicalModeOffBitmap(), size=(h,h))
self._physicalBtn.SetBitmapSelected(getPhysicalModeOnBitmap())
self._physicalBtn.SetToolTipString(_("View Files by Physical Disk Layout"))
panel.Bind(wx.EVT_BUTTON, self.OnSelectMode, self._physicalBtn)
butSizer.Add(self._projectChoice, 1, wx.EXPAND)
butSizer.Add(self._logicalBtn, 0)
butSizer.Add(self._physicalBtn, 0)
sizer.Add(butSizer, 0, wx.EXPAND)
self._treeCtrl = ProjectTreeCtrl(panel, -1, style = wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS | wx.TR_EDIT_LABELS | wx.TR_DEFAULT_STYLE | wx.TR_MULTIPLE | wx.TR_EXTENDED)
self._treeCtrl.AddRoot(_("Projects"))
wx.EVT_TREE_BEGIN_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnBeginDrag)
wx.EVT_TREE_END_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnEndDrag)
if self._embeddedWindow:
sizer.Add(self._treeCtrl, 1, wx.EXPAND|wx.BOTTOM, HALF_SPACE) # allow space for embedded window resize-sash
else:
sizer.Add(self._treeCtrl, 1, wx.EXPAND)
panel.SetSizer(sizer)
sizer = wx.BoxSizer(wx.VERTICAL)
if wx.GetApp().IsMDI():
sizer.Add(panel, 1, wx.EXPAND|wx.BOTTOM, 1) # wx.Bug: without bottom margin, can't resize embedded window
else:
sizer.Add(panel, 1, wx.EXPAND)
frame.SetSizer(sizer)
frame.Layout()
self.Activate()
if wx.GetApp().IsMDI():
wx.EVT_SET_FOCUS(self._treeCtrl, self.OnFocus)
wx.EVT_KILL_FOCUS(self._treeCtrl, self.OnKillFocus)
if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
wx.EVT_TREE_ITEM_ACTIVATED(self._treeCtrl, self._treeCtrl.GetId(), self.OnOpenSelectionSDI)
else:
wx.EVT_TREE_ITEM_ACTIVATED(self._treeCtrl, self._treeCtrl.GetId(), self.OnOpenSelection)
wx.EVT_TREE_BEGIN_LABEL_EDIT(self._treeCtrl, self._treeCtrl.GetId(), self.OnBeginLabelEdit)
wx.EVT_TREE_END_LABEL_EDIT(self._treeCtrl, self._treeCtrl.GetId(), self.OnEndLabelEdit)
wx.EVT_RIGHT_DOWN(self._treeCtrl, self.OnRightClick)
wx.EVT_LEFT_DOWN(self._treeCtrl, self.OnLeftClick)
wx.EVT_KEY_DOWN(self._treeCtrl, self.OnKeyPressed)
wx.EVT_TREE_ITEM_COLLAPSED(self._treeCtrl, self._treeCtrl.GetId(), self.SaveFolderState)
wx.EVT_TREE_ITEM_EXPANDED(self._treeCtrl, self._treeCtrl.GetId(), self.SaveFolderState)
# wx.EVT_COMMAND_RIGHT_CLICK(self._treeCtrl, self._treeCtrl.GetId(), self.OnRightClick) # wxBug: This isn't working for some reason
# drag-and-drop support
dt = ProjectFileDropTarget(self)
self._treeCtrl.SetDropTarget(dt)
return True
def OnSelectMode(self, event):
btn = event.GetEventObject()
down = event.GetIsDown()
if btn == self._logicalBtn:
self._physicalBtn.SetToggle(not down)
else: # btn == self._physicalBtn:
self._logicalBtn.SetToggle(not down)
self.LoadProject(self.GetDocument())
def GetMode(self):
if not self._physicalBtn.up:
return ProjectView.PHYSICAL_MODE
else: # elif self._logicalBtn.GetValue():
return ProjectView.LOGICAL_MODE
def OnProjectSelect(self, event=None):
self.LoadProject(self.GetDocument())
if self.GetDocument():
filename = self.GetDocument().GetFilename()
else:
filename = ''
self._projectChoice.SetToolTipString(filename)
def OnSize(self, event):
event.Skip()
wx.CallAfter(self.GetFrame().Layout)
def OnBeginDrag(self, event):
if self.GetMode() == ProjectView.PHYSICAL_MODE:
return
item = event.GetItem()
if item.IsOk():
self._draggingItems = []
for item in self._treeCtrl.GetSelections():
if self._IsItemFile(item):
self._draggingItems.append(item)
if len(self._draggingItems):
event.Allow()
def OnEndDrag(self, event):
item = event.GetItem()
if item.IsOk():
files = []
for ditem in self._draggingItems:
file = self._GetItemFile(ditem)
if file not in files:
files.append(file)
folderPath = self._GetItemFolderPath(item)
self.GetDocument().GetCommandProcessor().Submit(ProjectMoveFilesCommand(self.GetDocument(), files, folderPath))
def WriteProjectConfig(self):
frame = self.GetFrame()
config = wx.ConfigBase_Get()
if frame and not self._embeddedWindow:
if not frame.IsMaximized():
config.WriteInt("ProjectFrameXLoc", frame.GetPositionTuple()[0])
config.WriteInt("ProjectFrameYLoc", frame.GetPositionTuple()[1])
config.WriteInt("ProjectFrameXSize", frame.GetSizeTuple()[0])
config.WriteInt("ProjectFrameYSize", frame.GetSizeTuple()[1])
config.WriteInt("ProjectFrameMaximized", frame.IsMaximized())
if config.ReadInt("ProjectSaveDocs", True):
projectFileNames = []
curProject = None
if self._projectChoice:
for i in range(self._projectChoice.GetCount()):
project = self._projectChoice.GetClientData(i)
if not project.OnSaveModified():
return
if project.GetDocumentSaved(): # Might be a new document and "No" selected to save it
projectFileNames.append(str(project.GetFilename()))
config.Write("ProjectSavedDocs", projectFileNames.__repr__())
document = None
if self._projectChoice.GetCount():
i = self._projectChoice.GetSelection()
if i != wx.NOT_FOUND:
document = self._projectChoice.GetClientData(i)
if document:
config.Write("ProjectCurrent", document.GetFilename())
else:
config.DeleteEntry("ProjectCurrent")
def OnClose(self, deleteWindow = True):
if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
self.WriteProjectConfig()
project = self.GetDocument()
if not project:
return True
if not project.Close():
return True
if not deleteWindow:
self.RemoveCurrentDocumentUpdate()
else:
# need this to accelerate closing down app if treeCtrl has lots of items
self._treeCtrl.Freeze()
rootItem = self._treeCtrl.GetRootItem()
self._treeCtrl.DeleteChildren(rootItem)
self._treeCtrl.Thaw()
# We don't need to delete the window since it is a floater/embedded
return True
def _GetParentFrame(self):
return wx.GetTopLevelParent(self.GetFrame())
def OnUpdate(self, sender = None, hint = None):
wx.lib.docview.View.OnUpdate(self, sender, hint)
if hint:
if hint[0] == "add":
projectDoc = hint[1]
if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
return
self._treeCtrl.Freeze()
newFilePaths = hint[2] # need to be added and selected, and sorted
oldFilePaths = hint[3] # need to be selected
self._treeCtrl.UnselectAll()
mode = self.GetMode()
project = projectDoc.GetModel()
projectDir = project.homeDir
rootItem = self._treeCtrl.GetRootItem()
# add new folders and new items
addList = []
for filePath in newFilePaths:
file = project.FindFile(filePath)
if file:
if mode == ProjectView.LOGICAL_MODE:
folderPath = file.logicalFolder
else: # ProjectView.PHYSICAL_MODE
folderPath = file.GetRelativeFolder(projectDir)
if folderPath:
self._treeCtrl.AddFolder(folderPath)
folder = self._treeCtrl.FindFolder(folderPath)
else:
folder = rootItem
item = self._treeCtrl.AppendItem(folder, os.path.basename(file.filePath), file)
addList.append(item)
# sort folders with new items
parentList = []
for item in addList:
parentItem = self._treeCtrl.GetItemParent(item)
if parentItem not in parentList:
parentList.append(parentItem)
for parentItem in parentList:
self._treeCtrl.SortChildren(parentItem)
# select all the items user wanted to add
lastItem = None
for filePath in (oldFilePaths + newFilePaths):
item = self._treeCtrl.FindItem(filePath)
if item:
self._treeCtrl.SelectItem(item)
lastItem = item
if lastItem:
self._treeCtrl.EnsureVisible(lastItem)
self._treeCtrl.Thaw()
return
elif hint[0] == "remove":
projectDoc = hint[1]
if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
return
self._treeCtrl.Freeze()
filePaths = hint[2]
self._treeCtrl.UnselectAll()
for filePath in filePaths:
item = self._treeCtrl.FindItem(filePath)
if item:
self._treeCtrl.Delete(item)
self._treeCtrl.UnselectAll() # wxBug: even though we unselected earlier, an item still gets selected after the delete
self._treeCtrl.Thaw()
return
elif hint[0] == "rename":
projectDoc = hint[1]
if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
return
self._treeCtrl.Freeze()
item = self._treeCtrl.FindItem(hint[2])
self._treeCtrl.SetItemText(item, os.path.basename(hint[3]))
self._treeCtrl.EnsureVisible(item)
self._treeCtrl.Thaw()
return
elif hint[0] == "rename folder":
projectDoc = hint[1]
if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
return
self._treeCtrl.Freeze()
item = self._treeCtrl.FindFolder(hint[2])
if item:
self._treeCtrl.UnselectAll()
self._treeCtrl.SetItemText(item, os.path.basename(hint[3]))
self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
self._treeCtrl.SelectItem(item)
self._treeCtrl.EnsureVisible(item)
self._treeCtrl.Thaw()
return
def RemoveProjectUpdate(self, projectDoc):
""" Called by service after deleting a project, need to remove from project choices """
i = self._projectChoice.FindString(self._MakeProjectName(projectDoc))
self._projectChoice.Delete(i)
numProj = self._projectChoice.GetCount()
if i >= numProj:
i = numProj - 1
if i >= 0:
self._projectChoice.SetSelection(i)
self.OnProjectSelect()
def RemoveCurrentDocumentUpdate(self, i=-1):
""" Called by service after deleting a project, need to remove from project choices """
i = self._projectChoice.GetSelection()
self._projectChoice.Delete(i)
numProj = self._projectChoice.GetCount()
if i >= numProj:
i = numProj - 1
if i >= 0:
self._projectChoice.SetSelection(i)
self.OnProjectSelect()
def ProcessEvent(self, event):
id = event.GetId()
if id == ProjectService.CLOSE_PROJECT_ID:
document = self.GetDocument()
if document:
if self.GetDocumentManager().CloseDocument(document, False):
self.RemoveCurrentDocumentUpdate()
return True
elif id == ProjectService.ADD_FILES_TO_PROJECT_ID:
self.OnAddFileToProject(event)
return True
elif id == ProjectService.ADD_DIR_FILES_TO_PROJECT_ID:
self.OnAddDirToProject(event)
return True
elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
return False # Implement this one in the service
elif id == ProjectService.ADD_FOLDER_ID:
self.OnAddFolder(event)
return True
elif id == ProjectService.RENAME_ID:
self.OnRename(event)
return True
elif id == ProjectService.DELETE_FILE_ID:
self.OnDeleteFile(event)
return True
elif id == ProjectService.DELETE_PROJECT_ID:
self.OnDeleteProject(event)
return True
elif id == wx.ID_CUT:
self.OnCut(event)
return True
elif id == wx.ID_COPY:
self.OnCopy(event)
return True
elif id == wx.ID_PASTE:
self.OnPaste(event)
return True
elif (id == wx.ID_CLEAR
or id == ProjectService.REMOVE_FROM_PROJECT):
self.OnClear(event)
return True
elif id == wx.ID_SELECTALL:
self.OnSelectAll(event)
return True
elif id == ProjectService.OPEN_SELECTION_ID:
self.OnOpenSelection(event)
return True
elif id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID:
self.OnProperties(event)
return True
elif id == ProjectService.PROJECT_PROPERTIES_ID:
self.OnProjectProperties(event)
return True
else:
return False
def ProcessUpdateUIEvent(self, event):
# Hack: The edit menu is not being set for projects that are preloaded at startup, so make sure it is OK here
if self._checkEditMenu:
doc = self.GetDocument()
if doc and not doc.GetCommandProcessor().GetEditMenu():
doc.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame()))
self._checkEditMenu = False
id = event.GetId()
if id == wx.ID_CLOSE:
# Too confusing, so disable closing from "File | Close" menu, must close from "Project | Close Current Project" menu
if self.ProjectHasFocus() or self.FilesHasFocus():
event.Enable(False)
return True
else:
return False
elif (id == ProjectService.ADD_FILES_TO_PROJECT_ID
or id == ProjectService.ADD_DIR_FILES_TO_PROJECT_ID
or id == ProjectService.CLOSE_PROJECT_ID
or id == ProjectService.DELETE_PROJECT_ID):
event.Enable(self.GetDocument() != None)
return True
elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
event.Enable(False) # Implement this one in the service
return True
elif id == ProjectService.ADD_FOLDER_ID:
event.Enable((self.GetDocument() != None) and (self.GetMode() == ProjectView.LOGICAL_MODE))
return True
elif id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID:
status = False
if self.ProjectHasFocus():
if self.GetDocument():
status = True
elif self.FilesHasFocus():
items = self._treeCtrl.GetSelections()
if items:
item = items[0]
if self._IsItemFile(item):
status = True
event.Enable(status)
return True
elif (id == wx.ID_CUT
or id == wx.ID_COPY
or id == ProjectService.DELETE_FILE_ID
or id == ProjectService.REMOVE_FROM_PROJECT
or id == ProjectService.OPEN_SELECTION_ID):
event.Enable(self._HasFilesSelected())
return True
elif (id == wx.ID_CLEAR
or id == ProjectService.RENAME_ID):
event.Enable(self._HasFilesSelected() or (self.GetDocument() != None and self.GetMode() == ProjectView.LOGICAL_MODE and self._HasFoldersSelected()))
return True
elif id == wx.ID_PASTE:
event.Enable(self.CanPaste())
return True
elif id == wx.ID_SELECTALL:
event.Enable(self._HasFiles())
return True
elif (id == wx.ID_PREVIEW
or id == wx.ID_PRINT):
event.Enable(False)
return True
else:
return False
#----------------------------------------------------------------------------
# Display Methods
#----------------------------------------------------------------------------
def IsShown(self):
if not self.GetFrame():
return False
return self.GetFrame().IsShown()
def Hide(self):
self.Show(False)
def Show(self, show = True):
self.GetFrame().Show(show)
if wx.GetApp().IsMDI():
mdiParentFrame = wx.GetApp().GetTopWindow()
mdiParentFrame.ShowEmbeddedWindow(self.GetFrame(), show)
#----------------------------------------------------------------------------
# Methods for ProjectDocument and ProjectService to call
#----------------------------------------------------------------------------
def SetProject(self, projectPath):
curSel = self._projectChoice.GetSelection()
for i in range(self._projectChoice.GetCount()):
document = self._projectChoice.GetClientData(i)
if document.GetFilename() == projectPath:
if curSel != i: # don't reload if already loaded
self._projectChoice.SetSelection(i)
self.LoadProject(document)
break
def GetSelectedFile(self):
for item in self._treeCtrl.GetSelections():
filePath = self._GetItemFilePath(item)
if filePath:
return filePath
return None
def GetSelectedFiles(self):
filePaths = []
for item in self._treeCtrl.GetSelections():
filePath = self._GetItemFilePath(item)
if filePath and filePath not in filePaths:
filePaths.append(filePath)
return filePaths
def GetSelectedPhysicalFolder(self):
if self.GetMode() == ProjectView.LOGICAL_MODE:
return None
else:
for item in self._treeCtrl.GetSelections():
if not self._IsItemFile(item):
filePath = self._GetItemFolderPath(item)
if filePath:
return filePath
return None
def GetSelectedProject(self):
document = self.GetDocument()
if document:
return document.GetFilename()
else:
return None
def AddProjectToView(self, document):
i = self._projectChoice.Append(self._MakeProjectName(document), document)
self._projectChoice.SetSelection(i)
self.OnProjectSelect()
def LoadProject(self, document):
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
self._treeCtrl.Freeze()
rootItem = self._treeCtrl.GetRootItem()
self._treeCtrl.DeleteChildren(rootItem)
if document:
mode = self.GetMode()
docFilePath = document.GetFilename()
if mode == ProjectView.LOGICAL_MODE:
folders = document.GetModel().logicalFolders
else:
folders = document.GetModel().GetRelativeFolders()
folders.sort()
folderItems = []
for folderPath in folders:
folderItems = folderItems + self._treeCtrl.AddFolder(folderPath)
for file in document.GetModel()._files:
if mode == ProjectView.LOGICAL_MODE:
folder = file.logicalFolder
else:
folder = file.GetRelativeFolder(document.GetModel().homeDir)
if folder:
folderTree = folder.split('/')
item = rootItem
for folderName in folderTree:
found = False
(child, cookie) = self._treeCtrl.GetFirstChild(item)
while child.IsOk():
if self._treeCtrl.GetItemText(child) == folderName:
item = child
found = True
break
(child, cookie) = self._treeCtrl.GetNextChild(item, cookie)
if not found:
print "error folder '%s' not found for %s" % (folder, file.filePath)
break
else:
item = rootItem
fileItem = self._treeCtrl.AppendItem(item, os.path.basename(file.filePath), file)
self._treeCtrl.SortChildren(rootItem)
for item in folderItems:
self._treeCtrl.SortChildren(item)
self.LoadFolderState()
if self._embeddedWindow:
document.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame()))
self._treeCtrl.Thaw()
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
def ProjectHasFocus(self):
""" Does Project Choice have focus """
return (wx.Window.FindFocus() == self._projectChoice)
def FilesHasFocus(self):
""" Does Project Tree have focus """
winWithFocus = wx.Window.FindFocus()
if not winWithFocus:
return False
while winWithFocus:
if winWithFocus == self._treeCtrl:
return True
winWithFocus = winWithFocus.GetParent()
return False
def SaveFolderState(self, event=None):
""" Save the open/close state of folders """
if self._loading:
return
folderList = []
folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
for item in folderItemList:
if self._treeCtrl.IsExpanded(item):
folderList.append(self._GetItemFolderPath(item))
config = wx.ConfigBase_Get()
config.Write(getProjectKeyName(self.GetDocument().GetFilename(), self.GetMode()), repr(folderList))
def LoadFolderState(self):
""" Load the open/close state of folders """
self._loading = True
config = wx.ConfigBase_Get()
openFolderData = config.Read(getProjectKeyName(self.GetDocument().GetFilename(), self.GetMode()))
if openFolderData:
folderList = eval(openFolderData)
folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
for item in folderItemList:
f = self._GetItemFolderPath(item)
if f in folderList:
self._treeCtrl.Expand(item)
## else: # not needed, initial state is collapsed
## self._treeCtrl.Collapse(item)
else: # default is to open all folders
folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
for item in folderItemList:
self._treeCtrl.Expand(item)
self._loading = False
#----------------------------------------------------------------------------
# Control events
#----------------------------------------------------------------------------
def OnProperties(self, event):
if self.ProjectHasFocus():
self.OnProjectProperties(event)
elif self.FilesHasFocus():
items = self._treeCtrl.GetSelections()
if not items:
return
item = items[0]
filePath = self._GetItemFilePath(item)
if filePath:
filePropertiesService = wx.GetApp().GetService(wx.lib.pydocview.FilePropertiesService)
filePropertiesService.ShowPropertiesDialog(filePath)
def OnProjectProperties(self, event):
if self.GetDocument():
dlg = ProjectPropertiesDialog(wx.GetApp().GetTopWindow(), self.GetDocument())
dlg.CenterOnParent()
finished = False
while not finished:
if dlg.ShowModal() == wx.ID_OK:
if hasattr(dlg, "_appInfoCtrl") and dlg._appInfoCtrl._grid.IsCellEditControlShown(): # for Linux
dlg._appInfoCtrl._grid.DisableCellEditControl() # If editor is still active, force it to finish the edit before setting the new model.
homeDir = dlg._homeDirCtrl.GetValue()
if homeDir:
if homeDir == ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE:
homeDir = None
if homeDir and not os.path.isdir(homeDir):
wx.MessageBox(_("Home Dir '%s' does not exist. Please specify a valid directory.") % homeDir,
_("Project Properties"),
wx.OK | wx.ICON_EXCLAMATION)
else:
if self.GetDocument().GetModel()._homeDir != homeDir: # don't set it if it hasn't changed
self.GetDocument().GetModel().homeDir = homeDir
self.GetDocument().Modify(True)
finished = True
else:
wx.MessageBox(_("Blank Home Dir. Please specify a valid directory."),
_("Project Properties"),
wx.OK | wx.ICON_EXCLAMATION)
else: # ID_CANCEL
finished = True
dlg.Destroy()
def OnAddFolder(self, event):
if self.GetDocument():
items = self._treeCtrl.GetSelections()
if items:
item = items[0]
if self._IsItemFile(item):
item = self._treeCtrl.GetItemParent(item)
folderDir = self._GetItemFolderPath(item)
else:
folderDir = ""
if folderDir:
folderDir += "/"
folderPath = _("%sUntitled") % folderDir
i = 1
while self._treeCtrl.FindFolder(folderPath):
i += 1
folderPath = _("%sUntitled%s") % (folderDir, i)
self.GetDocument().GetCommandProcessor().Submit(ProjectAddFolderCommand(self, self.GetDocument(), folderPath))
self._treeCtrl.UnselectAll()
item = self._treeCtrl.FindFolder(folderPath)
self._treeCtrl.SelectItem(item)
self._treeCtrl.EnsureVisible(item)
self.OnRename()
def AddFolder(self, folderPath):
self._treeCtrl.AddFolder(folderPath)
return True
def DeleteFolder(self, folderPath):
item = self._treeCtrl.FindFolder(folderPath)
self._treeCtrl.Delete(item)
return True
def OnAddFileToProject(self, event):
if wx.Platform == "__WXMSW__" or wx.Platform == "__WXGTK__" or wx.Platform == "__WXMAC__":
descr = ''
for temp in self.GetDocumentManager()._templates:
if temp.IsVisible():
if len(descr) > 0:
descr = descr + _('|')
descr = descr + temp.GetDescription() + _(" (") + temp.GetFileFilter() + _(") |") + temp.GetFileFilter() # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
descr = _("All (*.*)|*.*|%s") % descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
else:
descr = _("*.*")
dialog = wx.FileDialog(self.GetFrame(), _("Add Files"), wildcard=descr, style=wx.OPEN|wx.HIDE_READONLY|wx.MULTIPLE|wx.CHANGE_DIR)
# dialog.CenterOnParent() # wxBug: caused crash with wx.FileDialog
if dialog.ShowModal() != wx.ID_OK:
dialog.Destroy()
return
paths = dialog.GetPaths()
dialog.Destroy()
if len(paths):
folderPath = None
if self.GetMode() == ProjectView.LOGICAL_MODE:
selections = self._treeCtrl.GetSelections()
if selections:
item = selections[0]
if not self._IsItemFile(item):
folderPath = self._GetItemFolderPath(item)
self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), paths, folderPath=folderPath))
self.Activate() # after add, should put focus on project editor
def OnAddDirToProject(self, event):
frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Add Directory Files to Project"), size= (320,200))
contentSizer = wx.BoxSizer(wx.VERTICAL)
flexGridSizer = wx.FlexGridSizer(cols = 2, vgap=HALF_SPACE, hgap=HALF_SPACE)
flexGridSizer.Add(wx.StaticText(frame, -1, _("Directory:")), 0, wx.ALIGN_CENTER_VERTICAL, 0)
lineSizer = wx.BoxSizer(wx.HORIZONTAL)
dirCtrl = wx.TextCtrl(frame, -1, os.path.dirname(self.GetDocument().GetFilename()), size=(250,-1))
dirCtrl.SetToolTipString(dirCtrl.GetValue())
lineSizer.Add(dirCtrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
findDirButton = wx.Button(frame, -1, _("Browse..."))
lineSizer.Add(findDirButton, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, HALF_SPACE)
flexGridSizer.Add(lineSizer, 1, wx.EXPAND)
def OnBrowseButton(event):
dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE)
dir = dirCtrl.GetValue()
if len(dir):
dlg.SetPath(dir)
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
dirCtrl.SetValue(dlg.GetPath())
dirCtrl.SetToolTipString(dirCtrl.GetValue())
dirCtrl.SetInsertionPointEnd()
dlg.Destroy()
wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton)
visibleTemplates = []
for template in self.GetDocumentManager()._templates:
if template.IsVisible():
visibleTemplates.append(template)
choices = []
descr = ''
for template in visibleTemplates:
if len(descr) > 0:
descr = descr + _('|')
descr = template.GetDescription() + _(" (") + template.GetFileFilter() + _(")")
choices.append(descr)
choices.insert(0, _("All (*.*)")) # first item
filterChoice = wx.Choice(frame, -1, size=(250, -1), choices=choices)
filterChoice.SetSelection(0)
filterChoice.SetToolTipString(_("Select file type filter."))
flexGridSizer.Add(wx.StaticText(frame, -1, _("Files of type:")), 0, wx.ALIGN_CENTER_VERTICAL)
flexGridSizer.Add(filterChoice, 1, wx.EXPAND)
contentSizer.Add(flexGridSizer, 0, wx.ALL|wx.EXPAND, SPACE)
subfolderCtrl = wx.CheckBox(frame, -1, _("Add files from subdirectories"))
subfolderCtrl.SetValue(True)
contentSizer.Add(subfolderCtrl, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, SPACE)
buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
findBtn = wx.Button(frame, wx.ID_OK, _("Add"))
findBtn.SetDefault()
buttonSizer.Add(findBtn, 0, wx.RIGHT, HALF_SPACE)
buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL), 0)
contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE)
frame.SetSizer(contentSizer)
frame.Fit()
frame.CenterOnParent()
status = frame.ShowModal()
passedCheck = False
while status == wx.ID_OK and not passedCheck:
if not os.path.exists(dirCtrl.GetValue()):
dlg = wx.MessageDialog(frame,
_("'%s' does not exist.") % dirCtrl.GetValue(),
_("Find in Directory"),
wx.OK | wx.ICON_EXCLAMATION
)
dlg.CenterOnParent()
dlg.ShowModal()
dlg.Destroy()
status = frame.ShowModal()
else:
passedCheck = True
frame.Destroy()
if status == wx.ID_OK:
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
doc = self.GetDocument()
searchSubfolders = subfolderCtrl.IsChecked()
dirString = dirCtrl.GetValue()
if os.path.isfile(dirString):
# If they pick a file explicitly, we won't prevent them from adding it even if it doesn't match the filter.
# We'll assume they know what they're doing.
paths = [dirString]
else:
paths = []
index = filterChoice.GetSelection()
lastIndex = filterChoice.GetCount()-1
if index and index != lastIndex: # if not All or Any
template = visibleTemplates[index-1]
# do search in files on disk
for root, dirs, files in os.walk(dirString):
if not searchSubfolders and root != dirString:
break
for name in files:
if index == 0: # All
for template in visibleTemplates:
if template.FileMatchesTemplate(name):
filename = os.path.join(root, name)
# if already in project, don't add it, otherwise undo will remove it from project even though it was already in it.
if doc.IsFileInProject(filename):
break
paths.append(filename)
break
elif index == lastIndex: # Any
filename = os.path.join(root, name)
# if already in project, don't add it, otherwise undo will remove it from project even though it was already in it.
if not doc.IsFileInProject(filename):
paths.append(filename)
else: # use selected filter
if template.FileMatchesTemplate(name):
filename = os.path.join(root, name)
# if already in project, don't add it, otherwise undo will remove it from project even though it was already in it.
if not doc.IsFileInProject(filename):
paths.append(filename)
folderPath = None
if self.GetMode() == ProjectView.LOGICAL_MODE:
selections = self._treeCtrl.GetSelections()
if selections:
item = selections[0]
if not self._IsItemFile(item):
folderPath = self._GetItemFolderPath(item)
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
doc.GetCommandProcessor().Submit(ProjectAddFilesCommand(doc, paths, folderPath=folderPath))
self.Activate() # after add, should put focus on project editor
def DoAddFilesToProject(self, filePaths, folderPath):
# method used by Drag-n-Drop to add files to current Project
self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), filePaths, folderPath))
def OnFocus(self, event):
self.GetDocumentManager().ActivateView(self)
event.Skip()
def OnKillFocus(self, event):
# Get the top MDI window and "activate" it since it is already active from the perspective of the MDIParentFrame
# wxBug: Would be preferable to call OnActivate, but have casting problem, so added Activate method to docview.DocMDIChildFrame
if not self._editingSoDontKillFocus: # wxBug: This didn't used to happen, but now when you start to edit an item in a wxTreeCtrl it puts out a KILL_FOCUS event, so we need to detect it
topWindow = wx.GetApp().GetTopWindow()
# wxBug: On Mac, this event can fire during shutdown, even after GetTopWindow()
# is set to NULL. So make sure we have a TLW before getting the active child.
if topWindow:
childFrame = topWindow.GetActiveChild()
if childFrame:
childFrame.Activate()
event.Skip()
def OnLeftClick(self, event):
""" wxBug: If tree has selection, but focus is in another window, single click in tree should do
single selection of item at mouse position. But what it does is just put focus back into the
window and all items go from inactive selection to active selection. Another click on the item
either activates double-click or edit for that item. This behavior is odd.
This fix makes gives the tree view the focus and makes the item under the mouse position the
only active selection, as expected.
"""
if not self.ProjectHasFocus() and not self.FilesHasFocus() and not event.ShiftDown() and not event.ControlDown() and not event.MetaDown():
self._treeCtrl.UnselectAll()
event.Skip()
item, flags = self._treeCtrl.HitTest(event.GetPosition())
self._treeCtrl.SelectItem(item)
return
event.Skip()
def OnRightClick(self, event):
self.Activate()
if not self.GetSelectedProject():
return
menu = wx.Menu()
if self._HasFilesSelected(): # Files context
menu.Append(ProjectService.OPEN_SELECTION_ID, _("&Open"), _("Opens the selection"))
menu.Enable(ProjectService.OPEN_SELECTION_ID, True)
wx.EVT_MENU(self._GetParentFrame(), ProjectService.OPEN_SELECTION_ID, self.OnOpenSelection)
extService = wx.GetApp().GetService(ExtensionService.ExtensionService)
if extService and extService.GetExtensions():
firstItem = True
for ext in extService.GetExtensions():
if not ext.opOnSelectedFile:
continue
if firstItem:
menu.AppendSeparator()
firstItem = False
menu.Append(ext.id, ext.menuItemName)
wx.EVT_MENU(self._GetParentFrame(), ext.id, extService.ProcessEvent)
wx.EVT_UPDATE_UI(self._GetParentFrame(), ext.id, extService.ProcessUpdateUIEvent)
itemIDs = [None]
for item in self._treeCtrl.GetSelections():
if self._IsItemProcessModelFile(item):
itemIDs = [None, ProjectService.RUN_SELECTED_PM_ID, None]
break
else: # Project context
itemIDs = []
menuBar = self._GetParentFrame().GetMenuBar()
itemIDs = itemIDs + [ProjectService.ADD_FILES_TO_PROJECT_ID, ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, ProjectService.ADD_FOLDER_ID, ProjectService.REMOVE_FROM_PROJECT, None, ProjectService.CLOSE_PROJECT_ID, ProjectService.DELETE_PROJECT_ID, None, ProjectService.PROJECT_PROPERTIES_ID]
svnIDs = [SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID]
if SVN_INSTALLED:
itemIDs = itemIDs + [None, SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID]
globalIDs = [wx.ID_UNDO, wx.ID_REDO, wx.ID_CLOSE, wx.ID_SAVE, wx.ID_SAVEAS]
itemIDs = itemIDs + [None, wx.ID_UNDO, wx.ID_REDO, None, wx.ID_CUT, wx.ID_COPY, wx.ID_PASTE, wx.ID_CLEAR, None, wx.ID_SELECTALL, ProjectService.RENAME_ID, ProjectService.DELETE_FILE_ID, None, wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID]
for itemID in itemIDs:
if not itemID:
menu.AppendSeparator()
else:
if itemID == ProjectService.RUN_SELECTED_PM_ID:
menu.Append(ProjectService.RUN_SELECTED_PM_ID, _("Run Process"))
wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_ID, self.OnRunSelectedPM)
elif itemID == ProjectService.REMOVE_FROM_PROJECT:
menu.Append(ProjectService.REMOVE_FROM_PROJECT, _("Remove Selected Files from Project"))
wx.EVT_MENU(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self.OnClear)
wx.EVT_UPDATE_UI(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self._GetParentFrame().ProcessUpdateUIEvent)
else:
svnService = wx.GetApp().GetService(SVNService.SVNService)
item = menuBar.FindItemById(itemID)
if item:
if itemID in svnIDs:
if SVN_INSTALLED and svnService:
wx.EVT_MENU(self._GetParentFrame(), itemID, svnService.ProcessEvent)
elif itemID in globalIDs:
pass
else:
wx.EVT_MENU(self._treeCtrl, itemID, self.ProcessEvent)
menu.Append(itemID, item.GetLabel())
self._treeCtrl.PopupMenu(menu, wx.Point(event.GetX(), event.GetY()))
menu.Destroy()
def OnRunSelectedPM(self, event):
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectService.OnRunProcessModel(event, runSelected=True)
def OnRename(self, event=None):
items = self._treeCtrl.GetSelections()
if items:
self._treeCtrl.EditLabel(items[0])
def OnBeginLabelEdit(self, event):
self._editingSoDontKillFocus = True
item = event.GetItem()
if (self.GetMode() == ProjectView.PHYSICAL_MODE) and not self._IsItemFile(item):
event.Veto()
def OnEndLabelEdit(self, event):
self._editingSoDontKillFocus = False
item = event.GetItem()
newName = event.GetLabel()
if not newName:
event.Veto()
return
if self._IsItemFile(item):
oldFilePath = self._GetItemFilePath(item)
newFilePath = os.path.join(os.path.dirname(oldFilePath), newName)
doc = self.GetDocument()
if not doc.GetCommandProcessor().Submit(ProjectRenameFileCommand(doc, oldFilePath, newFilePath)):
event.Veto()
return
self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
else:
oldFolderPath = self._GetItemFolderPath(item)
newFolderPath = os.path.dirname(oldFolderPath)
if newFolderPath:
newFolderPath += "/"
newFolderPath += newName
if self._treeCtrl.FindFolder(newFolderPath):
wx.MessageBox(_("Folder '%s' already exists.") % newName,
"Rename Folder",
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
event.Veto()
return
doc = self.GetDocument()
if not doc.GetCommandProcessor().Submit(ProjectRenameFolderCommand(doc, oldFolderPath, newFolderPath)):
event.Veto()
return
self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
def CanPaste(self):
# wxBug: Should be able to use IsSupported/IsSupportedFormat here
#fileDataObject = wx.FileDataObject()
#hasFilesInClipboard = wx.TheClipboard.IsSupportedFormat(wx.FileDataObject)
if not wx.TheClipboard.IsOpened():
if wx.TheClipboard.Open():
fileDataObject = wx.FileDataObject()
hasFilesInClipboard = wx.TheClipboard.GetData(fileDataObject)
wx.TheClipboard.Close()
else:
hasFilesInClipboard = False
return hasFilesInClipboard
def OnCut(self, event):
self.OnCopy(event)
self.OnClear(event)
def OnCopy(self, event):
fileDataObject = wx.FileDataObject()
items = self._treeCtrl.GetSelections()
for item in items:
filePath = self._GetItemFilePath(item)
if filePath:
fileDataObject.AddFile(filePath)
if len(fileDataObject.GetFilenames()) > 0 and wx.TheClipboard.Open():
wx.TheClipboard.SetData(fileDataObject)
wx.TheClipboard.Close()
def OnPaste(self, event):
if wx.TheClipboard.Open():
fileDataObject = wx.FileDataObject()
if wx.TheClipboard.GetData(fileDataObject):
folderPath = None
if self.GetMode() == ProjectView.LOGICAL_MODE:
items = self._treeCtrl.GetSelections()
if items:
item = items[0]
if item:
folderPath = self._GetItemFolderPath(item)
self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), fileDataObject.GetFilenames(), folderPath))
wx.TheClipboard.Close()
def OnClear(self, event):
if self._HasFilesSelected():
items = self._treeCtrl.GetSelections()
files = []
for item in items:
file = self._GetItemFile(item)
if file:
files.append(file)
self.GetDocument().GetCommandProcessor().Submit(ProjectRemoveFilesCommand(self.GetDocument(), files))
elif self._HasFoldersSelected():
items = self._treeCtrl.GetSelections()
item = items[0]
if self._treeCtrl.GetChildrenCount(item, False):
wx.MessageBox(_("Cannot remove folder '%s'. Folder is not empty.") % self._treeCtrl.GetItemText(item),
_("Remove Folder"),
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
return
folderPath = self._GetItemFolderPath(item)
self.GetDocument().GetCommandProcessor().Submit(ProjectRemoveFolderCommand(self, self.GetDocument(), folderPath))
def OnDeleteFile(self, event):
yesNoMsg = wx.MessageDialog(self.GetFrame(),
_("Delete cannot be reversed.\n\nRemove the selected files from the\nproject and file system permanently?"),
_("Delete File"),
wx.YES_NO|wx.ICON_QUESTION)
yesNoMsg.CenterOnParent()
status = yesNoMsg.ShowModal()
yesNoMsg.Destroy()
if status == wx.ID_NO:
return
items = self._treeCtrl.GetSelections()
delFiles = []
for item in items:
filePath = self._GetItemFilePath(item)
if filePath and filePath not in delFiles:
delFiles.append(filePath)
# remove selected files from project
self.GetDocument().RemoveFiles(delFiles)
# remove selected files from file system
for filePath in delFiles:
if os.path.exists(filePath):
try:
os.remove(filePath)
except:
wx.MessageBox("Could not delete '%s'. %s" % (os.path.basename(filePath), sys.exc_value),
_("Delete File"),
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
def OnDeleteProject(self, event=None, noPrompt=False, closeFiles=True, delFiles=True):
class DeleteProjectDialog(wx.Dialog):
def __init__(self, parent, doc):
wx.Dialog.__init__(self, parent, -1, _("Delete Project"), size = (310, 330))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(wx.StaticText(self, -1, _("Delete cannot be reversed.\nDeleted files are removed from the file system permanently.\n\nThe project file '%s' will be closed and deleted.") % os.path.basename(doc.GetFilename())), 0, wx.ALL, SPACE)
self._delFilesCtrl = wx.CheckBox(self, -1, _("Delete all files in project"))
self._delFilesCtrl.SetValue(True)
self._delFilesCtrl.SetToolTipString(_("Deletes files from disk, whether open or closed"))
sizer.Add(self._delFilesCtrl, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, SPACE)
self._closeDeletedCtrl = wx.CheckBox(self, -1, _("Close open files belonging to project"))
self._closeDeletedCtrl.SetValue(True)
self._closeDeletedCtrl.SetToolTipString(_("Closes open editors for files belonging to project"))
sizer.Add(self._closeDeletedCtrl, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, SPACE)
sizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_RIGHT|wx.RIGHT|wx.LEFT|wx.BOTTOM, SPACE)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
doc = self.GetDocument()
if not noPrompt:
dlg = DeleteProjectDialog(self.GetFrame(), doc)
dlg.CenterOnParent()
status = dlg.ShowModal()
delFiles = dlg._delFilesCtrl.GetValue()
closeFiles = dlg._closeDeletedCtrl.GetValue()
dlg.Destroy()
if status == wx.ID_CANCEL:
return
if closeFiles or delFiles:
filesInProject = doc.GetFiles()
filesInProject.append(self.GetDocument().GetDeploymentFilepath()) # remove deployment file also.
# don't remove self prematurely
filePath = doc.GetFilename()
if filePath in filesInProject:
filesInProject.remove(filePath)
# don't close/delete files outside of project's directory
homeDir = doc.GetModel().homeDir + os.sep
for filePath in filesInProject[:]:
fileDir = os.path.dirname(filePath) + os.sep
if not fileDir.startswith(homeDir):
filesInProject.remove(filePath)
if closeFiles:
# close any open views of documents in the project
openDocs = self.GetDocumentManager().GetDocuments()[:] # need copy or docs shift when closed
for d in openDocs:
if d.GetFilename() in filesInProject:
d.Modify(False) # make sure it doesn't ask to save the file
if isinstance(d.GetDocumentTemplate(), ProjectTemplate): # if project, remove from project list drop down
if self.GetDocumentManager().CloseDocument(d, True):
self.RemoveProjectUpdate(d)
else: # regular file
self.GetDocumentManager().CloseDocument(d, True)
# remove files in project from file system
if delFiles:
dirPaths = []
for filePath in filesInProject:
if os.path.isfile(filePath):
try:
dirPath = os.path.dirname(filePath)
if dirPath not in dirPaths:
dirPaths.append(dirPath)
os.remove(filePath)
except:
wx.MessageBox("Could not delete file '%s'.\n%s" % (filePath, sys.exc_value),
_("Delete Project"),
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
filePath = doc.GetFilename()
# close project
if doc:
doc.Modify(False) # make sure it doesn't ask to save the project
if self.GetDocumentManager().CloseDocument(doc, True):
self.RemoveCurrentDocumentUpdate()
# remove project file
if delFiles:
dirPath = os.path.dirname(filePath)
if dirPath not in dirPaths:
dirPaths.append(dirPath)
if os.path.isfile(filePath):
try:
os.remove(filePath)
except:
wx.MessageBox("Could not delete project file '%s'.\n%s" % (filePath, sys.exc_value),
_("Delete Prjoect"),
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
# remove empty directories from file system
if delFiles:
dirPaths.sort() # sorting puts parent directories ahead of child directories
dirPaths.reverse() # remove child directories first
for dirPath in dirPaths:
if os.path.isdir(dirPath):
files = os.listdir(dirPath)
if not files:
try:
os.rmdir(dirPath)
except:
wx.MessageBox("Could not delete empty directory '%s'.\n%s" % (dirPath, sys.exc_value),
_("Delete Project"),
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
def OnKeyPressed(self, event):
key = event.KeyCode()
if key == wx.WXK_DELETE:
self.OnClear(event)
else:
event.Skip()
def OnSelectAll(self, event):
project = self.GetDocument()
if project:
self.DoSelectAll(self._treeCtrl.GetRootItem())
def DoSelectAll(self, parentItem):
(child, cookie) = self._treeCtrl.GetFirstChild(parentItem)
while child.IsOk():
if self._IsItemFile(child):
self._treeCtrl.SelectItem(child)
else:
self.DoSelectAll(child)
(child, cookie) = self._treeCtrl.GetNextChild(parentItem, cookie)
def OnOpenSelectionSDI(self, event):
# Do a call after so that the second mouseclick on a doubleclick doesn't reselect the project window
wx.CallAfter(self.OnOpenSelection, None)
def OnOpenSelection(self, event):
doc = None
try:
items = self._treeCtrl.GetSelections()[:]
for item in items:
filepath = self._GetItemFilePath(item)
if filepath:
if not os.path.exists(filepath):
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("File Not Found")
yesNoMsg = wx.MessageDialog(self.GetFrame(),
_("The file '%s' was not found in '%s'.\n\nWould you like to browse for the file?") % (wx.lib.docview.FileNameFromPath(filepath), wx.lib.docview.PathOnly(filepath)),
msgTitle,
wx.YES_NO|wx.ICON_QUESTION
)
yesNoMsg.CenterOnParent()
status = yesNoMsg.ShowModal()
yesNoMsg.Destroy()
if status == wx.ID_NO:
continue
findFileDlg = wx.FileDialog(self.GetFrame(),
_("Choose a file"),
defaultFile=wx.lib.docview.FileNameFromPath(filepath),
style=wx.OPEN|wx.FILE_MUST_EXIST|wx.CHANGE_DIR
)
# findFileDlg.CenterOnParent() # wxBug: caused crash with wx.FileDialog
if findFileDlg.ShowModal() == wx.ID_OK:
newpath = findFileDlg.GetPath()
else:
newpath = None
findFileDlg.Destroy()
if newpath:
# update Project Model with new location
self.GetDocument().UpdateFilePath(filepath, newpath)
filepath = newpath
doc = self.GetDocumentManager().CreateDocument(filepath, wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE)
if not doc and filepath.endswith(PROJECT_EXTENSION): # project already open
self.SetProject(filepath)
elif doc:
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectService.AddProjectMapping(doc)
if hasattr(doc, "GetModel"):
projectService.AddProjectMapping(doc.GetModel())
except IOError, (code, message):
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("File Error")
wx.MessageBox("Could not open '%s'." % wx.lib.docview.FileNameFromPath(filepath),
msgTitle,
wx.OK | wx.ICON_EXCLAMATION,
self.GetFrame())
#----------------------------------------------------------------------------
# Convenience methods
#----------------------------------------------------------------------------
def _HasFiles(self):
if not self._treeCtrl:
return False
return self._treeCtrl.GetCount() > 1 # 1 item = root item, don't count as having files
def _HasFilesSelected(self):
if not self._treeCtrl:
return False
items = self._treeCtrl.GetSelections()
if not items:
return False
for item in items:
if self._IsItemFile(item):
return True
return False
def _HasFoldersSelected(self):
if not self._treeCtrl:
return False
items = self._treeCtrl.GetSelections()
if not items:
return False
for item in items:
if self._IsItemFile(item):
return False
return True
def _MakeProjectName(self, project):
return project.GetPrintableName()
def _GetItemFilePath(self, item):
file = self._GetItemFile(item)
if file:
return file.filePath
else:
return None
def _GetItemFolderPath(self, item):
rootItem = self._treeCtrl.GetRootItem()
if item == rootItem:
return ""
if self._IsItemFile(item):
item = self._treeCtrl.GetItemParent(item)
folderPath = ""
while item != rootItem:
if folderPath:
folderPath = self._treeCtrl.GetItemText(item) + "/" + folderPath
else:
folderPath = self._treeCtrl.GetItemText(item)
item = self._treeCtrl.GetItemParent(item)
return folderPath
def _GetItemFile(self, item):
return self._treeCtrl.GetPyData(item)
def _IsItemFile(self, item):
return self._GetItemFile(item) != None
def _IsItemProcessModelFile(self, item):
if ACTIVEGRID_BASE_IDE:
return False
if self._IsItemFile(item):
filepath = self._GetItemFilePath(item)
ext = None
for template in self.GetDocumentManager().GetTemplates():
if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
ext = template.GetDefaultExtension()
break;
if not ext:
return False
if filepath.endswith(ext):
return True
return False
def _GetChildItems(self, parentItem):
children = []
(child, cookie) = self._treeCtrl.GetFirstChild(parentItem)
while child.IsOk():
children.append(child)
(child, cookie) = self._treeCtrl.GetNextChild(parentItem, cookie)
return children
def _GetFolderItems(self, parentItem):
folderItems = []
childrenItems = self._GetChildItems(parentItem)
for childItem in childrenItems:
if not self._IsItemFile(childItem):
folderItems.append(childItem)
folderItems += self._GetFolderItems(childItem)
return folderItems
class ProjectFileDropTarget(wx.FileDropTarget):
def __init__(self, view):
wx.FileDropTarget.__init__(self)
self._view = view
def OnDropFiles(self, x, y, filePaths):
""" Do actual work of dropping files into project """
if self._view.GetDocument():
folderPath = None
if self._view.GetMode() == ProjectView.LOGICAL_MODE:
folderItem = self._view._treeCtrl.FindClosestFolder(x,y)
if folderItem:
folderPath = self._view._GetItemFolderPath(folderItem)
self._view.DoAddFilesToProject(filePaths, folderPath)
return True
return False
def OnDragOver(self, x, y, default):
""" Feedback to show copy cursor if copy is allowed """
if self._view.GetDocument(): # only allow drop if project exists
return wx.DragCopy
return wx.DragNone
class ProjectPropertiesDialog(wx.Dialog):
RELATIVE_TO_PROJECT_FILE = _("relative to project file")
def __init__(self, parent, document):
wx.Dialog.__init__(self, parent, -1, _("Project Properties"), size = (310, 330))
filePropertiesService = wx.GetApp().GetService(wx.lib.pydocview.FilePropertiesService)
notebook = wx.Notebook(self, -1)
tab = wx.Panel(notebook, -1)
gridSizer = wx.FlexGridSizer(cols = 2, vgap = SPACE, hgap = SPACE)
gridSizer.AddGrowableCol(1)
gridSizer.Add(wx.StaticText(tab, -1, _("Filename:")))
filename = document.GetFilename()
if os.path.isfile(filename):
gridSizer.Add(wx.StaticText(tab, -1, os.path.split(filename)[1]))
gridSizer.Add(wx.StaticText(tab, -1, _("Location:")))
gridSizer.Add(wx.StaticText(tab, -1, filePropertiesService.chopPath(os.path.dirname(filename), length=50)))
gridSizer.Add(wx.StaticText(tab, -1, _("Size:")))
gridSizer.Add(wx.StaticText(tab, -1, str(os.path.getsize(filename)) + ' ' + _("bytes")))
lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
lineSizer.Add(wx.StaticLine(tab, -1, size = (10,-1)), 0, wx.EXPAND)
gridSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.TOP)
lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
lineSizer.Add(wx.StaticLine(tab, -1, size = (10,-1)), 0, wx.EXPAND)
gridSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.TOP)
gridSizer.Add(wx.StaticText(tab, -1, _("Created:")))
gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getctime(filename))))
gridSizer.Add(wx.StaticText(tab, -1, _("Modified:")))
gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getmtime(filename))))
gridSizer.Add(wx.StaticText(tab, -1, _("Accessed:")))
gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getatime(filename))))
else:
gridSizer.Add(wx.StaticText(tab, -1, os.path.split(filename)[1] + ' ' + _("[new project]")))
spacerGrid = wx.BoxSizer(wx.HORIZONTAL) # add a border around the inside of the tab
spacerGrid.Add(gridSizer, 1, wx.ALL|wx.EXPAND, SPACE);
tab.SetSizer(spacerGrid)
notebook.AddPage(tab, _("General"))
tab = wx.Panel(notebook, -1)
spacerGrid = wx.BoxSizer(wx.VERTICAL) # add a border around the inside of the tab
homePathLabel = wx.StaticText(tab, -1, _("Home Dir:"))
if document.GetModel().isDefaultHomeDir:
defaultHomeDir = ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE
else:
defaultHomeDir = document.GetModel().homeDir
self._homeDirCtrl = wx.ComboBox(tab, -1, defaultHomeDir, size=(125,-1), choices=[ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE, document.GetModel().homeDir])
self._homeDirCtrl.SetToolTipString(self._homeDirCtrl.GetValue())
if not document.GetModel().isDefaultHomeDir:
self._homeDirCtrl.SetInsertionPointEnd()
def OnDirChanged(event):
self._homeDirCtrl.SetToolTip(wx.ToolTip(self._homeDirCtrl.GetValue())) # wx.Bug: SetToolTipString only sets it for the dropdown control, not for the text edit control, so need to replace it completely
wx.EVT_COMBOBOX(self._homeDirCtrl, -1, OnDirChanged)
wx.EVT_TEXT(self._homeDirCtrl, -1, OnDirChanged)
choosePathButton = wx.Button(tab, -1, _("Browse..."))
def OnBrowseButton(event):
if self._homeDirCtrl.GetValue() == ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE:
defaultHomeDir = document.GetModel().homeDir
else:
defaultHomeDir = self._homeDirCtrl.GetValue()
dlg = wx.DirDialog(self, "Choose a directory:", defaultHomeDir,
style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
if dlg.ShowModal() == wx.ID_OK:
self._homeDirCtrl.SetValue(dlg.GetPath())
self._homeDirCtrl.SetInsertionPointEnd()
self._homeDirCtrl.SetToolTip(wx.ToolTip(dlg.GetPath())) # wx.Bug: SetToolTipString only sets it for the dropdown control, not for the text edit control, so need to replace it completely
dlg.Destroy()
wx.EVT_BUTTON(choosePathButton, -1, OnBrowseButton)
pathSizer = wx.BoxSizer(wx.HORIZONTAL)
pathSizer.Add(homePathLabel, 0, wx.ALIGN_CENTER_VERTICAL)
pathSizer.Add(self._homeDirCtrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.LEFT, HALF_SPACE)
pathSizer.Add(choosePathButton, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, SPACE)
spacerGrid.Add(pathSizer, 0, wx.ALL|wx.EXPAND, SPACE);
instructionText = wx.StaticText(tab, -1, _("The physical view shows files relative to Home Dir.\nThe Home Dir default is the project file's directory.\nSetting the Home Dir overrides the default directory."))
spacerGrid.Add(instructionText, 0, wx.ALL, SPACE);
tab.SetSizer(spacerGrid)
notebook.AddPage(tab, _("Physical View"))
if not ACTIVEGRID_BASE_IDE:
tab = wx.Panel(notebook, -1)
self._appInfoCtrl = PropertyService.PropertyCtrl(tab, header=False)
self._appInfoCtrl.SetDocument(document)
self._appInfoCtrl.SetModel(document.GetAppInfo())
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self._appInfoCtrl, 1, wx.EXPAND)
tab.SetSizer(sizer)
notebook.AddPage(tab, _("App Info"))
if wx.Platform == "__WXMSW__":
notebook.SetPageSize((310,300))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(notebook, 0, wx.ALL | wx.EXPAND, SPACE)
sizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, HALF_SPACE)
self.SetSizer(sizer)
sizer.Fit(self)
self.Layout()
class ProjectOptionsPanel(wx.Panel):
def __init__(self, parent, id):
wx.Panel.__init__(self, parent, id)
self._useSashMessageShown = False
config = wx.ConfigBase_Get()
self._projSaveDocsCheckBox = wx.CheckBox(self, -1, _("Remember open projects"))
self._projSaveDocsCheckBox.SetValue(config.ReadInt("ProjectSaveDocs", True))
projectBorderSizer = wx.BoxSizer(wx.VERTICAL)
projectSizer = wx.BoxSizer(wx.VERTICAL)
projectSizer.Add(self._projSaveDocsCheckBox, 0, wx.ALL, HALF_SPACE)
if not ACTIVEGRID_BASE_IDE:
self._projShowWelcomeCheckBox = wx.CheckBox(self, -1, _("Show Welcome Dialog"))
self._projShowWelcomeCheckBox.SetValue(config.ReadInt("RunWelcomeDialog", True))
projectSizer.Add(self._projShowWelcomeCheckBox, 0, wx.ALL, HALF_SPACE)
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(wx.StaticText(self, -1, _("Default language for projects:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, HALF_SPACE)
self._langCtrl = wx.Choice(self, -1, choices=deploymentlib.LANGUAGE_LIST)
self._langCtrl.SetStringSelection(config.Read(APP_LAST_LANGUAGE, deploymentlib.LANGUAGE_DEFAULT))
self._langCtrl.SetToolTipString(_("Programming language to be used throughout the project."))
sizer.Add(self._langCtrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, MAC_RIGHT_BORDER)
projectSizer.Add(sizer, 0, wx.ALL, HALF_SPACE)
projectBorderSizer.Add(projectSizer, 0, wx.ALL, SPACE)
self.SetSizer(projectBorderSizer)
self.Layout()
parent.AddPage(self, _("Project"))
def OnUseSashSelect(self, event):
if not self._useSashMessageShown:
msgTitle = wx.GetApp().GetAppName()
if not msgTitle:
msgTitle = _("Document Options")
wx.MessageBox("Project window embedded mode changes will not appear until the application is restarted.",
msgTitle,
wx.OK | wx.ICON_INFORMATION,
self.GetParent())
self._useSashMessageShown = True
def OnOK(self, optionsDialog):
config = wx.ConfigBase_Get()
config.WriteInt("ProjectSaveDocs", self._projSaveDocsCheckBox.GetValue())
if not ACTIVEGRID_BASE_IDE:
config.WriteInt("RunWelcomeDialog", self._projShowWelcomeCheckBox.GetValue())
config.Write(APP_LAST_LANGUAGE, self._langCtrl.GetStringSelection())
def GetIcon(self):
return getProjectIcon()
class ProjectService(Service.Service):
#----------------------------------------------------------------------------
# Constants
#----------------------------------------------------------------------------
SHOW_WINDOW = wx.NewId() # keep this line for each subclass, need unique ID for each Service
RUN_SELECTED_PM_ID = wx.NewId()
RUN_CURRENT_PM_ID = wx.NewId()
RENAME_ID = wx.NewId()
OPEN_SELECTION_ID = wx.NewId()
REMOVE_FROM_PROJECT = wx.NewId()
DELETE_FILE_ID = wx.NewId()
ADD_FILES_TO_PROJECT_ID = wx.NewId()
ADD_CURRENT_FILE_TO_PROJECT_ID = wx.NewId()
ADD_DIR_FILES_TO_PROJECT_ID = wx.NewId()
CLOSE_PROJECT_ID = wx.NewId()
PROJECT_PROPERTIES_ID = wx.NewId()
ADD_FOLDER_ID = wx.NewId()
DELETE_PROJECT_ID = wx.NewId()
#----------------------------------------------------------------------------
# Overridden methods
#----------------------------------------------------------------------------
def __init__(self, serviceName, embeddedWindowLocation = wx.lib.pydocview.EMBEDDED_WINDOW_LEFT):
Service.Service.__init__(self, serviceName, embeddedWindowLocation)
self._runHandlers = []
self._suppressOpenProjectMessages = False
self._logicalViewDefaults = []
self._fileTypeDefaults = []
self._nameDefaults = []
self._mapToProject = dict()
def _CreateView(self):
return ProjectView(self)
def ShowWindow(self, show = True):
""" Force showing of saved projects on opening, otherwise empty Project Window is disconcerting for user """
Service.Service.ShowWindow(self, show)
if show:
project = self.GetView().GetDocument()
if not project:
self.OpenSavedProjects()
#----------------------------------------------------------------------------
# Service specific methods
#----------------------------------------------------------------------------
def GetSuppressOpenProjectMessages(self):
return self._suppressOpenProjectMessages
def SetSuppressOpenProjectMessages(self, suppressOpenProjectMessages):
self._suppressOpenProjectMessages = suppressOpenProjectMessages
def GetRunHandlers(self):
return self._runHandlers
def AddRunHandler(self, runHandler):
self._runHandlers.append(runHandler)
def RemoveRunHandler(self, runHandler):
self._runHandlers.remove(runHandler)
def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
Service.Service.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
projectMenu = wx.Menu()
## accelTable = wx.AcceleratorTable([
## eval(_("wx.ACCEL_CTRL, ord('R'), ProjectService.RUN_ID"))
## ])
## frame.SetAcceleratorTable(accelTable)
isProjectDocument = document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument
if wx.GetApp().IsMDI() or isProjectDocument:
if not menuBar.FindItemById(ProjectService.ADD_FILES_TO_PROJECT_ID):
projectMenu.Append(ProjectService.ADD_FILES_TO_PROJECT_ID, _("Add &Files to Project..."), _("Adds a document to the current project"))
wx.EVT_MENU(frame, ProjectService.ADD_FILES_TO_PROJECT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.ADD_FILES_TO_PROJECT_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.ADD_DIR_FILES_TO_PROJECT_ID):
projectMenu.Append(ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, _("Add Directory Files to Project..."), _("Adds a directory's documents to the current project"))
wx.EVT_MENU(frame, ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID):
projectMenu.Append(ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, _("&Add Active File to Project..."), _("Adds the active document to a project"))
wx.EVT_MENU(frame, ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.ADD_FOLDER_ID):
projectMenu.Append(ProjectService.ADD_FOLDER_ID, _("Add Folder to Project"), _("Adds a new folder"))
wx.EVT_MENU(frame, ProjectService.ADD_FOLDER_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.ADD_FOLDER_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.CLOSE_PROJECT_ID):
projectMenu.AppendSeparator()
projectMenu.Append(ProjectService.CLOSE_PROJECT_ID, _("Close Project"), _("Closes currently open project"))
wx.EVT_MENU(frame, ProjectService.CLOSE_PROJECT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.CLOSE_PROJECT_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.DELETE_PROJECT_ID):
projectMenu.Append(ProjectService.DELETE_PROJECT_ID, _("Delete Project..."), _("Delete currently open project and its files."))
wx.EVT_MENU(frame, ProjectService.DELETE_PROJECT_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.DELETE_PROJECT_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.PROJECT_PROPERTIES_ID):
projectMenu.AppendSeparator()
projectMenu.Append(ProjectService.PROJECT_PROPERTIES_ID, _("Project Properties"), _("Project Properties"))
wx.EVT_MENU(frame, ProjectService.PROJECT_PROPERTIES_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.PROJECT_PROPERTIES_ID, frame.ProcessUpdateUIEvent)
index = menuBar.FindMenu(_("&Format"))
if index == -1:
index = menuBar.FindMenu(_("&View"))
menuBar.Insert(index + 1, projectMenu, _("&Project"))
editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
if not menuBar.FindItemById(ProjectService.RENAME_ID):
editMenu.Append(ProjectService.RENAME_ID, _("&Rename"), _("Renames the active item"))
wx.EVT_MENU(frame, ProjectService.RENAME_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.RENAME_ID, frame.ProcessUpdateUIEvent)
if not menuBar.FindItemById(ProjectService.DELETE_FILE_ID):
editMenu.Append(ProjectService.DELETE_FILE_ID, _("Delete File"), _("Delete the file from the project and file system."))
wx.EVT_MENU(frame, ProjectService.DELETE_FILE_ID, frame.ProcessEvent)
wx.EVT_UPDATE_UI(frame, ProjectService.DELETE_FILE_ID, frame.ProcessUpdateUIEvent)
return True
def OnCloseFrame(self, event):
if not self.GetView():
return True
if wx.GetApp().IsMDI():
# close all non-project documents first
for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted
if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
if not self.GetDocumentManager().CloseDocument(document, False):
return False
# write project config afterwards because user may change filenames on closing of new documents
self.GetView().WriteProjectConfig() # Called onCloseWindow in all of the other services but needed to be factored out for ProjectService since it is called elsewhere
# close all project documents after closing other documents
# because user may save a new document with a new name or cancel closing a document
for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted
if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
if not document.OnSaveModified():
return False
# This is called when any SDI frame is closed, so need to check if message window is closing or some other window
elif self.GetView() == event.GetEventObject().GetView():
self.SetView(None)
return True
#----------------------------------------------------------------------------
# Document Manager Methods
#----------------------------------------------------------------------------
def FindProjectFromMapping(self, key):
""" Find which project a model or document belongs to """
return self._mapToProject.get(key)
def AddProjectMapping(self, key, projectDoc=None):
""" Generate a mapping from model or document to project. If no project given, use current project.
e.g. Which project does this model or document belong to (when it was opened)?
"""
if not projectDoc:
projectDoc = self.GetCurrentProject()
self._mapToProject[key] = projectDoc
#----------------------------------------------------------------------------
# Default Logical View Folder Methods
#----------------------------------------------------------------------------
def AddLogicalViewFolderDefault(self, pattern, folder):
self._logicalViewDefaults.append((pattern, folder))
def FindLogicalViewFolderDefault(self, filename):
for (pattern, folder) in self._logicalViewDefaults:
if filename.endswith(pattern):
return folder
return None
#----------------------------------------------------------------------------
# Default File Type Methods
#----------------------------------------------------------------------------
def AddFileTypeDefault(self, pattern, type):
self._fileTypeDefaults.append((pattern, type))
def FindFileTypeDefault(self, filename):
for (pattern, type) in self._fileTypeDefaults:
if filename.endswith(pattern):
return type
return None
#----------------------------------------------------------------------------
# Default Name Methods
#----------------------------------------------------------------------------
def AddNameDefault(self, pattern, method):
self._nameDefaults.append((pattern, method))
def FindNameDefault(self, filename):
for (pattern, method) in self._nameDefaults:
if filename.endswith(pattern):
return method(filename)
return None
def GetDefaultNameCallback(self, filename):
""" A method for generating name from filepath for Project Service """
return os.path.splitext(os.path.basename(filename))[0]
#----------------------------------------------------------------------------
# Event Processing Methods
#----------------------------------------------------------------------------
def ProcessEventBeforeWindows(self, event):
id = event.GetId()
if id == wx.ID_CLOSE_ALL:
self.OnFileCloseAll(event)
return True
return False
def ProcessUpdateUIEventBeforeWindows(self, event):
id = event.GetId()
if id == wx.ID_CLOSE_ALL:
for document in self.GetDocumentManager().GetDocuments():
if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
event.Enable(True)
return True
event.Enable(False)
return True
elif id == wx.ID_CLOSE:
# "File | Close" is too confusing and hard to determine whether user wants to close a viewed file or the current project.
# Disallow "File | Close" if project is current document or active in project view.
# User must explicitly close project via "Project | Close Current Project".
document = self.GetDocumentManager().GetCurrentDocument()
if document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
event.Enable(False)
return True
if self.GetView().ProcessUpdateUIEvent(event):
return True
return False
def ProcessEvent(self, event):
if Service.Service.ProcessEvent(self, event):
return True
id = event.GetId()
if id == ProjectService.RUN_SELECTED_PM_ID:
self.OnRunProcessModel(event, runSelected=True)
return True
elif id == ProjectService.RUN_CURRENT_PM_ID:
self.OnRunProcessModel(event, runCurrentFile=True)
return True
elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
self.OnAddCurrentFileToProject(event)
return True
elif (id == ProjectService.PROJECT_PROPERTIES_ID
or id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID
or id == ProjectService.ADD_FOLDER_ID
or id == ProjectService.DELETE_PROJECT_ID
or id == ProjectService.CLOSE_PROJECT_ID):
if self.GetView():
return self.GetView().ProcessEvent(event)
else:
return False
else:
return False
def ProcessUpdateUIEvent(self, event):
if Service.Service.ProcessUpdateUIEvent(self, event):
return True
id = event.GetId()
if (id == ProjectService.RUN_SELECTED_PM_ID
or id == ProjectService.RUN_CURRENT_PM_ID):
event.Enable(True)
return True
elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
event.Enable(self._CanAddCurrentFileToProject())
return True
elif (id == ProjectService.ADD_FILES_TO_PROJECT_ID
or id == ProjectService.ADD_DIR_FILES_TO_PROJECT_ID
or id == ProjectService.RENAME_ID
or id == ProjectService.OPEN_SELECTION_ID
or id == ProjectService.DELETE_FILE_ID):
event.Enable(False)
return True
elif id == ProjectService.PROJECT_PROPERTIES_ID:
event.Enable(self._HasOpenedProjects())
return True
elif (id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID
or id == ProjectService.ADD_FOLDER_ID
or id == ProjectService.DELETE_PROJECT_ID
or id == ProjectService.CLOSE_PROJECT_ID):
if self.GetView():
return self.GetView().ProcessUpdateUIEvent(event)
else:
return False
else:
return False
def OnRunProcessModel(self, event, runSelected=False, runCurrentFile=False):
project = self.GetCurrentProject()
if runCurrentFile:
doc = self.GetDocumentManager().GetCurrentDocument()
if not doc or not hasattr(doc, "GetFilename"):
return
fileToRun = doc.GetFilename()
projects = self.FindProjectByFile(fileToRun)
if not projects:
return
elif project in projects:
# use current project
pass
elif len(projects) == 1:
# only one project, display it
project = projects[0]
self.GetView().SetProject(project.GetFilename())
elif len(projects) > 1:
strings = map(lambda file: os.path.basename(file.GetFilename()), projects)
res = wx.GetSingleChoiceIndex(_("More than one project uses '%s'. Select project to run:") % os.path.basename(fileToRun),
_("Select Project"),
strings,
self.GetView()._GetParentFrame())
if res == -1:
return
project = projects[res]
self.GetView().SetProject(project.GetFilename())
if project:
ext = None
for template in self.GetDocumentManager().GetTemplates():
if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
ext = template.GetDefaultExtension()
break;
if not ext:
return
files = filter(lambda f: f.endswith(ext), project.GetFiles())
if not files:
return
docs = wx.GetApp().GetDocumentManager().GetDocuments()
filesModified = False
for doc in docs:
if doc.IsModified():
filesModified = True
break
if filesModified:
frame = self.GetView().GetFrame()
yesNoMsg = wx.MessageDialog(frame,
_("Files have been modified. Process may not reflect your current changes.\n\nWould you like to save all files before running?"),
_("Run Process"),
wx.YES_NO|wx.ICON_QUESTION
)
yesNoMsg.CenterOnParent()
status = yesNoMsg.ShowModal()
yesNoMsg.Destroy()
if status == wx.ID_YES:
wx.GetTopLevelParent(frame).OnFileSaveAll(None)
if runCurrentFile:
fileToRun = self.GetDocumentManager().GetCurrentDocument().GetFilename()
elif runSelected:
fileToRun = self.GetView().GetSelectedFile()
elif len(files) > 1:
files.sort(lambda a, b: cmp(os.path.basename(a).lower(), os.path.basename(b).lower()))
strings = map(lambda file: os.path.basename(file), files)
res = wx.GetSingleChoiceIndex(_("Select a process to run:"),
_("Run"),
strings,
self.GetView()._GetParentFrame())
if res == -1:
return
fileToRun = files[res]
else:
fileToRun = files[0]
deployFilePath = project.GenerateDeployment()
self.RunProcessModel(fileToRun, project.GetAppInfo().language, deployFilePath)
def RunProcessModel(self, fileToRun, language, deployFilePath):
for runHandler in self.GetRunHandlers():
if runHandler.RunProjectFile(fileToRun, language, deployFilePath):
return
os.system('"' + fileToRun + '"')
def _HasProcessModel(self):
project = self.GetView().GetDocument()
if project:
ext = None
for template in self.GetDocumentManager().GetTemplates():
if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
ext = template.GetDefaultExtension()
break;
if not ext:
return False
files = filter(lambda f: f.endswith(ext), project.GetFiles())
if not files:
return False
if len(files):
return True
return False
def _HasOpenedProjects(self):
for document in self.GetDocumentManager().GetDocuments():
if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
return True
return False
def _CanAddCurrentFileToProject(self):
currentDoc = self.GetDocumentManager().GetCurrentDocument()
if not currentDoc:
return False
if currentDoc.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
return False
if not currentDoc._savedYet:
return False
if self.GetView().GetDocument(): # a project is open
return True
return False # There are no documents open
def GetFilesFromCurrentProject(self):
view = self.GetView()
if view:
project = view.GetDocument()
if project:
return project.GetFiles()
return None
def GetCurrentProject(self):
view = self.GetView()
if view:
return view.GetDocument()
return None
def GetOpenProjects(self):
retval = []
for document in self.GetDocumentManager().GetDocuments():
if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
retval.append(document)
return retval
def FindProjectByFile(self, filename):
retval = []
for document in self.GetDocumentManager().GetDocuments():
if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
if document.GetFilename() == filename:
retval.append(document)
elif document.IsFileInProject(filename):
retval.append(document)
return retval
def OnAddCurrentFileToProject(self, event):
file = self.GetDocumentManager().GetCurrentDocument().GetFilename()
document = self.GetView().GetDocument()
document.GetCommandProcessor().Submit(ProjectAddFilesCommand(document, [file]))
self.GetView().Activate() # after add, should put focus on project editor
def OnFileCloseAll(self, event):
for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted
if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
if not self.GetDocumentManager().CloseDocument(document, False):
return
# document.DeleteAllViews() # Implicitly delete the document when the last view is removed
def OpenSavedProjects(self):
config = wx.ConfigBase_Get()
openedDocs = False
if config.ReadInt("ProjectSaveDocs", True):
docString = config.Read("ProjectSavedDocs")
if docString:
doc = None
docList = eval(docString)
for fileName in docList:
if isinstance(fileName, types.StringTypes):
if os.path.exists(fileName):
doc = self.GetDocumentManager().CreateDocument(fileName, wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE)
if doc:
openedDocs = True
currProject = config.Read("ProjectCurrent")
if currProject in docList:
self.GetView().SetProject(currProject)
return openedDocs
#----------------------------------------------------------------------------
# Icon Bitmaps - generated by encode_bitmaps.py
#----------------------------------------------------------------------------
from wx import ImageFromStream, BitmapFromImage
import cStringIO
def getProjectData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\x89IDAT8\x8d\xa5\x92\xcdJ\x02Q\x18\x86\x9fq&-+H\xd40\x033Bha\x05\
\xfd\xac*[\xb7l\xd1\xae\xfbhQ7\x10\x04A]\x86\xd0&\xba\x01CW\n!B\xa2\x882\x8b\
)R+"\x7fft\x9a\x16\x91\xcd4\xd3\x0f\xf4\xee\xce\xf9\xde\xf7\xe1\xfd\x0eG\x10\
\\"\x9arb\xe8\xcf\x1a\x9d\x9e\n\x80\xd6\xad\x03\x10Z;\x13\xf8ER\xa7xd\x88\
\xbe-D\x1f\xb8\xbf\x0c\xaf\xcf\x15C\xd2k\xf4\xc5(\x92^\x03 \xbe\x9b\xb3@\x85\
n\xe9\xd8h\xde\xe6\x1d\xe9\xfe\xa9E\xc7\xfb\x91\xf9\xfd\x01D\xfa\xc9\xd8\xf7\
\xcdPI\'\x01X\xd8>@p\xf7\x00($W\x8c\x8f&R\xa7\xa7\xa2u\xebL.\xef\xd9\x00\x97\
\xa7\x87D\\er\x15\x95\xb9\xf5\x12\xa3\x81Y\x9bG\xfax0\xb3Z\x8d*\x95t\x92z\
\xb5\x80yjhC\x83\x16\x96\x15\xdc\xc3AZ\x8d\xea{XN#g.,\xa6\xe0l\x9c\xde}\x89\
\xb6\xc3\x9aR\xff\xe5\x01\x801}\x1c\x80\x9b\xcc\x05\xde\xb0\x9f\xd0t\x04oX\
\xa6\xad4\xc9U\n\xc0&\x1e\xfd\xd6\x0e\x18\xd4Se\x00\xbca?m\xa5\xc9\x1d\xd0V\
\x9a\x03\xa3\xd6\xadc\xa8\x8fv\xc0S\xa3H\xc8\x13\x01\xa2\x00\xc4V\x13\x94\
\xb3)\xae\xae\x14\x8b\xd1\x17\x90laK\x03\xb3b\xab\t&\x02\xf7(\xf94\xf2k\x8c\
\x8d\x8dy\xc7\xf0\xb7\x00\x80`t\x92`t\x87%\xa0\x9cM\xd1\xa8}\xce\xcc\xbf\xd1\
\x11P\xce\xa6,\xe7\xaf\xdf\xd7,Ap\x89\x14\x92+\xc6_\x03\x8e\x80\xff\xc8\xf5\
\xaf4\xf0\x06=\xf3\x8fJr]C\xd9\x00\x00\x00\x00IEND\xaeB`\x82'
def getProjectBitmap():
return BitmapFromImage(getProjectImage())
def getProjectImage():
stream = cStringIO.StringIO(getProjectData())
return ImageFromStream(stream)
def getProjectIcon():
return wx.IconFromBitmap(getProjectBitmap())
#----------------------------------------------------------------------------
def getBlankData():
return \
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\x04IDAT8\x8d\xa5\x93\xbdj\x02A\x10\xc7\x7f{gme\xe5c\xe4\t\x82\x85\
\x85\x85oa\xe5+\xd8Z\xd8'e\xfa\x80\xd8\xd8X\x19R\xc4\x07\x90\x04\xd1J\x08\
\x17\x0cr\\V\xe1\xe4\xfc\x80\xb58\xf7\xd8\xbd\x0f\xa280\xec\xec2\xbf\xff\xce\
\xcc\xb2B8.\xf7X\xc9\xdc|L\x97J\xc7\xbe\x0c\x01\xf0\xd6\x01\x00RFtZu\x91Q\
\x10\x8e\x9b\xf8\xe4\xf3[-w*\xf1\xafm\xec\xcf\x83\x89\x1a\xad\x94\xea\xbe\
\x8c\x95\x99/\x1c\x17\xe7\xdaR\xcb%xh\xd4hw_\x95yn\xb5\xe0\xcb\x90\xea%\x0eO\
\xf1\xba\xd9\xc7\xe5\xbf\x0f\xdfX]\xda)\x140A\r\x03<6klO\xf0w\x84~\xef\xc9\
\xca/lA\xc3@\x02\xe7\x99U\x81\xb7\x0e\xa8\xec\xed\x04\x13\xde\x1c\xfe\x11\
\x902\xb2@\xc8\xc2\x8b\xd9\xbcX\xc0\x045\xac\xc1 Jg\xe6\x08\xe8)\xa7o\xd5\
\xb0\xbf\xcb\nd\x86x\x0b\x9c+p\x0b\x0c\xa9\x16~\xbc_\xeb\x9d\xd3\x03\xcb3q\
\xefo\xbc\xfa/\x14\xd9\x19\x1f\xfb\x8aa\x87\xf2\xf7\x16\x00\x00\x00\x00IEND\
\xaeB`\x82"
def getBlankBitmap():
return BitmapFromImage(getBlankImage())
def getBlankImage():
stream = cStringIO.StringIO(getBlankData())
return ImageFromStream(stream)
def getBlankIcon():
return wx.IconFromBitmap(getBlankBitmap())
#----------------------------------------------------------------------
def getFolderClosedData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x00\xffIDAT8\x8d\xa5\x93?N\x02A\x14\x87\xbf\x19&\x10B\xb4A\x0b*iL0!$\
\x06\x0f\xe0\x05lH\x88G\xe1\x0c\xdbx\x11ZN`,\xa5\x01\x8aM\xa4\x80\x84\xc4Fc\
\xd0\xe8\xb0\xae\xbbc\x01\x0b,\x19\x16X~\xd5\x9b\xf7\xe7\x9by3o\x84\x90\x19\
\x8e\x91\x8a\x0c\xed:\x06\xc0\xf7g\x00x\xde\x14\x80\xf3\x9b\x07\xb1\x13\xa0]\
\xc7d\xcbw\x00d\x17\x81\x82\xff\x01\xc0\xb0\xd3\x9f\x83\x7f\xf5\xb2\xe8\xaa\
\xf1\xb4\x84\n!3h\xd71\xef\xaf=\xeb\x0e\xc5R\xcd\xea\xcfWZ"\xd6\xc2\xb6\xc4\
\xdc\xe5\xad\xd5?h\xd7M\xb5\xd9\x15\n\xe6}{\xde\x94\xe2\xf5\xbd59I\x12V\x17\
\x96F\n \xfc\xfbD\xaaS\xc2\x9fI:@\x041\xdf\xa3\x8d\xb0Y\xb3\xed\xaf\xa9\x00\
\xbe\xde\xc6\x9c\x9c]\x10\xea\xc3O #\xc3\xd7:)/\x19\xb0>$\x87J\x01\x04\xc1n\
\xc0\xcb\xf3cl]mv\xe3\x83\xb4o\xc1\xa6D\xf4\x1b\x07\xed\xba\xd9\xa7`+ \xad\
\xfe\x01\xd1\x03SV!\xfbHa\x00\x00\x00\x00IEND\xaeB`\x82'
def getFolderClosedBitmap():
return BitmapFromImage(getFolderClosedImage())
def getFolderClosedImage():
stream = cStringIO.StringIO(getFolderClosedData())
return ImageFromStream(stream)
def getFolderClosedIcon():
return wx.IconFromBitmap(getFolderClosedBitmap())
#----------------------------------------------------------------------
def getFolderOpenData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01>IDAT8\x8d\xa5\x93\xbdJ\x03A\x14\x85\xbfY\x03i\xac\x14\x92\xc2F\xad$\
Z\xa4\x10\x11|\x01\xc1J\xdbt\xbe\x86\x9d\x85\x0f\xa0\xe0\x1b\x04,l\xc4J\x0b\
\x0bA;a\x11\x13\xb1H\xc2\xc2\xca\x84@\x88n\xb2\xd9?\xcd\xd8d6.\x9b\x104\xa7\
\xbas\xef=g\xce\x9d\xe1\na\xcc1\x0b\x8c\x99\xd8@F\x07_\xd6\xb9\n\xdd\x8f\xb8\
\xd0s\x9a\x00\xe4\xb6O\xc5T\x81~\xf5D\x89\xdc\x0e\xd9_\x85,\xa0\xa2\x06\xefw\
R\x01\x04\x9e\x03\xc0\xea\xde\x8dH\th\xa8\xa81:\xf8\x1e\x00\xf9\x8d\x03\x00\
\xa4U\x07\xc0,\xdb\xaaX\xaa\xc4"\x99\x04\xd9\xf7\xe0\xfbs$\x12\x0e\x90\xad\
\x0e\x00]\xeb*N\x9b\xe5u\x05P,UD\xc2\x81&K\xbb\r@\xd4\xba\x1f\x9a\xe9\xb0\
\xb6\x7f\x96h}\xbe8\x1c9\xe89M\x16\xfc\x15\xa4\xdd\xc6\xe8\x9a\x18\xc3\x99\
\x97w\x8f\x99\x86\xd8\x81\xb4\xea\x18]\x93\xfcf).\x0e\\9\x96\xf4r}\x84~\x87\
\xc4\x08\x81\xe7\xa0\xfa\xb5\xa9\xb7\xa6\x1c\xf4\xdao\xcc/B\x04\x0c<\xfb\xef\
\x02Zd\xa9P\x98\xd8\xf8\xfax\x1b\xc7\xa9o\xf4\xbdN\x8aP{z \x0c\xdc\xb1\xa4\
\xdf\x10z\x99\xaa\x97[J\'\xc3\xc0\x9dH\x98(\xf0_\xcc\xbc\x8d?\xf2)\x7f\x8e|f\
\xe54\x00\x00\x00\x00IEND\xaeB`\x82'
def getFolderOpenBitmap():
return BitmapFromImage(getFolderOpenImage())
def getFolderOpenImage():
stream = cStringIO.StringIO(getFolderOpenData())
return ImageFromStream(stream)
def getFolderOpenIcon():
return wx.IconFromBitmap(getFolderOpenBitmap())
#----------------------------------------------------------------------
def getLogicalModeOnData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\x83IDAT8\x8d\xa5\x93\xcbJ\xc3@\x14\x86\xbfI\x83buS\xabE+TE\x04\x17\
\xde\xf0\x02\x82\xa0k\x17\n.\xdc\xf9\x1e.\xf4\x05\\\t\xfa\x18\x057\xe2\x0b\
\x08ue@\xa4`\xb0\x84J\xd0(M\xa3"\xb65\x8d5.jcbS\x14\xfdW3\xe7\xfc\xe7\x9b9\
\xc3\x19!\xa4\x08\xff\x91\xdcXT\x8d=\xb7\xf6\\\xa5\xe2\xd8\xf5\xfd\xab\t@\
\xdf\xfc\x81\xf8\x11PQw\xddHl\x99H\x0c\xda\xbe\x19\xce\x0f\r\x17@\xae]{\xb1\
\xf1\r\xc5\x83\n!E\xa8\xa8\xbb\xaeuw\x11zB\xbc\x7f24\xde1\xb6%\x02-\xb42\xbe\
\xc5\x06\xd12i\x00&V\xb6\x11m\x0e\x00\xd9\xf4\xac;\xbe\xa1\x88z\x0b\x8eM\xf5\
\xd5$1\xb3\xd9\x048\xde\xdf!%\xe5P4\x9b\x91\xc5+:{\x86\x03y\x19\xbe\x1e\xcc\
\xafR1\x8f\x96Ic\xe6\xb34g\xbf\x01\xfcE\x00%=\x83~z\xd4dv\nW\x94\xc2\x00o/\
\x0f\xc8]\xdd\xb4\xd7\xee\x00\xb8<="\x9a\x8c\xd37\x90"\x9a\xd4Qo\xba1\xf3Y\
\x00\xcf\x13z\x03\xd7\xd6\x01\x88&\xe3\x00\xdc\xdf\xea\x94\r\x8b\x94da~\xb6\
\xea\xda\x8f\x01\x80\x04\xf0TT\x91\x9d\x1b/8:\xb7D\xd9\xb0(\x1b\x16\x8af\xa3\
h\xf5\xe1\x8a\xf5\x04\xcek\xbe\x81_Sk\xeb\x98\xd7\x05\xf4\xf7\x02\x00\x0b\
\xd3\x89P_K\x00@\xefP\x82\xd5\xa1za\xee\xec\x84\xa7\xa2\xea\xe5\x1a\xd3\xd8\
\x12\x90;;\t\xec\xfd\xe3\xeb\x97h\xfc\xc6lz\xd6\xfdMAK\xc0_\xf5\x01\xf4\x01\
\x91\xdc\xfe\x86\x9e^\x00\x00\x00\x00IEND\xaeB`\x82'
def getLogicalModeOnBitmap():
return BitmapFromImage(getLogicalModeOnImage())
def getLogicalModeOnImage():
stream = cStringIO.StringIO(getLogicalModeOnData())
return ImageFromStream(stream)
#----------------------------------------------------------------------
def getLogicalModeOffData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\x83IDAT8\x8d\xa5\x93\xcbJ\xc3@\x14\x86\xbfI\x83buS\xabE+TE\x04\x17\
\xde\xf0\x02\x82\xa0k\x17\n.\xdc\xf9\x1e.\xf4\x05\\\t\xfa\x18\x057\xe2\x0b\
\x08ue@\xa4`\xb0\x84J\xd0(M\xa3"\xb65\x8d5.jcbS\x14\xfdW3\xe7\xfc\xe7\x9b9\
\xc3\x19!\xa4\x08\xff\x91\xdcXT\x8d=\xb7\xf6\\\xa5\xe2\xd8\xf5\xfd\xab\t@\
\xdf\xfc\x81\xf8\x11PQw\xddHl\x99H\x0c\xda\xbe\x19\xce\x0f\r\x17@\xae]{\xb1\
\xf1\r\xc5\x83\n!E\xa8\xa8\xbb\xaeuw\x11zB\xbc\x7f24\xde1\xb6%\x02-\xb42\xbe\
\xc5\x06\xd12i\x00&V\xb6\x11m\x0e\x00\xd9\xf4\xac;\xbe\xa1\x88z\x0b\x8eM\xf5\
\xd5$1\xb3\xd9\x048\xde\xdf!%\xe5P4\x9b\x91\xc5+:{\x86\x03y\x19\xbe\x1e\xcc\
\xafR1\x8f\x96Ic\xe6\xb34g\xbf\x01\xfcE\x00%=\x83~z\xd4dv\nW\x94\xc2\x00o/\
\x0f\xc8]\xdd\xb4\xd7\xee\x00\xb8<="\x9a\x8c\xd37\x90"\x9a\xd4Qo\xba1\xf3Y\
\x00\xcf\x13z\x03\xd7\xd6\x01\x88&\xe3\x00\xdc\xdf\xea\x94\r\x8b\x94da~\xb6\
\xea\xda\x8f\x01\x80\x04\xf0TT\x91\x9d\x1b/8:\xb7D\xd9\xb0(\x1b\x16\x8af\xa3\
h\xf5\xe1\x8a\xf5\x04\xcek\xbe\x81_Sk\xeb\x98\xd7\x05\xf4\xf7\x02\x00\x0b\
\xd3\x89P_K\x00@\xefP\x82\xd5\xa1za\xee\xec\x84\xa7\xa2\xea\xe5\x1a\xd3\xd8\
\x12\x90;;\t\xec\xfd\xe3\xeb\x97h\xfc\xc6lz\xd6\xfdMAK\xc0_\xf5\x01\xf4\x01\
\x91\xdc\xfe\x86\x9e^\x00\x00\x00\x00IEND\xaeB`\x82'
def getLogicalModeOffBitmap():
return BitmapFromImage(getLogicalModeOffImage())
def getLogicalModeOffImage():
stream = cStringIO.StringIO(getLogicalModeOffData())
return ImageFromStream(stream)
#----------------------------------------------------------------------
def getPhysicalModeOnData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\xabIDAT8\x8d}\x931k\xdb@\x18\x86\x9f\xb3=\x98R\xb0\x06\xc7X\x01\x1d\
\x14\x1c\xeaA4?\xa0\xa1\x8b\x9d\x04C\xe6N\xed\xd8\xad\xbf\xc0\xbf!c\xb6@\x9d\
\xa1\xf4\'\xd4m\xd2l\x9dJ(\xb8R\x87\x90\x84\x80\xaeD\x8e\xad\xc1\xeePBIQ\x87\
\x8b.:+\xc9\x0b\x82\xef\xee\xd3\xf3\xde{\x1f\x9c\x10\xa52\xf7)\x99N\xd2q\x1c\
[{\xfe\xb3U\x91_\x8bE\x83E\xa8\xe9\xba\xa6\x1e\xc71*Rx\xd2\xa3\xe9\xba\xd4\
\x97\x1a\xa2\x92L\'i\xd6\xbc\x0bZ\xecy\xd2CE\n\x15)\x00*Y\xf3!hQ\x9e\xf4\xf8\
vt\xa4\r\xf2\xf0}\x90L|\xae\x93\xdb\xf5E;4uEE\xca\x184]\xd72\x91\x89\x0f\xc0\
\xe3\xf6\xaee\xf8\xe7\x83\xcf\x06\x00e\xc4`o/\r\x83\x80\x96\xf4x\xf9\xea\xb5\
I"\x13\xbf\x00ZJF\\\xec\xef >}\x1c\xa6\x00\x07\x87_hI\x8f\x17\x9d.*R<\x7f\
\xd43\xffZF7\xa0\xb9\xc2\xf9\xc91OV\x9e\xb2\xde\xe9Z\x07\\\'\xe0\xacip\xf6\
\xf5\xcdm\xfc\x08\x967\xde\xeaY\xec\xef\xe8!\x9e\x9f\x1c\x03\xf0[\xfe\x85\
\xa8\x98\xd6Y\xdb\x85d\xa4\xeb60>\x03\xe0\xe7!\x94N#E\xb5\xe6P\xad9\x06\x88\
\'\x97\x85\xfb\xea\xe1\x9c\x198Si\xbd\xd3%\x0c\x02\xae\xe63\x1a\xf3\x86\x15\
\xd5\x82\xf3\x9a^\xea\x0f(\xf5\xb6\xb6D\xbf\xdf\xa7Zs\x08\x83\x00\x80\xab\
\xf9\xac\x08g\'O\xedt\x15\x80\xfaRC\x00\x84?F\xe9\xbb\xc1\x80\x96\xf4t\xb7\
\xbezw\x82\x9c\n\x8f)\xaf_\xdb\xffR\xb8\x99z.\xc1\xc1\xfb\xef\x00l\x0e\xcb\
\xe2A\x83L\x9f{\xda(\xd3\xe6\xb0l\x9e\xf4\x7f\x85\x1d\xb2s\xbf\x8c\xaeh\x00\
\x00\x00\x00IEND\xaeB`\x82'
def getPhysicalModeOnBitmap():
return BitmapFromImage(getPhysicalModeOnImage())
def getPhysicalModeOnImage():
stream = cStringIO.StringIO(getPhysicalModeOnData())
return ImageFromStream(stream)
#----------------------------------------------------------------------
def getPhysicalModeOffData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x01\xabIDAT8\x8d}\x931k\xdb@\x18\x86\x9f\xb3=\x98R\xb0\x06\xc7X\x01\x1d\
\x14\x1c\xeaA4?\xa0\xa1\x8b\x9d\x04C\xe6N\xed\xd8\xad\xbf\xc0\xbf!c\xb6@\x9d\
\xa1\xf4\'\xd4m\xd2l\x9dJ(\xb8R\x87\x90\x84\x80\xaeD\x8e\xad\xc1\xeePBIQ\x87\
\x8b.:+\xc9\x0b\x82\xef\xee\xd3\xf3\xde{\x1f\x9c\x10\xa52\xf7)\x99N\xd2q\x1c\
[{\xfe\xb3U\x91_\x8bE\x83E\xa8\xe9\xba\xa6\x1e\xc71*Rx\xd2\xa3\xe9\xba\xd4\
\x97\x1a\xa2\x92L\'i\xd6\xbc\x0bZ\xecy\xd2CE\n\x15)\x00*Y\xf3!hQ\x9e\xf4\xf8\
vt\xa4\r\xf2\xf0}\x90L|\xae\x93\xdb\xf5E;4uEE\xca\x184]\xd72\x91\x89\x0f\xc0\
\xe3\xf6\xaee\xf8\xe7\x83\xcf\x06\x00e\xc4`o/\r\x83\x80\x96\xf4x\xf9\xea\xb5\
I"\x13\xbf\x00ZJF\\\xec\xef >}\x1c\xa6\x00\x07\x87_hI\x8f\x17\x9d.*R<\x7f\
\xd43\xffZF7\xa0\xb9\xc2\xf9\xc91OV\x9e\xb2\xde\xe9Z\x07\\\'\xe0\xacip\xf6\
\xf5\xcdm\xfc\x08\x967\xde\xeaY\xec\xef\xe8!\x9e\x9f\x1c\x03\xf0[\xfe\x85\
\xa8\x98\xd6Y\xdb\x85d\xa4\xeb60>\x03\xe0\xe7!\x94N#E\xb5\xe6P\xad9\x06\x88\
\'\x97\x85\xfb\xea\xe1\x9c\x198Si\xbd\xd3%\x0c\x02\xae\xe63\x1a\xf3\x86\x15\
\xd5\x82\xf3\x9a^\xea\x0f(\xf5\xb6\xb6D\xbf\xdf\xa7Zs\x08\x83\x00\x80\xab\
\xf9\xac\x08g\'O\xedt\x15\x80\xfaRC\x00\x84?F\xe9\xbb\xc1\x80\x96\xf4t\xb7\
\xbezw\x82\x9c\n\x8f)\xaf_\xdb\xffR\xb8\x99z.\xc1\xc1\xfb\xef\x00l\x0e\xcb\
\xe2A\x83L\x9f{\xda(\xd3\xe6\xb0l\x9e\xf4\x7f\x85\x1d\xb2s\xbf\x8c\xaeh\x00\
\x00\x00\x00IEND\xaeB`\x82'
def getPhysicalModeOffBitmap():
return BitmapFromImage(getPhysicalModeOffImage())
def getPhysicalModeOffImage():
stream = cStringIO.StringIO(getPhysicalModeOffData())
return ImageFromStream(stream)