Files
wxWidgets/wxPython/samples/ide/activegrid/tool/ProjectEditor.py
Robin Dunn 2fd34892c1 Don't use the old wxPython namespace
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41610 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2006-10-03 21:31:28 +00:00

4188 lines
173 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-2006 ActiveGrid, Inc.
# License: wxWindows License
#----------------------------------------------------------------------------
import wx
import wx.lib.docview
import wx.lib.pydocview
import wx.lib.buttons
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 activegrid.util.aglogging as aglogging
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 DeploymentGeneration
import WsdlAgEditor
import WsdlAgModel
APP_LAST_LANGUAGE = "LastLanguage"
import activegrid.model.basedocmgr as basedocmgr
import activegrid.model.basemodel as basemodel
import activegrid.model.projectmodel as projectmodel
import PropertyService
from activegrid.server.toolsupport import GetTemplate
import activegrid.util.xmlutils as xmlutils
import activegrid.util.sysutils as sysutils
DataServiceExistenceException = DeploymentGeneration.DataServiceExistenceException
import WebBrowserService
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"
if not ACTIVEGRID_BASE_IDE:
PRE_17_TMP_DPL_NAME = "RunTime_tmp" + deploymentlib.DEPLOYMENT_EXTENSION
_17_TMP_DPL_NAME = ".tmp" + deploymentlib.DEPLOYMENT_EXTENSION
# 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.getSystemDir()
#----------------------------------------------------------------------------
# Methods
#----------------------------------------------------------------------------
def AddProjectMapping(doc, projectDoc=None, hint=None):
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
if not projectDoc:
if not hint:
hint = doc.GetFilename()
projectDocs = projectService.FindProjectByFile(hint)
if projectDocs:
projectDoc = projectDocs[0]
projectService.AddProjectMapping(doc, projectDoc)
if hasattr(doc, "GetModel"):
projectService.AddProjectMapping(doc.GetModel(), projectDoc)
def getProjectKeyName(projectName, mode=None):
if mode:
return "%s/%s/%s" % (PROJECT_KEY, projectName.replace(os.sep, '|'), mode)
else:
return "%s/%s" % (PROJECT_KEY, projectName.replace(os.sep, '|'))
def GetDocCallback(filepath):
""" Get the Document used by the IDE and the in-memory document model used by runtime engine """
docMgr = wx.GetApp().GetDocumentManager()
try:
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:
AddProjectMapping(doc)
else: # already open
for d in docMgr.GetDocuments():
if os.path.normcase(d.GetFilename()) == os.path.normcase(filepath):
doc = d
break
except Exception,e:
doc = None
aglogging.reportException(e, stacktrace=True)
if doc and doc.GetDocumentTemplate().GetDocumentType() == WsdlAgEditor.WsdlAgDocument:
# get referenced wsdl doc instead
if doc.GetModel().filePath:
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
try:
doc = docMgr.CreateDocument(filepath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
except Exception,e:
doc = None
aglogging.reportException(e, stacktrace=True)
if doc:
AddProjectMapping(doc)
else: # already open
for d in docMgr.GetDocuments():
if os.path.normcase(d.GetFilename()) == os.path.normcase(filepath):
doc = d
break
else:
doc = None
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
#----------------------------------------------------------------------------
if not ACTIVEGRID_BASE_IDE:
class IDEResourceFactory(DeploymentGeneration.DeploymentResourceFactory):
def __init__(self, openDocs, dataSourceService, projectDir,
preview=False, deployFilepath=None):
self.openDocs = openDocs
self.dataSourceService = dataSourceService
self.projectDir = projectDir
self.preview = preview
self.deployFilepath = deployFilepath
self.defaultFlagsNoView = (
wx.GetApp().GetDocumentManager().GetFlags()|
wx.lib.docview.DOC_SILENT|
wx.lib.docview.DOC_OPEN_ONCE|
wx.lib.docview.DOC_NO_VIEW)
def getModel(self, projectFile):
doc = wx.GetApp().GetDocumentManager().CreateDocument(
projectFile.filePath, flags=self.defaultFlagsNoView)
if (doc == None): # already open
doc = self._findOpenDoc(projectFile.filePath)
else:
AddProjectMapping(doc)
if (doc != None):
return doc.GetModel()
def getDataSource(self, dataSourceName):
# in preview mode, runtime needs the generated Deployment
# to contain the requried data source. But runtime doesn't
# actually need to communicate to db. So here is the logic to
# make preview works if the required data soruce has not
# yet been defined.
dataSource = self.dataSourceService.getDataSource(dataSourceName)
if (dataSource != None):
return dataSource
elif not self.preview:
raise DataServiceExistenceException(dataSourceName)
else:
# first to see if an existing dpl file is there, if so,
# use the data source in dpl file
if (self.deployFilepath != None):
tempDply = None
try:
tempDply = xmlutils.load(deployFilepath)
except:
pass
if (tempDply != None):
for tempDataSource in tempDply.dataSources:
if (tempDataSource.name == dataSourceName):
return tempDataSource
# if unable to use dpl file, then create a dummy data source
import activegrid.data.dataservice as dataservice
return dataservice.DataSource(
name=dataSourceName, dbtype=dataservice.DB_TYPE_SQLITE)
def initDocumentRef(self, projectFile, documentRef, dpl):
doc = self._findOpenDoc(projectFile.filePath)
if (doc and hasattr(doc, 'GetModel')):
documentRef.document = doc.GetModel()
if isinstance(documentRef, deploymentlib.XFormRef):
doc.GetModel().linkDeployment(dpl, dpl.loader)
def _findOpenDoc(self, filePath):
for openDoc in self.openDocs:
if openDoc.GetFilename() == filePath:
return openDoc
return None
def getProjectDir(self):
return self.projectDir
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, stagedir):
"""Zips stagedir, creates a zipfile that has as name the projectname, in zipdest. Returns path to zipfile."""
if os.path.exists(zipdest):
raise AssertionError("Cannot archive project, %s already exists" % zipdest)
fileutils.zip(zipdest, stagedir)
return zipdest
def StageProject(self, tmpdir, targetDataSourceMapping={}):
""" Copies all files this 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)
# set target data source for schemas
self._SetSchemaTargetDataSource(fileDict, targetDataSourceMapping)
# 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)
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)
# if this project has deployment data sources configured, remove
# them. changing the project is fine, since this is a clone of
# the project the IDE has.
self.GetModel().GetAppInfo().ResetDeploymentDataSources()
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: if referenced artifact (wsdl or code file) is a known product file (such as securityservice.wsdl), make sure patch to it is parameterized with special env var. We do not want to copy those files. For user artifacts, ensure the file lives in root of stagedir. This should be the case if it is part of project (since 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
modified = False
try:
fileObject = open(wsdlagpath)
serviceref = WsdlAgEditor.load(fileObject)
# referenced wsdl
if (hasattr(serviceref, WsdlAgModel.WSDL_FILE_ATTR)):
modified = (modified |
self._UpdateServiceRefPathAttr(
stagedir, serviceref,
WsdlAgModel.WSDL_FILE_ATTR))
# referenced code file
if (hasattr(serviceref, WsdlAgModel.LOCAL_SERVICE_ELEMENT)):
lse = getattr(serviceref,
WsdlAgModel.LOCAL_SERVICE_ELEMENT)
if (hasattr(lse, WsdlAgModel.LOCAL_SERVICE_FILE_ATTR)):
modified = (modified |
self._UpdateServiceRefPathAttr(
stagedir, lse,
WsdlAgModel.LOCAL_SERVICE_FILE_ATTR))
finally:
try:
fileObject.close()
except:
pass
# no need to save the file if we did not change anything
if not modified: continue
# write the wsdlag file
fileObject = open(wsdlagpath)
try:
serviceref = WsdlAgEditor.save(fileObject, serviceref)
finally:
try:
fileObject.close()
except:
pass
def _UpdateServiceRefPathAttr(self, stagedir, serviceref, attrName):
"""Returns True if serviceref path has been updated, False otherwise."""
filePath = getattr(serviceref, attrName)
if (filePath == None):
return False
filePath = filePath.strip()
if (len(filePath) == 0):
return False
# if filePath starts with one of the AG systems vars, we don't
# have to do anything
if (fileutils.startsWithAgSystemVar(filePath)):
return False
# remove any known env var refs (we'll put them back a little below)
# we remove them here so that paths that do not have env vars also
# get parameterized correctly below
filePath = fileutils.expandKnownAGVars(filePath)
# make sure we have forward slashes. this is a workaround, which
# would not be necessary if we only write paths with forward slashes
# into our files
filePath = filePath.replace("\\", "/")
filePath = os.path.abspath(filePath)
if (not os.path.exists(filePath)):
# Wrong place to validate that referenced file exists, so just
# give up
return False
# If the referenced file is in stagedir already, there's nothing to do
if (fileutils.hasAncestorDir(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, unless it lives in one of the known
# product directories - in which case we parameterize the known path
# with one of our AG system vars
relPath = os.path.basename(filePath)
stagePath = os.path.join(stagedir, relPath)
if (not os.path.exists(stagePath)):
pFilePath = fileutils.parameterizePathWithAGSystemVar(filePath)
if pFilePath == filePath: # no parameterization happened, copy
fileutils.copyFile(filePath, stagePath)
setattr(serviceref, attrName, relPath)
else:
setattr(serviceref, attrName, pFilePath.replace("\\", "/"))
else:
setattr(serviceref, attrName, relPath)
return True
def _SetSchemaTargetDataSource(self, projectFiles, dsmapping):
"""Update schema's default data source, if necessary."""
for projectFile in projectFiles:
if (projectFile.type == basedocmgr.FILE_TYPE_SCHEMA):
name = os.path.basename(projectFile.filePath)
if (dsmapping.has_key(name)):
schema = xmlutils.load(projectFile.filePath)
defaultName = schema.getDefaultDataSourceName()
if (defaultName != dsmapping[name]):
schema.setDefaultDataSourceName(dsmapping[name])
xmlutils.save(projectFile.filePath, schema)
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)
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 GetSchemas(self):
"""Returns list of schema models (activegrid.model.schema.schema) for all schemas in this project."""
rtn = []
resourceFactory = self._GetResourceFactory()
for projectFile in self.GetModel().projectFiles:
if (projectFile.type == basedocmgr.FILE_TYPE_SCHEMA):
schema = resourceFactory.getModel(projectFile)
if (schema != None):
rtn.append(schema)
return rtn
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, pre17=False):
if (pre17):
name = self.GetProjectName() + PRE_17_TMP_DPL_NAME
else:
name = self.GetProjectName() + _17_TMP_DPL_NAME
return os.path.join(self.GetModel().homeDir, name)
def _GetResourceFactory(self, preview=False, deployFilepath=None):
return IDEResourceFactory(
openDocs=wx.GetApp().GetDocumentManager().GetDocuments(),
dataSourceService=wx.GetApp().GetService(DataModelEditor.DataSourceService),
projectDir=os.path.dirname(self.GetFilename()),
preview=preview,
deployFilepath=deployFilepath)
def GenerateDeployment(self, deployFilepath=None, preview=False):
if ACTIVEGRID_BASE_IDE:
return
if not deployFilepath:
deployFilepath = self.GetDeploymentFilepath()
d = DeploymentGeneration.DeploymentGenerator(
self.GetModel(), self._GetResourceFactory(preview,
deployFilepath))
dpl = d.getDeployment(deployFilepath)
if preview:
dpl.initialize() # used in preview only
# REVIEW 07-Apr-06 stoens@activegrid.com -- Check if there's a
# tmp dpl file with pre 17 name, if so, delete it, so user doesn't end
# up with unused file in project dir. We should probably remove this
# check after 1.7 goes out.
fileutils.remove(self.GetDeploymentFilepath(pre17=True))
deploymentlib.saveThroughCache(dpl.fileName, dpl)
return deployFilepath
def AddNameSpaces(self, filePaths):
""" Add any new wsdl and schema namespaces to bpel files """
""" Add any new schema namespaces to wsdl files """
if ACTIVEGRID_BASE_IDE:
return
processRefs = self.GetAppDocMgr().findRefsByFileType(basedocmgr.FILE_TYPE_PROCESS) # bpel
schemaRefs = self.GetAppDocMgr().findRefsByFileType(basedocmgr.FILE_TYPE_SCHEMA) # xsd
serviceRefs = self.GetAppDocMgr().allServiceRefs # wsdl
# update bpel files
if processRefs and (serviceRefs or schemaRefs):
for processRef in processRefs:
processDoc = processRef.ideDocument
process = processDoc.GetModel()
if processDoc and process:
modified = False
# add wsdl namespaces to bpel file
for serviceRef in serviceRefs:
wsdl = serviceRef.document
if (wsdl
and (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
# add schema namespaces to bpel file
for schemaRef in schemaRefs:
schema = schemaRef.document
if schema and schema.fileName in filePaths:
schemaLongNS = schema.targetNamespace
schemaShortNS = self.GetAppDocMgr().findShortNS(schemaLongNS)
if not schemaShortNS:
schemaShortNS = xmlutils.genShortNS(process, schemaLongNS)
xmlutils.addNSAttribute(process, schemaShortNS, schemaLongNS)
modified = True
if modified:
processDoc.OnSaveDocument(processDoc.GetFilename())
# update wsdl files
if serviceRefs and schemaRefs:
for serviceRef in serviceRefs:
wsdl = serviceRef.document
wsdlDoc = serviceRef.ideDocument
if wsdl and wsdlDoc:
modified = False
# add schema namespace to wsdl file
for schemaRef in schemaRefs:
schema = schemaRef.document
if schema and schema.fileName in filePaths:
schemaLongNS = schema.targetNamespace
schemaShortNS = self.GetAppDocMgr().findShortNS(schemaLongNS)
if not schemaShortNS:
schemaShortNS = xmlutils.genShortNS(wsdl, 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, _("Name and Location"))
page.GetSizer().Add(wx.StaticText(page, -1, _("\nEnter the name and location for the project.\n")))
self._projectName, self._dirCtrl, sizer, self._fileValidation = UICommon.CreateDirectoryControl(page, fileExtension="agp", appDirDefaultStartDir=True, fileLabel=_("Name:"), dirLabel=_("Location:"))
page.GetSizer().Add(sizer, 1, flag=wx.EXPAND)
wizard.Layout()
wizard.FitToPage(page)
return page
def RunWizard(self, existingTables = None, existingRelationships = None):
status = Wizard.BaseWizard.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(validClassName=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"))
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, 3) # wxBug: 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_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_TREE_BEGIN_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnBeginDrag)
wx.EVT_TREE_END_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnEndDrag)
wx.EVT_LEFT_DOWN(self._treeCtrl, self.OnLeftClick)
# 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()
try:
rootItem = self._treeCtrl.GetRootItem()
self._treeCtrl.DeleteChildren(rootItem)
finally:
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):
if wx.lib.docview.View.OnUpdate(self, sender, hint):
return
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()
try:
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.physicalFolder
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)
finally:
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()
try:
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
finally:
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()
try:
item = self._treeCtrl.FindItem(hint[2])
self._treeCtrl.SetItemText(item, os.path.basename(hint[3]))
self._treeCtrl.EnsureVisible(item)
finally:
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()
try:
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)
finally:
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:
projectDoc = self.GetDocument()
if projectDoc:
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
for openDoc in openDocs[:]: # need to make a copy, as each file closes we're off by one
if projectDoc == openDoc: # close project last
continue
if projectDoc == projectService.FindProjectFromMapping(openDoc):
self.GetDocumentManager().CloseDocument(openDoc, False)
projectService.RemoveProjectMapping(openDoc)
if hasattr(openDoc, "GetModel"):
projectService.RemoveProjectMapping(openDoc.GetModel())
if self.GetDocumentManager().CloseDocument(projectDoc, 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):
items = self._treeCtrl.GetSelections()
if items:
hasViewSelected = False
for item in items:
if self._IsItemFile(item):
file = self._GetItemFile(item)
if file.type == 'xform':
hasViewSelected = True
break
if hasViewSelected:
event.Enable(False)
return True
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()
try:
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().physicalFolders
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.physicalFolder
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()
self._treeCtrl.SetFocus()
(child, cookie) = self._treeCtrl.GetFirstChild(self._treeCtrl.GetRootItem())
if child.IsOk():
self._treeCtrl.UnselectAll()
self._treeCtrl.SelectItem(child)
self._treeCtrl.ScrollTo(child)
if self._embeddedWindow:
document.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame()))
finally:
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 ClearFolderState(self):
config = wx.ConfigBase_Get()
config.DeleteGroup(getProjectKeyName(self.GetDocument().GetFilename()))
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:
folderPath = self._GetItemFolderPath(item)
if folderPath in folderList:
self._treeCtrl.Expand(item)
else:
self._treeCtrl.Collapse(item)
else:
projectService = wx.GetApp().GetService(ProjectService)
folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
for item in folderItemList:
folderPath = self._GetItemFolderPath(item)
if projectService.FindLogicalViewFolderCollapsedDefault(folderPath): # get default initial state
self._treeCtrl.Collapse(item)
else:
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))
try:
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
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)
doc.GetCommandProcessor().Submit(ProjectAddFilesCommand(doc, paths, folderPath=folderPath))
self.Activate() # after add, should put focus on project editor
finally:
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
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: We also spurious drag events on a single click of on item that is already selected,
so the solution was to consume the left click event. But his broke the single click expand/collapse
of a folder, so if it is a folder, we do an event.Skip() to allow the expand/collapse,
otherwise we consume the event.
"""
# if folder let it collapse/expand
if wx.Platform == '__WXMSW__':
item, flags = self._treeCtrl.HitTest(event.GetPosition())
if item.IsOk() and self._treeCtrl.GetChildrenCount(item, False):
event.Skip()
else:
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 and not ACTIVEGRID_BASE_IDE:
webBrowserService = wx.GetApp().GetService(WebBrowserService.WebBrowserService)
if webBrowserService:
if wx.Platform == '__WXMSW__':
menu.Append(ProjectService.RUN_SELECTED_PM_ID, _("Run Process"))
wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_ID, self.ProjectServiceProcessEvent)
if wx.Platform == '__WXMSW__':
menuLabel = _("Run Process in External Browser")
else:
menuLabel = _("Run Process")
menu.Append(ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID, menuLabel)
wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID, self.ProjectServiceProcessEvent)
if wx.Platform == '__WXMSW__':
if wx.GetApp().GetUseTabbedMDI():
menuLabel = _("Run Process in new Tab")
else:
menuLabel = _("Run Process in new Window")
menu.Append(ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID, menuLabel)
wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID, self.ProjectServiceProcessEvent)
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:
item = menuBar.FindItemById(itemID)
if item:
if SVN_INSTALLED:
svnService = wx.GetApp().GetService(SVNService.SVNService)
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 ProjectServiceProcessEvent(self, event):
projectService = wx.GetApp().GetService(ProjectService)
if projectService:
projectService.ProcessEvent(event)
def OnRename(self, event=None):
items = self._treeCtrl.GetSelections()
if not items:
return
item = items[0]
if wx.Platform == "__WXGTK__":
dlg = wx.TextEntryDialog(self.GetFrame(), _("Enter New Name"), _("Enter New Name"))
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
text = dlg.GetValue()
self.ChangeLabel(item, text)
else:
if items:
self._treeCtrl.EditLabel(item)
def OnBeginLabelEdit(self, event):
self._editingSoDontKillFocus = True
item = event.GetItem()
if self._IsItemFile(item):
file = self._GetItemFile(item)
if file.type == 'xform':
event.Veto()
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 self.ChangeLabel(item, newName):
event.Veto()
def ChangeLabel(self, item, newName):
if not newName:
return False
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)):
return False
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())
return False
doc = self.GetDocument()
if not doc.GetCommandProcessor().Submit(ProjectRenameFolderCommand(doc, oldFolderPath, newFolderPath)):
return False
self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
return True
def CanPaste(self):
# wxBug: Should be able to use IsSupported/IsSupportedFormat here
#fileDataObject = wx.FileDataObject()
#hasFilesInClipboard = wx.TheClipboard.IsSupportedFormat(wx.FileDataObject)
hasFilesInClipboard = False
if not wx.TheClipboard.IsOpened():
if wx.TheClipboard.Open():
fileDataObject = wx.FileDataObject()
hasFilesInClipboard = wx.TheClipboard.GetData(fileDataObject)
wx.TheClipboard.Close()
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()
deploymentFilePath = self.GetDocument().GetDeploymentFilepath()
if deploymentFilePath:
filesInProject.append(deploymentFilePath) # remove deployment file also.
import activegrid.server.secutils as secutils
keystoreFilePath = os.path.join(os.path.dirname(deploymentFilePath), secutils.AGKEYSTORE_FILENAME)
filesInProject.append(keystoreFilePath) # remove keystore 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()
self.ClearFolderState() # remove from registry folder settings
# 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:
AddProjectMapping(doc)
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 wx.Platform == "__WXMSW__":
notebook.SetPageSize((310,300))
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|wx.ALL, PropertyService.LEAVE_MARGIN)
tab.SetSizer(sizer)
notebook.AddPage(tab, _("App Info"))
self._appInfoCtrl._grid.AutoSizeColumns()
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("RunWelcomeDialog2", 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=projectmodel.LANGUAGE_LIST)
self._langCtrl.SetStringSelection(config.Read(APP_LAST_LANGUAGE, projectmodel.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("RunWelcomeDialog2", 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_SELECTED_PM_INTERNAL_WINDOW_ID = wx.NewId()
RUN_SELECTED_PM_EXTERNAL_BROWSER_ID = wx.NewId()
RUN_CURRENT_PM_ID = wx.NewId()
RUN_CURRENT_PM_INTERNAL_WINDOW_ID = wx.NewId()
RUN_CURRENT_PM_EXTERNAL_BROWSER_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._logicalViewOpenDefaults = []
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, _("New Folder"), _("Creates 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
def RemoveProjectMapping(self, key):
""" Remove mapping from model or document to project. """
if self._mapToProject.has_key(key):
del self._mapToProject[key]
#----------------------------------------------------------------------------
# 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
def AddLogicalViewFolderCollapsedDefault(self, folderName, collapsed=True):
# default is collapsed, don't add to list if collapse is True
if not collapsed:
self._logicalViewOpenDefaults.append(folderName)
def FindLogicalViewFolderCollapsedDefault(self, folderName):
if folderName in self._logicalViewOpenDefaults:
return False
return True
#----------------------------------------------------------------------------
# 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_SELECTED_PM_INTERNAL_WINDOW_ID:
self.OnRunProcessModel(event, runSelected=True, newWindow=True, forceInternal=True)
return True
elif id == ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID:
self.OnRunProcessModel(event, runSelected=True, newWindow=True, forceExternal=True)
return True
elif id == ProjectService.RUN_CURRENT_PM_ID:
self.OnRunProcessModel(event, runCurrentFile=True)
return True
elif id == ProjectService.RUN_CURRENT_PM_INTERNAL_WINDOW_ID:
self.OnRunProcessModel(event, runCurrentFile=True, newWindow=True, forceInternal=True)
return True
elif id == ProjectService.RUN_CURRENT_PM_EXTERNAL_BROWSER_ID:
self.OnRunProcessModel(event, runCurrentFile=True, newWindow=True, forceExternal=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 in [ProjectService.RUN_SELECTED_PM_ID,
ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID,
ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID,
ProjectService.RUN_CURRENT_PM_ID,
ProjectService.RUN_CURRENT_PM_INTERNAL_WINDOW_ID,
ProjectService.RUN_CURRENT_PM_EXTERNAL_BROWSER_ID]:
event.Enable(True)
return True
elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
event.Enable(self._CanAddCurrentFileToProject())
return True
elif id in [ProjectService.ADD_FILES_TO_PROJECT_ID,
ProjectService.ADD_DIR_FILES_TO_PROJECT_ID,
ProjectService.RENAME_ID,
ProjectService.OPEN_SELECTION_ID,
ProjectService.DELETE_FILE_ID]:
event.Enable(False)
return True
elif id == ProjectService.PROJECT_PROPERTIES_ID:
event.Enable(self._HasOpenedProjects())
return True
elif id in [wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID,
ProjectService.ADD_FOLDER_ID,
ProjectService.DELETE_PROJECT_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, newWindow=False, forceExternal=False, forceInternal=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]
try:
deployFilePath = project.GenerateDeployment()
except DataServiceExistenceException, e:
dataSourceName = str(e)
self.PromptForMissingDataSource(dataSourceName)
return
self.RunProcessModel(fileToRun, project.GetAppInfo().language, deployFilePath, newWindow, forceExternal, forceInternal)
def RunProcessModel(self, fileToRun, language, deployFilePath, newWindow=True, forceExternal=False, forceInternal=False):
for runHandler in self.GetRunHandlers():
if runHandler.RunProjectFile(fileToRun, language, deployFilePath, newWindow, forceExternal, forceInternal):
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)
# make sure current project is first in list
currProject = self.GetCurrentProject()
if currProject and currProject in retval:
retval.remove(currProject)
retval.insert(0, currProject)
return retval
def OnAddCurrentFileToProject(self, event):
doc = self.GetDocumentManager().GetCurrentDocument()
file = doc.GetFilename()
projectDoc = self.GetView().GetDocument()
projectDoc.GetCommandProcessor().Submit(ProjectAddFilesCommand(projectDoc, [file]))
AddProjectMapping(doc, projectDoc)
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)
self.GetView()._treeCtrl.Freeze()
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)
self.GetView()._treeCtrl.Thaw()
if doc:
openedDocs = True
currProject = config.Read("ProjectCurrent")
if currProject in docList:
self.GetView().SetProject(currProject)
return openedDocs
def PromptForMissingDataSource(self, dataSourceName):
prompt = "A required Data Source '%s' was not found. The process cannot be run without this Data Source.\n\nWould you like to configure this Data Source now?" % dataSourceName
msgTitle = "Unknown Data Source"
dataSourceMissingDlg = wx.MessageDialog(self.GetView().GetFrame(), prompt, msgTitle, wx.YES_NO|wx.ICON_QUESTION)
dataSourceMissingDlg.CenterOnParent()
if dataSourceMissingDlg.ShowModal() == wx.ID_YES:
dataSourceMissingDlg.Destroy()
self._AddDataSource(dataSourceName)
else:
dataSourceMissingDlg.Destroy()
def _AddDataSource(self, defaultDataSourceName=None):
dataSourceService = wx.GetApp().GetService(DataModelEditor.DataSourceService)
dsChoices = dataSourceService.getDataSourceNames()
dlg = DataModelEditor.AddDataSourceDialog(self.GetView().GetFrame(), 'Add Data Source', dsChoices, defaultDataSourceName)
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
dataSource = dlg.GetDataSource()
dlg.Destroy()
else:
dlg.Destroy()
return False
if (dataSource == None):
wx.MessageBox(_("Error getting data source."), self._title)
dataSourceService.updateDataSource(dataSource)
if ((dsChoices == None) or (len(dsChoices) <= 0)):
wx.ConfigBase_Get().Write(DataModelEditor.SchemaOptionsPanel.DEFAULT_DATASOURCE_KEY, dataSource.name)
dataSourceService.save()
return True
#----------------------------------------------------------------------------
# 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)