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