X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1f780e48af479e7bf9a07eaaa1ab6b41f1ffb17b..e015e7f3acef09b57bcd34e8f6780a19afdfd97b:/wxPython/samples/ide/activegrid/tool/ProjectEditor.py diff --git a/wxPython/samples/ide/activegrid/tool/ProjectEditor.py b/wxPython/samples/ide/activegrid/tool/ProjectEditor.py index 763e74bc0a..4d88f9defc 100644 --- a/wxPython/samples/ide/activegrid/tool/ProjectEditor.py +++ b/wxPython/samples/ide/activegrid/tool/ProjectEditor.py @@ -19,14 +19,15 @@ import wx from wxPython.lib.rcsizer import RowColSizer import time import Service -import MessageService -import DebuggerService import sys -import activegrid.util.xmlmarshaller +import activegrid.util.objutils import UICommon +import Wizard +import SVNService from IDE import ACTIVEGRID_BASE_IDE if not ACTIVEGRID_BASE_IDE: import ProcessModelEditor +from SVNService import SVN_INSTALLED _ = wx.GetTranslation @@ -36,19 +37,22 @@ else: _WINDOWS = False +#---------------------------------------------------------------------------- +# Constants +#---------------------------------------------------------------------------- +SPACE = 10 +HALF_SPACE = 5 + + #---------------------------------------------------------------------------- # XML Marshalling Methods #---------------------------------------------------------------------------- def load(fileObject): - xml = fileObject.read() - projectModel = activegrid.util.xmlmarshaller.unmarshal(xml) - return projectModel - + return activegrid.util.objutils.defaultLoad(fileObject) def save(fileObject, projectModel): - xml = activegrid.util.xmlmarshaller.marshal(projectModel, prettyPrint=True) - fileObject.write(xml) + activegrid.util.objutils.defaultSave(fileObject, projectModel, prettyPrint=True) #---------------------------------------------------------------------------- @@ -57,19 +61,23 @@ def save(fileObject, projectModel): class ProjectModel: __xmlname__ = "projectmodel" - __xmlrename__ = { "_files":"files", "_homepath":"homepath" } + __xmlrename__ = { "_files":"files"} + def __init__(self): - self._homepath = None self._files = [] - - + + def initialize(self): + pass + + class ProjectDocument(wx.lib.docview.Document): + def __init__(self): wx.lib.docview.Document.__init__(self) self._projectModel = ProjectModel() - + def GetModel(self): return self._projectModel @@ -78,27 +86,62 @@ class ProjectDocument(wx.lib.docview.Document): def OnCreate(self, path, flags): projectService = wx.GetApp().GetService(ProjectService) if projectService.GetView(): + # All project documents share the same view. view = projectService.GetView() self.AddView(view) + + if view.GetDocument(): + # All project documents need to share the same command processor, + # to enable redo/undo of cross project document commands + cmdProcessor = view.GetDocument().GetCommandProcessor() + if cmdProcessor: + self.SetCommandProcessor(cmdProcessor) else: view = self.GetDocumentTemplate().CreateView(self, flags) projectService.SetView(view) + + return view def LoadObject(self, fileObject): self._projectModel = activegrid.tool.ProjectEditor.load(fileObject) + self._projectModel._files = self.RelativeToAbsPath(self._projectModel._files) return True def SaveObject(self, fileObject): + absPath = self._projectModel._files + self._projectModel._files = self.AbsToRelativePath(absPath) # temporarily change it to relative paths for saving activegrid.tool.ProjectEditor.save(fileObject, self._projectModel) + self._projectModel._files = absPath # swap it back to absolute path return True - def OnSaveDocument(self, filename): - self._projectModel._homepath = wx.lib.docview.PathOnly(filename) - return wx.lib.docview.Document.OnSaveDocument(self, filename) + def AbsToRelativePath(self, paths): + curPath = os.path.dirname(self.GetFilename()) + curPathLen = len(curPath) + + newFilePaths = [] + for path in paths: + if path.startswith(curPath): + path = "." + path[curPathLen:] # use relative path + if os.sep != '/': + path = path.replace(os.sep, '/', -1) # always save out with '/' as path separator for cross-platform compatibility. + else: + pass # use absolute path + newFilePaths.append(path) + return newFilePaths + + + def RelativeToAbsPath(self, paths): + newFilePaths = [] + for path in paths: + if path.startswith("."): # relative to project file + curPath = os.path.dirname(self.GetFilename()) + path = os.path.normpath(os.path.join(curPath, path)) + newFilePaths.append(path) + return newFilePaths def OnOpenDocument(self, filename): @@ -131,49 +174,9 @@ class ProjectDocument(wx.lib.docview.Document): return True # if we return False, the Project View is destroyed, Service windows shouldn't be destroyed self.Modify(False) - - # if the project file has moved, then ask the user if we should readjust the paths of all the files in the project - newHomepath = wx.lib.docview.PathOnly(filename) - if newHomepath != self._projectModel._homepath: - wx.GetApp().CloseSplash() - msgTitle = wx.GetApp().GetAppName() - if not msgTitle: - msgTitle = _("Project Moved") - projectService = wx.GetApp().GetService(activegrid.tool.ProjectEditor.ProjectService) - yesNoMsg = wx.MessageDialog(frame, - _("The project file '%s' was moved from:\n '%s'\nto:\n '%s'.\n\nWould you like to automatically adjust the project contents accordingly?") % (wx.lib.docview.FileNameFromPath(filename), self._projectModel._homepath, wx.lib.docview.PathOnly(filename)), - msgTitle, - wx.YES_NO | wx.STAY_ON_TOP - ) - if projectService.GetSuppressOpenProjectMessages() or yesNoMsg.ShowModal() == wx.ID_YES: - if not projectService.GetSuppressOpenProjectMessages(): - messageService = wx.GetApp().GetService(MessageService.MessageService) - messageService.ShowWindow() - messageView = messageService.GetView() - messageView.ClearLines() - messageView.AddLines(_("The project file '%s' was moved from:\n '%s'\nto:\n '%s'\n") % (wx.lib.docview.FileNameFromPath(filename), self._projectModel._homepath, wx.lib.docview.PathOnly(filename))) - messageView.AddLines(_("Updating file references:\n")) - - for index, filepath in enumerate(self._projectModel._files): - if filepath.startswith(self._projectModel._homepath + os.sep): - newfile = newHomepath + filepath[len(self._projectModel._homepath):len(filepath)] - if os.path.exists(newfile): - self._projectModel._files[index] = newfile - if not projectService.GetSuppressOpenProjectMessages(): - messageView.AddLines(_(" Success: '%s' location changed from '%s' to '%s'\n") % (wx.lib.docview.FileNameFromPath(filepath), wx.lib.docview.PathOnly(filepath), newHomepath)) - self.Modify(True) - else: - if not projectService.GetSuppressOpenProjectMessages(): - messageView.AddLines(_(" Failure: Couldn't find '%s', file wasn't located at '%s'\n") % (wx.lib.docview.FileNameFromPath(filepath), newHomepath)) - else: - if not projectService.GetSuppressOpenProjectMessages(): - messageView.AddLines(_( " Unmodified: '%s' location wasn't relative to '%s'\n") % (filepath, self._projectModel._homepath)) - self._projectModel._homepath = newHomepath - if not projectService.GetSuppressOpenProjectMessages(): - messageView.AddLines(_("Project file updated.")) - self.SetFilename(filename, True) view.AddProjectToView(self) + self.SetDocumentModificationDate() self.UpdateAllViews() self._savedYet = True view.Activate(True) @@ -221,7 +224,7 @@ class ProjectDocument(wx.lib.docview.Document): if isProject: documents = self.GetDocumentManager().GetDocuments() for document in documents: - if document.GetFilename() == oldFile: # If the renamed document is open, update it + if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFile): # If the renamed document is open, update it document.SetFilename(newFile) document.SetTitle(wx.lib.docview.FileNameFromPath(newFile)) document.UpdateAllViews(hint = ("rename", document, newFile)) @@ -230,7 +233,7 @@ class ProjectDocument(wx.lib.docview.Document): self.AddFile(newFile) documents = self.GetDocumentManager().GetDocuments() for document in documents: - if document.GetFilename() == oldFile: # If the renamed document is open, update it + if os.path.normcase(document.GetFilename()) == os.path.normcase(oldFile): # If the renamed document is open, update it document.SetFilename(newFile, notifyViews = True) document.UpdateAllViews(hint = ("rename", document, newFile)) return True @@ -253,8 +256,6 @@ class ProjectDocument(wx.lib.docview.Document): return filename in self.GetFiles() -import Wizard - class NewProjectWizard(Wizard.BaseWizard): WIZTITLE = _("New Project Wizard") @@ -265,7 +266,8 @@ class NewProjectWizard(Wizard.BaseWizard): Wizard.BaseWizard.__init__(self, parent, self.WIZTITLE) self._projectLocationPage = self.CreateProjectLocation(self) wx.wizard.EVT_WIZARD_PAGE_CHANGING(self, self.GetId(), self.OnWizPageChanging) - + + def CreateProjectLocation(self,wizard): page = Wizard.TitledWizardPage(wizard, _("Project File Location")) @@ -277,6 +279,7 @@ class NewProjectWizard(Wizard.BaseWizard): wizard.FitToPage(page) return page + def RunWizard(self, existingTables = None, existingRelationships = None): status = wx.wizard.Wizard.RunWizard(self, self._projectLocationPage) if status: @@ -285,7 +288,7 @@ class NewProjectWizard(Wizard.BaseWizard): # What if the document is already open and we're overwriting it? documents = docManager.GetDocuments() for document in documents: - if document.GetFilename() == self._fullProjectPath: # If the renamed document is open, update it + if os.path.normcase(document.GetFilename()) == os.path.normcase(self._fullProjectPath): # If the renamed document is open, update it document.DeleteAllViews() break os.remove(self._fullProjectPath) @@ -325,8 +328,10 @@ class NewProjectWizard(Wizard.BaseWizard): wiz.Destroy() self.Show(True) + class ProjectTemplate(wx.lib.docview.DocTemplate): + def CreateDocument(self, path, flags): if path: return wx.lib.docview.DocTemplate.CreateDocument(self, path, flags) @@ -336,8 +341,10 @@ class ProjectTemplate(wx.lib.docview.DocTemplate): wiz.Destroy() return None # never return the doc, otherwise docview will think it is a new file and rename it + class ProjectAddFilesCommand(wx.lib.docview.Command): + def __init__(self, projectDoc, files): wx.lib.docview.Command.__init__(self, canUndo = True) self._projectDoc = projectDoc @@ -346,7 +353,7 @@ class ProjectAddFilesCommand(wx.lib.docview.Command): def GetName(self): if len(self._files) == 1: - return _("Add File") + return _("Add File %s") % os.path.basename(self._files[0]) else: return _("Add Files") @@ -361,29 +368,56 @@ class ProjectAddFilesCommand(wx.lib.docview.Command): class ProjectRemoveFilesCommand(wx.lib.docview.Command): - def __init__(self, projectDoc, files): + + def __init__(self, files): wx.lib.docview.Command.__init__(self, canUndo = True) - self._projectDoc = projectDoc self._files = files def GetName(self): if len(self._files) == 1: - return _("Remove File") + return _("Remove File %s") % os.path.basename((self._files[0])[1]) else: return _("Remove Files") def Do(self): - return self._projectDoc.RemoveFiles(self._files) + status = False + projects = [] + for data in self._files: + proj, filename = data + if proj not in projects: + projects.append(proj) + for project in projects: + files = [] + for data in self._files: + proj, filename = data + if project == proj: + files.append(filename) + status = project.RemoveFiles(files) or status + return status def Undo(self): - return self._projectDoc.AddFiles(self._files) - + status = False + projects = [] + for data in self._files: + proj, filename = data + if proj not in projects: + projects.append(proj) + for project in projects: + files = [] + for data in self._files: + proj, filename = data + if project == proj: + files.append(filename) + status = project.AddFiles(files) or status + return status + class ProjectRenameFileCommand(wx.lib.docview.Command): + def __init__(self, projectDoc, oldFile, newFile, isProject = False): wx.lib.docview.Command.__init__(self, canUndo = True) self._projectDoc = projectDoc @@ -393,7 +427,7 @@ class ProjectRenameFileCommand(wx.lib.docview.Command): def GetName(self): - return _("Rename File") + return _("Rename File %s to %s") % (os.path.basename(self._oldFile), os.path.basename(self._newFile)) def Do(self): @@ -405,6 +439,11 @@ class ProjectRenameFileCommand(wx.lib.docview.Command): class ProjectTreeCtrl(wx.TreeCtrl): + + + #---------------------------------------------------------------------------- + # Overridden Methods + #---------------------------------------------------------------------------- def __init__(self, parent, id, style): wx.TreeCtrl.__init__(self, parent, id, style = style) @@ -415,18 +454,20 @@ class ProjectTreeCtrl(wx.TreeCtrl): for template in templates: icon = template.GetIcon() if icon: - if icon.GetHeight() != 16: - icon.SetHeight(16) # wxBug: img2py.py uses EmptyIcon which is 32x32 - if icon.GetWidth() != 16: - icon.SetWidth(16) # wxBug: img2py.py uses EmptyIcon which is 32x32 + if icon.GetHeight() != 16 or icon.GetWidth() != 16: + icon.SetHeight(16) + icon.SetWidth(16) + if wx.GetApp().GetDebug(): + print "Warning: icon for '%s' isn't 16x16, not crossplatform" % template._docTypeName iconIndex = iconList.AddIcon(icon) self._iconIndexLookup.append((template, iconIndex)) icon = getBlankIcon() - if icon.GetHeight() != 16: - icon.SetHeight(16) # wxBug: img2py.py uses EmptyIcon which is 32x32 - if icon.GetWidth() != 16: - icon.SetWidth(16) # wxBug: img2py.py uses EmptyIcon which is 32x32 + if icon.GetHeight() != 16 or icon.GetWidth() != 16: + icon.SetHeight(16) + icon.SetWidth(16) + if wx.GetApp().GetDebug(): + print "Warning: getBlankIcon isn't 16x16, not crossplatform" self._blankIconIndex = iconList.AddIcon(icon) self.AssignImageList(iconList) @@ -459,6 +500,31 @@ class ProjectTreeCtrl(wx.TreeCtrl): return item + #---------------------------------------------------------------------------- + # Client Data + #---------------------------------------------------------------------------- + + def SetData(self, item, longFilename, projectDoc=None): + self.SetPyData(item, (longFilename, projectDoc)) + + + def GetData(self, item): + """ returns longFilename and optional + """ + data = self.GetPyData(item) + if not data: + return (None, None) + return data + + + def GetLongFilename(self, item): + return self.GetData(item)[0] + + + def GetProjectDoc(self, item): + return self.GetData(item)[1] + + class ProjectView(wx.lib.docview.View): @@ -469,7 +535,6 @@ class ProjectView(wx.lib.docview.View): def __init__(self, service = None): wx.lib.docview.View.__init__(self) self._service = service # not used, but kept to match other Services - self._lastDirectory = "" self._treeCtrl = None self._editingSoDontKillFocus = False self._checkEditMenu = True @@ -561,6 +626,8 @@ class ProjectView(wx.lib.docview.View): sizer = wx.BoxSizer() self._treeCtrl = ProjectTreeCtrl(frame, -1, style = wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS | wx.TR_EDIT_LABELS | wx.TR_DEFAULT_STYLE | wx.TR_MULTIPLE) self._treeCtrl.AddRoot(_("Projects")) + wx.EVT_TREE_BEGIN_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnBeginDrag) + wx.EVT_TREE_END_DRAG(self._treeCtrl, self._treeCtrl.GetId(), self.OnEndDrag) if self._embeddedWindow: sizer.Add(self._treeCtrl) @@ -592,6 +659,48 @@ class ProjectView(wx.lib.docview.View): return True + def OnBeginDrag(self, event): + item = event.GetItem() + if item.IsOk(): + if item == self._treeCtrl.GetRootItem(): + return + self._draggingItem = item + event.Allow() + + + def OnEndDrag(self, event): + item = event.GetItem() + if item.IsOk(): + # don't allow object to be dragged to itself + if item == self._draggingItem: + return + + rootItem = self._treeCtrl.GetRootItem() + + # don't let object replace root view + if item == rootItem: + wx.MessageBox(_("Cannot replace root view with item.")) + return + + # don't allow object to be dragged to a direct descendant + ancestor = self._treeCtrl.GetItemParent(item) + while ancestor != rootItem: + if ancestor == self._draggingItem: + wx.MessageBox(_("Cannot make item direct descendant of self.")) + return + else: + ancestor = self._treeCtrl.GetItemParent(ancestor) + + if self._treeCtrl.GetItemParent(item) == self._treeCtrl.GetItemParent(self._draggingItem): + # put it in same folder as it was originally, no-op. + return + if item == self._treeCtrl.GetItemParent(self._draggingItem): + # put it in same folder as it was originally, no-op. + return + + self.GetDocument().GetCommandProcessor().Submit(ProjectEditorMoveCommand(self, item, self._draggingItem)) + + def WriteProjectConfig(self): frame = self.GetFrame() config = wx.ConfigBase_Get() @@ -647,15 +756,19 @@ class ProjectView(wx.lib.docview.View): files = hint[2] self._treeCtrl.UnselectAll() self._treeCtrl.Expand(projectItem) + item = None for file in files: item = self._treeCtrl.AppendItem(projectItem, os.path.basename(file)) - self._treeCtrl.SetPyData(item, file) + self._treeCtrl.SetData(item, file) self._treeCtrl.SelectItem(item) - self._treeCtrl.EnsureVisible(item) # wxBug: Doesn't work + self._treeCtrl.EnsureVisible(item) self._treeCtrl.SortChildren(projectItem) + if item: + self._treeCtrl.EnsureVisible(item) # need to be called after SortChildren elif hint[0] == "remove": projectItem = self._GetProjectItem(hint[1]) files = hint[2] + self._treeCtrl.UnselectAll() children = self._GetChildItems(projectItem) for child in children: if self._GetItemFile(child) in files: @@ -668,7 +781,7 @@ class ProjectView(wx.lib.docview.View): for child in children: if self._GetItemFile(child) in files: self._treeCtrl.SelectItem(child) - self._treeCtrl.EnsureVisible(child) # wxBug: Doesn't work + self._treeCtrl.EnsureVisible(child) elif hint[0] == "rename": projectItem = self._GetProjectItem(hint[1]) self._treeCtrl.SetItemText(projectItem, os.path.basename(hint[2])) @@ -679,11 +792,17 @@ class ProjectView(wx.lib.docview.View): if id == ProjectService.ADD_FILES_TO_PROJECT_ID: self.OnAddFileToProject(event) return True + elif id == ProjectService.ADD_ALL_FILES_TO_PROJECT_ID: + self.OnAddDirToProject(event) + return True elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID: return False # Implement this one in the service elif id == ProjectService.RENAME_ID: self.OnRename(event) return True + elif id == ProjectService.DELETE_FILE_ID: + self.OnDeleteFile(event) + return True elif id == wx.ID_CUT: self.OnCut(event) return True @@ -693,7 +812,8 @@ class ProjectView(wx.lib.docview.View): elif id == wx.ID_PASTE: self.OnPaste(event) return True - elif id == wx.ID_CLEAR or id == ProjectService.REMOVE_FROM_PROJECT: + elif (id == wx.ID_CLEAR + or id == ProjectService.REMOVE_FROM_PROJECT): self.OnClear(event) return True elif id == wx.ID_SELECTALL: @@ -708,6 +828,7 @@ class ProjectView(wx.lib.docview.View): else: return False + def ProcessUpdateUIEvent(self, event): # Hack: The edit menu is not being set for projects that are preloaded at startup, so make sure it is OK here if self._checkEditMenu: @@ -715,37 +836,37 @@ class ProjectView(wx.lib.docview.View): if doc and not doc.GetCommandProcessor().GetEditMenu(): doc.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame())) self._checkEditMenu = False + id = event.GetId() - if id == ProjectService.ADD_FILES_TO_PROJECT_ID: - event.Enable(self._HasProjectsSelected() or self._HasFilesSelected()) + if (id == wx.ID_CUT + or id == wx.ID_COPY + or id == ProjectService.RENAME_ID + or id == ProjectService.ADD_FILES_TO_PROJECT_ID + or id == ProjectService.ADD_ALL_FILES_TO_PROJECT_ID + or id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID): + event.Enable(self._HasSelection()) + return True + elif id == ProjectService.DELETE_FILE_ID: + event.Enable(len(self.GetSelectedFiles()) > 0) return True elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID: event.Enable(False) return True - elif id == ProjectService.RENAME_ID: - event.Enable(self._HasFilesSelected() or self._HasProjectsSelected()) - return True - elif id == wx.ID_CUT: - event.Enable(self._AreSelectedItemsFromSameProject()) - return True - elif id == wx.ID_COPY: - event.Enable(self._HasFilesSelected()) - return True elif id == wx.ID_PASTE: event.Enable(self.CanPaste()) return True - elif id == wx.ID_CLEAR or id == ProjectService.REMOVE_FROM_PROJECT: - event.Enable(self._AreSelectedItemsFromSameProject()) - return True elif id == wx.ID_SELECTALL: event.Enable(self._HasFiles()) return True - elif id == ProjectService.OPEN_SELECTION_ID: + elif (id == wx.ID_CLEAR + or id == ProjectService.REMOVE_FROM_PROJECT + or id == ProjectService.OPEN_SELECTION_ID): event.Enable(self._HasFilesSelected()) return True - elif id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID: - event.Enable(self._HasProjectsSelected() or self._HasFilesSelected()) - return True + elif (id == wx.ID_PREVIEW + or id == wx.ID_PRINT): + event.Enable(False) + return True else: return False @@ -780,32 +901,47 @@ class ProjectView(wx.lib.docview.View): for i, item in enumerate(self._GetChildItems(self._treeCtrl.GetRootItem())): if i == 0: firstItem = item + if expandedProjects[i]: self._treeCtrl.Expand(item) else: self._treeCtrl.Collapse(item) - # wxBug: This causes a crash, tried using ScrollTo which crashed as well. Then tried calling it with wx.CallAfter and that crashed as well, with both EnsureVisible and ScrollTo - # self._treeCtrl.EnsureVisible(self._treeCtrl.GetRootItem()) - # So doing the following massive hack which forces the treectrl to scroll up to the top item + if firstItem: - if expandedProjects[i]: - self._treeCtrl.Collapse(firstItem) - self._treeCtrl.Expand(firstItem) - else: - self._treeCtrl.Expand(firstItem) - self._treeCtrl.Collapse(firstItem) + self._treeCtrl.EnsureVisible(firstItem) + def GetSelectedFile(self): for item in self._treeCtrl.GetSelections(): return self._GetItemFile(item) + + def GetSelectedFiles(self): + filenames = [] + for item in self._treeCtrl.GetSelections(): + filename = self._GetItemFile(item) + if filename and filename not in filenames: + filenames.append(filename) + return filenames + + + def GetSelectedProjects(self): + filenames = [] + for item in self._treeCtrl.GetSelections(): + if self._IsItemProject(item): + filename = self._treeCtrl.GetLongFilename(item) + if filename and filename not in filenames: + filenames.append(filename) + return filenames + + def AddProjectToView(self, document): rootItem = self._treeCtrl.GetRootItem() projectItem = self._treeCtrl.AppendItem(rootItem, self._MakeProjectName(document)) - self._treeCtrl.SetPyData(projectItem, document) + self._treeCtrl.SetData(projectItem, document.GetFilename(), document) for file in document.GetFiles(): fileItem = self._treeCtrl.AppendItem(projectItem, os.path.basename(file)) - self._treeCtrl.SetPyData(fileItem, file) + self._treeCtrl.SetData(fileItem, file) self._treeCtrl.SortChildren(rootItem) self._treeCtrl.SortChildren(projectItem) self._treeCtrl.UnselectAll() @@ -814,17 +950,17 @@ class ProjectView(wx.lib.docview.View): if self._embeddedWindow: document.GetCommandProcessor().SetEditMenu(wx.GetApp().GetEditMenu(self._GetParentFrame())) - #---------------------------------------------------------------------------- - # Methods for OutlineService - #---------------------------------------------------------------------------- - def DoLoadOutlineCallback(self, force=False): - """ Project Editor is a special case for the Outline Service. - You need to be able to be active in the Project Manager without clearing - the Outline View. So we make the Project Editor a client of the Outline - Service, but we don't load anything in the Outline View, leaving the - contents of the Outline View alone (e.g. last document's outline view). - """ - pass + + def HasFocus(self): + winWithFocus = wx.Window.FindFocus() + if not winWithFocus: + return False + while winWithFocus: + if winWithFocus == self._treeCtrl: + return True + winWithFocus = winWithFocus.GetParent() + return False + #---------------------------------------------------------------------------- # Control events @@ -856,26 +992,161 @@ class ProjectView(wx.lib.docview.View): allfilter = allfilter + _(';') 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 allfilter = allfilter + temp.GetFileFilter() - descr = _("All") + _(" (") + allfilter + _(") |") + allfilter + _('|') + descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk - descr = descr + _("|") + _("Any (*.*) | *.*") + descr = _("All (%s)|%s|%s|Any (*.*) | *.*") % (allfilter, allfilter, descr) # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk else: descr = _("*.*") + + startDirectory = os.path.dirname(self.GetDocument().GetFilename()) + if True or _WINDOWS: - dialog = wx.FileDialog(self.GetFrame(), _("Add Files"), self._lastDirectory, "", descr, wx.OPEN | wx.HIDE_READONLY | wx.MULTIPLE) + dialog = wx.FileDialog(self.GetFrame(), _("Add Files"), startDirectory, "", descr, wx.OPEN | wx.HIDE_READONLY | wx.MULTIPLE) if dialog.ShowModal() != wx.ID_OK: return paths = dialog.GetPaths() dialog.Destroy() else: - paths = wx.FileSelector(_("Add Files"), self._lastDirectory, "", wildcard = descr, flags = wx.OPEN | wx.HIDE_READONLY | wx.MULTIPLE, parent=self.GetFrame()) + paths = wx.FileSelector(_("Add Files"), startDirectory, "", wildcard = descr, flags = wx.OPEN | wx.HIDE_READONLY | wx.MULTIPLE, parent=self.GetFrame()) if type(paths) == types.StringType: paths = [paths] if len(paths): - self._lastDirectory = wx.lib.docview.PathOnly(paths[0]) self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), paths)) self.Activate(True) # after add, should put focus on project editor + def OnAddDirToProject(self, event): + frame = wx.Dialog(None, -1, _("Add Directory Files to Project"), size= (320,200)) + contentSizer = wx.BoxSizer(wx.VERTICAL) + + flexGridSizer = wx.FlexGridSizer(cols = 2, vgap=HALF_SPACE, hgap=HALF_SPACE) + flexGridSizer.Add(wx.StaticText(frame, -1, _("Directory:")), 0, wx.ALIGN_CENTER_VERTICAL, 0) + lineSizer = wx.BoxSizer(wx.HORIZONTAL) + dirCtrl = wx.TextCtrl(frame, -1, os.path.dirname(self.GetDocument().GetFilename()), size=(250,-1)) + dirCtrl.SetToolTipString(dirCtrl.GetValue()) + lineSizer.Add(dirCtrl, 1, wx.ALIGN_CENTER_VERTICAL|wx.EXPAND) + findDirButton = wx.Button(frame, -1, _("Browse...")) + lineSizer.Add(findDirButton, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, HALF_SPACE) + flexGridSizer.Add(lineSizer, 1, wx.EXPAND) + + def OnBrowseButton(event): + dlg = wx.DirDialog(frame, _("Choose a directory:"), style=wx.DD_DEFAULT_STYLE) + dir = dirCtrl.GetValue() + if len(dir): + dlg.SetPath(dir) + if dlg.ShowModal() == wx.ID_OK: + dirCtrl.SetValue(dlg.GetPath()) + dirCtrl.SetToolTipString(dirCtrl.GetValue()) + dirCtrl.SetInsertionPointEnd() + + dlg.Destroy() + wx.EVT_BUTTON(findDirButton, -1, OnBrowseButton) + + visibleTemplates = [] + for template in self.GetDocumentManager()._templates: + if template.IsVisible(): + visibleTemplates.append(template) + + choices = [] + allfilter = '' + descr = '' + for template in visibleTemplates: + if len(descr) > 0: + descr = descr + _('|') + allfilter = allfilter + _(';') + descr = template.GetDescription() + _(" (") + template.GetFileFilter() + _(")") + choices.append(descr) + allfilter = allfilter + template.GetFileFilter() + choices.insert(0, _("All (%s)") % allfilter) + filterChoice = wx.Choice(frame, -1, size=(250, -1), choices=choices) + filterChoice.SetSelection(0) + filterChoice.SetToolTipString(_("Select file type filter.")) + flexGridSizer.Add(wx.StaticText(frame, -1, _("Files of type:")), 0, wx.ALIGN_CENTER_VERTICAL) + flexGridSizer.Add(filterChoice, 1, wx.EXPAND) + + contentSizer.Add(flexGridSizer, 0, wx.ALL|wx.EXPAND, SPACE) + + subfolderCtrl = wx.CheckBox(frame, -1, _("Add files from subdirectories")) + subfolderCtrl.SetValue(True) + contentSizer.Add(subfolderCtrl, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, SPACE) + + buttonSizer = wx.BoxSizer(wx.HORIZONTAL) + findBtn = wx.Button(frame, wx.ID_OK, _("Add")) + findBtn.SetDefault() + buttonSizer.Add(findBtn, 0, wx.RIGHT, HALF_SPACE) + buttonSizer.Add(wx.Button(frame, wx.ID_CANCEL), 0) + contentSizer.Add(buttonSizer, 0, wx.ALL|wx.ALIGN_RIGHT, SPACE) + + frame.SetSizer(contentSizer) + frame.Fit() + + status = frame.ShowModal() + + passedCheck = False + while status == wx.ID_OK and not passedCheck: + if not os.path.exists(dirCtrl.GetValue()): + dlg = wx.MessageDialog(frame, + _("'%s' does not exist.") % dirCtrl.GetValue(), + _("Find in Directory"), + wx.OK | wx.ICON_EXCLAMATION + ) + dlg.ShowModal() + dlg.Destroy() + + status = frame.ShowModal() + else: + passedCheck = True + + if status == wx.ID_OK: + frame.Destroy() + + wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) + + doc = self.GetDocument() + searchSubfolders = subfolderCtrl.IsChecked() + dirString = dirCtrl.GetValue() + + if os.path.isfile(dirString): + # If they pick a file explicitly, we won't prevent them from adding it even if it doesn't match the filter. + # We'll assume they know what they're doing. + paths = [dirString] + else: + paths = [] + + index = filterChoice.GetSelection() + if index: + template = visibleTemplates[index-1] + + # do search in files on disk + for root, dirs, files in os.walk(dirString): + if not searchSubfolders and root != dirString: + break + + for name in files: + if index == 0: # all + for template in visibleTemplates: + if template.FileMatchesTemplate(name): + filename = os.path.join(root, name) + + # if already in project, don't add it, otherwise undo will remove it from project even though it was already in it. + if doc.IsFileInProject(filename): + break + + paths.append(filename) + break + else: # use selected filter + if template.FileMatchesTemplate(name): + filename = os.path.join(root, name) + # if already in project, don't add it, otherwise undo will remove it from project even though it was already in it. + if not doc.IsFileInProject(filename): + paths.append(filename) + + wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) + + doc.GetCommandProcessor().Submit(ProjectAddFilesCommand(doc, paths)) + self.Activate(True) # after add, should put focus on project editor + else: + frame.Destroy() + + def DoAddFilesToProject(self, filenames): # method used by Drag-n-Drop to add files to current Project self.GetDocument().GetCommandProcessor().Submit(ProjectAddFilesCommand(self.GetDocument(), filenames)) @@ -883,8 +1154,7 @@ class ProjectView(wx.lib.docview.View): def DoSelectFiles(self, filenames): # method used by Drag-n-Drop to select files in current Project - for selection in self._treeCtrl.GetSelections(): - self._treeCtrl.SelectItem(selection, False) + self._treeCtrl.UnselectAll() for file in filenames: item = self._GetFileItem(longFileName=file) if item: @@ -942,7 +1212,12 @@ class ProjectView(wx.lib.docview.View): else: # Project context itemIDs = [wx.ID_CLOSE, wx.ID_SAVE, wx.ID_SAVEAS, None] menuBar = self._GetParentFrame().GetMenuBar() - itemIDs = itemIDs + [wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID, None, ProjectService.ADD_FILES_TO_PROJECT_ID, ProjectService.REMOVE_FROM_PROJECT, None, wx.ID_UNDO, wx.ID_REDO, None, wx.ID_CUT, wx.ID_COPY, wx.ID_PASTE, wx.ID_CLEAR, None, wx.ID_SELECTALL, None, ProjectService.RENAME_ID] + itemIDs = itemIDs + [ProjectService.ADD_FILES_TO_PROJECT_ID, ProjectService.ADD_ALL_FILES_TO_PROJECT_ID, ProjectService.REMOVE_FROM_PROJECT] + svnIDs = [SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID] + if SVN_INSTALLED: + itemIDs = itemIDs + [None, SVNService.SVNService.SVN_UPDATE_ID, SVNService.SVNService.SVN_CHECKIN_ID, SVNService.SVNService.SVN_REVERT_ID] + globalIDs = [wx.ID_UNDO, wx.ID_REDO, wx.ID_CLOSE, wx.ID_SAVE, wx.ID_SAVEAS] + itemIDs = itemIDs + [None, wx.ID_UNDO, wx.ID_REDO, None, wx.ID_CUT, wx.ID_COPY, wx.ID_PASTE, wx.ID_CLEAR, None, wx.ID_SELECTALL, ProjectService.RENAME_ID, ProjectService.DELETE_FILE_ID, None, wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID] for itemID in itemIDs: if not itemID: menu.AppendSeparator() @@ -955,15 +1230,26 @@ class ProjectView(wx.lib.docview.View): wx.EVT_MENU(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self.OnClear) wx.EVT_UPDATE_UI(self._GetParentFrame(), ProjectService.REMOVE_FROM_PROJECT, self._GetParentFrame().ProcessUpdateUIEvent) else: + svnService = wx.GetApp().GetService(SVNService.SVNService) item = menuBar.FindItemById(itemID) if item: + if itemID in svnIDs: + if SVN_INSTALLED and svnService: + wx.EVT_MENU(self._GetParentFrame(), itemID, svnService.ProcessEvent) + elif itemID in globalIDs: + pass + else: + wx.EVT_MENU(self._treeCtrl, itemID, self.ProcessEvent) menu.Append(itemID, item.GetLabel()) self._treeCtrl.PopupMenu(menu, wx.Point(event.GetX(), event.GetY())) menu.Destroy() + def OnRunSelectedPM(self, event): projectService = wx.GetApp().GetService(ProjectService) - projectService.OnRunProcessModel(event, runSelected=True) + if projectService: + projectService.OnRunProcessModel(event, runSelected=True) + def OnRename(self, event): if self._treeCtrl.GetSelections(): @@ -987,14 +1273,16 @@ class ProjectView(wx.lib.docview.View): if self._IsItemFile(item): oldFile = self._GetItemFile(item) newFile = os.path.join(os.path.split(oldFile)[0], newName) - if not self._GetItemProject(item).GetCommandProcessor().Submit(ProjectRenameFileCommand(self.GetDocument(), oldFile, newFile)): + project = self._GetItemProject(item) + if not project.GetCommandProcessor().Submit(ProjectRenameFileCommand(project, oldFile, newFile)): event.Veto() return self._treeCtrl.SortChildren(self._treeCtrl.GetItemParent(self._treeCtrl.GetSelections()[0])) elif self._IsItemProject(item): oldFile = self._GetItemProject(item).GetFilename() newFile = os.path.join(os.path.split(oldFile)[0], newName) - if not self._GetItemProject(item).GetCommandProcessor().Submit(ProjectRenameFileCommand(self.GetDocument(), oldFile, newFile, True)): + project = self._GetItemProject(item) + if not project.GetCommandProcessor().Submit(ProjectRenameFileCommand(project, oldFile, newFile, True)): event.Veto() return self._treeCtrl.SortChildren(self._treeCtrl.GetRootItem()) @@ -1015,9 +1303,8 @@ class ProjectView(wx.lib.docview.View): def OnCut(self, event): - if self._AreSelectedItemsFromSameProject(): - self.OnCopy(event) - self.OnClear(event) + self.OnCopy(event) + self.OnClear(event) def OnCopy(self, event): @@ -1025,7 +1312,7 @@ class ProjectView(wx.lib.docview.View): items = self._treeCtrl.GetSelections() for item in items: if self._IsItemFile(item): - file = self._treeCtrl.GetPyData(item) + file = self._treeCtrl.GetLongFilename(item) fileDataObject.AddFile(file) if len(fileDataObject.GetFilenames()) > 0 and wx.TheClipboard.Open(): wx.TheClipboard.SetData(fileDataObject) @@ -1041,15 +1328,57 @@ class ProjectView(wx.lib.docview.View): def OnClear(self, event): - if self._AreSelectedItemsFromSameProject(): - items = self._treeCtrl.GetSelections() - files = [] - for item in items: - if self._IsItemFile(item): - files.append(self._GetItemFile(item)) - self.GetDocument().GetCommandProcessor().Submit(ProjectRemoveFilesCommand(self._GetItemProject(items[0]), files)) + items = self._treeCtrl.GetSelections() + files = [] + for item in items: + if self._IsItemFile(item): + files.append((self._GetItemProject(item), self._GetItemFile(item))) + self.GetDocument().GetCommandProcessor().Submit(ProjectRemoveFilesCommand(files)) + def OnDeleteFile(self, event): + yesNoMsg = wx.MessageDialog(self.GetFrame(), + _("Delete cannot be reversed.\n\nRemove the selected files from the\nprojects and file system permanently?"), + _("Delete File"), + wx.YES_NO|wx.ICON_QUESTION) + if yesNoMsg.ShowModal() == wx.ID_NO: + return + + items = self._treeCtrl.GetSelections() + files = [] + delFiles = [] + for item in items: + if self._IsItemFile(item): + filename = self._GetItemFile(item) + files.append((self._GetItemProject(item), filename)) + if filename not in delFiles: + delFiles.append(filename) + + # remove selected files from projects + projects = [] + for data in files: + proj, filename = data + if proj not in projects: + projects.append(proj) + for project in projects: + filenames = [] + for data in files: + proj, filename = data + if project == proj: + filenames.append(filename) + project.RemoveFiles(filenames) + + # remove selected files from file system + for filename in delFiles: + if os.path.exists(filename): + try: + os.remove(filename) + except: + wx.MessageBox("Could not delete '%s'. %s" % (os.path.basename(filename), sys.exc_value), + _("Delete File"), + wx.OK | wx.ICON_EXCLAMATION) + + def OnKeyPressed(self, event): key = event.KeyCode() if key == wx.WXK_DELETE: @@ -1085,7 +1414,7 @@ class ProjectView(wx.lib.docview.View): yesNoMsg = wx.MessageDialog(self.GetFrame(), _("The file '%s' was not found in '%s'.\n\nWould you like to browse for the file?") % (wx.lib.docview.FileNameFromPath(filepath), wx.lib.docview.PathOnly(filepath)), msgTitle, - wx.YES_NO + wx.YES_NO|wx.ICON_QUESTION ) if yesNoMsg.ShowModal() == wx.ID_NO: continue @@ -1102,11 +1431,23 @@ class ProjectView(wx.lib.docview.View): findFile.Destroy() if newpath: # update Project Model with new location - self.GetDocument().RemoveFile(filepath) - self.GetDocument().AddFile(newpath) + project = self._GetItemProject(item) + project.RemoveFile(filepath) + project.AddFile(newpath) filepath = newpath doc = self.GetDocumentManager().CreateDocument(filepath, wx.lib.docview.DOC_SILENT) + if not doc: + shortFilename = self._treeCtrl.GetItemText(item) + if shortFilename.endswith(".agp"): + projItem = self._GetProjectItem(shortFilename=shortFilename) + self._treeCtrl.UnselectAll() + if not self._treeCtrl.IsExpanded(projItem): + self._treeCtrl.Expand(projItem) + if not self._treeCtrl.IsVisible(projItem): + self._treeCtrl.EnsureVisible(projItem) + if not self._treeCtrl.IsSelected(projItem): + self._treeCtrl.SelectItem(projItem) except IOError, (code, message): msgTitle = wx.GetApp().GetAppName() @@ -1128,15 +1469,14 @@ class ProjectView(wx.lib.docview.View): return self._treeCtrl.GetCount() > 1 # 1 item = root item, don't count as having files - def _HasProjectsSelected(self): + def _HasSelection(self): if not self._treeCtrl: return False + items = self._treeCtrl.GetSelections() - if not items: - return False - for item in items: - if self._IsItemProject(item): - return True + if items: + return True + return False @@ -1157,11 +1497,17 @@ class ProjectView(wx.lib.docview.View): # Return the tree item for a project - def _GetProjectItem(self, project): - children = self._GetChildItems(self._treeCtrl.GetRootItem()) - for child in children: - if self._treeCtrl.GetPyData(child) == project: - return child + def _GetProjectItem(self, project=None, shortFilename=None): + rootItem = self._treeCtrl.GetRootItem() + (child, cookie) = self._treeCtrl.GetFirstChild(rootItem) + while child.IsOk(): + if project: + if self._treeCtrl.GetProjectDoc(child) == project: + return child + elif shortFilename: + if self._treeCtrl.GetItemText(child) == shortFilename: + return child + (child, cookie) = self._treeCtrl.GetNextChild(rootItem, cookie) return None @@ -1170,15 +1516,15 @@ class ProjectView(wx.lib.docview.View): if self._IsItemRoot(item): return None if self._IsItemProject(item): - return self._treeCtrl.GetPyData(item) + return self._treeCtrl.GetProjectDoc(item) if self._IsItemFile(item): - return self._treeCtrl.GetPyData(self._treeCtrl.GetItemParent(item)) + return self._treeCtrl.GetProjectDoc(self._treeCtrl.GetItemParent(item)) return None def _GetItemFile(self, item): if self._IsItemFile(item): - return self._treeCtrl.GetPyData(item) + return self._treeCtrl.GetLongFilename(item) else: return None @@ -1186,39 +1532,20 @@ class ProjectView(wx.lib.docview.View): def _GetFileItem(self, shortFileName = None, longFileName = None): """ Returns the tree item for a file given the short (display) or long (fullpath) file name. """ - if shortFileName: - project_children = self._GetChildItems(self._treeCtrl.GetRootItem()) - for child in project_children: - file_children = self._GetChildItems(child) - for file_child in file_children: - if self._treeCtrl.GetItemText(file_child) == shortFileName: - return file_child - return None - else: - project_children = self._GetChildItems(self._treeCtrl.GetRootItem()) - for child in project_children: - file_children = self._GetChildItems(child) - for file_child in file_children: - if self._treeCtrl.GetPyData(file_child) == longFileName: - return file_child - return None - - - def GetFilePathFromTreeName(self, shortFileName): - """ - Returns the data object given a short (display) file name for a file. The data - object should be the full path. - """ - return self._GetItemFile(self._GetFileItem(shortFileName)) - - - def SelectFileInTree(self, shortFileName): - item = self._GetFileItem(shortFileName) - if item: - for selection in self._treeCtrl.GetSelections(): - self._treeCtrl.SelectItem(selection, False) - self._treeCtrl.SelectItem(item, True) - self._treeCtrl.EnsureVisible(item) + rootItem = self._treeCtrl.GetRootItem() + (project, cookie) = self._treeCtrl.GetFirstChild(rootItem) + while project.IsOk(): + (child, cookie2) = self._treeCtrl.GetFirstChild(project) + while child.IsOk(): + if shortFileName: + if self._treeCtrl.GetItemText(child) == shortFileName: + return child + else: + if self._treeCtrl.GetLongFilename(child) == longFileName: + return child + (child, cookie2) = self._treeCtrl.GetNextChild(project, cookie2) + (project, cookie) = self._treeCtrl.GetNextChild(rootItem, cookie) + return None def _IsItemRoot(self, item): @@ -1226,19 +1553,19 @@ class ProjectView(wx.lib.docview.View): def _IsItemProject(self, item): - return isinstance(self._treeCtrl.GetPyData(item), ProjectDocument) + return self._treeCtrl.GetProjectDoc(item) != None def _IsItemFile(self, item): - return isinstance(self._treeCtrl.GetPyData(item), types.StringTypes) + return self._treeCtrl.GetProjectDoc(item) == None def _IsItemProcessModelFile(self, item): if ACTIVEGRID_BASE_IDE: return False - if isinstance(self._treeCtrl.GetPyData(item), types.StringTypes): - filename = self._treeCtrl.GetPyData(item) + if self._IsItemFile(item): + filename = self._treeCtrl.GetLongFilename(item) ext = None for template in self.GetDocumentManager().GetTemplates(): if template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument: @@ -1253,23 +1580,6 @@ class ProjectView(wx.lib.docview.View): return False - def _AreSelectedItemsFromSameProject(self): - if not self._treeCtrl: - return False - items = self._treeCtrl.GetSelections() - if not items: - return False - project = self._GetItemProject(items[0]) - if project == None: - return False - for item in items: - if not self._IsItemFile(item): - return False - if self._GetItemProject(item) != project: - return False - return True - - def _GetChildItems(self, parentItem): children = [] (child, cookie) = self._treeCtrl.GetFirstChild(parentItem) @@ -1307,9 +1617,6 @@ class ProjectPropertiesDialog(wx.Dialog): def __init__(self, parent, filename): wx.Dialog.__init__(self, parent, -1, _("Project Properties"), size = (310, 330)) - HALF_SPACE = 5 - SPACE = 10 - filePropertiesService = wx.GetApp().GetService(wx.lib.pydocview.FilePropertiesService) notebook = wx.Notebook(self, -1) @@ -1355,9 +1662,8 @@ class ProjectPropertiesDialog(wx.Dialog): sizer.Add(notebook, 0, wx.ALL | wx.EXPAND, SPACE) sizer.Add(self.CreateButtonSizer(wx.OK), 0, wx.ALIGN_RIGHT | wx.RIGHT | wx.BOTTOM, HALF_SPACE) - sizer.Fit(self) - self.SetDimensions(-1, -1, 310, -1, wx.SIZE_USE_EXISTING) self.SetSizer(sizer) + sizer.Fit(self) self.Layout() @@ -1367,17 +1673,16 @@ class ProjectOptionsPanel(wx.Panel): def __init__(self, parent, id): wx.Panel.__init__(self, parent, id) self._useSashMessageShown = False - SPACE = 10 - HALF_SPACE = 5 config = wx.ConfigBase_Get() self._projSaveDocsCheckBox = wx.CheckBox(self, -1, _("Remember open projects")) self._projSaveDocsCheckBox.SetValue(config.ReadInt("ProjectSaveDocs", True)) projectBorderSizer = wx.BoxSizer(wx.VERTICAL) projectSizer = wx.BoxSizer(wx.VERTICAL) projectSizer.Add(self._projSaveDocsCheckBox, 0, wx.ALL, HALF_SPACE) - self._projShowWelcomeCheckBox = wx.CheckBox(self, -1, _("Show Welcome Dialog")) - self._projShowWelcomeCheckBox.SetValue(config.ReadInt("RunWelcomeDialog", True)) - projectSizer.Add(self._projShowWelcomeCheckBox, 0, wx.ALL, HALF_SPACE) + if not ACTIVEGRID_BASE_IDE: + self._projShowWelcomeCheckBox = wx.CheckBox(self, -1, _("Show Welcome Dialog")) + self._projShowWelcomeCheckBox.SetValue(config.ReadInt("RunWelcomeDialog", True)) + projectSizer.Add(self._projShowWelcomeCheckBox, 0, wx.ALL, HALF_SPACE) projectBorderSizer.Add(projectSizer, 0, wx.ALL, SPACE) self.SetSizer(projectBorderSizer) self.Layout() @@ -1398,7 +1703,8 @@ class ProjectOptionsPanel(wx.Panel): def OnOK(self, optionsDialog): config = wx.ConfigBase_Get() config.WriteInt("ProjectSaveDocs", self._projSaveDocsCheckBox.GetValue()) - config.WriteInt("RunWelcomeDialog", self._projShowWelcomeCheckBox.GetValue()) + if not ACTIVEGRID_BASE_IDE: + config.WriteInt("RunWelcomeDialog", self._projShowWelcomeCheckBox.GetValue()) class ProjectService(Service.Service): @@ -1415,7 +1721,9 @@ class ProjectService(Service.Service): RENAME_ID = wx.NewId() OPEN_SELECTION_ID = wx.NewId() REMOVE_FROM_PROJECT = wx.NewId() - + DELETE_FILE_ID = wx.NewId() + ADD_ALL_FILES_TO_PROJECT_ID = wx.NewId() + #---------------------------------------------------------------------------- # Overridden methods @@ -1468,8 +1776,6 @@ class ProjectService(Service.Service): def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None): Service.Service.InstallControls(self, frame, menuBar, toolBar, statusBar, document) - config = wx.ConfigBase_Get() - projectMenu = wx.Menu() ## accelTable = wx.AcceleratorTable([ @@ -1479,9 +1785,13 @@ class ProjectService(Service.Service): isProjectDocument = document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument if wx.GetApp().IsMDI() or isProjectDocument: if not menuBar.FindItemById(ProjectService.ADD_FILES_TO_PROJECT_ID): - projectMenu.Append(ProjectService.ADD_FILES_TO_PROJECT_ID, _("&Add Files to Project..."), _("Adds a document to the current project")) + projectMenu.Append(ProjectService.ADD_FILES_TO_PROJECT_ID, _("Add &Files to Project..."), _("Adds a document to the current project")) wx.EVT_MENU(frame, ProjectService.ADD_FILES_TO_PROJECT_ID, frame.ProcessEvent) wx.EVT_UPDATE_UI(frame, ProjectService.ADD_FILES_TO_PROJECT_ID, frame.ProcessUpdateUIEvent) + if not menuBar.FindItemById(ProjectService.ADD_ALL_FILES_TO_PROJECT_ID): + projectMenu.Append(ProjectService.ADD_ALL_FILES_TO_PROJECT_ID, _("Add Directory Files to Project..."), _("Adds a directory's documents to the current project")) + wx.EVT_MENU(frame, ProjectService.ADD_ALL_FILES_TO_PROJECT_ID, frame.ProcessEvent) + wx.EVT_UPDATE_UI(frame, ProjectService.ADD_ALL_FILES_TO_PROJECT_ID, frame.ProcessUpdateUIEvent) if not menuBar.FindItemById(ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID): projectMenu.Append(ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, _("&Add Active File to Project..."), _("Adds the active document to a project")) wx.EVT_MENU(frame, ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID, frame.ProcessEvent) @@ -1490,10 +1800,13 @@ class ProjectService(Service.Service): menuBar.Insert(viewMenuIndex + 1, projectMenu, _("&Project")) editMenu = menuBar.GetMenu(menuBar.FindMenu(_("&Edit"))) if not menuBar.FindItemById(ProjectService.RENAME_ID): - editMenu.AppendSeparator() editMenu.Append(ProjectService.RENAME_ID, _("&Rename"), _("Renames the active item")) wx.EVT_MENU(frame, ProjectService.RENAME_ID, frame.ProcessEvent) wx.EVT_UPDATE_UI(frame, ProjectService.RENAME_ID, frame.ProcessUpdateUIEvent) + if not menuBar.FindItemById(ProjectService.DELETE_FILE_ID): + editMenu.Append(ProjectService.DELETE_FILE_ID, _("Delete File"), _("Delete the file from the project and file system.")) + wx.EVT_MENU(frame, ProjectService.DELETE_FILE_ID, frame.ProcessEvent) + wx.EVT_UPDATE_UI(frame, ProjectService.DELETE_FILE_ID, frame.ProcessUpdateUIEvent) return True @@ -1531,9 +1844,43 @@ class ProjectService(Service.Service): def ProcessEventBeforeWindows(self, event): id = event.GetId() + if id == wx.ID_CLOSE_ALL: self.OnFileCloseAll(event) return True + + elif id == wx.ID_CLOSE: + document = self.GetDocumentManager().GetCurrentDocument() + if document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument: + self.OnProjectClose(event) + return True + else: + return False + return False + + + def ProcessUpdateUIEventBeforeWindows(self, event): + id = event.GetId() + + if id == wx.ID_CLOSE_ALL: + for document in self.GetDocumentManager().GetDocuments(): + if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument: + event.Enable(True) + return True + + event.Enable(False) + return True + + elif id == wx.ID_CLOSE: + document = self.GetDocumentManager().GetCurrentDocument() + if document and document.GetDocumentTemplate().GetDocumentType() == ProjectDocument: + projectFilenames = self.GetView().GetSelectedProjects() + if projectFilenames and len(projectFilenames): + event.Enable(True) + else: + event.Enable(False) + return True + return False @@ -1565,19 +1912,19 @@ class ProjectService(Service.Service): return True id = event.GetId() - if id == ProjectService.RUNPM_ID or id == ProjectService.RUN_SELECTED_PM_ID or id == ProjectService.RUN_CURRENT_PM_ID: + if (id == ProjectService.RUNPM_ID + or id == ProjectService.RUN_SELECTED_PM_ID + or id == ProjectService.RUN_CURRENT_PM_ID): event.Enable(self._HasOpenedProjects() and self._HasProcessModel()) return True - elif id == ProjectService.ADD_FILES_TO_PROJECT_ID: - event.Enable(False) - return True elif id == ProjectService.ADD_CURRENT_FILE_TO_PROJECT_ID: event.Enable(self._CanAddCurrentFileToProject()) return True - elif id == ProjectService.RENAME_ID: - event.Enable(False) - return True - elif id == ProjectService.OPEN_SELECTION_ID: + elif (id == ProjectService.ADD_FILES_TO_PROJECT_ID + or id == ProjectService.ADD_ALL_FILES_TO_PROJECT_ID + or id == ProjectService.RENAME_ID + or id == ProjectService.OPEN_SELECTION_ID + or id == ProjectService.DELETE_FILE_ID): event.Enable(False) return True elif id == wx.lib.pydocview.FilePropertiesService.PROPERTIES_ID: @@ -1622,7 +1969,7 @@ class ProjectService(Service.Service): yesNoMsg = wx.MessageDialog(frame, _("Files have been modified. Process may not reflect your current changes.\n\nWould you like to save all files before running?"), _("Run Process"), - wx.YES_NO + wx.YES_NO|wx.ICON_QUESTION ) if yesNoMsg.ShowModal() == wx.ID_YES: wx.GetTopLevelParent(frame).OnFileSaveAll(None) @@ -1739,6 +2086,7 @@ class ProjectService(Service.Service): strings = map(lambda project: project.GetPrintableName(), projects) return strings + def OnAddCurrentFileToProject(self, event): if not self._CanAddCurrentFileToProject(): return @@ -1761,6 +2109,14 @@ class ProjectService(Service.Service): self.GetView().Activate(True) # after add, should put focus on project editor + def OnProjectClose(self, event): + projectFilenames = self.GetView().GetSelectedProjects() + for filename in projectFilenames: + doc = self.FindProjectByFile(filename) + if doc: + self.GetDocumentManager().CloseDocument(doc, False) + + def OnFileCloseAll(self, event): for document in self.GetDocumentManager().GetDocuments()[:]: # Cloning list to make sure we go through all docs even as they are deleted if document.GetDocumentTemplate().GetDocumentType() != ProjectDocument: @@ -1789,11 +2145,45 @@ class ProjectService(Service.Service): view.SetExpandedProjects(eval(expandedString)) return openedDocs + +class ProjectEditorMoveCommand(wx.lib.docview.Command): + + def __init__(self, view, newPositionItem, item): + wx.lib.docview.Command.__init__(self, canUndo = True) + self._view = view + self._item = item + self._file = view._treeCtrl.GetLongFilename(item) + if view._IsItemFile(item): + self._projectOld = view._GetItemProject(item) + else: # view._IsItemProject(item): + self._projectOld = None + self._projectNew = view._GetItemProject(newPositionItem) + + + def GetName(self): + return _("Move File %s") % os.path.basename(self._file) + + + def Do(self): + if self._projectOld: + self._projectOld.RemoveFile(self._file) + if self._projectNew: + self._projectNew.AddFile(self._file) + return True + + + def Undo(self): + if self._projectNew: + self._projectNew.RemoveFile(self._file) + if self._projectOld: + self._projectOld.AddFile(self._file) + return True + + #---------------------------------------------------------------------------- # Icon Bitmaps - generated by encode_bitmaps.py #---------------------------------------------------------------------------- from wx import ImageFromStream, BitmapFromImage -from wx import EmptyIcon import cStringIO @@ -1814,23 +2204,20 @@ def getProjectImage(): return ImageFromStream(stream) def getProjectIcon(): - icon = EmptyIcon() - icon.CopyFromBitmap(getProjectBitmap()) - return icon + return wx.IconFromBitmap(getProjectBitmap()) #---------------------------------------------------------------------------- def getBlankData(): return \ -"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ -\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00\ -\x85IDATX\x85\xed\x97\xc9\n\xc0 \x0cD3\xda\xff\xffcMo\x96Z\xc4\xa5\x91\x14:9\ -\x8a\xe8\xcb\xd3\xb8\x00!\x8ag\x04\xd7\xd9E\xe4\xa8\x1b4'}3 B\xc4L\x7fs\x03\ -\xb3\t<\x0c\x94\x81tN\x04p%\xae9\xe9\xa8\x89m{`\xd4\x84\xfd\x12\xa8\x16{#\ -\x10\xdb\xab\xa0\x07a\x0e\x00\xe0\xb6\x1fz\x10\xdf;\x07V\xa3U5\xb5\x8d:\xdc\ -\r\x10\x80\x00\x04 \x00\x01\x08@\x80\xe6{\xa0w\x8f[\x85\xbb\x01\xfc\xfeoH\ -\x80\x13>\xf9(3zH\x1e\xfb\x00\x00\x00\x00IEND\xaeB`\x82" +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ +\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ +\x00\x00]IDAT8\x8d\xed\x931\x0e\xc00\x08\x03m\x92\xff\xff8q\x87\xb6C\x11\x89\ +\xa8X:\xd4\x13\x03:\x1b\x01\xa45T\xd4\xefBsh\xd7Hk\xdc\x02\x00@\x8a\x19$\xa1\ +9\x14A,\x95\xf3\x82G)\xd3\x00\xf24\xf7\x90\x1ev\x07\xee\x1e\xf4:\xc1J?\xe0\ +\x0b\x80\xc7\x1d\xf8\x1dg\xc4\xea7\x96G8\x00\xa8\x91\x19(\x85#P\x7f\x00\x00\ +\x00\x00IEND\xaeB`\x82' def getBlankBitmap(): @@ -1841,7 +2228,5 @@ def getBlankImage(): return ImageFromStream(stream) def getBlankIcon(): - icon = EmptyIcon() - icon.CopyFromBitmap(getBlankBitmap()) - return icon + return wx.IconFromBitmap(getBlankBitmap())