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