# Part of the A-A-P GUI IDE: Navigation Tree, part of the GUI # Copyright (C) 2002-2003 Stichting NLnet Labs # Permission to copy and use this file is specified in the file COPYING. # If this file is missing you can find it here: http://www.a-a-p.org/COPYING # # This is the tree that shows items in a Navigator. # It is displayed in each notebook of an activity. # import string import os.path from wxPython.wx import * import Util import Tool # message translation def _(x): return Tool._gettext(x) [ # Menu IDs ID_CMENU_OPEN, ID_CMENU_BUILD, ID_CMENU_EXECUTE, ID_CMENU_ADDITEM, ID_CMENU_ADDFILE, ID_CMENU_ADDVAL, ID_CMENU_DELETE, ID_CMENU_RENAMEFILE, ID_CMENU_RENAMEVALUE, ] = map(lambda x: wxNewId(), range(9)) class NavTree(wxTreeCtrl): """A tree view for a Navigator.""" def __init__(self, parent, treecontrols, topitem): id = wxNewId() wxTreeCtrl.__init__(self, parent = parent, id = id, name = 'treeCtrl' + str(len(treecontrols)), style = wxTR_HAS_BUTTONS | wxTR_EDIT_LABELS, validator = wxDefaultValidator) # XXX specify the status line to be used for menu texts EVT_TREE_ITEM_ACTIVATED(self, id, self.OnTreeItemActivate) EVT_TREE_BEGIN_LABEL_EDIT (self, id, self.OnBeginEdit) EVT_TREE_END_LABEL_EDIT (self, id, self.OnEndEdit) EVT_RIGHT_DOWN(self, self.OnRightDown) EVT_RIGHT_UP(self, self.OnRightUp) root = self.AddRoot(topitem.listName(), data = wxTreeItemData(topitem)) self.showNavItems(root, topitem.children) self.Expand(root) self.dirname = os.path.dirname(topitem.fullName()) self.topview = topitem.acty.topmodel.view def showNavItems(self, parent, actyitemlist): if actyitemlist: for item in actyitemlist.itemlist: i = self.AppendItem(parent, item.shortName(), data = wxTreeItemData(item)) self.showNavItems(i, item.children) def setStatusMessage(self, msg): self.topview.SetStatusText(msg) def OnTreeItemActivate(self, e): """Double click on an item.""" item = e.GetItem() root = self.GetRootItem() if item != root and self.GetItemParent(item) == root: # Variable item: expand self.Expand(item) elif item != root and self.isValueItem(self.GetItemParent(item)): # Value item (e.g., CFLAGS): edit self.EditLabel(item) else: # Root item or something else: run default tool actyitem = self.GetPyData(item) if actyitem.node: # XXX check that it's really an ActiItem instance. actyitem.runTool() def OnBeginEdit(self, e): """Trying to edit an item in the tree. Reject editing the topitem (should use "save as" and read-only items.""" item = e.GetItem() if item == self.GetRootItem() or self.IsReadOnlyItem(item): e.Veto() def OnEndEdit(self, e): """An item in the tree was edited.""" treeitem = e.GetItem() newtext = e.GetLabel() if not self.NewTextOK(treeitem, newtext): e.Veto() else: actyitem = self.GetPyData(treeitem) actyitem.rename(newtext, actyitem.dir) # on Win32 rename is not enough, so call additionally: self.SetItemText(treeitem, newtext) def NewTextOK(self, item, newtext): if not newtext: return 0 # empty text is not accepted if self.GetItemParent(item) == self.GetRootItem(): for c in newtext: if not c in string.letters + '_': return 0 return 1 def OnRightDown(self, e): """Right mouse button down: select item.""" pt = e.GetPosition() item, flags = self.HitTest(pt) self.SelectItem(item) def OnRightUp(self, e): """Right mouse button up: popup context menu.""" pt = e.GetPosition() item, flags = self.HitTest(pt) if not self.GetItemText(item): # Moved to somewhere else. return # XXX primitive way to check whether this is a project. txt = self.GetItemText(self.GetRootItem()) isproject = (len(txt) > 4 and (txt[-4:] == ".aap") or string.find(txt, ".aap ") > 0) # Use the selected item, not the one where the mouse button was # released. item = self.GetSelection() if self.GetItemText(item) and not self.IsReadOnlyItem(item): # Create popup menu menu = wxMenu() actyitem = self.GetPyData(item) # Actions available in Tools self.actionnames = {} actionlist = Tool.availableActions(actyitem) for act in actionlist: id = wxNewId() menu.Append(id, act, _("%s item in default tool") % act) EVT_MENU(self, id, self.OnMenuAction) self.actionnames[id] = act # Build if isproject and (item == self.GetRootItem() or self.GetItemText(self.GetItemParent(item)) == "TARGET"): menu.Append(ID_CMENU_BUILD, _("&Build"), _("Build the (default) target")) EVT_MENU(self, ID_CMENU_BUILD, self.OnMenuBuild) # Execute if actyitem.node: name = actyitem.node.name if not os.path.exists(name): from RecPython import program_path name = program_path(name) if name and os.access(name, os.X_OK): menu.Append(ID_CMENU_EXECUTE, _("&Execute"), _("Execute this program")) EVT_MENU(self, ID_CMENU_EXECUTE, self.OnMenuExecute) if isproject: menu.AppendSeparator() if item == self.GetRootItem(): # Add/Rename item menu.Append(ID_CMENU_ADDITEM, _("&Add item"), _("Add item to project")) EVT_MENU(self, ID_CMENU_ADDITEM, self.OnMenuAddValue) else: parent = self.GetItemParent(item) root = self.GetRootItem() if parent == root: checkitem = item else: checkitem = parent if not self.isValueItem(checkitem): menu.Append(ID_CMENU_ADDFILE, _("&Add file"), _("Add file to selected item")) EVT_MENU(self, ID_CMENU_ADDFILE, self.OnMenuAddFile) if not self.isFileItem(checkitem): menu.Append(ID_CMENU_ADDVAL, _("&Add value"), _("Add value in selected item")) EVT_MENU(self, ID_CMENU_ADDVAL, self.OnMenuAddValue) # Delete menu.Append(ID_CMENU_DELETE, _("&Delete"), _("Delete selected item")) EVT_MENU(self, ID_CMENU_DELETE, self.OnMenuDelete) # Rename if parent != root and not self.isValueItem(parent): menu.Append(ID_CMENU_RENAMEFILE, _("&Rename"), _("Rename selected file")) EVT_MENU(self, ID_CMENU_RENAMEFILE, self.OnMenuRename) if parent == root or not self.isFileItem(parent): menu.Append(ID_CMENU_RENAMEVALUE, _("&Change"), _("Change selected item")) EVT_MENU(self, ID_CMENU_RENAMEVALUE, self.OnMenuChange) self.PopupMenu(menu, e.GetPosition()) def isFileItem(self, item): """Return non-zero if "item" has files for value.""" return self.GetItemText(item) in [ "SOURCE", "TARGET" ] def isValueItem(self, item): """Return non-zero if "item" never has files for value.""" return self.GetItemText(item) in [ "CFLAGS", "CPPFLAGS" ] def OnMenuAction(self, e): """Perform one of the available actions on an item. Triggered from context menu.""" actyitem = self.GetPyData(self.GetSelection()) actionname = self.actionnames[e.GetId()] actyitem.runTool(actionname) def OnMenuBuild(self, e): """Build a target, triggered from context menu.""" actyitem = self.GetPyData(self.GetSelection()) self.setStatusMessage(_("Building %s...") % actyitem.listName()) cwd = os.getcwd() actyitem.build() os.chdir(cwd) self.setStatusMessage(_("Finished building %s.") % actyitem.listName()) def OnMenuExecute(self, e): """Build a target, triggered from context menu.""" actyitem = self.GetPyData(self.GetSelection()) self.topview.execute(actyitem) def OnMenuAddFile(self, e): """Add a file item, triggered from context menu.""" item = self.GetSelection() name = self.fileDialog("Name for new item") if not name: return parent = self.GetItemParent(item) if not parent == self.GetRootItem(): item = parent actyitem = self.GetPyData(item) newactyitem = actyitem.addChildByName(name) newitem = self.findActyItem(newactyitem) self.EnsureVisible(newitem) def OnMenuAddValue(self, e): """Add an item, triggered from context menu.""" item = self.GetSelection() if item != self.GetRootItem(): parent = self.GetItemParent(item) if not parent == self.GetRootItem(): item = parent name = "NEW" actyitem = self.GetPyData(item) newactyitem = actyitem.addChildByName(name) newitem = self.findActyItem(newactyitem) self.EnsureVisible(newitem) self.EditLabel(newitem) def addActyItem(self, actyitem): """Add an actyitem to the tree.""" # Need to search for the parent item in the tree. item = self.findActyItem(actyitem.parent) if item: self.AppendItem(item, actyitem.shortName(), data = wxTreeItemData(actyitem)) else: print "Failed to add item '%s'" % actyitem.shortName() print "Parent: '%s'" % actyitem.parent.shortName() def findActyItem(self, actyitem): """Find an ActyItem in the tree, return its ID.""" return self.findActyItemRec(actyitem, self.GetRootItem()) def findActyItemRec(self, actyitem, item): if self.GetPyData(item) == actyitem: return item cookie = 0 if wxVERSION_STRING < "2.5": child, cookie = self.GetFirstChild(item, cookie) else: child, cookie = self.GetFirstChild(item) while child.IsOk(): i = self.findActyItemRec(actyitem, child) if i: return i child, cookie = self.GetNextChild(item, cookie) return None def OnMenuDelete(self, e): """Delete item, triggered from context menu.""" item = self.GetSelection() self.GetPyData(self.GetItemParent(item)).delChild(self.GetPyData(item)) self.Delete(item) def OnMenuRename(self, e): """Rename item, triggered from context menu.""" item = self.GetSelection() newtext = self.fileDialog("Name for new item", self.GetItemText(item)) if newtext and self.NewTextOK(item, newtext): actyitem = self.GetPyData(item) name = Util.shorten_name(Util.full_fname(newtext), actyitem.dir) actyitem.rename(name, actyitem.dir) self.SetItemText(item, name) def OnMenuChange(self, e): """Change value of item, triggered from context menu.""" item = self.GetSelection() self.EditLabel(item) def IsReadOnlyItem(self, item): """Return non-zero if "item" can't be deleted or renamed.""" while 1: text = self.GetItemText(item)[0] if item == self.GetRootItem() or len(text) == 0: break if len(text) > 0 and text[0] == '|': return 1 item = self.GetItemParent(item) return 0 def fileDialog(self, title, name = ""): """Show a normal file dialog. Used to obtain the name of a new item or changing an existing item.""" dlg = wxFileDialog(self, title, self.dirname, name, "*.*", wxOPEN) if dlg.ShowModal() == wxID_OK: name = dlg.GetPath() name = Util.shorten_name(name) # Remember dir for next time. self.dirname = dlg.GetDirectory() else: name = None dlg.Destroy() return name # vim: set sw=4 et sts=4 tw=79 fo+=l: