]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/ProjectEditor.py
DocView and ActiveGrid IDE updates from Morgan Hua:
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / ProjectEditor.py
1 #----------------------------------------------------------------------------
2 # Name: ProjectEditor.py
3 # Purpose: IDE-style Project Editor for wx.lib.pydocview
4 #
5 # Author: Morgan Hua, Peter Yared
6 #
7 # Created: 8/15/03
8 # CVS-ID: $Id$
9 # Copyright: (c) 2003-2006 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
12
13 import wx
14 import wx.lib.docview
15 import wx.lib.pydocview
16 import wx.lib.buttons
17 from wxPython.lib.rcsizer import RowColSizer
18 import Service
19 import copy
20 import os
21 import os.path
22 import sets
23 import sys
24 import time
25 import types
26 import activegrid.util.appdirs as appdirs
27 import activegrid.util.fileutils as fileutils
28 import activegrid.util.aglogging as aglogging
29 import UICommon
30 import Wizard
31 import SVNService
32 import project as projectlib
33 import ExtensionService
34
35 from IDE import ACTIVEGRID_BASE_IDE
36 if not ACTIVEGRID_BASE_IDE:
37 import activegrid.server.deployment as deploymentlib
38 import ProcessModelEditor
39 import DataModelEditor
40 import DeploymentGeneration
41 import WsdlAgEditor
42 import WsdlAgModel
43 APP_LAST_LANGUAGE = "LastLanguage"
44 import activegrid.model.basedocmgr as basedocmgr
45 import activegrid.model.basemodel as basemodel
46 import activegrid.model.projectmodel as projectmodel
47 import PropertyService
48 from activegrid.server.toolsupport import GetTemplate
49 import activegrid.util.xmlutils as xmlutils
50 import activegrid.util.sysutils as sysutils
51 DataServiceExistenceException = DeploymentGeneration.DataServiceExistenceException
52 import WebBrowserService
53
54 from SVNService import SVN_INSTALLED
55
56 _ = wx.GetTranslation
57
58 if wx.Platform == '__WXMSW__':
59 _WINDOWS = True
60 else:
61 _WINDOWS = False
62
63 #----------------------------------------------------------------------------
64 # Constants
65 #----------------------------------------------------------------------------
66 SPACE = 10
67 HALF_SPACE = 5
68 PROJECT_EXTENSION = ".agp"
69
70 if not ACTIVEGRID_BASE_IDE:
71 PRE_17_TMP_DPL_NAME = "RunTime_tmp" + deploymentlib.DEPLOYMENT_EXTENSION
72 _17_TMP_DPL_NAME = ".tmp" + deploymentlib.DEPLOYMENT_EXTENSION
73
74 # wxBug: the wxTextCtrl and wxChoice controls on Mac do not correctly size
75 # themselves with sizers, so we need to add a right border to the sizer to
76 # get the control to shrink itself to fit in the sizer.
77 MAC_RIGHT_BORDER = 0
78 if wx.Platform == "__WXMAC__":
79 MAC_RIGHT_BORDER = 5
80
81
82 PROJECT_KEY = "/AG_Projects"
83 PROJECT_DIRECTORY_KEY = "NewProjectDirectory"
84
85 NEW_PROJECT_DIRECTORY_DEFAULT = appdirs.getSystemDir()
86
87 #----------------------------------------------------------------------------
88 # Methods
89 #----------------------------------------------------------------------------
90
91 def AddProjectMapping(doc, projectDoc=None, hint=None):
92 projectService = wx.GetApp().GetService(ProjectService)
93 if projectService:
94 if not projectDoc:
95 if not hint:
96 hint = doc.GetFilename()
97 projectDocs = projectService.FindProjectByFile(hint)
98 if projectDocs:
99 projectDoc = projectDocs[0]
100
101 projectService.AddProjectMapping(doc, projectDoc)
102 if hasattr(doc, "GetModel"):
103 projectService.AddProjectMapping(doc.GetModel(), projectDoc)
104
105
106 def getProjectKeyName(projectName, mode=None):
107 if mode:
108 return "%s/%s/%s" % (PROJECT_KEY, projectName.replace(os.sep, '|'), mode)
109 else:
110 return "%s/%s" % (PROJECT_KEY, projectName.replace(os.sep, '|'))
111
112
113 def GetDocCallback(filepath):
114 """ Get the Document used by the IDE and the in-memory document model used by runtime engine """
115 docMgr = wx.GetApp().GetDocumentManager()
116
117 try:
118 doc = docMgr.CreateDocument(filepath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
119 if doc:
120 AddProjectMapping(doc)
121 else: # already open
122 for d in docMgr.GetDocuments():
123 if os.path.normcase(d.GetFilename()) == os.path.normcase(filepath):
124 doc = d
125 break
126 except Exception,e:
127 doc = None
128 aglogging.reportException(e, stacktrace=True)
129
130 if doc and doc.GetDocumentTemplate().GetDocumentType() == WsdlAgEditor.WsdlAgDocument:
131 # get referenced wsdl doc instead
132 if doc.GetModel().filePath:
133 if os.path.isabs(doc.GetModel().filePath): # if absolute path, leave it alone
134 filepath = doc.GetModel().filePath
135 else:
136 filepath = doc.GetAppDocMgr().fullPath(doc.GetModel().filePath) # check relative to project homeDir
137
138 if not os.path.isfile(filepath):
139 filepath = os.path.normpath(os.path.join(os.path.dirname(doc.GetFilename()), doc.GetModel().filePath)) # check relative to wsdlag file
140
141 if not os.path.isfile(filepath):
142 filename = os.sep + os.path.basename(doc.GetModel().filePath) # check to see if in project file
143 filePaths = findDocumentMgr(doc).filePaths
144 for fp in filePaths:
145 if fp.endswith(filename):
146 filepath = fp
147 break
148
149 try:
150 doc = docMgr.CreateDocument(filepath, docMgr.GetFlags()|wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE|wx.lib.docview.DOC_NO_VIEW)
151 except Exception,e:
152 doc = None
153 aglogging.reportException(e, stacktrace=True)
154
155 if doc:
156 AddProjectMapping(doc)
157 else: # already open
158 for d in docMgr.GetDocuments():
159 if os.path.normcase(d.GetFilename()) == os.path.normcase(filepath):
160 doc = d
161 break
162 else:
163 doc = None
164
165 if doc:
166 docModel = doc.GetModel()
167 else:
168 docModel = None
169
170 return doc, docModel
171
172
173 def findDocumentMgr(root):
174 projectService = wx.GetApp().GetService(ProjectService)
175 if projectService:
176 projectDoc = projectService.FindProjectFromMapping(root)
177 if projectDoc:
178 return projectDoc.GetModel()
179
180 projectDoc = projectService.GetCurrentProject()
181 if not projectDoc:
182 return None
183
184 if isinstance(root, wx.lib.docview.Document):
185 filepath = root.GetFilename()
186 elif hasattr(root, "fileName") and root.fileName:
187 filepath = root.fileName
188 else:
189 filepath = None
190
191 if filepath:
192 if projectDoc.IsFileInProject(filepath):
193 return projectDoc.GetModel()
194
195 projects = []
196 openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
197 for openDoc in openDocs:
198 if openDoc == projectDoc:
199 continue
200 if(isinstance(openDoc, ProjectDocument)):
201 if openDoc.IsFileInProject(filepath):
202 projects.append(openDoc)
203
204 if projects:
205 if len(projects) == 1:
206 return projects[0].GetModel()
207 else:
208 choices = [os.path.basename(project.GetFilename()) for project in projects]
209 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)
210 dlg.CenterOnParent()
211 projectDoc = None
212 if dlg.ShowModal() == wx.ID_OK:
213 i = dlg.GetSelection()
214 projectDoc = projects[i]
215 dlg.Destroy()
216 return projectDoc.GetModel()
217 return projectDoc.GetModel()
218
219 return None
220
221
222 if not ACTIVEGRID_BASE_IDE:
223 basemodel.findGlobalDocumentMgr = findDocumentMgr
224
225
226 #----------------------------------------------------------------------------
227 # Classes
228 #----------------------------------------------------------------------------
229
230 if not ACTIVEGRID_BASE_IDE:
231 class IDEResourceFactory(DeploymentGeneration.DeploymentResourceFactory):
232
233 def __init__(self, openDocs, dataSourceService, projectDir,
234 preview=False, deployFilepath=None):
235
236 self.openDocs = openDocs
237 self.dataSourceService = dataSourceService
238 self.projectDir = projectDir
239 self.preview = preview
240 self.deployFilepath = deployFilepath
241
242 self.defaultFlagsNoView = (
243 wx.GetApp().GetDocumentManager().GetFlags()|
244 wx.lib.docview.DOC_SILENT|
245 wx.lib.docview.DOC_OPEN_ONCE|
246 wx.lib.docview.DOC_NO_VIEW)
247
248 def getModel(self, projectFile):
249 doc = wx.GetApp().GetDocumentManager().CreateDocument(
250 projectFile.filePath, flags=self.defaultFlagsNoView)
251 if (doc == None): # already open
252 doc = self._findOpenDoc(projectFile.filePath)
253 else:
254 AddProjectMapping(doc)
255 if (doc != None):
256 return doc.GetModel()
257
258 def getDataSource(self, dataSourceName):
259 # in preview mode, runtime needs the generated Deployment
260 # to contain the requried data source. But runtime doesn't
261 # actually need to communicate to db. So here is the logic to
262 # make preview works if the required data soruce has not
263 # yet been defined.
264 dataSource = self.dataSourceService.getDataSource(dataSourceName)
265 if (dataSource != None):
266 return dataSource
267 elif not self.preview:
268 raise DataServiceExistenceException(dataSourceName)
269 else:
270 # first to see if an existing dpl file is there, if so,
271 # use the data source in dpl file
272 if (self.deployFilepath != None):
273 tempDply = None
274 try:
275 tempDply = xmlutils.load(deployFilepath)
276 except:
277 pass
278 if (tempDply != None):
279 for tempDataSource in tempDply.dataSources:
280 if (tempDataSource.name == dataSourceName):
281 return tempDataSource
282
283 # if unable to use dpl file, then create a dummy data source
284 import activegrid.data.dataservice as dataservice
285 return dataservice.DataSource(
286 name=dataSourceName, dbtype=dataservice.DB_TYPE_SQLITE)
287
288 def initDocumentRef(self, projectFile, documentRef, dpl):
289 doc = self._findOpenDoc(projectFile.filePath)
290 if (doc and hasattr(doc, 'GetModel')):
291 documentRef.document = doc.GetModel()
292 if isinstance(documentRef, deploymentlib.XFormRef):
293 doc.GetModel().linkDeployment(dpl, dpl.loader)
294
295 def _findOpenDoc(self, filePath):
296 for openDoc in self.openDocs:
297 if openDoc.GetFilename() == filePath:
298 return openDoc
299 return None
300
301 def getProjectDir(self):
302 return self.projectDir
303
304
305 class ProjectDocument(wx.lib.docview.Document):
306
307 def __init__(self, model=None):
308 wx.lib.docview.Document.__init__(self)
309 if model:
310 self.SetModel(model)
311 else:
312 self.SetModel(projectlib.Project()) # initial model used by "File | New... | Project"
313 self.GetModel().SetDocCallback(GetDocCallback)
314
315 self._stageProjectFile = False
316
317
318 def __copy__(self):
319 model = copy.copy(self.GetModel())
320 clone = ProjectDocument(model)
321 clone.SetFilename(self.GetFilename())
322 return clone
323
324
325 def GetFirstView(self):
326 """ 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.
327 And to the user, it appears as if nothing has happened. The user expects to see the open project.
328 This forces the project view to show the correct project.
329 """
330 view = wx.lib.docview.Document.GetFirstView(self)
331 view.SetProject(self.GetFilename()) # ensure project is displayed in view
332 return view
333
334
335 def GetModel(self):
336 return self._projectModel
337
338
339 def SetModel(self, model):
340 self._projectModel = model
341
342
343 def OnCreate(self, path, flags):
344 projectService = wx.GetApp().GetService(ProjectService)
345 view = projectService.GetView()
346 if view: # view already exists, reuse
347 # All project documents share the same view.
348 self.AddView(view)
349
350 if view.GetDocument():
351 # All project documents need to share the same command processor,
352 # to enable redo/undo of cross project document commands
353 cmdProcessor = view.GetDocument().GetCommandProcessor()
354 if cmdProcessor:
355 self.SetCommandProcessor(cmdProcessor)
356 else: # generate view
357 view = self.GetDocumentTemplate().CreateView(self, flags)
358 projectService.SetView(view)
359
360 return view
361
362
363 def LoadObject(self, fileObject):
364 self.SetModel(projectlib.load(fileObject))
365 self.GetModel().SetDocCallback(GetDocCallback)
366 return True
367
368
369 def SaveObject(self, fileObject):
370 projectlib.save(fileObject, self.GetModel())
371 return True
372
373
374 def OnOpenDocument(self, filePath):
375 projectService = wx.GetApp().GetService(ProjectService)
376 view = projectService.GetView()
377
378 if not os.path.exists(filePath):
379 wx.GetApp().CloseSplash()
380 msgTitle = wx.GetApp().GetAppName()
381 if not msgTitle:
382 msgTitle = _("File Error")
383 wx.MessageBox(_("Could not find '%s'.") % filePath,
384 msgTitle,
385 wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP,
386 wx.GetApp().GetTopWindow())
387 return True # if we return False, the Project View is destroyed, Service windows shouldn't be destroyed
388
389 fileObject = file(filePath, 'r')
390 try:
391 self.LoadObject(fileObject)
392 except:
393 wx.GetApp().CloseSplash()
394 msgTitle = wx.GetApp().GetAppName()
395 if not msgTitle:
396 msgTitle = _("File Error")
397 wx.MessageBox(_("Could not open '%s'. %s") % (wx.lib.docview.FileNameFromPath(filePath), sys.exc_value),
398 msgTitle,
399 wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP,
400 wx.GetApp().GetTopWindow())
401 return True # if we return False, the Project View is destroyed, Service windows shouldn't be destroyed
402
403 self.Modify(False)
404 self.SetFilename(filePath, True)
405 view.AddProjectToView(self)
406 self.SetDocumentModificationDate()
407 self.UpdateAllViews()
408 self._savedYet = True
409 view.Activate()
410 return True
411
412
413 def AddFile(self, filePath, folderPath=None, type=None, name=None):
414 if type:
415 types = [type]
416 else:
417 types = None
418 if name:
419 names = [name]
420 else:
421 names = None
422
423 return self.AddFiles([filePath], folderPath, types, names)
424
425
426 def AddFiles(self, filePaths=None, folderPath=None, types=None, names=None, files=None):
427 # Filter out files that are not already in the project
428 if filePaths:
429 newFilePaths = []
430 oldFilePaths = []
431 for filePath in filePaths:
432 if self.GetModel().FindFile(filePath):
433 oldFilePaths.append(filePath)
434 else:
435 newFilePaths.append(filePath)
436
437 projectService = wx.GetApp().GetService(ProjectService)
438 for i, filePath in enumerate(newFilePaths):
439 if types:
440 type = types[i]
441 else:
442 type = None
443
444 if names:
445 name = names[i]
446 else:
447 name = projectService.FindNameDefault(filePath)
448
449 if not folderPath:
450 folder = projectService.FindLogicalViewFolderDefault(filePath)
451 else:
452 folder = folderPath
453
454 self.GetModel().AddFile(filePath, folder, type, name)
455 elif files:
456 newFilePaths = []
457 oldFilePaths = []
458 for file in files:
459 if self.GetModel().FindFile(file.filePath):
460 oldFilePaths.append(file.filePath)
461 else:
462 newFilePaths.append(file.filePath)
463 self.GetModel().AddFile(file=file)
464 else:
465 return False
466
467 self.AddNameSpaces(newFilePaths)
468
469 self.UpdateAllViews(hint = ("add", self, newFilePaths, oldFilePaths))
470 if len(newFilePaths):
471 self.Modify(True)
472 return True
473 else:
474 return False
475
476
477 def RemoveFile(self, filePath):
478 return self.RemoveFiles([filePath])
479
480
481 def RemoveFiles(self, filePaths=None, files=None):
482 removedFiles = []
483
484 if files:
485 filePaths = []
486 for file in files:
487 filePaths.append(file.filePath)
488
489 for filePath in filePaths:
490 file = self.GetModel().FindFile(filePath)
491 if file:
492 self.GetModel().RemoveFile(file)
493 removedFiles.append(file.filePath)
494
495 self.UpdateAllViews(hint = ("remove", self, removedFiles))
496 if len(removedFiles):
497 self.Modify(True)
498 return True
499 else:
500 return False
501
502
503 def RenameFile(self, oldFilePath, newFilePath, isProject = False):
504 try:
505 if oldFilePath == newFilePath:
506 return False
507
508 # projects don't have to exist yet, so not required to rename old file,
509 # but files must exist, so we'll try to rename and allow exceptions to occur if can't.
510 if not isProject or (isProject and os.path.exists(oldFilePath)):
511 os.rename(oldFilePath, newFilePath)
512
513 if isProject:
514 documents = self.GetDocumentManager().GetDocuments()
515 for document in documents:
516 if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFilePath): # If the renamed document is open, update it
517 document.SetFilename(newFilePath)
518 document.SetTitle(wx.lib.docview.FileNameFromPath(newFilePath))
519 document.UpdateAllViews(hint = ("rename", self, oldFilePath, newFilePath))
520 else:
521 self.UpdateFilePath(oldFilePath, newFilePath)
522 documents = self.GetDocumentManager().GetDocuments()
523 for document in documents:
524 if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFilePath): # If the renamed document is open, update it
525 document.SetFilename(newFilePath, notifyViews = True)
526 document.UpdateAllViews(hint = ("rename", self, oldFilePath, newFilePath))
527 return True
528 except OSError, (code, message):
529 msgTitle = wx.GetApp().GetAppName()
530 if not msgTitle:
531 msgTitle = _("File Error")
532 wx.MessageBox("Could not rename '%s'. '%s'" % (wx.lib.docview.FileNameFromPath(oldFilePath), message),
533 msgTitle,
534 wx.OK | wx.ICON_EXCLAMATION,
535 wx.GetApp().GetTopWindow())
536 return False
537
538
539 def MoveFile(self, file, newFolderPath):
540 return self.MoveFiles([file], newFolderPath)
541
542
543 def MoveFiles(self, files, newFolderPath):
544 filePaths = []
545 isArray = isinstance(newFolderPath, type([]))
546 for i in range(len(files)):
547 if isArray:
548 files[i].logicalFolder = newFolderPath[i]
549 else:
550 files[i].logicalFolder = newFolderPath
551 filePaths.append(files[i].filePath)
552
553 self.UpdateAllViews(hint = ("remove", self, filePaths))
554 self.UpdateAllViews(hint = ("add", self, filePaths, []))
555 self.Modify(True)
556 return True
557
558
559 def UpdateFilePath(self, oldFilePath, newFilePath):
560 file = self.GetModel().FindFile(oldFilePath)
561 self.RemoveFile(oldFilePath)
562 if file:
563 self.AddFile(newFilePath, file.logicalFolder, file.type, file.name)
564 else:
565 self.AddFile(newFilePath)
566
567
568 def RemoveInvalidPaths(self):
569 """Makes sure all paths project knows about are valid and point to existing files. Removes and returns list of invalid paths."""
570
571 invalidFileRefs = []
572
573 fileRefs = self.GetFileRefs()
574
575 for fileRef in fileRefs:
576 if not os.path.exists(fileRef.filePath):
577 invalidFileRefs.append(fileRef)
578
579 for fileRef in invalidFileRefs:
580 fileRefs.remove(fileRef)
581
582 return [fileRef.filePath for fileRef in invalidFileRefs]
583
584
585 def SetStageProjectFile(self):
586 self._stageProjectFile = True
587
588
589 def ArchiveProject(self, zipdest, stagedir):
590 """Zips stagedir, creates a zipfile that has as name the projectname, in zipdest. Returns path to zipfile."""
591 if os.path.exists(zipdest):
592 raise AssertionError("Cannot archive project, %s already exists" % zipdest)
593 fileutils.zip(zipdest, stagedir)
594
595 return zipdest
596
597
598 def StageProject(self, tmpdir, targetDataSourceMapping={}):
599 """ 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."""
600
601 projname = self.GetProjectName()
602 stagedir = os.path.join(tmpdir, projname)
603 fileutils.remove(stagedir)
604 os.makedirs(stagedir)
605
606 # remove invalid files from project
607 self.RemoveInvalidPaths()
608
609 # required so relative paths are written correctly when .dpl file is
610 # generated below.
611 self.SetFilename(os.path.join(stagedir,
612 os.path.basename(self.GetFilename())))
613 projectdir = self.GetModel().homeDir
614
615 # Validate paths before actually copying, and populate a dict
616 # with src->dest so copying is easy.
617 # (fileDict: ProjectFile instance -> dest path (string))
618 fileDict = self._ValidateFilePaths(projectdir, stagedir)
619
620 # copy files to staging dir
621 self._StageFiles(fileDict)
622
623 # set target data source for schemas
624 self._SetSchemaTargetDataSource(fileDict, targetDataSourceMapping)
625
626 # it is unfortunate we require this. it would be nice if filepaths
627 # were only in the project
628 self._FixWsdlAgFiles(stagedir)
629
630 # generate .dpl file
631 dplfilename = projname + deploymentlib.DEPLOYMENT_EXTENSION
632 dplfilepath = os.path.join(stagedir, dplfilename)
633 self.GenerateDeployment(dplfilepath)
634
635 if self._stageProjectFile:
636 # save project so we get the .agp file. not required for deployment
637 # but convenient if user wants to open the deployment in the IDE
638 agpfilename = projname + PROJECT_EXTENSION
639 agpfilepath = os.path.join(stagedir, agpfilename)
640
641 # if this project has deployment data sources configured, remove
642 # them. changing the project is fine, since this is a clone of
643 # the project the IDE has.
644 self.GetModel().GetAppInfo().ResetDeploymentDataSources()
645
646 f = None
647 try:
648 f = open(agpfilepath, "w")
649
650 # setting homeDir correctly is required for the "figuring out
651 # relative paths" logic when saving the project
652 self.GetModel().homeDir = stagedir
653
654 projectlib.save(f, self.GetModel(), productionDeployment=True)
655 finally:
656 try:
657 f.close()
658 except: pass
659
660 return stagedir
661
662 def _FixWsdlAgFiles(self, stagedir):
663 """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."""
664 files = os.listdir(stagedir)
665 for f in files:
666 if (f.endswith(WsdlAgEditor.WsdlAgDocument.WSDL_AG_EXT)):
667 wsdlagpath = os.path.join(stagedir, f)
668 fileObject = None
669 modified = False
670 try:
671 fileObject = open(wsdlagpath)
672 serviceref = WsdlAgEditor.load(fileObject)
673
674 # referenced wsdl
675 if (hasattr(serviceref, WsdlAgModel.WSDL_FILE_ATTR)):
676 modified = (modified |
677 self._UpdateServiceRefPathAttr(
678 stagedir, serviceref,
679 WsdlAgModel.WSDL_FILE_ATTR))
680
681 # referenced code file
682 if (hasattr(serviceref, WsdlAgModel.LOCAL_SERVICE_ELEMENT)):
683 lse = getattr(serviceref,
684 WsdlAgModel.LOCAL_SERVICE_ELEMENT)
685 if (hasattr(lse, WsdlAgModel.LOCAL_SERVICE_FILE_ATTR)):
686 modified = (modified |
687 self._UpdateServiceRefPathAttr(
688 stagedir, lse,
689 WsdlAgModel.LOCAL_SERVICE_FILE_ATTR))
690
691
692 finally:
693 try:
694 fileObject.close()
695 except:
696 pass
697
698 # no need to save the file if we did not change anything
699 if not modified: continue
700
701 # write the wsdlag file
702 fileObject = open(wsdlagpath)
703 try:
704 serviceref = WsdlAgEditor.save(fileObject, serviceref)
705 finally:
706 try:
707 fileObject.close()
708 except:
709 pass
710
711
712 def _UpdateServiceRefPathAttr(self, stagedir, serviceref, attrName):
713 """Returns True if serviceref path has been updated, False otherwise."""
714
715 filePath = getattr(serviceref, attrName)
716
717 if (filePath == None):
718 return False
719
720 filePath = filePath.strip()
721
722 if (len(filePath) == 0):
723 return False
724
725
726 # if filePath starts with one of the AG systems vars, we don't
727 # have to do anything
728 if (fileutils.startsWithAgSystemVar(filePath)):
729 return False
730
731 # remove any known env var refs (we'll put them back a little below)
732 # we remove them here so that paths that do not have env vars also
733 # get parameterized correctly below
734 filePath = fileutils.expandKnownAGVars(filePath)
735
736 # make sure we have forward slashes. this is a workaround, which
737 # would not be necessary if we only write paths with forward slashes
738 # into our files
739 filePath = filePath.replace("\\", "/")
740
741 filePath = os.path.abspath(filePath)
742
743 if (not os.path.exists(filePath)):
744 # Wrong place to validate that referenced file exists, so just
745 # give up
746 return False
747
748 # If the referenced file is in stagedir already, there's nothing to do
749 if (fileutils.hasAncestorDir(filePath, stagedir)):
750 return False
751
752 # The path points outside of stagedir.
753
754 # Check if we already have the referenced wsdl file at root, should be
755 # the case if the referenced wsdl is part of project.
756 # Copy it if we don't have it, unless it lives in one of the known
757 # product directories - in which case we parameterize the known path
758 # with one of our AG system vars
759 relPath = os.path.basename(filePath)
760 stagePath = os.path.join(stagedir, relPath)
761
762 if (not os.path.exists(stagePath)):
763 pFilePath = fileutils.parameterizePathWithAGSystemVar(filePath)
764 if pFilePath == filePath: # no parameterization happened, copy
765 fileutils.copyFile(filePath, stagePath)
766 setattr(serviceref, attrName, relPath)
767 else:
768 setattr(serviceref, attrName, pFilePath.replace("\\", "/"))
769 else:
770 setattr(serviceref, attrName, relPath)
771
772 return True
773
774
775 def _SetSchemaTargetDataSource(self, projectFiles, dsmapping):
776 """Update schema's default data source, if necessary."""
777
778 for projectFile in projectFiles:
779 if (projectFile.type == basedocmgr.FILE_TYPE_SCHEMA):
780 name = os.path.basename(projectFile.filePath)
781 if (dsmapping.has_key(name)):
782 schema = xmlutils.load(projectFile.filePath)
783 defaultName = schema.getDefaultDataSourceName()
784 if (defaultName != dsmapping[name]):
785 schema.setDefaultDataSourceName(dsmapping[name])
786 xmlutils.save(projectFile.filePath, schema)
787
788
789 def _StageFiles(self, fileDict):
790 """Copy files to staging directory, update filePath attr of project's ProjectFile instances."""
791
792 # fileDict: ProjectFile instance -> dest path (string)
793
794 for fileRef, fileDest in fileDict.items():
795 fileutils.copyFile(fileRef.filePath, fileDest)
796 fileRef.filePath = fileDest
797
798 def _ValidateFilePaths(self, projectdir, stagedir):
799 """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.
800 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:
801 - match filenames of files living at the root of the project.
802 - are same as those of any other file that lives outside of the projectdir.
803
804 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)."""
805
806 # ProjectFile instance -> dest path (string)
807 rtn = {}
808
809 projectRootFiles = sets.Set() # live at project root
810 foreignFiles = sets.Set() # live outside of project
811
812 fileRefsToDeploy = self.GetFileRefs()
813
814 for fileRef in fileRefsToDeploy:
815 relPath = fileutils.getRelativePath(fileRef.filePath, projectdir)
816 filename = os.path.basename(fileRef.filePath)
817 if not relPath: # file lives outside of project dir...
818
819 # do we have another file with the same name already?
820 if filename in foreignFiles:
821 raise IOError("More than one file with name \"%s\" lives outside of the project. These files need to have unique names" % filename)
822 foreignFiles.add(filename)
823 fileDest = os.path.join(stagedir, filename)
824 else:
825 # file lives somewhere within the project dir
826 fileDest = os.path.join(stagedir, relPath)
827 if not os.path.dirname(relPath):
828 projectRootFiles.add(filename)
829
830 rtn[fileRef] = fileDest
831
832 # make sure we won't collide with a file that lives at root of
833 # projectdir when moving files into project
834 for filename in foreignFiles:
835 if filename in projectRootFiles:
836 raise IOError("File outside of project, \"%s\", cannot have same name as file at project root" % filename)
837 return rtn
838
839
840 def RenameFolder(self, oldFolderPath, newFolderPath):
841 for file in self.GetModel()._files:
842 if file.logicalFolder == oldFolderPath:
843 file.logicalFolder = newFolderPath
844 self.UpdateAllViews(hint = ("rename folder", self, oldFolderPath, newFolderPath))
845 self.Modify(True)
846 return True
847
848 def GetSchemas(self):
849 """Returns list of schema models (activegrid.model.schema.schema) for all schemas in this project."""
850
851 rtn = []
852 resourceFactory = self._GetResourceFactory()
853 for projectFile in self.GetModel().projectFiles:
854 if (projectFile.type == basedocmgr.FILE_TYPE_SCHEMA):
855 schema = resourceFactory.getModel(projectFile)
856 if (schema != None):
857 rtn.append(schema)
858
859 return rtn
860
861 def GetFiles(self):
862 return self.GetModel().filePaths
863
864
865 def GetFileRefs(self):
866 return self.GetModel().findAllRefs()
867
868
869 def SetFileRefs(self, fileRefs):
870 return self.GetModel().setRefs(fileRefs)
871
872
873 def IsFileInProject(self, filename):
874 return self.GetModel().FindFile(filename)
875
876
877 def GetAppInfo(self):
878 return self.GetModel().GetAppInfo()
879
880
881 def GetAppDocMgr(self):
882 return self.GetModel()
883
884
885 def GetProjectName(self):
886 return os.path.splitext(os.path.basename(self.GetFilename()))[0]
887
888
889 def GetDeploymentFilepath(self, pre17=False):
890 if (pre17):
891 name = self.GetProjectName() + PRE_17_TMP_DPL_NAME
892 else:
893 name = self.GetProjectName() + _17_TMP_DPL_NAME
894 return os.path.join(self.GetModel().homeDir, name)
895
896
897 def _GetResourceFactory(self, preview=False, deployFilepath=None):
898 return IDEResourceFactory(
899 openDocs=wx.GetApp().GetDocumentManager().GetDocuments(),
900 dataSourceService=wx.GetApp().GetService(DataModelEditor.DataSourceService),
901 projectDir=os.path.dirname(self.GetFilename()),
902 preview=preview,
903 deployFilepath=deployFilepath)
904
905 def GenerateDeployment(self, deployFilepath=None, preview=False):
906
907 if ACTIVEGRID_BASE_IDE:
908 return
909
910 if not deployFilepath:
911 deployFilepath = self.GetDeploymentFilepath()
912
913 d = DeploymentGeneration.DeploymentGenerator(
914 self.GetModel(), self._GetResourceFactory(preview,
915 deployFilepath))
916
917 dpl = d.getDeployment(deployFilepath)
918
919 if preview:
920 dpl.initialize() # used in preview only
921
922 # REVIEW 07-Apr-06 stoens@activegrid.com -- Check if there's a
923 # tmp dpl file with pre 17 name, if so, delete it, so user doesn't end
924 # up with unused file in project dir. We should probably remove this
925 # check after 1.7 goes out.
926 fileutils.remove(self.GetDeploymentFilepath(pre17=True))
927
928 deploymentlib.saveThroughCache(dpl.fileName, dpl)
929 return deployFilepath
930
931 def AddNameSpaces(self, filePaths):
932 """ Add any new wsdl and schema namespaces to bpel files """
933 """ Add any new schema namespaces to wsdl files """
934 if ACTIVEGRID_BASE_IDE:
935 return
936
937 processRefs = self.GetAppDocMgr().findRefsByFileType(basedocmgr.FILE_TYPE_PROCESS) # bpel
938 schemaRefs = self.GetAppDocMgr().findRefsByFileType(basedocmgr.FILE_TYPE_SCHEMA) # xsd
939 serviceRefs = self.GetAppDocMgr().allServiceRefs # wsdl
940
941 # update bpel files
942 if processRefs and (serviceRefs or schemaRefs):
943 for processRef in processRefs:
944 processDoc = processRef.ideDocument
945 process = processDoc.GetModel()
946
947 if processDoc and process:
948 modified = False
949
950 # add wsdl namespaces to bpel file
951 for serviceRef in serviceRefs:
952 wsdl = serviceRef.document
953 if (wsdl
954 and (wsdl.fileName in filePaths
955 or serviceRef.filePath in filePaths)):
956 wsdlLongNS = wsdl.targetNamespace
957 wsdlShortNS = self.GetAppDocMgr().findShortNS(wsdlLongNS)
958 if not wsdlShortNS:
959 wsdlShortNS = xmlutils.genShortNS(process, wsdlLongNS)
960 xmlutils.addNSAttribute(process, wsdlShortNS, wsdlLongNS)
961 modified = True
962
963 # add schema namespaces to bpel file
964 for schemaRef in schemaRefs:
965 schema = schemaRef.document
966 if schema and schema.fileName in filePaths:
967 schemaLongNS = schema.targetNamespace
968 schemaShortNS = self.GetAppDocMgr().findShortNS(schemaLongNS)
969 if not schemaShortNS:
970 schemaShortNS = xmlutils.genShortNS(process, schemaLongNS)
971 xmlutils.addNSAttribute(process, schemaShortNS, schemaLongNS)
972 modified = True
973
974 if modified:
975 processDoc.OnSaveDocument(processDoc.GetFilename())
976
977
978 # update wsdl files
979 if serviceRefs and schemaRefs:
980 for serviceRef in serviceRefs:
981 wsdl = serviceRef.document
982 wsdlDoc = serviceRef.ideDocument
983
984 if wsdl and wsdlDoc:
985 modified = False
986
987 # add schema namespace to wsdl file
988 for schemaRef in schemaRefs:
989 schema = schemaRef.document
990 if schema and schema.fileName in filePaths:
991 schemaLongNS = schema.targetNamespace
992 schemaShortNS = self.GetAppDocMgr().findShortNS(schemaLongNS)
993 if not schemaShortNS:
994 schemaShortNS = xmlutils.genShortNS(wsdl, schemaLongNS)
995 xmlutils.addNSAttribute(wsdl, schemaShortNS, schemaLongNS)
996 modified = True
997
998 if modified:
999 wsdlDoc.OnSaveDocument(wsdlDoc.GetFilename())
1000
1001
1002 class NewProjectWizard(Wizard.BaseWizard):
1003
1004 WIZTITLE = _("New Project Wizard")
1005
1006
1007 def __init__(self, parent):
1008 self._parent = parent
1009 self._fullProjectPath = None
1010 Wizard.BaseWizard.__init__(self, parent, self.WIZTITLE)
1011 self._projectLocationPage = self.CreateProjectLocation(self)
1012 wx.wizard.EVT_WIZARD_PAGE_CHANGING(self, self.GetId(), self.OnWizPageChanging)
1013
1014
1015 def CreateProjectLocation(self,wizard):
1016 page = Wizard.TitledWizardPage(wizard, _("Name and Location"))
1017
1018 page.GetSizer().Add(wx.StaticText(page, -1, _("\nEnter the name and location for the project.\n")))
1019 self._projectName, self._dirCtrl, sizer, self._fileValidation = UICommon.CreateDirectoryControl(page, fileExtension="agp", appDirDefaultStartDir=True, fileLabel=_("Name:"), dirLabel=_("Location:"))
1020 page.GetSizer().Add(sizer, 1, flag=wx.EXPAND)
1021
1022 wizard.Layout()
1023 wizard.FitToPage(page)
1024 return page
1025
1026
1027 def RunWizard(self, existingTables = None, existingRelationships = None):
1028 status = Wizard.BaseWizard.RunWizard(self, self._projectLocationPage)
1029 if status:
1030 wx.ConfigBase_Get().Write(PROJECT_DIRECTORY_KEY, self._dirCtrl.GetValue())
1031 docManager = wx.GetApp().GetTopWindow().GetDocumentManager()
1032 if os.path.exists(self._fullProjectPath):
1033 # What if the document is already open and we're overwriting it?
1034 documents = docManager.GetDocuments()
1035 for document in documents:
1036 if os.path.normcase(document.GetFilename()) == os.path.normcase(self._fullProjectPath): # If the renamed document is open, update it
1037 document.DeleteAllViews()
1038 break
1039 os.remove(self._fullProjectPath)
1040
1041 for template in docManager.GetTemplates():
1042 if template.GetDocumentType() == ProjectDocument:
1043 doc = template.CreateDocument(self._fullProjectPath, flags = wx.lib.docview.DOC_NEW)
1044 doc.OnSaveDocument(self._fullProjectPath)
1045 projectService = wx.GetApp().GetService(ProjectService)
1046 view = projectService.GetView()
1047 view.AddProjectToView(doc)
1048 break
1049
1050 self.Destroy()
1051 return status
1052
1053
1054 def OnWizPageChanging(self, event):
1055 if event.GetDirection(): # It's going forwards
1056 if event.GetPage() == self._projectLocationPage:
1057 if not self._fileValidation(validClassName=True):
1058 event.Veto()
1059 return
1060 self._fullProjectPath = os.path.join(self._dirCtrl.GetValue(),UICommon.MakeNameEndInExtension(self._projectName.GetValue(), PROJECT_EXTENSION))
1061
1062
1063 def OnShowCreatePages(self):
1064 self.Hide()
1065 import DataModelEditor
1066 requestedPos = self.GetPositionTuple()
1067 projectService = wx.GetApp().GetService(ProjectService)
1068 projectView = projectService.GetView()
1069
1070 wiz = DataModelEditor.ImportExportWizard(projectView.GetFrame(), pos=requestedPos)
1071 if wiz.RunWizard(dontDestroy=True):
1072 self._schemaName.SetValue(wiz.GetSchemaFileName())
1073 wiz.Destroy()
1074 self.Show(True)
1075
1076
1077 class ProjectTemplate(wx.lib.docview.DocTemplate):
1078
1079
1080 def CreateDocument(self, path, flags):
1081 if path:
1082 doc = wx.lib.docview.DocTemplate.CreateDocument(self, path, flags)
1083 if path:
1084 doc.GetModel()._projectDir = os.path.dirname(path)
1085 return doc
1086 else:
1087 wiz = NewProjectWizard(wx.GetApp().GetTopWindow())
1088 wiz.RunWizard()
1089 wiz.Destroy()
1090 return None # never return the doc, otherwise docview will think it is a new file and rename it
1091
1092
1093 class ProjectAddFilesCommand(wx.lib.docview.Command):
1094
1095
1096 def __init__(self, projectDoc, filePaths, folderPath=None, types=None, names=None):
1097 wx.lib.docview.Command.__init__(self, canUndo = True)
1098 self._projectDoc = projectDoc
1099 self._allFilePaths = filePaths
1100 self._folderPath = folderPath
1101 self._types = types
1102 self._names = names
1103
1104 if not self._types:
1105 self._types = []
1106 projectService = wx.GetApp().GetService(ProjectService)
1107 for filePath in self._allFilePaths:
1108 self._types.append(projectService.FindFileTypeDefault(filePath))
1109
1110 # list of files that will really be added
1111 self._newFiles = []
1112 for filePath in self._allFilePaths:
1113 if not projectDoc.GetModel().FindFile(filePath):
1114 self._newFiles.append(filePath)
1115
1116
1117 def GetName(self):
1118 if len(self._allFilePaths) == 1:
1119 return _("Add File %s") % os.path.basename(self._allFilePaths[0])
1120 else:
1121 return _("Add Files")
1122
1123
1124 def Do(self):
1125 return self._projectDoc.AddFiles(self._allFilePaths, self._folderPath, self._types, self._names)
1126
1127
1128 def Undo(self):
1129 return self._projectDoc.RemoveFiles(self._newFiles)
1130
1131
1132 class ProjectRemoveFilesCommand(wx.lib.docview.Command):
1133
1134
1135 def __init__(self, projectDoc, files):
1136 wx.lib.docview.Command.__init__(self, canUndo = True)
1137 self._projectDoc = projectDoc
1138 self._files = files
1139
1140
1141 def GetName(self):
1142 if len(self._files) == 1:
1143 return _("Remove File %s") % os.path.basename(self._files[0].filePath)
1144 else:
1145 return _("Remove Files")
1146
1147
1148 def Do(self):
1149 return self._projectDoc.RemoveFiles(files=self._files)
1150
1151
1152 def Undo(self):
1153 return self._projectDoc.AddFiles(files=self._files)
1154
1155
1156
1157 class ProjectRenameFileCommand(wx.lib.docview.Command):
1158
1159
1160 def __init__(self, projectDoc, oldFilePath, newFilePath, isProject = False):
1161 wx.lib.docview.Command.__init__(self, canUndo = True)
1162 self._projectDoc = projectDoc
1163 self._oldFilePath = oldFilePath
1164 self._newFilePath = newFilePath
1165 self._isProject = isProject
1166
1167
1168 def GetName(self):
1169 return _("Rename File %s to %s") % (os.path.basename(self._oldFilePath), os.path.basename(self._newFilePath))
1170
1171
1172 def Do(self):
1173 return self._projectDoc.RenameFile(self._oldFilePath, self._newFilePath, self._isProject)
1174
1175
1176 def Undo(self):
1177 return self._projectDoc.RenameFile(self._newFilePath, self._oldFilePath, self._isProject)
1178
1179
1180 class ProjectRenameFolderCommand(wx.lib.docview.Command):
1181 def __init__(self, doc, oldFolderPath, newFolderPath):
1182 wx.lib.docview.Command.__init__(self, canUndo = True)
1183 self._doc = doc
1184 self._oldFolderPath = oldFolderPath
1185 self._newFolderPath = newFolderPath
1186
1187
1188 def GetName(self):
1189 return _("Rename Folder %s to %s") % (os.path.basename(self._oldFolderPath), os.path.basename(self._newFolderPath))
1190
1191
1192 def Do(self):
1193 return self._doc.RenameFolder(self._oldFolderPath, self._newFolderPath)
1194
1195
1196 def Undo(self):
1197 return self._doc.RenameFolder(self._newFolderPath, self._oldFolderPath)
1198
1199
1200 class ProjectAddFolderCommand(wx.lib.docview.Command):
1201 def __init__(self, view, doc, folderpath):
1202 wx.lib.docview.Command.__init__(self, canUndo = True)
1203 self._doc = doc
1204 self._view = view
1205 self._folderpath = folderpath
1206
1207
1208 def GetName(self):
1209 return _("Add Folder %s") % (os.path.basename(self._folderpath))
1210
1211
1212 def Do(self):
1213 if self._view.GetDocument() != self._doc:
1214 return True
1215 status = self._view.AddFolder(self._folderpath)
1216 if status:
1217 self._view._treeCtrl.UnselectAll()
1218 item = self._view._treeCtrl.FindFolder(self._folderpath)
1219 self._view._treeCtrl.SelectItem(item)
1220 return status
1221
1222
1223 def Undo(self):
1224 if self._view.GetDocument() != self._doc:
1225 return True
1226 return self._view.DeleteFolder(self._folderpath)
1227
1228
1229 class ProjectRemoveFolderCommand(wx.lib.docview.Command):
1230 def __init__(self, view, doc, folderpath):
1231 wx.lib.docview.Command.__init__(self, canUndo = True)
1232 self._doc = doc
1233 self._view = view
1234 self._folderpath = folderpath
1235
1236
1237 def GetName(self):
1238 return _("Remove Folder %s") % (os.path.basename(self._folderpath))
1239
1240
1241 def Do(self):
1242 if self._view.GetDocument() != self._doc:
1243 return True
1244 return self._view.DeleteFolder(self._folderpath)
1245
1246
1247 def Undo(self):
1248 if self._view.GetDocument() != self._doc:
1249 return True
1250 status = self._view.AddFolder(self._folderpath)
1251 if status:
1252 self._view._treeCtrl.UnselectAll()
1253 item = self._view._treeCtrl.FindFolder(self._folderpath)
1254 self._view._treeCtrl.SelectItem(item)
1255 return status
1256
1257
1258 class ProjectMoveFilesCommand(wx.lib.docview.Command):
1259
1260 def __init__(self, doc, files, folderPath):
1261 wx.lib.docview.Command.__init__(self, canUndo = True)
1262 self._doc = doc
1263 self._files = files
1264 self._newFolderPath = folderPath
1265
1266 self._oldFolderPaths = []
1267 for file in self._files:
1268 self._oldFolderPaths.append(file.logicalFolder)
1269
1270
1271 def GetName(self):
1272 if len(self._files) == 1:
1273 return _("Move File %s") % os.path.basename(self._files[0].filePath)
1274 else:
1275 return _("Move Files")
1276
1277
1278 def Do(self):
1279 return self._doc.MoveFiles(self._files, self._newFolderPath)
1280
1281
1282 def Undo(self):
1283 return self._doc.MoveFiles(self._files, self._oldFolderPaths)
1284
1285
1286 class ProjectTreeCtrl(wx.TreeCtrl):
1287
1288 #----------------------------------------------------------------------------
1289 # Overridden Methods
1290 #----------------------------------------------------------------------------
1291
1292 def __init__(self, parent, id, style):
1293 wx.TreeCtrl.__init__(self, parent, id, style = style)
1294
1295 templates = wx.GetApp().GetDocumentManager().GetTemplates()
1296 iconList = wx.ImageList(16, 16, initialCount = len(templates))
1297 self._iconIndexLookup = []
1298 for template in templates:
1299 icon = template.GetIcon()
1300 if icon:
1301 if icon.GetHeight() != 16 or icon.GetWidth() != 16:
1302 icon.SetHeight(16)
1303 icon.SetWidth(16)
1304 if wx.GetApp().GetDebug():
1305 print "Warning: icon for '%s' isn't 16x16, not crossplatform" % template._docTypeName
1306 iconIndex = iconList.AddIcon(icon)
1307 self._iconIndexLookup.append((template, iconIndex))
1308
1309 icon = getBlankIcon()
1310 if icon.GetHeight() != 16 or icon.GetWidth() != 16:
1311 icon.SetHeight(16)
1312 icon.SetWidth(16)
1313 if wx.GetApp().GetDebug():
1314 print "Warning: getBlankIcon isn't 16x16, not crossplatform"
1315 self._blankIconIndex = iconList.AddIcon(icon)
1316
1317 icon = getFolderClosedIcon()
1318 if icon.GetHeight() != 16 or icon.GetWidth() != 16:
1319 icon.SetHeight(16)
1320 icon.SetWidth(16)
1321 if wx.GetApp().GetDebug():
1322 print "Warning: getFolderIcon isn't 16x16, not crossplatform"
1323 self._folderClosedIconIndex = iconList.AddIcon(icon)
1324
1325 icon = getFolderOpenIcon()
1326 if icon.GetHeight() != 16 or icon.GetWidth() != 16:
1327 icon.SetHeight(16)
1328 icon.SetWidth(16)
1329 if wx.GetApp().GetDebug():
1330 print "Warning: getFolderIcon isn't 16x16, not crossplatform"
1331 self._folderOpenIconIndex = iconList.AddIcon(icon)
1332
1333 self.AssignImageList(iconList)
1334
1335
1336 def OnCompareItems(self, item1, item2):
1337 item1IsFolder = (self.GetPyData(item1) == None)
1338 item2IsFolder = (self.GetPyData(item2) == None)
1339 if (item1IsFolder == item2IsFolder): # if both are folders or both not
1340 return cmp(self.GetItemText(item1).lower(), self.GetItemText(item2).lower())
1341 elif item1IsFolder and not item2IsFolder: # folders sort above non-folders
1342 return -1
1343 elif not item1IsFolder and item2IsFolder: # folders sort above non-folders
1344 return 1
1345
1346
1347 def AppendFolder(self, parent, folderName):
1348 item = wx.TreeCtrl.AppendItem(self, parent, folderName)
1349 self.SetItemImage(item, self._folderClosedIconIndex, wx.TreeItemIcon_Normal)
1350 self.SetItemImage(item, self._folderOpenIconIndex, wx.TreeItemIcon_Expanded)
1351 self.SetPyData(item, None)
1352 return item
1353
1354
1355 def AppendItem(self, parent, filename, file):
1356 item = wx.TreeCtrl.AppendItem(self, parent, filename)
1357
1358 found = False
1359 template = wx.GetApp().GetDocumentManager().FindTemplateForPath(filename)
1360 if template:
1361 for t, iconIndex in self._iconIndexLookup:
1362 if t is template:
1363 self.SetItemImage(item, iconIndex, wx.TreeItemIcon_Normal)
1364 self.SetItemImage(item, iconIndex, wx.TreeItemIcon_Expanded)
1365 ## self.SetItemImage(item, iconIndex, wx.TreeItemIcon_Selected)
1366 found = True
1367 break
1368
1369 if not found:
1370 self.SetItemImage(item, self._blankIconIndex, wx.TreeItemIcon_Normal)
1371 self.SetItemImage(item, self._blankIconIndex, wx.TreeItemIcon_Expanded)
1372 ## self.SetItemImage(item, self._blankIconIndex, wx.TreeItemIcon_Selected)
1373
1374 self.SetPyData(item, file)
1375
1376 return item
1377
1378
1379 def AddFolder(self, folderPath):
1380 folderItems = []
1381
1382 if folderPath != None:
1383 folderTree = folderPath.split('/')
1384
1385 item = self.GetRootItem()
1386 for folderName in folderTree:
1387 found = False
1388
1389 (child, cookie) = self.GetFirstChild(item)
1390 while child.IsOk():
1391 file = self.GetPyData(child)
1392 if file:
1393 pass
1394 else: # folder
1395 if self.GetItemText(child) == folderName:
1396 item = child
1397 found = True
1398 break
1399 (child, cookie) = self.GetNextChild(item, cookie)
1400
1401 if not found:
1402 item = self.AppendFolder(item, folderName)
1403 folderItems.append(item)
1404
1405 return folderItems
1406
1407
1408 def FindItem(self, filePath, parentItem=None):
1409 if not parentItem:
1410 parentItem = self.GetRootItem()
1411
1412 (child, cookie) = self.GetFirstChild(parentItem)
1413 while child.IsOk():
1414 file = self.GetPyData(child)
1415 if file:
1416 if file.filePath == filePath:
1417 return child
1418 else: # folder
1419 result = self.FindItem(filePath, child) # do recursive call
1420 if result:
1421 return result
1422 (child, cookie) = self.GetNextChild(parentItem, cookie)
1423
1424 return None
1425
1426
1427 def FindFolder(self, folderPath):
1428 if folderPath != None:
1429 folderTree = folderPath.split('/')
1430
1431 item = self.GetRootItem()
1432 for folderName in folderTree:
1433 found = False
1434
1435 (child, cookie) = self.GetFirstChild(item)
1436 while child.IsOk():
1437 file = self.GetPyData(child)
1438 if file:
1439 pass
1440 else: # folder
1441 if self.GetItemText(child) == folderName:
1442 item = child
1443 found = True
1444 break
1445 (child, cookie) = self.GetNextChild(item, cookie)
1446
1447 if found:
1448 return item
1449
1450 return None
1451
1452
1453 def FindClosestFolder(self, x, y):
1454 item, flags = self.HitTest((x,y))
1455 if item:
1456 file = self.GetPyData(item)
1457 if file:
1458 item = self.GetItemParent(item)
1459 return item
1460 return item
1461 return None
1462
1463
1464 class ProjectView(wx.lib.docview.View):
1465 LOGICAL_MODE = "logical"
1466 PHYSICAL_MODE = "physical"
1467
1468 #----------------------------------------------------------------------------
1469 # Overridden methods
1470 #----------------------------------------------------------------------------
1471
1472 def __init__(self, service = None):
1473 wx.lib.docview.View.__init__(self)
1474 # self._service = service # not used, but kept to match other Services
1475 self._projectChoice = None
1476 self._logicalBtn = None
1477 self._physicalBtn = None
1478 self._treeCtrl = None
1479 self._editingSoDontKillFocus = False
1480 self._checkEditMenu = True
1481 self._loading = False # flag to not to try to saving state of folders while it is loading
1482
1483
1484 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
1485 return wx.GetApp().GetDocumentManager()
1486
1487
1488 def Destroy(self):
1489 projectService = wx.GetApp().GetService(ProjectService)
1490 if projectService:
1491 projectService.SetView(None)
1492 wx.lib.docview.View.Destroy(self)
1493
1494
1495 def GetDocument(self):
1496 if not self._projectChoice:
1497 return None
1498
1499 selItem = self._projectChoice.GetSelection()
1500 if selItem == wx.NOT_FOUND:
1501 return None
1502
1503 document = self._projectChoice.GetClientData(selItem)
1504 return document
1505
1506
1507 def Activate(self, activate = True):
1508 if not wx.GetApp().IsMDI():
1509 if activate and not self.IsShown():
1510 self.Show()
1511
1512 if self.IsShown():
1513 wx.lib.docview.View.Activate(self, activate = activate)
1514 if activate and self._treeCtrl:
1515 self._treeCtrl.SetFocus()
1516
1517
1518 def OnCreate(self, doc, flags):
1519 config = wx.ConfigBase_Get()
1520 if wx.GetApp().IsMDI():
1521 self._embeddedWindow = wx.GetApp().GetTopWindow().GetEmbeddedWindow(wx.lib.pydocview.EMBEDDED_WINDOW_TOPLEFT)
1522 self.SetFrame(self._embeddedWindow)
1523 frame = self._embeddedWindow
1524 wx.EVT_SIZE(frame, self.OnSize)
1525 else:
1526 self._embeddedWindow = None
1527 pos = config.ReadInt("ProjectFrameXLoc", -1), config.ReadInt("ProjectFrameYLoc", -1)
1528 # make sure frame is visible
1529 screenWidth = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_X)
1530 screenHeight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
1531 if pos[0] < 0 or pos[0] >= screenWidth or pos[1] < 0 or pos[1] >= screenHeight:
1532 pos = wx.DefaultPosition
1533
1534 size = wx.Size(config.ReadInt("ProjectFrameXSize", -1), config.ReadInt("ProjectFrameYSize", -1))
1535
1536 title = _("Projects")
1537 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI and wx.GetApp().GetAppName():
1538 title = title + " - " + wx.GetApp().GetAppName()
1539
1540 frame = wx.GetApp().CreateDocumentFrame(self, doc, 0, title = title, pos = pos, size = size)
1541 if config.ReadInt("ProjectFrameMaximized", False):
1542 frame.Maximize(True)
1543
1544 panel = wx.Panel(frame, -1)
1545
1546 sizer = wx.BoxSizer(wx.VERTICAL)
1547
1548 butSizer = wx.BoxSizer(wx.HORIZONTAL)
1549
1550 self._projectChoice = wx.Choice(panel, -1)
1551 panel.Bind(wx.EVT_CHOICE, self.OnProjectSelect, self._projectChoice)
1552 w, h = self._projectChoice.GetSize()
1553
1554 self._logicalBtn = wx.lib.buttons.GenBitmapToggleButton(panel, -1, getLogicalModeOffBitmap(), size=(h,h))
1555 self._logicalBtn.SetBitmapSelected(getLogicalModeOnBitmap())
1556 self._logicalBtn.SetToggle(True)
1557 self._logicalBtn.SetToolTipString(_("View Files by Logical Groups"))
1558 panel.Bind(wx.EVT_BUTTON, self.OnSelectMode, self._logicalBtn)
1559 self._physicalBtn = wx.lib.buttons.GenBitmapToggleButton(panel, -1, getPhysicalModeOffBitmap(), size=(h,h))
1560 self._physicalBtn.SetBitmapSelected(getPhysicalModeOnBitmap())
1561 self._physicalBtn.SetToolTipString(_("View Files by Physical Disk Layout"))
1562 panel.Bind(wx.EVT_BUTTON, self.OnSelectMode, self._physicalBtn)
1563
1564 butSizer.Add(self._projectChoice, 1, wx.EXPAND)
1565 butSizer.Add(self._logicalBtn, 0)
1566 butSizer.Add(self._physicalBtn, 0)
1567 sizer.Add(butSizer, 0, wx.EXPAND)
1568
1569 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)
1570 self._treeCtrl.AddRoot(_("Projects"))
1571 if self._embeddedWindow:
1572 sizer.Add(self._treeCtrl, 1, wx.EXPAND|wx.BOTTOM, HALF_SPACE) # allow space for embedded window resize-sash
1573 else:
1574 sizer.Add(self._treeCtrl, 1, wx.EXPAND)
1575 panel.SetSizer(sizer)
1576
1577 sizer = wx.BoxSizer(wx.VERTICAL)
1578
1579 if wx.GetApp().IsMDI():
1580 sizer.Add(panel, 1, wx.EXPAND|wx.BOTTOM, 3) # wxBug: without bottom margin, can't resize embedded window
1581 else:
1582 sizer.Add(panel, 1, wx.EXPAND)
1583
1584 frame.SetSizer(sizer)
1585 frame.Layout()
1586 self.Activate()
1587
1588 if wx.GetApp().IsMDI():
1589 wx.EVT_SET_FOCUS(self._treeCtrl, self.OnFocus)
1590 wx.EVT_KILL_FOCUS(self._treeCtrl, self.OnKillFocus)
1591
1592 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
1593 wx.EVT_TREE_ITEM_ACTIVATED(self._treeCtrl, self._treeCtrl.GetId(), self.OnOpenSelectionSDI)
1594 else:
1595 wx.EVT_TREE_ITEM_ACTIVATED(self._treeCtrl, self._treeCtrl.GetId(), self.OnOpenSelection)
1596 wx.EVT_TREE_BEGIN_LABEL_EDIT(self._treeCtrl, self._treeCtrl.GetId(), self.OnBeginLabelEdit)
1597 wx.EVT_TREE_END_LABEL_EDIT(self._treeCtrl, self._treeCtrl.GetId(), self.OnEndLabelEdit)
1598 wx.EVT_RIGHT_DOWN(self._treeCtrl, self.OnRightClick)
1599 wx.EVT_KEY_DOWN(self._treeCtrl, self.OnKeyPressed)
1600 wx.EVT_TREE_ITEM_COLLAPSED(self._treeCtrl, self._treeCtrl.GetId(), self.SaveFolderState)
1601 wx.EVT_TREE_ITEM_EXPANDED(self._treeCtrl, self._treeCtrl.GetId(), self.SaveFolderState)
1602 wx.EVT_TREE_BEGIN_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnBeginDrag)
1603 wx.EVT_TREE_END_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnEndDrag)
1604 wx.EVT_LEFT_DOWN(self._treeCtrl, self.OnLeftClick)
1605
1606 # drag-and-drop support
1607 dt = ProjectFileDropTarget(self)
1608 self._treeCtrl.SetDropTarget(dt)
1609
1610 return True
1611
1612
1613 def OnSelectMode(self, event):
1614 btn = event.GetEventObject()
1615 down = event.GetIsDown()
1616 if btn == self._logicalBtn:
1617 self._physicalBtn.SetToggle(not down)
1618 else: # btn == self._physicalBtn:
1619 self._logicalBtn.SetToggle(not down)
1620 self.LoadProject(self.GetDocument())
1621
1622
1623 def GetMode(self):
1624 if not self._physicalBtn.up:
1625 return ProjectView.PHYSICAL_MODE
1626 else: # elif self._logicalBtn.GetValue():
1627 return ProjectView.LOGICAL_MODE
1628
1629
1630 def OnProjectSelect(self, event=None):
1631 self.LoadProject(self.GetDocument())
1632 if self.GetDocument():
1633 filename = self.GetDocument().GetFilename()
1634 else:
1635 filename = ''
1636 self._projectChoice.SetToolTipString(filename)
1637
1638
1639 def OnSize(self, event):
1640 event.Skip()
1641 wx.CallAfter(self.GetFrame().Layout)
1642
1643
1644 def OnBeginDrag(self, event):
1645 if self.GetMode() == ProjectView.PHYSICAL_MODE:
1646 return
1647
1648 item = event.GetItem()
1649 if item.IsOk():
1650 self._draggingItems = []
1651 for item in self._treeCtrl.GetSelections():
1652 if self._IsItemFile(item):
1653 self._draggingItems.append(item)
1654 if len(self._draggingItems):
1655 event.Allow()
1656
1657
1658 def OnEndDrag(self, event):
1659 item = event.GetItem()
1660 if item.IsOk():
1661 files = []
1662 for ditem in self._draggingItems:
1663 file = self._GetItemFile(ditem)
1664 if file not in files:
1665 files.append(file)
1666
1667 folderPath = self._GetItemFolderPath(item)
1668
1669 self.GetDocument().GetCommandProcessor().Submit(ProjectMoveFilesCommand(self.GetDocument(), files, folderPath))
1670
1671
1672 def WriteProjectConfig(self):
1673 frame = self.GetFrame()
1674 config = wx.ConfigBase_Get()
1675 if frame and not self._embeddedWindow:
1676 if not frame.IsMaximized():
1677 config.WriteInt("ProjectFrameXLoc", frame.GetPositionTuple()[0])
1678 config.WriteInt("ProjectFrameYLoc", frame.GetPositionTuple()[1])
1679 config.WriteInt("ProjectFrameXSize", frame.GetSizeTuple()[0])
1680 config.WriteInt("ProjectFrameYSize", frame.GetSizeTuple()[1])
1681 config.WriteInt("ProjectFrameMaximized", frame.IsMaximized())
1682
1683 if config.ReadInt("ProjectSaveDocs", True):
1684 projectFileNames = []
1685 curProject = None
1686
1687 if self._projectChoice:
1688 for i in range(self._projectChoice.GetCount()):
1689 project = self._projectChoice.GetClientData(i)
1690 if not project.OnSaveModified():
1691 return
1692 if project.GetDocumentSaved(): # Might be a new document and "No" selected to save it
1693 projectFileNames.append(str(project.GetFilename()))
1694 config.Write("ProjectSavedDocs", projectFileNames.__repr__())
1695
1696 document = None
1697 if self._projectChoice.GetCount():
1698 i = self._projectChoice.GetSelection()
1699 if i != wx.NOT_FOUND:
1700 document = self._projectChoice.GetClientData(i)
1701 if document:
1702 config.Write("ProjectCurrent", document.GetFilename())
1703 else:
1704 config.DeleteEntry("ProjectCurrent")
1705
1706
1707 def OnClose(self, deleteWindow = True):
1708 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
1709 self.WriteProjectConfig()
1710
1711 project = self.GetDocument()
1712 if not project:
1713 return True
1714 if not project.Close():
1715 return True
1716
1717 if not deleteWindow:
1718 self.RemoveCurrentDocumentUpdate()
1719 else:
1720 # need this to accelerate closing down app if treeCtrl has lots of items
1721 self._treeCtrl.Freeze()
1722 try:
1723 rootItem = self._treeCtrl.GetRootItem()
1724 self._treeCtrl.DeleteChildren(rootItem)
1725 finally:
1726 self._treeCtrl.Thaw()
1727
1728 # We don't need to delete the window since it is a floater/embedded
1729 return True
1730
1731
1732 def _GetParentFrame(self):
1733 return wx.GetTopLevelParent(self.GetFrame())
1734
1735
1736 def OnUpdate(self, sender = None, hint = None):
1737 if wx.lib.docview.View.OnUpdate(self, sender, hint):
1738 return
1739
1740 if hint:
1741 if hint[0] == "add":
1742 projectDoc = hint[1]
1743 if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
1744 return
1745
1746 self._treeCtrl.Freeze()
1747
1748 try:
1749 newFilePaths = hint[2] # need to be added and selected, and sorted
1750 oldFilePaths = hint[3] # need to be selected
1751 self._treeCtrl.UnselectAll()
1752
1753 mode = self.GetMode()
1754
1755 project = projectDoc.GetModel()
1756 projectDir = project.homeDir
1757 rootItem = self._treeCtrl.GetRootItem()
1758
1759 # add new folders and new items
1760 addList = []
1761 for filePath in newFilePaths:
1762 file = project.FindFile(filePath)
1763 if file:
1764 if mode == ProjectView.LOGICAL_MODE:
1765 folderPath = file.logicalFolder
1766 else: # ProjectView.PHYSICAL_MODE
1767 folderPath = file.physicalFolder
1768 if folderPath:
1769 self._treeCtrl.AddFolder(folderPath)
1770 folder = self._treeCtrl.FindFolder(folderPath)
1771 else:
1772 folder = rootItem
1773 item = self._treeCtrl.AppendItem(folder, os.path.basename(file.filePath), file)
1774 addList.append(item)
1775
1776 # sort folders with new items
1777 parentList = []
1778 for item in addList:
1779 parentItem = self._treeCtrl.GetItemParent(item)
1780 if parentItem not in parentList:
1781 parentList.append(parentItem)
1782 for parentItem in parentList:
1783 self._treeCtrl.SortChildren(parentItem)
1784
1785 # select all the items user wanted to add
1786 lastItem = None
1787 for filePath in (oldFilePaths + newFilePaths):
1788 item = self._treeCtrl.FindItem(filePath)
1789 if item:
1790 self._treeCtrl.SelectItem(item)
1791 lastItem = item
1792
1793 if lastItem:
1794 self._treeCtrl.EnsureVisible(lastItem)
1795
1796 finally:
1797 self._treeCtrl.Thaw()
1798 return
1799
1800 elif hint[0] == "remove":
1801 projectDoc = hint[1]
1802 if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
1803 return
1804
1805 self._treeCtrl.Freeze()
1806
1807 try:
1808 filePaths = hint[2]
1809 self._treeCtrl.UnselectAll()
1810
1811 for filePath in filePaths:
1812 item = self._treeCtrl.FindItem(filePath)
1813 if item:
1814 self._treeCtrl.Delete(item)
1815
1816 self._treeCtrl.UnselectAll() # wxBug: even though we unselected earlier, an item still gets selected after the delete
1817
1818 finally:
1819 self._treeCtrl.Thaw()
1820 return
1821
1822 elif hint[0] == "rename":
1823 projectDoc = hint[1]
1824 if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
1825 return
1826
1827 self._treeCtrl.Freeze()
1828 try:
1829 item = self._treeCtrl.FindItem(hint[2])
1830 self._treeCtrl.SetItemText(item, os.path.basename(hint[3]))
1831 self._treeCtrl.EnsureVisible(item)
1832 finally:
1833 self._treeCtrl.Thaw()
1834 return
1835
1836 elif hint[0] == "rename folder":
1837 projectDoc = hint[1]
1838 if self.GetDocument() != projectDoc: # project being updated isn't currently viewed project
1839 return
1840
1841 self._treeCtrl.Freeze()
1842 try:
1843 item = self._treeCtrl.FindFolder(hint[2])
1844 if item:
1845 self._treeCtrl.UnselectAll()
1846 self._treeCtrl.SetItemText(item, os.path.basename(hint[3]))
1847 self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
1848 self._treeCtrl.SelectItem(item)
1849 self._treeCtrl.EnsureVisible(item)
1850 finally:
1851 self._treeCtrl.Thaw()
1852 return
1853
1854
1855 def RemoveProjectUpdate(self, projectDoc):
1856 """ Called by service after deleting a project, need to remove from project choices """
1857 i = self._projectChoice.FindString(self._MakeProjectName(projectDoc))
1858 self._projectChoice.Delete(i)
1859
1860 numProj = self._projectChoice.GetCount()
1861 if i >= numProj:
1862 i = numProj - 1
1863 if i >= 0:
1864 self._projectChoice.SetSelection(i)
1865 self.OnProjectSelect()
1866
1867
1868 def RemoveCurrentDocumentUpdate(self, i=-1):
1869 """ Called by service after deleting a project, need to remove from project choices """
1870 i = self._projectChoice.GetSelection()
1871 self._projectChoice.Delete(i)
1872
1873 numProj = self._projectChoice.GetCount()
1874 if i >= numProj:
1875 i = numProj - 1
1876 if i >= 0:
1877 self._projectChoice.SetSelection(i)
1878 self.OnProjectSelect()
1879
1880
1881 def ProcessEvent(self, event):
1882 id = event.GetId()
1883 if id == ProjectService.CLOSE_PROJECT_ID:
1884 projectDoc = self.GetDocument()
1885 if projectDoc:
1886 projectService = wx.GetApp().GetService(ProjectService)
1887 if projectService:
1888 openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
1889 for openDoc in openDocs[:]: # need to make a copy, as each file closes we're off by one
1890 if projectDoc == openDoc: # close project last
1891 continue
1892
1893 if projectDoc == projectService.FindProjectFromMapping(openDoc):
1894 self.GetDocumentManager().CloseDocument(openDoc, False)
1895
1896 projectService.RemoveProjectMapping(openDoc)
1897 if hasattr(openDoc, "GetModel"):
1898 projectService.RemoveProjectMapping(openDoc.GetModel())
1899
1900 if self.GetDocumentManager().CloseDocument(projectDoc, False):
1901 self.RemoveCurrentDocumentUpdate()
1902 return True
1903 elif id == ProjectService.ADD_FILES_TO_PROJECT_ID:
1904 self.OnAddFileToProject(event)
1905 return True
1906 elif id == ProjectService.ADD_DIR_FILES_TO_PROJECT_ID:
1907 self.OnAddDirToProject(event)
1908 return True
1909 elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
1910 return False # Implement this one in the service
1911 elif id == ProjectService.ADD_FOLDER_ID:
1912 self.OnAddFolder(event)
1913 return True
1914 elif id == ProjectService.RENAME_ID:
1915 self.OnRename(event)
1916 return True
1917 elif id == ProjectService.DELETE_FILE_ID:
1918 self.OnDeleteFile(event)
1919 return True
1920 elif id == ProjectService.DELETE_PROJECT_ID:
1921 self.OnDeleteProject(event)
1922 return True
1923 elif id == wx.ID_CUT:
1924 self.OnCut(event)
1925 return True
1926 elif id == wx.ID_COPY:
1927 self.OnCopy(event)
1928 return True
1929 elif id == wx.ID_PASTE:
1930 self.OnPaste(event)
1931 return True
1932 elif (id == wx.ID_CLEAR
1933 or id == ProjectService.REMOVE_FROM_PROJECT):
1934 self.OnClear(event)
1935 return True
1936 elif id == wx.ID_SELECTALL:
1937 self.OnSelectAll(event)
1938 return True
1939 elif id == ProjectService.OPEN_SELECTION_ID:
1940 self.OnOpenSelection(event)
1941 return True
1942 elif id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID:
1943 self.OnProperties(event)
1944 return True
1945 elif id == ProjectService.PROJECT_PROPERTIES_ID:
1946 self.OnProjectProperties(event)
1947 return True
1948 else:
1949 return False
1950
1951
1952 def ProcessUpdateUIEvent(self, event):
1953 # Hack: The edit menu is not being set for projects that are preloaded at startup, so make sure it is OK here
1954 if self._checkEditMenu:
1955 doc = self.GetDocument()
1956 if doc and not doc.GetCommandProcessor().GetEditMenu():
1957 doc.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame()))
1958 self._checkEditMenu = False
1959
1960 id = event.GetId()
1961 if id == wx.ID_CLOSE:
1962 # Too confusing, so disable closing from "File | Close" menu, must close from "Project | Close Current Project" menu
1963 if self.ProjectHasFocus() or self.FilesHasFocus():
1964 event.Enable(False)
1965 return True
1966 else:
1967 return False
1968 elif (id == ProjectService.ADD_FILES_TO_PROJECT_ID
1969 or id == ProjectService.ADD_DIR_FILES_TO_PROJECT_ID
1970 or id == ProjectService.CLOSE_PROJECT_ID
1971 or id == ProjectService.DELETE_PROJECT_ID):
1972 event.Enable(self.GetDocument() != None)
1973 return True
1974 elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
1975 event.Enable(False) # Implement this one in the service
1976 return True
1977 elif id == ProjectService.ADD_FOLDER_ID:
1978 event.Enable((self.GetDocument() != None) and (self.GetMode() == ProjectView.LOGICAL_MODE))
1979 return True
1980 elif id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID:
1981 status = False
1982 if self.ProjectHasFocus():
1983 if self.GetDocument():
1984 status = True
1985 elif self.FilesHasFocus():
1986 items = self._treeCtrl.GetSelections()
1987 if items:
1988 item = items[0]
1989 if self._IsItemFile(item):
1990 status = True
1991
1992 event.Enable(status)
1993 return True
1994 elif (id == wx.ID_CUT
1995 or id == wx.ID_COPY
1996 or id == ProjectService.DELETE_FILE_ID
1997 or id == ProjectService.REMOVE_FROM_PROJECT
1998 or id == ProjectService.OPEN_SELECTION_ID):
1999 event.Enable(self._HasFilesSelected())
2000 return True
2001 elif (id == wx.ID_CLEAR
2002 or id == ProjectService.RENAME_ID):
2003 items = self._treeCtrl.GetSelections()
2004 if items:
2005 hasViewSelected = False
2006 for item in items:
2007 if self._IsItemFile(item):
2008 file = self._GetItemFile(item)
2009 if file.type == 'xform':
2010 hasViewSelected = True
2011 break
2012 if hasViewSelected:
2013 event.Enable(False)
2014 return True
2015
2016 event.Enable(self._HasFilesSelected() or (self.GetDocument() != None and self.GetMode() == ProjectView.LOGICAL_MODE and self._HasFoldersSelected()))
2017 return True
2018 elif id == wx.ID_PASTE:
2019 event.Enable(self.CanPaste())
2020 return True
2021 elif id == wx.ID_SELECTALL:
2022 event.Enable(self._HasFiles())
2023 return True
2024 elif (id == wx.ID_PREVIEW
2025 or id == wx.ID_PRINT):
2026 event.Enable(False)
2027 return True
2028 else:
2029 return False
2030
2031 #----------------------------------------------------------------------------
2032 # Display Methods
2033 #----------------------------------------------------------------------------
2034
2035 def IsShown(self):
2036 if not self.GetFrame():
2037 return False
2038 return self.GetFrame().IsShown()
2039
2040
2041 def Hide(self):
2042 self.Show(False)
2043
2044
2045 def Show(self, show = True):
2046 self.GetFrame().Show(show)
2047 if wx.GetApp().IsMDI():
2048 mdiParentFrame = wx.GetApp().GetTopWindow()
2049 mdiParentFrame.ShowEmbeddedWindow(self.GetFrame(), show)
2050
2051
2052 #----------------------------------------------------------------------------
2053 # Methods for ProjectDocument and ProjectService to call
2054 #----------------------------------------------------------------------------
2055
2056 def SetProject(self, projectPath):
2057 curSel = self._projectChoice.GetSelection()
2058 for i in range(self._projectChoice.GetCount()):
2059 document = self._projectChoice.GetClientData(i)
2060 if document.GetFilename() == projectPath:
2061 if curSel != i: # don't reload if already loaded
2062 self._projectChoice.SetSelection(i)
2063 self.LoadProject(document)
2064 break
2065
2066
2067 def GetSelectedFile(self):
2068 for item in self._treeCtrl.GetSelections():
2069 filePath = self._GetItemFilePath(item)
2070 if filePath:
2071 return filePath
2072 return None
2073
2074
2075 def GetSelectedFiles(self):
2076 filePaths = []
2077 for item in self._treeCtrl.GetSelections():
2078 filePath = self._GetItemFilePath(item)
2079 if filePath and filePath not in filePaths:
2080 filePaths.append(filePath)
2081 return filePaths
2082
2083
2084 def GetSelectedPhysicalFolder(self):
2085 if self.GetMode() == ProjectView.LOGICAL_MODE:
2086 return None
2087 else:
2088 for item in self._treeCtrl.GetSelections():
2089 if not self._IsItemFile(item):
2090 filePath = self._GetItemFolderPath(item)
2091 if filePath:
2092 return filePath
2093 return None
2094
2095
2096 def GetSelectedProject(self):
2097 document = self.GetDocument()
2098 if document:
2099 return document.GetFilename()
2100 else:
2101 return None
2102
2103
2104 def AddProjectToView(self, document):
2105 i = self._projectChoice.Append(self._MakeProjectName(document), document)
2106 self._projectChoice.SetSelection(i)
2107 self.OnProjectSelect()
2108
2109
2110 def LoadProject(self, document):
2111 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
2112 self._treeCtrl.Freeze()
2113
2114 try:
2115 rootItem = self._treeCtrl.GetRootItem()
2116 self._treeCtrl.DeleteChildren(rootItem)
2117
2118 if document:
2119 mode = self.GetMode()
2120 docFilePath = document.GetFilename()
2121
2122 if mode == ProjectView.LOGICAL_MODE:
2123 folders = document.GetModel().logicalFolders
2124 else:
2125 folders = document.GetModel().physicalFolders
2126
2127 folders.sort()
2128 folderItems = []
2129 for folderPath in folders:
2130 folderItems = folderItems + self._treeCtrl.AddFolder(folderPath)
2131
2132 for file in document.GetModel()._files:
2133 if mode == ProjectView.LOGICAL_MODE:
2134 folder = file.logicalFolder
2135 else:
2136 folder = file.physicalFolder
2137 if folder:
2138 folderTree = folder.split('/')
2139
2140 item = rootItem
2141 for folderName in folderTree:
2142 found = False
2143 (child, cookie) = self._treeCtrl.GetFirstChild(item)
2144 while child.IsOk():
2145 if self._treeCtrl.GetItemText(child) == folderName:
2146 item = child
2147 found = True
2148 break
2149 (child, cookie) = self._treeCtrl.GetNextChild(item, cookie)
2150
2151 if not found:
2152 print "error folder '%s' not found for %s" % (folder, file.filePath)
2153 break
2154 else:
2155 item = rootItem
2156
2157 fileItem = self._treeCtrl.AppendItem(item, os.path.basename(file.filePath), file)
2158
2159 self._treeCtrl.SortChildren(rootItem)
2160 for item in folderItems:
2161 self._treeCtrl.SortChildren(item)
2162
2163 self.LoadFolderState()
2164
2165 self._treeCtrl.SetFocus()
2166 (child, cookie) = self._treeCtrl.GetFirstChild(self._treeCtrl.GetRootItem())
2167 if child.IsOk():
2168 self._treeCtrl.UnselectAll()
2169 self._treeCtrl.SelectItem(child)
2170 self._treeCtrl.ScrollTo(child)
2171
2172 if self._embeddedWindow:
2173 document.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame()))
2174
2175 finally:
2176 self._treeCtrl.Thaw()
2177 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
2178
2179
2180 def ProjectHasFocus(self):
2181 """ Does Project Choice have focus """
2182 return (wx.Window.FindFocus() == self._projectChoice)
2183
2184
2185 def FilesHasFocus(self):
2186 """ Does Project Tree have focus """
2187 winWithFocus = wx.Window.FindFocus()
2188 if not winWithFocus:
2189 return False
2190 while winWithFocus:
2191 if winWithFocus == self._treeCtrl:
2192 return True
2193 winWithFocus = winWithFocus.GetParent()
2194 return False
2195
2196
2197 def ClearFolderState(self):
2198 config = wx.ConfigBase_Get()
2199 config.DeleteGroup(getProjectKeyName(self.GetDocument().GetFilename()))
2200
2201
2202 def SaveFolderState(self, event=None):
2203 """ Save the open/close state of folders """
2204
2205 if self._loading:
2206 return
2207
2208 folderList = []
2209 folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
2210 for item in folderItemList:
2211 if self._treeCtrl.IsExpanded(item):
2212 folderList.append(self._GetItemFolderPath(item))
2213
2214 config = wx.ConfigBase_Get()
2215 config.Write(getProjectKeyName(self.GetDocument().GetFilename(), self.GetMode()), repr(folderList))
2216
2217
2218 def LoadFolderState(self):
2219 """ Load the open/close state of folders. """
2220 self._loading = True
2221
2222 config = wx.ConfigBase_Get()
2223 openFolderData = config.Read(getProjectKeyName(self.GetDocument().GetFilename(), self.GetMode()), "")
2224 if openFolderData:
2225 folderList = eval(openFolderData)
2226
2227 folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
2228 for item in folderItemList:
2229 folderPath = self._GetItemFolderPath(item)
2230 if folderPath in folderList:
2231 self._treeCtrl.Expand(item)
2232 else:
2233 self._treeCtrl.Collapse(item)
2234
2235 else:
2236 projectService = wx.GetApp().GetService(ProjectService)
2237
2238 folderItemList = self._GetFolderItems(self._treeCtrl.GetRootItem())
2239 for item in folderItemList:
2240 folderPath = self._GetItemFolderPath(item)
2241 if projectService.FindLogicalViewFolderCollapsedDefault(folderPath): # get default initial state
2242 self._treeCtrl.Collapse(item)
2243 else:
2244 self._treeCtrl.Expand(item)
2245
2246 self._loading = False
2247
2248
2249 #----------------------------------------------------------------------------
2250 # Control events
2251 #----------------------------------------------------------------------------
2252
2253 def OnProperties(self, event):
2254 if self.ProjectHasFocus():
2255 self.OnProjectProperties(event)
2256 elif self.FilesHasFocus():
2257 items = self._treeCtrl.GetSelections()
2258 if not items:
2259 return
2260 item = items[0]
2261 filePath = self._GetItemFilePath(item)
2262 if filePath:
2263 filePropertiesService = wx.GetApp().GetService(wx.lib.pydocview.FilePropertiesService)
2264 filePropertiesService.ShowPropertiesDialog(filePath)
2265
2266
2267 def OnProjectProperties(self, event):
2268 if self.GetDocument():
2269 dlg = ProjectPropertiesDialog(wx.GetApp().GetTopWindow(), self.GetDocument())
2270 dlg.CenterOnParent()
2271 finished = False
2272 while not finished:
2273 if dlg.ShowModal() == wx.ID_OK:
2274 if hasattr(dlg, "_appInfoCtrl") and dlg._appInfoCtrl._grid.IsCellEditControlShown(): # for Linux
2275 dlg._appInfoCtrl._grid.DisableCellEditControl() # If editor is still active, force it to finish the edit before setting the new model.
2276
2277 homeDir = dlg._homeDirCtrl.GetValue()
2278 if homeDir:
2279 if homeDir == ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE:
2280 homeDir = None
2281 if homeDir and not os.path.isdir(homeDir):
2282 wx.MessageBox(_("Home Dir '%s' does not exist. Please specify a valid directory.") % homeDir,
2283 _("Project Properties"),
2284 wx.OK | wx.ICON_EXCLAMATION)
2285 else:
2286 if self.GetDocument().GetModel()._homeDir != homeDir: # don't set it if it hasn't changed
2287 self.GetDocument().GetModel().homeDir = homeDir
2288 self.GetDocument().Modify(True)
2289 finished = True
2290 else:
2291 wx.MessageBox(_("Blank Home Dir. Please specify a valid directory."),
2292 _("Project Properties"),
2293 wx.OK | wx.ICON_EXCLAMATION)
2294 else: # ID_CANCEL
2295 finished = True
2296 dlg.Destroy()
2297
2298
2299 def OnAddFolder(self, event):
2300 if self.GetDocument():
2301 items = self._treeCtrl.GetSelections()
2302 if items:
2303 item = items[0]
2304 if self._IsItemFile(item):
2305 item = self._treeCtrl.GetItemParent(item)
2306
2307 folderDir = self._GetItemFolderPath(item)
2308 else:
2309 folderDir = ""
2310
2311 if folderDir:
2312 folderDir += "/"
2313 folderPath = _("%sUntitled") % folderDir
2314 i = 1
2315 while self._treeCtrl.FindFolder(folderPath):
2316 i += 1
2317 folderPath = _("%sUntitled%s") % (folderDir, i)
2318 self.GetDocument().GetCommandProcessor().Submit(ProjectAddFolderCommand(self, self.GetDocument(), folderPath))
2319
2320 self._treeCtrl.UnselectAll()
2321 item = self._treeCtrl.FindFolder(folderPath)
2322 self._treeCtrl.SelectItem(item)
2323 self._treeCtrl.EnsureVisible(item)
2324 self.OnRename()
2325
2326
2327 def AddFolder(self, folderPath):
2328 self._treeCtrl.AddFolder(folderPath)
2329 return True
2330
2331
2332 def DeleteFolder(self, folderPath):
2333 item = self._treeCtrl.FindFolder(folderPath)
2334 self._treeCtrl.Delete(item)
2335 return True
2336
2337
2338 def OnAddFileToProject(self, event):
2339 if wx.Platform == "__WXMSW__" or wx.Platform == "__WXGTK__" or wx.Platform == "__WXMAC__":
2340 descr = ''
2341 for temp in self.GetDocumentManager()._templates:
2342 if temp.IsVisible():
2343 if len(descr) > 0:
2344 descr = descr + _('|')
2345 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
2346 descr = _("All|*.*|%s") % descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
2347 else:
2348 descr = _("*.*")
2349
2350 dialog = wx.FileDialog(self.GetFrame(), _("Add Files"), wildcard=descr, style=wx.OPEN|wx.HIDE_READONLY|wx.MULTIPLE|wx.CHANGE_DIR)
2351 # dialog.CenterOnParent() # wxBug: caused crash with wx.FileDialog
2352 if dialog.ShowModal() != wx.ID_OK:
2353 dialog.Destroy()
2354 return
2355 paths = dialog.GetPaths()
2356 dialog.Destroy()
2357 if len(paths):
2358
2359 folderPath = None
2360 if self.GetMode() == ProjectView.LOGICAL_MODE:
2361 selections = self._treeCtrl.GetSelections()
2362 if selections:
2363 item = selections[0]
2364 if not self._IsItemFile(item):
2365 folderPath = self._GetItemFolderPath(item)
2366
2367 self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), paths, folderPath=folderPath))
2368 self.Activate() # after add, should put focus on project editor
2369
2370
2371 def OnAddDirToProject(self, event):
2372 frame = wx.Dialog(wx.GetApp().GetTopWindow(), -1, _("Add Directory Files to Project"), size= (320,200))
2373 contentSizer = wx.BoxSizer(wx.VERTICAL)
2374
2375 flexGridSizer = wx.FlexGridSizer(cols = 2, vgap=HALF_SPACE, hgap=HALF_SPACE)
2376 flexGridSizer.Add(wx.StaticText(frame, -1, _("Directory:")), 0, wx.ALIGN_CENTER_VERTICAL, 0)
2377 lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2378 dirCtrl = wx.TextCtrl(frame, -1, os.path.dirname(self.GetDocument().GetFilename()), size=(250,-1))
2379 dirCtrl.SetToolTipString(dirCtrl.GetValue())
2380 lineSizer.Add(dirCtrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND)
2381 findDirButton = wx.Button(frame, -1, _("Browse..."))
2382 lineSizer.Add(findDirButton, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, HALF_SPACE)
2383 flexGridSizer.Add(lineSizer, 1, wx.EXPAND)
2384
2385 def OnBrowseButton(event):
2386 dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE)
2387 dir = dirCtrl.GetValue()
2388 if len(dir):
2389 dlg.SetPath(dir)
2390 dlg.CenterOnParent()
2391 if dlg.ShowModal() == wx.ID_OK:
2392 dirCtrl.SetValue(dlg.GetPath())
2393 dirCtrl.SetToolTipString(dirCtrl.GetValue())
2394 dirCtrl.SetInsertionPointEnd()
2395 dlg.Destroy()
2396 wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton)
2397
2398 visibleTemplates = []
2399 for template in self.GetDocumentManager()._templates:
2400 if template.IsVisible():
2401 visibleTemplates.append(template)
2402
2403 choices = []
2404 descr = ''
2405 for template in visibleTemplates:
2406 if len(descr) > 0:
2407 descr = descr + _('|')
2408 descr = template.GetDescription() + _(" (") + template.GetFileFilter() + _(")")
2409 choices.append(descr)
2410 choices.insert(0, _("All")) # first item
2411 filterChoice = wx.Choice(frame, -1, size=(250, -1), choices=choices)
2412 filterChoice.SetSelection(0)
2413 filterChoice.SetToolTipString(_("Select file type filter."))
2414 flexGridSizer.Add(wx.StaticText(frame, -1, _("Files of type:")), 0, wx.ALIGN_CENTER_VERTICAL)
2415 flexGridSizer.Add(filterChoice, 1, wx.EXPAND)
2416
2417 contentSizer.Add(flexGridSizer, 0, wx.ALL|wx.EXPAND, SPACE)
2418
2419 subfolderCtrl = wx.CheckBox(frame, -1, _("Add files from subdirectories"))
2420 subfolderCtrl.SetValue(True)
2421 contentSizer.Add(subfolderCtrl, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, SPACE)
2422
2423 buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
2424 findBtn = wx.Button(frame, wx.ID_OK, _("Add"))
2425 findBtn.SetDefault()
2426 buttonSizer.Add(findBtn, 0, wx.RIGHT, HALF_SPACE)
2427 buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL), 0)
2428 contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE)
2429
2430 frame.SetSizer(contentSizer)
2431 frame.Fit()
2432
2433 frame.CenterOnParent()
2434 status = frame.ShowModal()
2435
2436 passedCheck = False
2437 while status == wx.ID_OK and not passedCheck:
2438 if not os.path.exists(dirCtrl.GetValue()):
2439 dlg = wx.MessageDialog(frame,
2440 _("'%s' does not exist.") % dirCtrl.GetValue(),
2441 _("Find in Directory"),
2442 wx.OK | wx.ICON_EXCLAMATION
2443 )
2444 dlg.CenterOnParent()
2445 dlg.ShowModal()
2446 dlg.Destroy()
2447
2448 status = frame.ShowModal()
2449 else:
2450 passedCheck = True
2451
2452 frame.Destroy()
2453
2454 if status == wx.ID_OK:
2455 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
2456
2457 try:
2458 doc = self.GetDocument()
2459 searchSubfolders = subfolderCtrl.IsChecked()
2460 dirString = dirCtrl.GetValue()
2461
2462 if os.path.isfile(dirString):
2463 # If they pick a file explicitly, we won't prevent them from adding it even if it doesn't match the filter.
2464 # We'll assume they know what they're doing.
2465 paths = [dirString]
2466 else:
2467 paths = []
2468
2469 index = filterChoice.GetSelection()
2470 lastIndex = filterChoice.GetCount()-1
2471 if index and index != lastIndex: # if not All or Any
2472 template = visibleTemplates[index-1]
2473
2474 # do search in files on disk
2475 for root, dirs, files in os.walk(dirString):
2476 if not searchSubfolders and root != dirString:
2477 break
2478
2479 for name in files:
2480 if index == 0: # All
2481 filename = os.path.join(root, name)
2482 # if already in project, don't add it, otherwise undo will remove it from project even though it was already in it.
2483 if not doc.IsFileInProject(filename):
2484 paths.append(filename)
2485 else: # use selected filter
2486 if template.FileMatchesTemplate(name):
2487 filename = os.path.join(root, name)
2488 # if already in project, don't add it, otherwise undo will remove it from project even though it was already in it.
2489 if not doc.IsFileInProject(filename):
2490 paths.append(filename)
2491
2492 folderPath = None
2493 if self.GetMode() == ProjectView.LOGICAL_MODE:
2494 selections = self._treeCtrl.GetSelections()
2495 if selections:
2496 item = selections[0]
2497 if not self._IsItemFile(item):
2498 folderPath = self._GetItemFolderPath(item)
2499
2500 doc.GetCommandProcessor().Submit(ProjectAddFilesCommand(doc, paths, folderPath=folderPath))
2501 self.Activate() # after add, should put focus on project editor
2502
2503 finally:
2504 wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
2505
2506
2507 def DoAddFilesToProject(self, filePaths, folderPath):
2508 # method used by Drag-n-Drop to add files to current Project
2509 self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), filePaths, folderPath))
2510
2511
2512 def OnFocus(self, event):
2513 self.GetDocumentManager().ActivateView(self)
2514 event.Skip()
2515
2516
2517 def OnKillFocus(self, event):
2518 # Get the top MDI window and "activate" it since it is already active from the perspective of the MDIParentFrame
2519 # wxBug: Would be preferable to call OnActivate, but have casting problem, so added Activate method to docview.DocMDIChildFrame
2520 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
2521 topWindow = wx.GetApp().GetTopWindow()
2522 # wxBug: On Mac, this event can fire during shutdown, even after GetTopWindow()
2523 # is set to NULL. So make sure we have a TLW before getting the active child.
2524 if topWindow:
2525 childFrame = topWindow.GetActiveChild()
2526 if childFrame:
2527 childFrame.Activate()
2528 event.Skip()
2529
2530
2531 def OnLeftClick(self, event):
2532 """
2533 wxBug: We also spurious drag events on a single click of on item that is already selected,
2534 so the solution was to consume the left click event. But his broke the single click expand/collapse
2535 of a folder, so if it is a folder, we do an event.Skip() to allow the expand/collapse,
2536 otherwise we consume the event.
2537 """
2538 # if folder let it collapse/expand
2539 if wx.Platform == '__WXMSW__':
2540 item, flags = self._treeCtrl.HitTest(event.GetPosition())
2541 if item.IsOk() and self._treeCtrl.GetChildrenCount(item, False):
2542 event.Skip()
2543 else:
2544 event.Skip()
2545
2546 def OnRightClick(self, event):
2547 self.Activate()
2548 if not self.GetSelectedProject():
2549 return
2550 menu = wx.Menu()
2551 if self._HasFilesSelected(): # Files context
2552 menu.Append(ProjectService.OPEN_SELECTION_ID, _("&Open"), _("Opens the selection"))
2553 menu.Enable(ProjectService.OPEN_SELECTION_ID, True)
2554 wx.EVT_MENU(self._GetParentFrame(), ProjectService.OPEN_SELECTION_ID, self.OnOpenSelection)
2555
2556 extService = wx.GetApp().GetService(ExtensionService.ExtensionService)
2557 if extService and extService.GetExtensions():
2558 firstItem = True
2559 for ext in extService.GetExtensions():
2560 if not ext.opOnSelectedFile:
2561 continue
2562 if firstItem:
2563 menu.AppendSeparator()
2564 firstItem = False
2565 menu.Append(ext.id, ext.menuItemName)
2566 wx.EVT_MENU(self._GetParentFrame(), ext.id, extService.ProcessEvent)
2567 wx.EVT_UPDATE_UI(self._GetParentFrame(), ext.id, extService.ProcessUpdateUIEvent)
2568
2569 itemIDs = [None]
2570 for item in self._treeCtrl.GetSelections():
2571 if self._IsItemProcessModelFile(item):
2572 itemIDs = [None, ProjectService.RUN_SELECTED_PM_ID, None]
2573 break
2574 else: # Project context
2575 itemIDs = []
2576 menuBar = self._GetParentFrame().GetMenuBar()
2577 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]
2578 svnIDs = [SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID]
2579 if SVN_INSTALLED:
2580 itemIDs = itemIDs + [None, SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID]
2581 globalIDs = [wx.ID_UNDO, wx.ID_REDO, wx.ID_CLOSE, wx.ID_SAVE, wx.ID_SAVEAS]
2582 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]
2583 for itemID in itemIDs:
2584 if not itemID:
2585 menu.AppendSeparator()
2586 else:
2587 if itemID == ProjectService.RUN_SELECTED_PM_ID and not ACTIVEGRID_BASE_IDE:
2588 webBrowserService = wx.GetApp().GetService(WebBrowserService.WebBrowserService)
2589 if webBrowserService:
2590 if wx.Platform == '__WXMSW__':
2591 menu.Append(ProjectService.RUN_SELECTED_PM_ID, _("Run Process"))
2592 wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_ID, self.ProjectServiceProcessEvent)
2593
2594 if wx.Platform == '__WXMSW__':
2595 menuLabel = _("Run Process in External Browser")
2596 else:
2597 menuLabel = _("Run Process")
2598 menu.Append(ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID, menuLabel)
2599 wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID, self.ProjectServiceProcessEvent)
2600
2601 if wx.Platform == '__WXMSW__':
2602
2603 if wx.GetApp().GetUseTabbedMDI():
2604 menuLabel = _("Run Process in new Tab")
2605 else:
2606 menuLabel = _("Run Process in new Window")
2607 menu.Append(ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID, menuLabel)
2608 wx.EVT_MENU(self._GetParentFrame(), ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID, self.ProjectServiceProcessEvent)
2609
2610 elif itemID == ProjectService.REMOVE_FROM_PROJECT:
2611 menu.Append(ProjectService.REMOVE_FROM_PROJECT, _("Remove Selected Files from Project"))
2612 wx.EVT_MENU(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self.OnClear)
2613 wx.EVT_UPDATE_UI(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self._GetParentFrame().ProcessUpdateUIEvent)
2614 else:
2615 item = menuBar.FindItemById(itemID)
2616 if item:
2617 if SVN_INSTALLED:
2618 svnService = wx.GetApp().GetService(SVNService.SVNService)
2619
2620 if itemID in svnIDs:
2621 if SVN_INSTALLED and svnService:
2622 wx.EVT_MENU(self._GetParentFrame(), itemID, svnService.ProcessEvent)
2623 elif itemID in globalIDs:
2624 pass
2625 else:
2626 wx.EVT_MENU(self._treeCtrl, itemID, self.ProcessEvent)
2627 menu.Append(itemID, item.GetLabel())
2628 self._treeCtrl.PopupMenu(menu, wx.Point(event.GetX(), event.GetY()))
2629 menu.Destroy()
2630
2631
2632 def ProjectServiceProcessEvent(self, event):
2633 projectService = wx.GetApp().GetService(ProjectService)
2634 if projectService:
2635 projectService.ProcessEvent(event)
2636
2637
2638 def OnRename(self, event=None):
2639 items = self._treeCtrl.GetSelections()
2640 if not items:
2641 return
2642 item = items[0]
2643 if wx.Platform == "__WXGTK__":
2644 dlg = wx.TextEntryDialog(self.GetFrame(), _("Enter New Name"), _("Enter New Name"))
2645 dlg.CenterOnParent()
2646 if dlg.ShowModal() == wx.ID_OK:
2647 text = dlg.GetValue()
2648 self.ChangeLabel(item, text)
2649 else:
2650 if items:
2651 self._treeCtrl.EditLabel(item)
2652
2653
2654 def OnBeginLabelEdit(self, event):
2655 self._editingSoDontKillFocus = True
2656 item = event.GetItem()
2657 if self._IsItemFile(item):
2658 file = self._GetItemFile(item)
2659 if file.type == 'xform':
2660 event.Veto()
2661 if (self.GetMode() == ProjectView.PHYSICAL_MODE) and not self._IsItemFile(item):
2662 event.Veto()
2663
2664
2665 def OnEndLabelEdit(self, event):
2666 self._editingSoDontKillFocus = False
2667 item = event.GetItem()
2668 newName = event.GetLabel()
2669 if not self.ChangeLabel(item, newName):
2670 event.Veto()
2671
2672
2673 def ChangeLabel(self, item, newName):
2674 if not newName:
2675 return False
2676 if self._IsItemFile(item):
2677 oldFilePath = self._GetItemFilePath(item)
2678 newFilePath = os.path.join(os.path.dirname(oldFilePath), newName)
2679 doc = self.GetDocument()
2680 if not doc.GetCommandProcessor().Submit(ProjectRenameFileCommand(doc, oldFilePath, newFilePath)):
2681 return False
2682 self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
2683 else:
2684 oldFolderPath = self._GetItemFolderPath(item)
2685 newFolderPath = os.path.dirname(oldFolderPath)
2686 if newFolderPath:
2687 newFolderPath += "/"
2688 newFolderPath += newName
2689 if self._treeCtrl.FindFolder(newFolderPath):
2690 wx.MessageBox(_("Folder '%s' already exists.") % newName,
2691 "Rename Folder",
2692 wx.OK | wx.ICON_EXCLAMATION,
2693 self.GetFrame())
2694 return False
2695 doc = self.GetDocument()
2696 if not doc.GetCommandProcessor().Submit(ProjectRenameFolderCommand(doc, oldFolderPath, newFolderPath)):
2697 return False
2698 self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(item))
2699
2700 return True
2701
2702
2703 def CanPaste(self):
2704 # wxBug: Should be able to use IsSupported/IsSupportedFormat here
2705 #fileDataObject = wx.FileDataObject()
2706 #hasFilesInClipboard = wx.TheClipboard.IsSupportedFormat(wx.FileDataObject)
2707 hasFilesInClipboard = False
2708 if not wx.TheClipboard.IsOpened():
2709 if wx.TheClipboard.Open():
2710 fileDataObject = wx.FileDataObject()
2711 hasFilesInClipboard = wx.TheClipboard.GetData(fileDataObject)
2712 wx.TheClipboard.Close()
2713 return hasFilesInClipboard
2714
2715
2716 def OnCut(self, event):
2717 self.OnCopy(event)
2718 self.OnClear(event)
2719
2720
2721 def OnCopy(self, event):
2722 fileDataObject = wx.FileDataObject()
2723 items = self._treeCtrl.GetSelections()
2724 for item in items:
2725 filePath = self._GetItemFilePath(item)
2726 if filePath:
2727 fileDataObject.AddFile(filePath)
2728 if len(fileDataObject.GetFilenames()) > 0 and wx.TheClipboard.Open():
2729 wx.TheClipboard.SetData(fileDataObject)
2730 wx.TheClipboard.Close()
2731
2732
2733 def OnPaste(self, event):
2734 if wx.TheClipboard.Open():
2735 fileDataObject = wx.FileDataObject()
2736 if wx.TheClipboard.GetData(fileDataObject):
2737 folderPath = None
2738 if self.GetMode() == ProjectView.LOGICAL_MODE:
2739 items = self._treeCtrl.GetSelections()
2740 if items:
2741 item = items[0]
2742 if item:
2743 folderPath = self._GetItemFolderPath(item)
2744 self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), fileDataObject.GetFilenames(), folderPath))
2745 wx.TheClipboard.Close()
2746
2747
2748 def OnClear(self, event):
2749 if self._HasFilesSelected():
2750 items = self._treeCtrl.GetSelections()
2751 files = []
2752 for item in items:
2753 file = self._GetItemFile(item)
2754 if file:
2755 files.append(file)
2756 self.GetDocument().GetCommandProcessor().Submit(ProjectRemoveFilesCommand(self.GetDocument(), files))
2757
2758 elif self._HasFoldersSelected():
2759 items = self._treeCtrl.GetSelections()
2760 item = items[0]
2761 if self._treeCtrl.GetChildrenCount(item, False):
2762 wx.MessageBox(_("Cannot remove folder '%s'. Folder is not empty.") % self._treeCtrl.GetItemText(item),
2763 _("Remove Folder"),
2764 wx.OK | wx.ICON_EXCLAMATION,
2765 self.GetFrame())
2766 return
2767
2768 folderPath = self._GetItemFolderPath(item)
2769 self.GetDocument().GetCommandProcessor().Submit(ProjectRemoveFolderCommand(self, self.GetDocument(), folderPath))
2770
2771
2772 def OnDeleteFile(self, event):
2773 yesNoMsg = wx.MessageDialog(self.GetFrame(),
2774 _("Delete cannot be reversed.\n\nRemove the selected files from the\nproject and file system permanently?"),
2775 _("Delete File"),
2776 wx.YES_NO|wx.ICON_QUESTION)
2777 yesNoMsg.CenterOnParent()
2778 status = yesNoMsg.ShowModal()
2779 yesNoMsg.Destroy()
2780 if status == wx.ID_NO:
2781 return
2782
2783 items = self._treeCtrl.GetSelections()
2784 delFiles = []
2785 for item in items:
2786 filePath = self._GetItemFilePath(item)
2787 if filePath and filePath not in delFiles:
2788 delFiles.append(filePath)
2789
2790 # remove selected files from project
2791 self.GetDocument().RemoveFiles(delFiles)
2792
2793 # remove selected files from file system
2794 for filePath in delFiles:
2795 if os.path.exists(filePath):
2796 try:
2797 os.remove(filePath)
2798 except:
2799 wx.MessageBox("Could not delete '%s'. %s" % (os.path.basename(filePath), sys.exc_value),
2800 _("Delete File"),
2801 wx.OK | wx.ICON_EXCLAMATION,
2802 self.GetFrame())
2803
2804 def OnDeleteProject(self, event=None, noPrompt=False, closeFiles=True, delFiles=True):
2805
2806 class DeleteProjectDialog(wx.Dialog):
2807
2808 def __init__(self, parent, doc):
2809 wx.Dialog.__init__(self, parent, -1, _("Delete Project"), size = (310, 330))
2810
2811 sizer = wx.BoxSizer(wx.VERTICAL)
2812 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)
2813 self._delFilesCtrl = wx.CheckBox(self, -1, _("Delete all files in project"))
2814 self._delFilesCtrl.SetValue(True)
2815 self._delFilesCtrl.SetToolTipString(_("Deletes files from disk, whether open or closed"))
2816 sizer.Add(self._delFilesCtrl, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, SPACE)
2817 self._closeDeletedCtrl = wx.CheckBox(self, -1, _("Close open files belonging to project"))
2818 self._closeDeletedCtrl.SetValue(True)
2819 self._closeDeletedCtrl.SetToolTipString(_("Closes open editors for files belonging to project"))
2820 sizer.Add(self._closeDeletedCtrl, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, SPACE)
2821
2822 sizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_RIGHT|wx.RIGHT|wx.LEFT|wx.BOTTOM, SPACE)
2823
2824 self.SetSizer(sizer)
2825 sizer.Fit(self)
2826 self.Layout()
2827
2828 doc = self.GetDocument()
2829 if not noPrompt:
2830 dlg = DeleteProjectDialog(self.GetFrame(), doc)
2831 dlg.CenterOnParent()
2832 status = dlg.ShowModal()
2833 delFiles = dlg._delFilesCtrl.GetValue()
2834 closeFiles = dlg._closeDeletedCtrl.GetValue()
2835 dlg.Destroy()
2836 if status == wx.ID_CANCEL:
2837 return
2838
2839 if closeFiles or delFiles:
2840 filesInProject = doc.GetFiles()
2841 deploymentFilePath = self.GetDocument().GetDeploymentFilepath()
2842 if deploymentFilePath:
2843 filesInProject.append(deploymentFilePath) # remove deployment file also.
2844 import activegrid.server.secutils as secutils
2845 keystoreFilePath = os.path.join(os.path.dirname(deploymentFilePath), secutils.AGKEYSTORE_FILENAME)
2846 filesInProject.append(keystoreFilePath) # remove keystore file also.
2847
2848 # don't remove self prematurely
2849 filePath = doc.GetFilename()
2850 if filePath in filesInProject:
2851 filesInProject.remove(filePath)
2852
2853 # don't close/delete files outside of project's directory
2854 homeDir = doc.GetModel().homeDir + os.sep
2855 for filePath in filesInProject[:]:
2856 fileDir = os.path.dirname(filePath) + os.sep
2857 if not fileDir.startswith(homeDir):
2858 filesInProject.remove(filePath)
2859
2860 if closeFiles:
2861 # close any open views of documents in the project
2862 openDocs = self.GetDocumentManager().GetDocuments()[:] # need copy or docs shift when closed
2863 for d in openDocs:
2864 if d.GetFilename() in filesInProject:
2865 d.Modify(False) # make sure it doesn't ask to save the file
2866 if isinstance(d.GetDocumentTemplate(), ProjectTemplate): # if project, remove from project list drop down
2867 if self.GetDocumentManager().CloseDocument(d, True):
2868 self.RemoveProjectUpdate(d)
2869 else: # regular file
2870 self.GetDocumentManager().CloseDocument(d, True)
2871
2872 # remove files in project from file system
2873 if delFiles:
2874 dirPaths = []
2875 for filePath in filesInProject:
2876 if os.path.isfile(filePath):
2877 try:
2878 dirPath = os.path.dirname(filePath)
2879 if dirPath not in dirPaths:
2880 dirPaths.append(dirPath)
2881
2882 os.remove(filePath)
2883 except:
2884 wx.MessageBox("Could not delete file '%s'.\n%s" % (filePath, sys.exc_value),
2885 _("Delete Project"),
2886 wx.OK | wx.ICON_EXCLAMATION,
2887 self.GetFrame())
2888
2889 filePath = doc.GetFilename()
2890
2891 self.ClearFolderState() # remove from registry folder settings
2892
2893 # close project
2894 if doc:
2895 doc.Modify(False) # make sure it doesn't ask to save the project
2896 if self.GetDocumentManager().CloseDocument(doc, True):
2897 self.RemoveCurrentDocumentUpdate()
2898
2899 # remove project file
2900 if delFiles:
2901 dirPath = os.path.dirname(filePath)
2902 if dirPath not in dirPaths:
2903 dirPaths.append(dirPath)
2904 if os.path.isfile(filePath):
2905 try:
2906 os.remove(filePath)
2907 except:
2908 wx.MessageBox("Could not delete project file '%s'.\n%s" % (filePath, sys.exc_value),
2909 _("Delete Prjoect"),
2910 wx.OK | wx.ICON_EXCLAMATION,
2911 self.GetFrame())
2912
2913 # remove empty directories from file system
2914 if delFiles:
2915 dirPaths.sort() # sorting puts parent directories ahead of child directories
2916 dirPaths.reverse() # remove child directories first
2917
2918 for dirPath in dirPaths:
2919 if os.path.isdir(dirPath):
2920 files = os.listdir(dirPath)
2921 if not files:
2922 try:
2923 os.rmdir(dirPath)
2924 except:
2925 wx.MessageBox("Could not delete empty directory '%s'.\n%s" % (dirPath, sys.exc_value),
2926 _("Delete Project"),
2927 wx.OK | wx.ICON_EXCLAMATION,
2928 self.GetFrame())
2929
2930
2931 def OnKeyPressed(self, event):
2932 key = event.KeyCode()
2933 if key == wx.WXK_DELETE:
2934 self.OnClear(event)
2935 else:
2936 event.Skip()
2937
2938
2939 def OnSelectAll(self, event):
2940 project = self.GetDocument()
2941 if project:
2942 self.DoSelectAll(self._treeCtrl.GetRootItem())
2943
2944
2945 def DoSelectAll(self, parentItem):
2946 (child, cookie) = self._treeCtrl.GetFirstChild(parentItem)
2947 while child.IsOk():
2948 if self._IsItemFile(child):
2949 self._treeCtrl.SelectItem(child)
2950 else:
2951 self.DoSelectAll(child)
2952 (child, cookie) = self._treeCtrl.GetNextChild(parentItem, cookie)
2953
2954
2955 def OnOpenSelectionSDI(self, event):
2956 # Do a call after so that the second mouseclick on a doubleclick doesn't reselect the project window
2957 wx.CallAfter(self.OnOpenSelection, None)
2958
2959
2960 def OnOpenSelection(self, event):
2961 doc = None
2962 try:
2963 items = self._treeCtrl.GetSelections()[:]
2964 for item in items:
2965 filepath = self._GetItemFilePath(item)
2966 if filepath:
2967 if not os.path.exists(filepath):
2968 msgTitle = wx.GetApp().GetAppName()
2969 if not msgTitle:
2970 msgTitle = _("File Not Found")
2971 yesNoMsg = wx.MessageDialog(self.GetFrame(),
2972 _("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)),
2973 msgTitle,
2974 wx.YES_NO|wx.ICON_QUESTION
2975 )
2976 yesNoMsg.CenterOnParent()
2977 status = yesNoMsg.ShowModal()
2978 yesNoMsg.Destroy()
2979 if status == wx.ID_NO:
2980 continue
2981 findFileDlg = wx.FileDialog(self.GetFrame(),
2982 _("Choose a file"),
2983 defaultFile=wx.lib.docview.FileNameFromPath(filepath),
2984 style=wx.OPEN|wx.FILE_MUST_EXIST|wx.CHANGE_DIR
2985 )
2986 # findFileDlg.CenterOnParent() # wxBug: caused crash with wx.FileDialog
2987 if findFileDlg.ShowModal() == wx.ID_OK:
2988 newpath = findFileDlg.GetPath()
2989 else:
2990 newpath = None
2991 findFileDlg.Destroy()
2992 if newpath:
2993 # update Project Model with new location
2994 self.GetDocument().UpdateFilePath(filepath, newpath)
2995 filepath = newpath
2996
2997 doc = self.GetDocumentManager().CreateDocument(filepath, wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE)
2998 if not doc and filepath.endswith(PROJECT_EXTENSION): # project already open
2999 self.SetProject(filepath)
3000 elif doc:
3001 AddProjectMapping(doc)
3002
3003
3004 except IOError, (code, message):
3005 msgTitle = wx.GetApp().GetAppName()
3006 if not msgTitle:
3007 msgTitle = _("File Error")
3008 wx.MessageBox("Could not open '%s'." % wx.lib.docview.FileNameFromPath(filepath),
3009 msgTitle,
3010 wx.OK | wx.ICON_EXCLAMATION,
3011 self.GetFrame())
3012
3013
3014 #----------------------------------------------------------------------------
3015 # Convenience methods
3016 #----------------------------------------------------------------------------
3017
3018 def _HasFiles(self):
3019 if not self._treeCtrl:
3020 return False
3021 return self._treeCtrl.GetCount() > 1 # 1 item = root item, don't count as having files
3022
3023
3024 def _HasFilesSelected(self):
3025 if not self._treeCtrl:
3026 return False
3027 items = self._treeCtrl.GetSelections()
3028 if not items:
3029 return False
3030 for item in items:
3031 if self._IsItemFile(item):
3032 return True
3033 return False
3034
3035
3036 def _HasFoldersSelected(self):
3037 if not self._treeCtrl:
3038 return False
3039 items = self._treeCtrl.GetSelections()
3040 if not items:
3041 return False
3042 for item in items:
3043 if self._IsItemFile(item):
3044 return False
3045 return True
3046
3047
3048 def _MakeProjectName(self, project):
3049 return project.GetPrintableName()
3050
3051
3052 def _GetItemFilePath(self, item):
3053 file = self._GetItemFile(item)
3054 if file:
3055 return file.filePath
3056 else:
3057 return None
3058
3059
3060 def _GetItemFolderPath(self, item):
3061 rootItem = self._treeCtrl.GetRootItem()
3062 if item == rootItem:
3063 return ""
3064
3065 if self._IsItemFile(item):
3066 item = self._treeCtrl.GetItemParent(item)
3067
3068 folderPath = ""
3069 while item != rootItem:
3070 if folderPath:
3071 folderPath = self._treeCtrl.GetItemText(item) + "/" + folderPath
3072 else:
3073 folderPath = self._treeCtrl.GetItemText(item)
3074 item = self._treeCtrl.GetItemParent(item)
3075
3076 return folderPath
3077
3078
3079 def _GetItemFile(self, item):
3080 return self._treeCtrl.GetPyData(item)
3081
3082
3083 def _IsItemFile(self, item):
3084 return self._GetItemFile(item) != None
3085
3086
3087 def _IsItemProcessModelFile(self, item):
3088 if ACTIVEGRID_BASE_IDE:
3089 return False
3090
3091 if self._IsItemFile(item):
3092 filepath = self._GetItemFilePath(item)
3093 ext = None
3094 for template in self.GetDocumentManager().GetTemplates():
3095 if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
3096 ext = template.GetDefaultExtension()
3097 break;
3098 if not ext:
3099 return False
3100
3101 if filepath.endswith(ext):
3102 return True
3103
3104 return False
3105
3106
3107 def _GetChildItems(self, parentItem):
3108 children = []
3109 (child, cookie) = self._treeCtrl.GetFirstChild(parentItem)
3110 while child.IsOk():
3111 children.append(child)
3112 (child, cookie) = self._treeCtrl.GetNextChild(parentItem, cookie)
3113 return children
3114
3115
3116 def _GetFolderItems(self, parentItem):
3117 folderItems = []
3118 childrenItems = self._GetChildItems(parentItem)
3119 for childItem in childrenItems:
3120 if not self._IsItemFile(childItem):
3121 folderItems.append(childItem)
3122 folderItems += self._GetFolderItems(childItem)
3123 return folderItems
3124
3125
3126 class ProjectFileDropTarget(wx.FileDropTarget):
3127
3128 def __init__(self, view):
3129 wx.FileDropTarget.__init__(self)
3130 self._view = view
3131
3132
3133 def OnDropFiles(self, x, y, filePaths):
3134 """ Do actual work of dropping files into project """
3135 if self._view.GetDocument():
3136 folderPath = None
3137 if self._view.GetMode() == ProjectView.LOGICAL_MODE:
3138 folderItem = self._view._treeCtrl.FindClosestFolder(x,y)
3139 if folderItem:
3140 folderPath = self._view._GetItemFolderPath(folderItem)
3141 self._view.DoAddFilesToProject(filePaths, folderPath)
3142 return True
3143 return False
3144
3145
3146 def OnDragOver(self, x, y, default):
3147 """ Feedback to show copy cursor if copy is allowed """
3148 if self._view.GetDocument(): # only allow drop if project exists
3149 return wx.DragCopy
3150 return wx.DragNone
3151
3152
3153 class ProjectPropertiesDialog(wx.Dialog):
3154 RELATIVE_TO_PROJECT_FILE = _("relative to project file")
3155
3156 def __init__(self, parent, document):
3157 wx.Dialog.__init__(self, parent, -1, _("Project Properties"), size = (310, 330))
3158
3159 filePropertiesService = wx.GetApp().GetService(wx.lib.pydocview.FilePropertiesService)
3160
3161 notebook = wx.Notebook(self, -1)
3162
3163 tab = wx.Panel(notebook, -1)
3164 gridSizer = wx.FlexGridSizer(cols = 2, vgap = SPACE, hgap = SPACE)
3165 gridSizer.AddGrowableCol(1)
3166 gridSizer.Add(wx.StaticText(tab, -1, _("Filename:")))
3167 filename = document.GetFilename()
3168 if os.path.isfile(filename):
3169 gridSizer.Add(wx.StaticText(tab, -1, os.path.split(filename)[1]))
3170
3171 gridSizer.Add(wx.StaticText(tab, -1, _("Location:")))
3172 gridSizer.Add(wx.StaticText(tab, -1, filePropertiesService.chopPath(os.path.dirname(filename), length=50)))
3173
3174 gridSizer.Add(wx.StaticText(tab, -1, _("Size:")))
3175 gridSizer.Add(wx.StaticText(tab, -1, str(os.path.getsize(filename)) + ' ' + _("bytes")))
3176
3177 lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
3178 lineSizer.Add(wx.StaticLine(tab, -1, size = (10,-1)), 0, wx.EXPAND)
3179 gridSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.TOP)
3180
3181 lineSizer = wx.BoxSizer(wx.VERTICAL) # let the line expand horizontally without vertical expansion
3182 lineSizer.Add(wx.StaticLine(tab, -1, size = (10,-1)), 0, wx.EXPAND)
3183 gridSizer.Add(lineSizer, flag=wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.TOP)
3184
3185 gridSizer.Add(wx.StaticText(tab, -1, _("Created:")))
3186 gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getctime(filename))))
3187
3188 gridSizer.Add(wx.StaticText(tab, -1, _("Modified:")))
3189 gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getmtime(filename))))
3190
3191 gridSizer.Add(wx.StaticText(tab, -1, _("Accessed:")))
3192 gridSizer.Add(wx.StaticText(tab, -1, time.ctime(os.path.getatime(filename))))
3193 else:
3194 gridSizer.Add(wx.StaticText(tab, -1, os.path.split(filename)[1] + ' ' + _("[new project]")))
3195 spacerGrid = wx.BoxSizer(wx.HORIZONTAL) # add a border around the inside of the tab
3196 spacerGrid.Add(gridSizer, 1, wx.ALL|wx.EXPAND, SPACE);
3197 tab.SetSizer(spacerGrid)
3198 notebook.AddPage(tab, _("General"))
3199
3200 tab = wx.Panel(notebook, -1)
3201 spacerGrid = wx.BoxSizer(wx.VERTICAL) # add a border around the inside of the tab
3202 homePathLabel = wx.StaticText(tab, -1, _("Home Dir:"))
3203 if document.GetModel().isDefaultHomeDir:
3204 defaultHomeDir = ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE
3205 else:
3206 defaultHomeDir = document.GetModel().homeDir
3207 self._homeDirCtrl = wx.ComboBox(tab, -1, defaultHomeDir, size=(125,-1), choices=[ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE, document.GetModel().homeDir])
3208 self._homeDirCtrl.SetToolTipString(self._homeDirCtrl.GetValue())
3209 if not document.GetModel().isDefaultHomeDir:
3210 self._homeDirCtrl.SetInsertionPointEnd()
3211 def OnDirChanged(event):
3212 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
3213 wx.EVT_COMBOBOX(self._homeDirCtrl, -1, OnDirChanged)
3214 wx.EVT_TEXT(self._homeDirCtrl, -1, OnDirChanged)
3215 choosePathButton = wx.Button(tab, -1, _("Browse..."))
3216 def OnBrowseButton(event):
3217 if self._homeDirCtrl.GetValue() == ProjectPropertiesDialog.RELATIVE_TO_PROJECT_FILE:
3218 defaultHomeDir = document.GetModel().homeDir
3219 else:
3220 defaultHomeDir = self._homeDirCtrl.GetValue()
3221
3222 dlg = wx.DirDialog(self, "Choose a directory:", defaultHomeDir,
3223 style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
3224 if dlg.ShowModal() == wx.ID_OK:
3225 self._homeDirCtrl.SetValue(dlg.GetPath())
3226 self._homeDirCtrl.SetInsertionPointEnd()
3227 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
3228 dlg.Destroy()
3229 wx.EVT_BUTTON(choosePathButton, -1, OnBrowseButton)
3230 pathSizer = wx.BoxSizer(wx.HORIZONTAL)
3231 pathSizer.Add(homePathLabel, 0, wx.ALIGN_CENTER_VERTICAL)
3232 pathSizer.Add(self._homeDirCtrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND|wx.LEFT, HALF_SPACE)
3233 pathSizer.Add(choosePathButton, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, SPACE)
3234 spacerGrid.Add(pathSizer, 0, wx.ALL|wx.EXPAND, SPACE);
3235 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."))
3236 spacerGrid.Add(instructionText, 0, wx.ALL, SPACE);
3237 tab.SetSizer(spacerGrid)
3238 notebook.AddPage(tab, _("Physical View"))
3239
3240 if wx.Platform == "__WXMSW__":
3241 notebook.SetPageSize((310,300))
3242
3243 if not ACTIVEGRID_BASE_IDE:
3244 tab = wx.Panel(notebook, -1)
3245 self._appInfoCtrl = PropertyService.PropertyCtrl(tab, header=False)
3246 self._appInfoCtrl.SetDocument(document)
3247 self._appInfoCtrl.SetModel(document.GetAppInfo())
3248 sizer = wx.BoxSizer(wx.HORIZONTAL)
3249 sizer.Add(self._appInfoCtrl, 1, wx.EXPAND|wx.ALL, PropertyService.LEAVE_MARGIN)
3250 tab.SetSizer(sizer)
3251 notebook.AddPage(tab, _("App Info"))
3252 self._appInfoCtrl._grid.AutoSizeColumns()
3253
3254
3255 sizer = wx.BoxSizer(wx.VERTICAL)
3256 sizer.Add(notebook, 0, wx.ALL | wx.EXPAND, SPACE)
3257 sizer.Add(self.CreateButtonSizer(wx.OK | wx.CANCEL), 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, HALF_SPACE)
3258
3259 self.SetSizer(sizer)
3260 sizer.Fit(self)
3261 self.Layout()
3262
3263
3264 class ProjectOptionsPanel(wx.Panel):
3265
3266
3267 def __init__(self, parent, id):
3268 wx.Panel.__init__(self, parent, id)
3269 self._useSashMessageShown = False
3270 config = wx.ConfigBase_Get()
3271 self._projSaveDocsCheckBox = wx.CheckBox(self, -1, _("Remember open projects"))
3272 self._projSaveDocsCheckBox.SetValue(config.ReadInt("ProjectSaveDocs", True))
3273 projectBorderSizer = wx.BoxSizer(wx.VERTICAL)
3274 projectSizer = wx.BoxSizer(wx.VERTICAL)
3275 projectSizer.Add(self._projSaveDocsCheckBox, 0, wx.ALL, HALF_SPACE)
3276 if not ACTIVEGRID_BASE_IDE:
3277 self._projShowWelcomeCheckBox = wx.CheckBox(self, -1, _("Show Welcome Dialog"))
3278 self._projShowWelcomeCheckBox.SetValue(config.ReadInt("RunWelcomeDialog2", True))
3279 projectSizer.Add(self._projShowWelcomeCheckBox, 0, wx.ALL, HALF_SPACE)
3280
3281 sizer = wx.BoxSizer(wx.HORIZONTAL)
3282 sizer.Add(wx.StaticText(self, -1, _("Default language for projects:")), 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, HALF_SPACE)
3283 self._langCtrl = wx.Choice(self, -1, choices=projectmodel.LANGUAGE_LIST)
3284 self._langCtrl.SetStringSelection(config.Read(APP_LAST_LANGUAGE, projectmodel.LANGUAGE_DEFAULT))
3285 self._langCtrl.SetToolTipString(_("Programming language to be used throughout the project."))
3286 sizer.Add(self._langCtrl, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, MAC_RIGHT_BORDER)
3287 projectSizer.Add(sizer, 0, wx.ALL, HALF_SPACE)
3288
3289 projectBorderSizer.Add(projectSizer, 0, wx.ALL, SPACE)
3290 self.SetSizer(projectBorderSizer)
3291 self.Layout()
3292 parent.AddPage(self, _("Project"))
3293
3294
3295 def OnUseSashSelect(self, event):
3296 if not self._useSashMessageShown:
3297 msgTitle = wx.GetApp().GetAppName()
3298 if not msgTitle:
3299 msgTitle = _("Document Options")
3300 wx.MessageBox("Project window embedded mode changes will not appear until the application is restarted.",
3301 msgTitle,
3302 wx.OK | wx.ICON_INFORMATION,
3303 self.GetParent())
3304 self._useSashMessageShown = True
3305
3306
3307 def OnOK(self, optionsDialog):
3308 config = wx.ConfigBase_Get()
3309 config.WriteInt("ProjectSaveDocs", self._projSaveDocsCheckBox.GetValue())
3310 if not ACTIVEGRID_BASE_IDE:
3311 config.WriteInt("RunWelcomeDialog2", self._projShowWelcomeCheckBox.GetValue())
3312 config.Write(APP_LAST_LANGUAGE, self._langCtrl.GetStringSelection())
3313
3314
3315 def GetIcon(self):
3316 return getProjectIcon()
3317
3318
3319 class ProjectService(Service.Service):
3320
3321 #----------------------------------------------------------------------------
3322 # Constants
3323 #----------------------------------------------------------------------------
3324 SHOW_WINDOW = wx.NewId() # keep this line for each subclass, need unique ID for each Service
3325 RUN_SELECTED_PM_ID = wx.NewId()
3326 RUN_SELECTED_PM_INTERNAL_WINDOW_ID = wx.NewId()
3327 RUN_SELECTED_PM_EXTERNAL_BROWSER_ID = wx.NewId()
3328 RUN_CURRENT_PM_ID = wx.NewId()
3329 RUN_CURRENT_PM_INTERNAL_WINDOW_ID = wx.NewId()
3330 RUN_CURRENT_PM_EXTERNAL_BROWSER_ID = wx.NewId()
3331 RENAME_ID = wx.NewId()
3332 OPEN_SELECTION_ID = wx.NewId()
3333 REMOVE_FROM_PROJECT = wx.NewId()
3334 DELETE_FILE_ID = wx.NewId()
3335 ADD_FILES_TO_PROJECT_ID = wx.NewId()
3336 ADD_CURRENT_FILE_TO_PROJECT_ID = wx.NewId()
3337 ADD_DIR_FILES_TO_PROJECT_ID = wx.NewId()
3338 CLOSE_PROJECT_ID = wx.NewId()
3339 PROJECT_PROPERTIES_ID = wx.NewId()
3340 ADD_FOLDER_ID = wx.NewId()
3341 DELETE_PROJECT_ID = wx.NewId()
3342
3343
3344 #----------------------------------------------------------------------------
3345 # Overridden methods
3346 #----------------------------------------------------------------------------
3347
3348 def __init__(self, serviceName, embeddedWindowLocation = wx.lib.pydocview.EMBEDDED_WINDOW_LEFT):
3349 Service.Service.__init__(self, serviceName, embeddedWindowLocation)
3350 self._runHandlers = []
3351 self._suppressOpenProjectMessages = False
3352 self._logicalViewDefaults = []
3353 self._logicalViewOpenDefaults = []
3354 self._fileTypeDefaults = []
3355 self._nameDefaults = []
3356 self._mapToProject = dict()
3357
3358
3359 def _CreateView(self):
3360 return ProjectView(self)
3361
3362
3363 def ShowWindow(self, show = True):
3364 """ Force showing of saved projects on opening, otherwise empty Project Window is disconcerting for user """
3365 Service.Service.ShowWindow(self, show)
3366
3367 if show:
3368 project = self.GetView().GetDocument()
3369 if not project:
3370 self.OpenSavedProjects()
3371
3372
3373 #----------------------------------------------------------------------------
3374 # Service specific methods
3375 #----------------------------------------------------------------------------
3376
3377 def GetSuppressOpenProjectMessages(self):
3378 return self._suppressOpenProjectMessages
3379
3380
3381 def SetSuppressOpenProjectMessages(self, suppressOpenProjectMessages):
3382 self._suppressOpenProjectMessages = suppressOpenProjectMessages
3383
3384
3385 def GetRunHandlers(self):
3386 return self._runHandlers
3387
3388
3389 def AddRunHandler(self, runHandler):
3390 self._runHandlers.append(runHandler)
3391
3392
3393 def RemoveRunHandler(self, runHandler):
3394 self._runHandlers.remove(runHandler)
3395
3396
3397 def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
3398 Service.Service.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
3399
3400 projectMenu = wx.Menu()
3401
3402 ## accelTable = wx.AcceleratorTable([
3403 ## eval(_("wx.ACCEL_CTRL, ord('R'), ProjectService.RUN_ID"))
3404 ## ])
3405 ## frame.SetAcceleratorTable(accelTable)
3406 isProjectDocument = document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument
3407 if wx.GetApp().IsMDI() or isProjectDocument:
3408 if not menuBar.FindItemById(ProjectService.ADD_FILES_TO_PROJECT_ID):
3409 projectMenu.Append(ProjectService.ADD_FILES_TO_PROJECT_ID, _("Add &Files to Project..."), _("Adds a document to the current project"))
3410 wx.EVT_MENU(frame, ProjectService.ADD_FILES_TO_PROJECT_ID, frame.ProcessEvent)
3411 wx.EVT_UPDATE_UI(frame, ProjectService.ADD_FILES_TO_PROJECT_ID, frame.ProcessUpdateUIEvent)
3412 if not menuBar.FindItemById(ProjectService.ADD_DIR_FILES_TO_PROJECT_ID):
3413 projectMenu.Append(ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, _("Add Directory Files to Project..."), _("Adds a directory's documents to the current project"))
3414 wx.EVT_MENU(frame, ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, frame.ProcessEvent)
3415 wx.EVT_UPDATE_UI(frame, ProjectService.ADD_DIR_FILES_TO_PROJECT_ID, frame.ProcessUpdateUIEvent)
3416 if not menuBar.FindItemById(ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID):
3417 projectMenu.Append(ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, _("&Add Active File to Project..."), _("Adds the active document to a project"))
3418 wx.EVT_MENU(frame, ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, frame.ProcessEvent)
3419 wx.EVT_UPDATE_UI(frame, ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, frame.ProcessUpdateUIEvent)
3420 if not menuBar.FindItemById(ProjectService.ADD_FOLDER_ID):
3421 projectMenu.Append(ProjectService.ADD_FOLDER_ID, _("New Folder"), _("Creates a new folder"))
3422 wx.EVT_MENU(frame, ProjectService.ADD_FOLDER_ID, frame.ProcessEvent)
3423 wx.EVT_UPDATE_UI(frame, ProjectService.ADD_FOLDER_ID, frame.ProcessUpdateUIEvent)
3424 if not menuBar.FindItemById(ProjectService.CLOSE_PROJECT_ID):
3425 projectMenu.AppendSeparator()
3426 projectMenu.Append(ProjectService.CLOSE_PROJECT_ID, _("Close Project"), _("Closes currently open project"))
3427 wx.EVT_MENU(frame, ProjectService.CLOSE_PROJECT_ID, frame.ProcessEvent)
3428 wx.EVT_UPDATE_UI(frame, ProjectService.CLOSE_PROJECT_ID, frame.ProcessUpdateUIEvent)
3429 if not menuBar.FindItemById(ProjectService.DELETE_PROJECT_ID):
3430 projectMenu.Append(ProjectService.DELETE_PROJECT_ID, _("Delete Project..."), _("Delete currently open project and its files."))
3431 wx.EVT_MENU(frame, ProjectService.DELETE_PROJECT_ID, frame.ProcessEvent)
3432 wx.EVT_UPDATE_UI(frame, ProjectService.DELETE_PROJECT_ID, frame.ProcessUpdateUIEvent)
3433 if not menuBar.FindItemById(ProjectService.PROJECT_PROPERTIES_ID):
3434 projectMenu.AppendSeparator()
3435 projectMenu.Append(ProjectService.PROJECT_PROPERTIES_ID, _("Project Properties"), _("Project Properties"))
3436 wx.EVT_MENU(frame, ProjectService.PROJECT_PROPERTIES_ID, frame.ProcessEvent)
3437 wx.EVT_UPDATE_UI(frame, ProjectService.PROJECT_PROPERTIES_ID, frame.ProcessUpdateUIEvent)
3438 index = menuBar.FindMenu(_("&Format"))
3439 if index == -1:
3440 index = menuBar.FindMenu(_("&View"))
3441 menuBar.Insert(index + 1, projectMenu, _("&Project"))
3442 editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit")))
3443 if not menuBar.FindItemById(ProjectService.RENAME_ID):
3444 editMenu.Append(ProjectService.RENAME_ID, _("&Rename"), _("Renames the active item"))
3445 wx.EVT_MENU(frame, ProjectService.RENAME_ID, frame.ProcessEvent)
3446 wx.EVT_UPDATE_UI(frame, ProjectService.RENAME_ID, frame.ProcessUpdateUIEvent)
3447 if not menuBar.FindItemById(ProjectService.DELETE_FILE_ID):
3448 editMenu.Append(ProjectService.DELETE_FILE_ID, _("Delete File"), _("Delete the file from the project and file system."))
3449 wx.EVT_MENU(frame, ProjectService.DELETE_FILE_ID, frame.ProcessEvent)
3450 wx.EVT_UPDATE_UI(frame, ProjectService.DELETE_FILE_ID, frame.ProcessUpdateUIEvent)
3451
3452 return True
3453
3454
3455 def OnCloseFrame(self, event):
3456 if not self.GetView():
3457 return True
3458
3459 if wx.GetApp().IsMDI():
3460 # close all non-project documents first
3461 for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted
3462 if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
3463 if not self.GetDocumentManager().CloseDocument(document, False):
3464 return False
3465
3466 # write project config afterwards because user may change filenames on closing of new documents
3467 self.GetView().WriteProjectConfig() # Called onCloseWindow in all of the other services but needed to be factored out for ProjectService since it is called elsewhere
3468
3469 # close all project documents after closing other documents
3470 # because user may save a new document with a new name or cancel closing a document
3471 for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted
3472 if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
3473 if not document.OnSaveModified():
3474 return False
3475
3476 # This is called when any SDI frame is closed, so need to check if message window is closing or some other window
3477 elif self.GetView() == event.GetEventObject().GetView():
3478 self.SetView(None)
3479 return True
3480
3481
3482 #----------------------------------------------------------------------------
3483 # Document Manager Methods
3484 #----------------------------------------------------------------------------
3485
3486 def FindProjectFromMapping(self, key):
3487 """ Find which project a model or document belongs to """
3488 return self._mapToProject.get(key)
3489
3490
3491 def AddProjectMapping(self, key, projectDoc=None):
3492 """ Generate a mapping from model or document to project. If no project given, use current project.
3493 e.g. Which project does this model or document belong to (when it was opened)?
3494 """
3495 if not projectDoc:
3496 projectDoc = self.GetCurrentProject()
3497 self._mapToProject[key] = projectDoc
3498
3499
3500 def RemoveProjectMapping(self, key):
3501 """ Remove mapping from model or document to project. """
3502 if self._mapToProject.has_key(key):
3503 del self._mapToProject[key]
3504
3505
3506 #----------------------------------------------------------------------------
3507 # Default Logical View Folder Methods
3508 #----------------------------------------------------------------------------
3509
3510 def AddLogicalViewFolderDefault(self, pattern, folder):
3511 self._logicalViewDefaults.append((pattern, folder))
3512
3513
3514 def FindLogicalViewFolderDefault(self, filename):
3515 for (pattern, folder) in self._logicalViewDefaults:
3516 if filename.endswith(pattern):
3517 return folder
3518 return None
3519
3520
3521 def AddLogicalViewFolderCollapsedDefault(self, folderName, collapsed=True):
3522 # default is collapsed, don't add to list if collapse is True
3523 if not collapsed:
3524 self._logicalViewOpenDefaults.append(folderName)
3525
3526
3527 def FindLogicalViewFolderCollapsedDefault(self, folderName):
3528 if folderName in self._logicalViewOpenDefaults:
3529 return False
3530 return True
3531
3532
3533 #----------------------------------------------------------------------------
3534 # Default File Type Methods
3535 #----------------------------------------------------------------------------
3536
3537 def AddFileTypeDefault(self, pattern, type):
3538 self._fileTypeDefaults.append((pattern, type))
3539
3540
3541 def FindFileTypeDefault(self, filename):
3542 for (pattern, type) in self._fileTypeDefaults:
3543 if filename.endswith(pattern):
3544 return type
3545 return None
3546
3547
3548 #----------------------------------------------------------------------------
3549 # Default Name Methods
3550 #----------------------------------------------------------------------------
3551
3552 def AddNameDefault(self, pattern, method):
3553 self._nameDefaults.append((pattern, method))
3554
3555
3556 def FindNameDefault(self, filename):
3557 for (pattern, method) in self._nameDefaults:
3558 if filename.endswith(pattern):
3559 return method(filename)
3560 return None
3561
3562
3563 def GetDefaultNameCallback(self, filename):
3564 """ A method for generating name from filepath for Project Service """
3565 return os.path.splitext(os.path.basename(filename))[0]
3566
3567
3568 #----------------------------------------------------------------------------
3569 # Event Processing Methods
3570 #----------------------------------------------------------------------------
3571
3572 def ProcessEventBeforeWindows(self, event):
3573 id = event.GetId()
3574
3575 if id == wx.ID_CLOSE_ALL:
3576 self.OnFileCloseAll(event)
3577 return True
3578 return False
3579
3580
3581 def ProcessUpdateUIEventBeforeWindows(self, event):
3582 id = event.GetId()
3583
3584 if id == wx.ID_CLOSE_ALL:
3585 for document in self.GetDocumentManager().GetDocuments():
3586 if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
3587 event.Enable(True)
3588 return True
3589
3590 event.Enable(False)
3591 return True
3592
3593 elif id == wx.ID_CLOSE:
3594 # "File | Close" is too confusing and hard to determine whether user wants to close a viewed file or the current project.
3595 # Disallow "File | Close" if project is current document or active in project view.
3596 # User must explicitly close project via "Project | Close Current Project".
3597 document = self.GetDocumentManager().GetCurrentDocument()
3598 if document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
3599 event.Enable(False)
3600 return True
3601 if self.GetView().ProcessUpdateUIEvent(event):
3602 return True
3603
3604 return False
3605
3606
3607 def ProcessEvent(self, event):
3608 if Service.Service.ProcessEvent(self, event):
3609 return True
3610
3611 id = event.GetId()
3612 if id == ProjectService.RUN_SELECTED_PM_ID:
3613 self.OnRunProcessModel(event, runSelected=True)
3614 return True
3615 elif id == ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID:
3616 self.OnRunProcessModel(event, runSelected=True, newWindow=True, forceInternal=True)
3617 return True
3618 elif id == ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID:
3619 self.OnRunProcessModel(event, runSelected=True, newWindow=True, forceExternal=True)
3620 return True
3621 elif id == ProjectService.RUN_CURRENT_PM_ID:
3622 self.OnRunProcessModel(event, runCurrentFile=True)
3623 return True
3624 elif id == ProjectService.RUN_CURRENT_PM_INTERNAL_WINDOW_ID:
3625 self.OnRunProcessModel(event, runCurrentFile=True, newWindow=True, forceInternal=True)
3626 return True
3627 elif id == ProjectService.RUN_CURRENT_PM_EXTERNAL_BROWSER_ID:
3628 self.OnRunProcessModel(event, runCurrentFile=True, newWindow=True, forceExternal=True)
3629 return True
3630 elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
3631 self.OnAddCurrentFileToProject(event)
3632 return True
3633 elif (id == ProjectService.PROJECT_PROPERTIES_ID
3634 or id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID
3635 or id == ProjectService.ADD_FOLDER_ID
3636 or id == ProjectService.DELETE_PROJECT_ID
3637 or id == ProjectService.CLOSE_PROJECT_ID):
3638 if self.GetView():
3639 return self.GetView().ProcessEvent(event)
3640 else:
3641 return False
3642 else:
3643 return False
3644
3645
3646 def ProcessUpdateUIEvent(self, event):
3647 if Service.Service.ProcessUpdateUIEvent(self, event):
3648 return True
3649
3650 id = event.GetId()
3651 if id in [ProjectService.RUN_SELECTED_PM_ID,
3652 ProjectService.RUN_SELECTED_PM_INTERNAL_WINDOW_ID,
3653 ProjectService.RUN_SELECTED_PM_EXTERNAL_BROWSER_ID,
3654 ProjectService.RUN_CURRENT_PM_ID,
3655 ProjectService.RUN_CURRENT_PM_INTERNAL_WINDOW_ID,
3656 ProjectService.RUN_CURRENT_PM_EXTERNAL_BROWSER_ID]:
3657 event.Enable(True)
3658 return True
3659 elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID:
3660 event.Enable(self._CanAddCurrentFileToProject())
3661 return True
3662 elif id in [ProjectService.ADD_FILES_TO_PROJECT_ID,
3663 ProjectService.ADD_DIR_FILES_TO_PROJECT_ID,
3664 ProjectService.RENAME_ID,
3665 ProjectService.OPEN_SELECTION_ID,
3666 ProjectService.DELETE_FILE_ID]:
3667 event.Enable(False)
3668 return True
3669 elif id == ProjectService.PROJECT_PROPERTIES_ID:
3670 event.Enable(self._HasOpenedProjects())
3671 return True
3672 elif id in [wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID,
3673 ProjectService.ADD_FOLDER_ID,
3674 ProjectService.DELETE_PROJECT_ID,
3675 ProjectService.CLOSE_PROJECT_ID]:
3676 if self.GetView():
3677 return self.GetView().ProcessUpdateUIEvent(event)
3678 else:
3679 return False
3680 else:
3681 return False
3682
3683
3684 def OnRunProcessModel(self, event, runSelected=False, runCurrentFile=False, newWindow=False, forceExternal=False, forceInternal=False):
3685 project = self.GetCurrentProject()
3686
3687 if runCurrentFile:
3688 doc = self.GetDocumentManager().GetCurrentDocument()
3689 if not doc or not hasattr(doc, "GetFilename"):
3690 return
3691 fileToRun = doc.GetFilename()
3692 projects = self.FindProjectByFile(fileToRun)
3693 if not projects:
3694 return
3695 elif project in projects:
3696 # use current project
3697 pass
3698 elif len(projects) == 1:
3699 # only one project, display it
3700 project = projects[0]
3701 self.GetView().SetProject(project.GetFilename())
3702 elif len(projects) > 1:
3703 strings = map(lambda file: os.path.basename(file.GetFilename()), projects)
3704 res = wx.GetSingleChoiceIndex(_("More than one project uses '%s'. Select project to run:") % os.path.basename(fileToRun),
3705 _("Select Project"),
3706 strings,
3707 self.GetView()._GetParentFrame())
3708 if res == -1:
3709 return
3710 project = projects[res]
3711 self.GetView().SetProject(project.GetFilename())
3712
3713 if project:
3714 ext = None
3715 for template in self.GetDocumentManager().GetTemplates():
3716 if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
3717 ext = template.GetDefaultExtension()
3718 break;
3719 if not ext:
3720 return
3721
3722 files = filter(lambda f: f.endswith(ext), project.GetFiles())
3723 if not files:
3724 return
3725
3726 docs = wx.GetApp().GetDocumentManager().GetDocuments()
3727
3728 filesModified = False
3729 for doc in docs:
3730 if doc.IsModified():
3731 filesModified = True
3732 break
3733 if filesModified:
3734 frame = self.GetView().GetFrame()
3735 yesNoMsg = wx.MessageDialog(frame,
3736 _("Files have been modified. Process may not reflect your current changes.\n\nWould you like to save all files before running?"),
3737 _("Run Process"),
3738 wx.YES_NO|wx.ICON_QUESTION
3739 )
3740 yesNoMsg.CenterOnParent()
3741 status = yesNoMsg.ShowModal()
3742 yesNoMsg.Destroy()
3743 if status == wx.ID_YES:
3744 wx.GetTopLevelParent(frame).OnFileSaveAll(None)
3745
3746 if runCurrentFile:
3747 fileToRun = self.GetDocumentManager().GetCurrentDocument().GetFilename()
3748 elif runSelected:
3749 fileToRun = self.GetView().GetSelectedFile()
3750 elif len(files) > 1:
3751 files.sort(lambda a, b: cmp(os.path.basename(a).lower(), os.path.basename(b).lower()))
3752 strings = map(lambda file: os.path.basename(file), files)
3753 res = wx.GetSingleChoiceIndex(_("Select a process to run:"),
3754 _("Run"),
3755 strings,
3756 self.GetView()._GetParentFrame())
3757 if res == -1:
3758 return
3759 fileToRun = files[res]
3760 else:
3761 fileToRun = files[0]
3762
3763 try:
3764 deployFilePath = project.GenerateDeployment()
3765 except DataServiceExistenceException, e:
3766 dataSourceName = str(e)
3767 self.PromptForMissingDataSource(dataSourceName)
3768 return
3769 self.RunProcessModel(fileToRun, project.GetAppInfo().language, deployFilePath, newWindow, forceExternal, forceInternal)
3770
3771
3772 def RunProcessModel(self, fileToRun, language, deployFilePath, newWindow=True, forceExternal=False, forceInternal=False):
3773 for runHandler in self.GetRunHandlers():
3774 if runHandler.RunProjectFile(fileToRun, language, deployFilePath, newWindow, forceExternal, forceInternal):
3775 return
3776 os.system('"' + fileToRun + '"')
3777
3778
3779 def _HasProcessModel(self):
3780 project = self.GetView().GetDocument()
3781
3782 if project:
3783 ext = None
3784 for template in self.GetDocumentManager().GetTemplates():
3785 if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
3786 ext = template.GetDefaultExtension()
3787 break;
3788 if not ext:
3789 return False
3790
3791 files = filter(lambda f: f.endswith(ext), project.GetFiles())
3792 if not files:
3793 return False
3794
3795 if len(files):
3796 return True
3797
3798 return False
3799
3800
3801 def _HasOpenedProjects(self):
3802 for document in self.GetDocumentManager().GetDocuments():
3803 if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
3804 return True
3805 return False
3806
3807
3808 def _CanAddCurrentFileToProject(self):
3809 currentDoc = self.GetDocumentManager().GetCurrentDocument()
3810 if not currentDoc:
3811 return False
3812 if currentDoc.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
3813 return False
3814 if not currentDoc._savedYet:
3815 return False
3816 if self.GetView().GetDocument(): # a project is open
3817 return True
3818 return False # There are no documents open
3819
3820
3821 def GetFilesFromCurrentProject(self):
3822 view = self.GetView()
3823 if view:
3824 project = view.GetDocument()
3825 if project:
3826 return project.GetFiles()
3827 return None
3828
3829
3830 def GetCurrentProject(self):
3831 view = self.GetView()
3832 if view:
3833 return view.GetDocument()
3834 return None
3835
3836
3837 def GetOpenProjects(self):
3838 retval = []
3839 for document in self.GetDocumentManager().GetDocuments():
3840 if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
3841 retval.append(document)
3842 return retval
3843
3844
3845 def FindProjectByFile(self, filename):
3846 retval = []
3847 for document in self.GetDocumentManager().GetDocuments():
3848 if document.GetDocumentTemplate().GetDocumentType() == ProjectDocument:
3849 if document.GetFilename() == filename:
3850 retval.append(document)
3851 elif document.IsFileInProject(filename):
3852 retval.append(document)
3853
3854 # make sure current project is first in list
3855 currProject = self.GetCurrentProject()
3856 if currProject and currProject in retval:
3857 retval.remove(currProject)
3858 retval.insert(0, currProject)
3859
3860 return retval
3861
3862
3863 def OnAddCurrentFileToProject(self, event):
3864 doc = self.GetDocumentManager().GetCurrentDocument()
3865 file = doc.GetFilename()
3866 projectDoc = self.GetView().GetDocument()
3867 projectDoc.GetCommandProcessor().Submit(ProjectAddFilesCommand(projectDoc, [file]))
3868
3869 AddProjectMapping(doc, projectDoc)
3870
3871 self.GetView().Activate() # after add, should put focus on project editor
3872
3873
3874 def OnFileCloseAll(self, event):
3875 for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted
3876 if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument:
3877 if not self.GetDocumentManager().CloseDocument(document, False):
3878 return
3879 # document.DeleteAllViews() # Implicitly delete the document when the last view is removed
3880
3881
3882 def OpenSavedProjects(self):
3883 config = wx.ConfigBase_Get()
3884 openedDocs = False
3885 if config.ReadInt("ProjectSaveDocs", True):
3886 docString = config.Read("ProjectSavedDocs")
3887 if docString:
3888 doc = None
3889 docList = eval(docString)
3890 self.GetView()._treeCtrl.Freeze()
3891
3892 for fileName in docList:
3893 if isinstance(fileName, types.StringTypes):
3894 if os.path.exists(fileName):
3895 doc = self.GetDocumentManager().CreateDocument(fileName, wx.lib.docview.DOC_SILENT|wx.lib.docview.DOC_OPEN_ONCE)
3896 self.GetView()._treeCtrl.Thaw()
3897
3898 if doc:
3899 openedDocs = True
3900
3901 currProject = config.Read("ProjectCurrent")
3902 if currProject in docList:
3903 self.GetView().SetProject(currProject)
3904
3905 return openedDocs
3906
3907
3908 def PromptForMissingDataSource(self, dataSourceName):
3909 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
3910 msgTitle = "Unknown Data Source"
3911 dataSourceMissingDlg = wx.MessageDialog(self.GetView().GetFrame(), prompt, msgTitle, wx.YES_NO|wx.ICON_QUESTION)
3912 dataSourceMissingDlg.CenterOnParent()
3913 if dataSourceMissingDlg.ShowModal() == wx.ID_YES:
3914 dataSourceMissingDlg.Destroy()
3915 self._AddDataSource(dataSourceName)
3916 else:
3917 dataSourceMissingDlg.Destroy()
3918
3919
3920 def _AddDataSource(self, defaultDataSourceName=None):
3921 dataSourceService = wx.GetApp().GetService(DataModelEditor.DataSourceService)
3922 dsChoices = dataSourceService.getDataSourceNames()
3923 dlg = DataModelEditor.AddDataSourceDialog(self.GetView().GetFrame(), 'Add Data Source', dsChoices, defaultDataSourceName)
3924 dlg.CenterOnParent()
3925 if dlg.ShowModal() == wx.ID_OK:
3926 dataSource = dlg.GetDataSource()
3927 dlg.Destroy()
3928 else:
3929 dlg.Destroy()
3930 return False
3931 if (dataSource == None):
3932 wx.MessageBox(_("Error getting data source."), self._title)
3933 dataSourceService.updateDataSource(dataSource)
3934 if ((dsChoices == None) or (len(dsChoices) <= 0)):
3935 wx.ConfigBase_Get().Write(DataModelEditor.SchemaOptionsPanel.DEFAULT_DATASOURCE_KEY, dataSource.name)
3936 dataSourceService.save()
3937 return True
3938
3939
3940 #----------------------------------------------------------------------------
3941 # Icon Bitmaps - generated by encode_bitmaps.py
3942 #----------------------------------------------------------------------------
3943 from wx import ImageFromStream, BitmapFromImage
3944 import cStringIO
3945
3946
3947 def getProjectData():
3948 return \
3949 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
3950 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
3951 \x00\x01\x89IDAT8\x8d\xa5\x92\xcdJ\x02Q\x18\x86\x9fq&-+H\xd40\x033Bha\x05\
3952 \xfd\xac*[\xb7l\xd1\xae\xfbhQ7\x10\x04A]\x86\xd0&\xba\x01CW\n!B\xa2\x882\x8b\
3953 )R+"\x7fft\x9a\x16\x91\xcd4\xd3\x0f\xf4\xee\xce\xf9\xde\xf7\xe1\xfd\x0eG\x10\
3954 \\"\x9arb\xe8\xcf\x1a\x9d\x9e\n\x80\xd6\xad\x03\x10Z;\x13\xf8ER\xa7xd\x88\
3955 \xbe-D\x1f\xb8\xbf\x0c\xaf\xcf\x15C\xd2k\xf4\xc5(\x92^\x03 \xbe\x9b\xb3@\x85\
3956 n\xe9\xd8h\xde\xe6\x1d\xe9\xfe\xa9E\xc7\xfb\x91\xf9\xfd\x01D\xfa\xc9\xd8\xf7\
3957 \xcdPI\'\x01X\xd8>@p\xf7\x00($W\x8c\x8f&R\xa7\xa7\xa2u\xebL.\xef\xd9\x00\x97\
3958 \xa7\x87D\\er\x15\x95\xb9\xf5\x12\xa3\x81Y\x9bG\xfax0\xb3Z\x8d*\x95t\x92z\
3959 \xb5\x80yjhC\x83\x16\x96\x15\xdc\xc3AZ\x8d\xea{XN#g.,\xa6\xe0l\x9c\xde}\x89\
3960 \xb6\xc3\x9aR\xff\xe5\x01\x801}\x1c\x80\x9b\xcc\x05\xde\xb0\x9f\xd0t\x04oX\
3961 \xa6\xad4\xc9U\n\xc0&\x1e\xfd\xd6\x0e\x18\xd4Se\x00\xbca?m\xa5\xc9\x1d\xd0V\
3962 \x9a\x03\xa3\xd6\xadc\xa8\x8fv\xc0S\xa3H\xc8\x13\x01\xa2\x00\xc4V\x13\x94\
3963 \xb3)\xae\xae\x14\x8b\xd1\x17\x90laK\x03\xb3b\xab\t&\x02\xf7(\xf94\xf2k\x8c\
3964 \x8d\x8dy\xc7\xf0\xb7\x00\x80`t\x92`t\x87%\xa0\x9cM\xd1\xa8}\xce\xcc\xbf\xd1\
3965 \x11P\xce\xa6,\xe7\xaf\xdf\xd7,Ap\x89\x14\x92+\xc6_\x03\x8e\x80\xff\xc8\xf5\
3966 \xaf4\xf0\x06=\xf3\x8fJr]C\xd9\x00\x00\x00\x00IEND\xaeB`\x82'
3967
3968 def getProjectBitmap():
3969 return BitmapFromImage(getProjectImage())
3970
3971 def getProjectImage():
3972 stream = cStringIO.StringIO(getProjectData())
3973 return ImageFromStream(stream)
3974
3975 def getProjectIcon():
3976 return wx.IconFromBitmap(getProjectBitmap())
3977
3978
3979 #----------------------------------------------------------------------------
3980
3981 def getBlankData():
3982 return \
3983 "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
3984 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
3985 \x00\x01\x04IDAT8\x8d\xa5\x93\xbdj\x02A\x10\xc7\x7f{gme\xe5c\xe4\t\x82\x85\
3986 \x85\x85oa\xe5+\xd8Z\xd8'e\xfa\x80\xd8\xd8X\x19R\xc4\x07\x90\x04\xd1J\x08\
3987 \x17\x0cr\\V\xe1\xe4\xfc\x80\xb58\xf7\xd8\xbd\x0f\xa280\xec\xec2\xbf\xff\xce\
3988 \xcc\xb2B8.\xf7X\xc9\xdc|L\x97J\xc7\xbe\x0c\x01\xf0\xd6\x01\x00RFtZu\x91Q\
3989 \x10\x8e\x9b\xf8\xe4\xf3[-w*\xf1\xafm\xec\xcf\x83\x89\x1a\xad\x94\xea\xbe\
3990 \x8c\x95\x99/\x1c\x17\xe7\xdaR\xcb%xh\xd4hw_\x95yn\xb5\xe0\xcb\x90\xea%\x0eO\
3991 \xf1\xba\xd9\xc7\xe5\xbf\x0f\xdfX]\xda)\x140A\r\x03<6klO\xf0w\x84~\xef\xc9\
3992 \xca/lA\xc3@\x02\xe7\x99U\x81\xb7\x0e\xa8\xec\xed\x04\x13\xde\x1c\xfe\x11\
3993 \x902\xb2@\xc8\xc2\x8b\xd9\xbcX\xc0\x045\xac\xc1 Jg\xe6\x08\xe8)\xa7o\xd5\
3994 \xb0\xbf\xcb\nd\x86x\x0b\x9c+p\x0b\x0c\xa9\x16~\xbc_\xeb\x9d\xd3\x03\xcb3q\
3995 \xefo\xbc\xfa/\x14\xd9\x19\x1f\xfb\x8aa\x87\xf2\xf7\x16\x00\x00\x00\x00IEND\
3996 \xaeB`\x82"
3997
3998
3999 def getBlankBitmap():
4000 return BitmapFromImage(getBlankImage())
4001
4002 def getBlankImage():
4003 stream = cStringIO.StringIO(getBlankData())
4004 return ImageFromStream(stream)
4005
4006 def getBlankIcon():
4007 return wx.IconFromBitmap(getBlankBitmap())
4008
4009
4010 #----------------------------------------------------------------------
4011 def getFolderClosedData():
4012 return \
4013 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
4014 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
4015 \x00\x00\xffIDAT8\x8d\xa5\x93?N\x02A\x14\x87\xbf\x19&\x10B\xb4A\x0b*iL0!$\
4016 \x06\x0f\xe0\x05lH\x88G\xe1\x0c\xdbx\x11ZN`,\xa5\x01\x8aM\xa4\x80\x84\xc4Fc\
4017 \xd0\xe8\xb0\xae\xbbc\x01\x0b,\x19\x16X~\xd5\x9b\xf7\xe7\x9by3o\x84\x90\x19\
4018 \x8e\x91\x8a\x0c\xed:\x06\xc0\xf7g\x00x\xde\x14\x80\xf3\x9b\x07\xb1\x13\xa0]\
4019 \xc7d\xcbw\x00d\x17\x81\x82\xff\x01\xc0\xb0\xd3\x9f\x83\x7f\xf5\xb2\xe8\xaa\
4020 \xf1\xb4\x84\n!3h\xd71\xef\xaf=\xeb\x0e\xc5R\xcd\xea\xcfWZ"\xd6\xc2\xb6\xc4\
4021 \xdc\xe5\xad\xd5?h\xd7M\xb5\xd9\x15\n\xe6}{\xde\x94\xe2\xf5\xbd59I\x12V\x17\
4022 \x96F\n \xfc\xfbD\xaaS\xc2\x9fI:@\x041\xdf\xa3\x8d\xb0Y\xb3\xed\xaf\xa9\x00\
4023 \xbe\xde\xc6\x9c\x9c]\x10\xea\xc3O #\xc3\xd7:)/\x19\xb0>$\x87J\x01\x04\xc1n\
4024 \xc0\xcb\xf3cl]mv\xe3\x83\xb4o\xc1\xa6D\xf4\x1b\x07\xed\xba\xd9\xa7`+ \xad\
4025 \xfe\x01\xd1\x03SV!\xfbHa\x00\x00\x00\x00IEND\xaeB`\x82'
4026
4027 def getFolderClosedBitmap():
4028 return BitmapFromImage(getFolderClosedImage())
4029
4030 def getFolderClosedImage():
4031 stream = cStringIO.StringIO(getFolderClosedData())
4032 return ImageFromStream(stream)
4033
4034 def getFolderClosedIcon():
4035 return wx.IconFromBitmap(getFolderClosedBitmap())
4036
4037
4038 #----------------------------------------------------------------------
4039 def getFolderOpenData():
4040 return \
4041 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
4042 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
4043 \x00\x01>IDAT8\x8d\xa5\x93\xbdJ\x03A\x14\x85\xbfY\x03i\xac\x14\x92\xc2F\xad$\
4044 Z\xa4\x10\x11|\x01\xc1J\xdbt\xbe\x86\x9d\x85\x0f\xa0\xe0\x1b\x04,l\xc4J\x0b\
4045 \x0bA;a\x11\x13\xb1H\xc2\xc2\xca\x84@\x88n\xb2\xd9?\xcd\xd8d6.\x9b\x104\xa7\
4046 \xbas\xef=g\xce\x9d\xe1\na\xcc1\x0b\x8c\x99\xd8@F\x07_\xd6\xb9\n\xdd\x8f\xb8\
4047 \xd0s\x9a\x00\xe4\xb6O\xc5T\x81~\xf5D\x89\xdc\x0e\xd9_\x85,\xa0\xa2\x06\xefw\
4048 R\x01\x04\x9e\x03\xc0\xea\xde\x8dH\th\xa8\xa81:\xf8\x1e\x00\xf9\x8d\x03\x00\
4049 \xa4U\x07\xc0,\xdb\xaaX\xaa\xc4"\x99\x04\xd9\xf7\xe0\xfbs$\x12\x0e\x90\xad\
4050 \x0e\x00]\xeb*N\x9b\xe5u\x05P,UD\xc2\x81&K\xbb\r@\xd4\xba\x1f\x9a\xe9\xb0\
4051 \xb6\x7f\x96h}\xbe8\x1c9\xe89M\x16\xfc\x15\xa4\xdd\xc6\xe8\x9a\x18\xc3\x99\
4052 \x97w\x8f\x99\x86\xd8\x81\xb4\xea\x18]\x93\xfcf).\x0e\\9\x96\xf4r}\x84~\x87\
4053 \xc4\x08\x81\xe7\xa0\xfa\xb5\xa9\xb7\xa6\x1c\xf4\xdao\xcc/B\x04\x0c<\xfb\xef\
4054 \x02Zd\xa9P\x98\xd8\xf8\xfax\x1b\xc7\xa9o\xf4\xbdN\x8aP{z \x0c\xdc\xb1\xa4\
4055 \xdf\x10z\x99\xaa\x97[J\'\xc3\xc0\x9dH\x98(\xf0_\xcc\xbc\x8d?\xf2)\x7f\x8e|f\
4056 \xe54\x00\x00\x00\x00IEND\xaeB`\x82'
4057
4058 def getFolderOpenBitmap():
4059 return BitmapFromImage(getFolderOpenImage())
4060
4061 def getFolderOpenImage():
4062 stream = cStringIO.StringIO(getFolderOpenData())
4063 return ImageFromStream(stream)
4064
4065 def getFolderOpenIcon():
4066 return wx.IconFromBitmap(getFolderOpenBitmap())
4067
4068
4069 #----------------------------------------------------------------------
4070 def getLogicalModeOnData():
4071 return \
4072 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
4073 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
4074 \x00\x01\x83IDAT8\x8d\xa5\x93\xcbJ\xc3@\x14\x86\xbfI\x83buS\xabE+TE\x04\x17\
4075 \xde\xf0\x02\x82\xa0k\x17\n.\xdc\xf9\x1e.\xf4\x05\\\t\xfa\x18\x057\xe2\x0b\
4076 \x08ue@\xa4`\xb0\x84J\xd0(M\xa3"\xb65\x8d5.jcbS\x14\xfdW3\xe7\xfc\xe7\x9b9\
4077 \xc3\x19!\xa4\x08\xff\x91\xdcXT\x8d=\xb7\xf6\\\xa5\xe2\xd8\xf5\xfd\xab\t@\
4078 \xdf\xfc\x81\xf8\x11PQw\xddHl\x99H\x0c\xda\xbe\x19\xce\x0f\r\x17@\xae]{\xb1\
4079 \xf1\r\xc5\x83\n!E\xa8\xa8\xbb\xaeuw\x11zB\xbc\x7f24\xde1\xb6%\x02-\xb42\xbe\
4080 \xc5\x06\xd12i\x00&V\xb6\x11m\x0e\x00\xd9\xf4\xac;\xbe\xa1\x88z\x0b\x8eM\xf5\
4081 \xd5$1\xb3\xd9\x048\xde\xdf!%\xe5P4\x9b\x91\xc5+:{\x86\x03y\x19\xbe\x1e\xcc\
4082 \xafR1\x8f\x96Ic\xe6\xb34g\xbf\x01\xfcE\x00%=\x83~z\xd4dv\nW\x94\xc2\x00o/\
4083 \x0f\xc8]\xdd\xb4\xd7\xee\x00\xb8<="\x9a\x8c\xd37\x90"\x9a\xd4Qo\xba1\xf3Y\
4084 \x00\xcf\x13z\x03\xd7\xd6\x01\x88&\xe3\x00\xdc\xdf\xea\x94\r\x8b\x94da~\xb6\
4085 \xea\xda\x8f\x01\x80\x04\xf0TT\x91\x9d\x1b/8:\xb7D\xd9\xb0(\x1b\x16\x8af\xa3\
4086 h\xf5\xe1\x8a\xf5\x04\xcek\xbe\x81_Sk\xeb\x98\xd7\x05\xf4\xf7\x02\x00\x0b\
4087 \xd3\x89P_K\x00@\xefP\x82\xd5\xa1za\xee\xec\x84\xa7\xa2\xea\xe5\x1a\xd3\xd8\
4088 \x12\x90;;\t\xec\xfd\xe3\xeb\x97h\xfc\xc6lz\xd6\xfdMAK\xc0_\xf5\x01\xf4\x01\
4089 \x91\xdc\xfe\x86\x9e^\x00\x00\x00\x00IEND\xaeB`\x82'
4090
4091 def getLogicalModeOnBitmap():
4092 return BitmapFromImage(getLogicalModeOnImage())
4093
4094 def getLogicalModeOnImage():
4095 stream = cStringIO.StringIO(getLogicalModeOnData())
4096 return ImageFromStream(stream)
4097
4098 #----------------------------------------------------------------------
4099 def getLogicalModeOffData():
4100 return \
4101 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
4102 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
4103 \x00\x01\x83IDAT8\x8d\xa5\x93\xcbJ\xc3@\x14\x86\xbfI\x83buS\xabE+TE\x04\x17\
4104 \xde\xf0\x02\x82\xa0k\x17\n.\xdc\xf9\x1e.\xf4\x05\\\t\xfa\x18\x057\xe2\x0b\
4105 \x08ue@\xa4`\xb0\x84J\xd0(M\xa3"\xb65\x8d5.jcbS\x14\xfdW3\xe7\xfc\xe7\x9b9\
4106 \xc3\x19!\xa4\x08\xff\x91\xdcXT\x8d=\xb7\xf6\\\xa5\xe2\xd8\xf5\xfd\xab\t@\
4107 \xdf\xfc\x81\xf8\x11PQw\xddHl\x99H\x0c\xda\xbe\x19\xce\x0f\r\x17@\xae]{\xb1\
4108 \xf1\r\xc5\x83\n!E\xa8\xa8\xbb\xaeuw\x11zB\xbc\x7f24\xde1\xb6%\x02-\xb42\xbe\
4109 \xc5\x06\xd12i\x00&V\xb6\x11m\x0e\x00\xd9\xf4\xac;\xbe\xa1\x88z\x0b\x8eM\xf5\
4110 \xd5$1\xb3\xd9\x048\xde\xdf!%\xe5P4\x9b\x91\xc5+:{\x86\x03y\x19\xbe\x1e\xcc\
4111 \xafR1\x8f\x96Ic\xe6\xb34g\xbf\x01\xfcE\x00%=\x83~z\xd4dv\nW\x94\xc2\x00o/\
4112 \x0f\xc8]\xdd\xb4\xd7\xee\x00\xb8<="\x9a\x8c\xd37\x90"\x9a\xd4Qo\xba1\xf3Y\
4113 \x00\xcf\x13z\x03\xd7\xd6\x01\x88&\xe3\x00\xdc\xdf\xea\x94\r\x8b\x94da~\xb6\
4114 \xea\xda\x8f\x01\x80\x04\xf0TT\x91\x9d\x1b/8:\xb7D\xd9\xb0(\x1b\x16\x8af\xa3\
4115 h\xf5\xe1\x8a\xf5\x04\xcek\xbe\x81_Sk\xeb\x98\xd7\x05\xf4\xf7\x02\x00\x0b\
4116 \xd3\x89P_K\x00@\xefP\x82\xd5\xa1za\xee\xec\x84\xa7\xa2\xea\xe5\x1a\xd3\xd8\
4117 \x12\x90;;\t\xec\xfd\xe3\xeb\x97h\xfc\xc6lz\xd6\xfdMAK\xc0_\xf5\x01\xf4\x01\
4118 \x91\xdc\xfe\x86\x9e^\x00\x00\x00\x00IEND\xaeB`\x82'
4119
4120 def getLogicalModeOffBitmap():
4121 return BitmapFromImage(getLogicalModeOffImage())
4122
4123 def getLogicalModeOffImage():
4124 stream = cStringIO.StringIO(getLogicalModeOffData())
4125 return ImageFromStream(stream)
4126
4127 #----------------------------------------------------------------------
4128 def getPhysicalModeOnData():
4129 return \
4130 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
4131 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
4132 \x00\x01\xabIDAT8\x8d}\x931k\xdb@\x18\x86\x9f\xb3=\x98R\xb0\x06\xc7X\x01\x1d\
4133 \x14\x1c\xeaA4?\xa0\xa1\x8b\x9d\x04C\xe6N\xed\xd8\xad\xbf\xc0\xbf!c\xb6@\x9d\
4134 \xa1\xf4\'\xd4m\xd2l\x9dJ(\xb8R\x87\x90\x84\x80\xaeD\x8e\xad\xc1\xeePBIQ\x87\
4135 \x8b.:+\xc9\x0b\x82\xef\xee\xd3\xf3\xde{\x1f\x9c\x10\xa52\xf7)\x99N\xd2q\x1c\
4136 [{\xfe\xb3U\x91_\x8bE\x83E\xa8\xe9\xba\xa6\x1e\xc71*Rx\xd2\xa3\xe9\xba\xd4\
4137 \x97\x1a\xa2\x92L\'i\xd6\xbc\x0bZ\xecy\xd2CE\n\x15)\x00*Y\xf3!hQ\x9e\xf4\xf8\
4138 vt\xa4\r\xf2\xf0}\x90L|\xae\x93\xdb\xf5E;4uEE\xca\x184]\xd72\x91\x89\x0f\xc0\
4139 \xe3\xf6\xaee\xf8\xe7\x83\xcf\x06\x00e\xc4`o/\r\x83\x80\x96\xf4x\xf9\xea\xb5\
4140 I"\x13\xbf\x00ZJF\\\xec\xef >}\x1c\xa6\x00\x07\x87_hI\x8f\x17\x9d.*R<\x7f\
4141 \xd43\xffZF7\xa0\xb9\xc2\xf9\xc91OV\x9e\xb2\xde\xe9Z\x07\\\'\xe0\xacip\xf6\
4142 \xf5\xcdm\xfc\x08\x967\xde\xeaY\xec\xef\xe8!\x9e\x9f\x1c\x03\xf0[\xfe\x85\
4143 \xa8\x98\xd6Y\xdb\x85d\xa4\xeb60>\x03\xe0\xe7!\x94N#E\xb5\xe6P\xad9\x06\x88\
4144 \'\x97\x85\xfb\xea\xe1\x9c\x198Si\xbd\xd3%\x0c\x02\xae\xe63\x1a\xf3\x86\x15\
4145 \xd5\x82\xf3\x9a^\xea\x0f(\xf5\xb6\xb6D\xbf\xdf\xa7Zs\x08\x83\x00\x80\xab\
4146 \xf9\xac\x08g\'O\xedt\x15\x80\xfaRC\x00\x84?F\xe9\xbb\xc1\x80\x96\xf4t\xb7\
4147 \xbezw\x82\x9c\n\x8f)\xaf_\xdb\xffR\xb8\x99z.\xc1\xc1\xfb\xef\x00l\x0e\xcb\
4148 \xe2A\x83L\x9f{\xda(\xd3\xe6\xb0l\x9e\xf4\x7f\x85\x1d\xb2s\xbf\x8c\xaeh\x00\
4149 \x00\x00\x00IEND\xaeB`\x82'
4150
4151 def getPhysicalModeOnBitmap():
4152 return BitmapFromImage(getPhysicalModeOnImage())
4153
4154 def getPhysicalModeOnImage():
4155 stream = cStringIO.StringIO(getPhysicalModeOnData())
4156 return ImageFromStream(stream)
4157
4158 #----------------------------------------------------------------------
4159 def getPhysicalModeOffData():
4160 return \
4161 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
4162 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
4163 \x00\x01\xabIDAT8\x8d}\x931k\xdb@\x18\x86\x9f\xb3=\x98R\xb0\x06\xc7X\x01\x1d\
4164 \x14\x1c\xeaA4?\xa0\xa1\x8b\x9d\x04C\xe6N\xed\xd8\xad\xbf\xc0\xbf!c\xb6@\x9d\
4165 \xa1\xf4\'\xd4m\xd2l\x9dJ(\xb8R\x87\x90\x84\x80\xaeD\x8e\xad\xc1\xeePBIQ\x87\
4166 \x8b.:+\xc9\x0b\x82\xef\xee\xd3\xf3\xde{\x1f\x9c\x10\xa52\xf7)\x99N\xd2q\x1c\
4167 [{\xfe\xb3U\x91_\x8bE\x83E\xa8\xe9\xba\xa6\x1e\xc71*Rx\xd2\xa3\xe9\xba\xd4\
4168 \x97\x1a\xa2\x92L\'i\xd6\xbc\x0bZ\xecy\xd2CE\n\x15)\x00*Y\xf3!hQ\x9e\xf4\xf8\
4169 vt\xa4\r\xf2\xf0}\x90L|\xae\x93\xdb\xf5E;4uEE\xca\x184]\xd72\x91\x89\x0f\xc0\
4170 \xe3\xf6\xaee\xf8\xe7\x83\xcf\x06\x00e\xc4`o/\r\x83\x80\x96\xf4x\xf9\xea\xb5\
4171 I"\x13\xbf\x00ZJF\\\xec\xef >}\x1c\xa6\x00\x07\x87_hI\x8f\x17\x9d.*R<\x7f\
4172 \xd43\xffZF7\xa0\xb9\xc2\xf9\xc91OV\x9e\xb2\xde\xe9Z\x07\\\'\xe0\xacip\xf6\
4173 \xf5\xcdm\xfc\x08\x967\xde\xeaY\xec\xef\xe8!\x9e\x9f\x1c\x03\xf0[\xfe\x85\
4174 \xa8\x98\xd6Y\xdb\x85d\xa4\xeb60>\x03\xe0\xe7!\x94N#E\xb5\xe6P\xad9\x06\x88\
4175 \'\x97\x85\xfb\xea\xe1\x9c\x198Si\xbd\xd3%\x0c\x02\xae\xe63\x1a\xf3\x86\x15\
4176 \xd5\x82\xf3\x9a^\xea\x0f(\xf5\xb6\xb6D\xbf\xdf\xa7Zs\x08\x83\x00\x80\xab\
4177 \xf9\xac\x08g\'O\xedt\x15\x80\xfaRC\x00\x84?F\xe9\xbb\xc1\x80\x96\xf4t\xb7\
4178 \xbezw\x82\x9c\n\x8f)\xaf_\xdb\xffR\xb8\x99z.\xc1\xc1\xfb\xef\x00l\x0e\xcb\
4179 \xe2A\x83L\x9f{\xda(\xd3\xe6\xb0l\x9e\xf4\x7f\x85\x1d\xb2s\xbf\x8c\xaeh\x00\
4180 \x00\x00\x00IEND\xaeB`\x82'
4181
4182 def getPhysicalModeOffBitmap():
4183 return BitmapFromImage(getPhysicalModeOffImage())
4184
4185 def getPhysicalModeOffImage():
4186 stream = cStringIO.StringIO(getPhysicalModeOffData())
4187 return ImageFromStream(stream)
4188