home *** CD-ROM | disk | FTP | other *** search
- # ***** BEGIN LICENSE BLOCK *****
- # Version: MPL 1.1/GPL 2.0/LGPL 2.1
- #
- # The contents of this file are subject to the Mozilla Public License Version
- # 1.1 (the "License"); you may not use this file except in compliance with
- # the License. You may obtain a copy of the License at
- # http://www.mozilla.org/MPL/
- #
- # Software distributed under the License is distributed on an "AS IS" basis,
- # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- # for the specific language governing rights and limitations under the
- # License.
- #
- # The Original Code is the Python Computer Graphics Kit.
- #
- # The Initial Developer of the Original Code is Matthias Baas.
- # Portions created by the Initial Developer are Copyright (C) 2004
- # the Initial Developer. All Rights Reserved.
- #
- # Contributor(s):
- #
- # Alternatively, the contents of this file may be used under the terms of
- # either the GNU General Public License Version 2 or later (the "GPL"), or
- # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- # in which case the provisions of the GPL or the LGPL are applicable instead
- # of those above. If you wish to allow use of your version of this file only
- # under the terms of either the GPL or the LGPL, and not to allow others to
- # use your version of this file under the terms of the MPL, indicate your
- # decision by deleting the provisions above and replace them with the notice
- # and other provisions required by the GPL or the LGPL. If you do not delete
- # the provisions above, a recipient may use your version of this file under
- # the terms of any one of the MPL, the GPL or the LGPL.
- #
- # ***** END LICENSE BLOCK *****
-
- ## \file menu.py
- ## Contains the menu tree classes.
-
- import wx
- import types
-
-
- class MenuNodeNotFound(Exception):
- """Exception class."""
- pass
-
- class DuplicateNames(Exception):
- """Exception class."""
- pass
-
- class InvalidMenuRoot(Exception):
- """Exception class."""
- pass
-
- class NoWxMenuObjectFound(Exception):
- """Exception class."""
- pass
-
- class MenuAlreadyInUse(Exception):
- """Exception class."""
- pass
-
- class NoMenuRoot(Exception):
- """Exception class."""
- pass
-
- NODE_NORMAL_ITEM = 0x01
- NODE_CHECK_ITEM = 0x02
- NODE_COMMAND_ITEM = NODE_NORMAL_ITEM | NODE_CHECK_ITEM
- NODE_SEPARATOR = 0x04
- NODE_MENU = 0x08
- NODE_MARKER = 0x10
- NODE_ALL_NODES = 0xff
-
-
- # MenuNode
- class MenuNode(object):
- """Base class for a menu node.
-
- This is the base class for all menu nodes (inner node or leaf).
- A %MenuNode class can be used as a sequence where the items are
- the children nodes. Leaf nodes are always empty.
-
- Each node has the following attributes:
-
- - \b name (\c str): Node name
- - \b absname (\c str): Absolute node name
- - \b parent (\c %MenuNode): Parent node
- - \b root (\c %MenuNode): Root node
- - \b text (\c str): Text that's visible to the user
- - \b enabled (\c bool): If this flag is false the menu or menu item is grayed out.
- - \b visible (\c bool): If this flag is false the menu or menu item isn't displayed at all.
- - \b wx (\c wxMenu, \c wxMenuBar or \c wxMenuItem): Corresponding wxPython object (or None if the menu isn't attached).
-
- - flags
-
- A menu node can be either in an \em attached or \em detached state
- which tells if a node is attached to a wxPython menu or not. An
- attached menu is "active" and usually has a corresponding wxPython
- menu object associated with it. When you create a menu node it's
- not attached to a menu. A node automatically becomes attached when
- it's added to another node that is already attached.
-
- Any class that is derived from this base class has to implement the
- following methods:
-
- - setEnabled()
- - setVisibility()
- - _wx_menu_count()
- - _create_wx()
-
- """
-
- def __init__(self, name=None, parent=None, text=None,
- enabled=True, visible=True):
- """Constructor.
-
- If no name is given the constructor tries to create a name
- from the \a text argument (using _create_auto_name()).
-
- \param name (\c str) Node name
- \param parent (\c %MenuNode) Parent node
- \param text (\c str) %Menu title or item text
- \param enabled (\c bool) Initial enabled state
- \param visible (\c bool) Initial visibility state
- """
- # Node name
- self._name = name
- # Parent node
- self._parent = parent
- # Text (menu title or item text)
- self._text = text
- # NODE_xxx flags
- self._flags = 0
- # Enabled state
- self._enabled = enabled
- # Visbility state
- self._visible = visible
- # The corresponding wxPython object (or None)
- self._wx = None
- # The wxPython ID of the object
- self._id = None
- # Activation flag
- self._attached = False
-
- if self._name==None:
- self._create_auto_name(self._text)
-
-
- # isAttached
- def isAttached(self):
- return self._attached
-
- def setEnabled(self, flag=True):
- """Set the enabled flag of this node.
-
- If a node is disabled all of its children are considered disabled
- as well.
-
- This method should be overridden by derived classes. Those
- implementations should call the inherited method (where the
- internal flag _enabled is set). If the node is attached to a
- menu this method should update their corresponding menu items
- to reflect the state change.
-
- This method is called automatically when the \em enabled property
- receives a new value.
-
- \param flag (\c bool) New enabled state.
- """
- self._enabled = flag
-
- def setVisibility(self, flag=True):
- """Set the visibility flag of this node.
-
- If a node is invisible all of its children are considered invisible
- as well.
-
- This method should be overridden by derived classes. Those
- implementations should call the inherited method (where the
- internal flag _visible is set). If the node is attached to a
- menu this method should remove their corresponding menu items
- to reflect the state change.
-
- This method is called automatically when the \em visible property
- receives a new value.
-
- \param flag (\c bool) New visibility state.
- """
-
- self._visible = flag
-
- if flag:
- if not self.isAttached():
- self._create_wx()
- else:
- if self.isAttached():
- self._destroy_wx()
-
-
- # remove
- def remove(self, node=""):
- """Remove a menu node.
-
- Removes the node with the given name. The name may contain an
- entire (relative) path to a menu node or may be left blank if
- self should be removed (which is the default behavior). The node
- is removed from the visible wx menu and from the menu tree and
- is returned to the caller which may ignore it or use it to add
- it later or to another menu.
-
- \param node (\c str) Name of the node which should be removed (default: "").
- \return The removed menu node object (\c MenuNode).
- """
-
- # Find the node n which is to be removed
- n = self.findNode(node)
-
- # Remove the corresponding wx objects from the visible menu
- if n.isAttached():
- n._destroy_wx()
-
- parent = n.parent
- if parent!=None:
- del parent[n]
-
- return n
-
- def findCommandNodes(self, func):
- """Return all nodes that are bound to func.
-
- \return A list of all nodes that are bound to func.
- """
-
- res = []
-
- # Check if this node is bound to func
- f = getattr(self, "_command", None)
- if f!=None:
- if f==func:
- res.append(self)
-
- # Now check the children
- for n in self:
- res+=n.findCommandNodes(func)
-
- return res
-
-
- # findNode
- def findNode(self, path, exc=True):
- """Search for a node with a specific relative name.
-
- The name can include an entire path. Each node name is separated
- by a dot. If path is empty then self is returned.
-
- \param path (\c str) Name of the item
- \param exc (\c bool) If True then an exception is generated when the
- node is not found.
- \return Node or None/Exception.
- """
-
- if path=="":
- return self
-
- f = path.split(".")
- name = f[0]
- for n in self:
- if name==n.name:
- if len(f)==1:
- return n
- else:
- return n.findNode(".".join(f[1:]))
-
- if exc:
- errpath = name
- s = self.absname
- if s!="":
- errpath = ".".join([s,errpath])
- raise MenuNodeNotFound, 'Menu node "%s" not found.'%(errpath)
- else:
- return None
-
-
- ######################################################################
- ## protected:
-
- def __len__(self):
- return 0
-
- def __getitem__(self, key):
- if isinstance(key, int):
- raise IndexError, "sequence index out of range"
- else:
- raise TypeError, "sequence indices must be integers"
-
- # _create_auto_name
- def _create_auto_name(self, text):
- """Create a name from the given text.
-
- The argument \a text is the text that's visible to the user
- in the menu. The method tries to generate a node name out
- of the given text. If the text only consists of dashes or is None
- then no name is generated (None), otherwise blanks and tabs are
- collapsed and replaced by underscores, dots and ampersands are
- deleted and the text is made lower case to create the name.
-
- The result of the automatic name generation is stored in the
- name property (_name).
-
- \param text (\c str) Menu text.
- """
- if text==None:
- self._name = None
- return
- text = text.strip()
- # Collapse dash sequences
- while text.find("--")!=-1:
- text = text.replace("--", "-")
- # Was the text that of a separator? then no name is generated
- if text=="-":
- self._name = None
- return
- # Replace tabs with spaces
- text = text.replace("\t", " ")
- # Collapse spaces
- while text.find(" ")!=-1:
- text = text.replace(" ", " ")
- # Replace/delete special characters
- text = text.replace("&","")
- text = text.replace(".","")
- text = text.replace(" ","_")
- self._name = text.lower()
-
- def _wx_menu_count(self):
- """Return the number of menu "slots" that are occupied by this node.
-
- The return value is the number of attached menu items (or
- menus) that are beneath this node. Invisble nodes must not be
- counted. This value is used to determine the position of a
- node in the wx menu.
-
- By default this method returns 0. Usually, a derived class should
- override this method.
-
- \return Number of visible items occupied by this node.
- \see _wx_menu_pos()
- """
- return 0
-
- def _wx_menu_pos(self):
- """Return the position of the node inside the parent wx menu.
-
- The return value is the starting index where self is located
- (or would be located) in the corresponding wx menu. This value
- is used to insert the node into a menu or menubar.
-
- The node has to be added to the menu tree but doesn't have to
- be attached.
-
- \pre self is in the children list of parent.
- \pre The parent nodes must already be attached.
- \return Position (\c int) or None if the node doesn't have a parent.
- \see _wx_menu_count()
- """
-
- parent = self.parent
- if parent==None:
- return None
-
- # Determine the index of self within parent
- idx = 0
- for n in parent:
- if n==self:
- break
- idx += n._wx_menu_count()
-
- if parent._wx==None:
- idx += parent._wx_menu_pos()
-
- return idx
-
-
-
- def _attach(self, IDmanager, window, wxmenubar):
- """Attach the menu to a window.
-
- \param IDmanager ID generator
- \param window (\c Window) wxPython window
- \param wxmenubar (\c wxMenuBar) wxPython menu bar or None
- """
- root = self.root
- if not isinstance(root, Menu):
- raise InvalidMenuRoot, 'The root of a menu has to be a Menu object.'
- # The node must not be attached to another menu
- if self.isAttached():
- raise MenuAlreadyInUse, "The menu node is already in use."
-
- root._IDmanager = IDmanager
- root._window = window
- if wxmenubar!=None:
- root._wx_menubar = wxmenubar
- root._menu_id_lut = {}
- root._create_wx()
-
- def _detach(self):
- """Detach the menu from a window."""
-
- if self.root!=self:
- raise NoMenuRoot, "Only root nodes can be detached."
-
- self._destroy_wx()
- del self._IDmanager
- del self._window
- if hasattr(self, "_wx_menubar"):
- del self._wx_menubar
- del self._menu_id_lut
-
-
- def _create_wx(self):
- """Create the corresponding wxPython object.
-
- This method has to create the appropriate wxPython object which
- is represented by the node and insert it into the parent menu,
- submenu or menubar at the correct position as returned by
- _wx_menu_pos().
-
- The wxPython object has to be stored in the attribute self._wx
- and its ID in self._id.
- The method may only be called if the parent wxPython object
- of the node exists or if the node represents the entire menu bar.
-
- A derived class must call this inherited method!
- """
- self._attached = True
-
- def _destroy_wx(self):
- """Destroy the associated wxPython object.
-
- This method has to remove its corresponding wxPython object
- from the visible wx menu. The method may only be called in
- attached state!
-
- A derived class must call this inherited method!
- """
- self._attached = False
- self._wx = None
- self._id = -1
-
- def _wx_parent(self):
- """Return the wxPython parent object.
-
- The object returned is either a wx.Menu, a wx.MenuBar or None.
- If a node has no direct wx parent, the wx parent of the
- parent node is returned.
-
- This method must not be called when the node is part of an
- invisible tree.
-
- \return wxPython object or None.
- """
- p = self.parent
-
- while p!=None:
- if p._wx!=None:
- if isinstance(p._wx, wx.MenuItem):
- return p._wx.GetSubMenu()
- else:
- return p._wx
- p = p.parent
-
- return None
-
-
- def _is_menubar(self):
- return False
-
- def _is_embedded_menu(self):
- return False
-
-
- # "name" property...
-
- def _getName(self):
- """Return the node name.
-
- This method is used for retrieving the \a name property.
-
- \return Node name (\c str).
- """
- return self._name
-
- name = property(_getName, None, None, "Node name")
-
- # "absname" property...
-
- def _getAbsName(self):
- """Return the absolute name of the node.
-
- Returns the absolute name of the node. This name
- uniquely identifies the node within its tree and is composed
- of all the names from the root to the node separated by a dot.
- The root node is always unnamed.
-
- This method is used for retrieving the \a absname property.
-
- \return Absolute name of the node (\c str).
- """
- if self._parent==None:
- return ""
- else:
- pre = self._parent.getFullName()
- if self._name==None:
- name = "<unnamed>"
- else:
- name = self._name
- if pre=="":
- return name
- else:
- return pre+"."+name
-
- absname = property(_getAbsName, None, None, "Absolute node name")
-
- # "parent" property...
-
- def _getParent(self):
- """Return the parent node.
-
- This method is used for retrieving the \a parent property.
-
- \return Parent node (\c MenuNode).
- """
- return self._parent
-
- parent = property(_getParent, None, None, "Parent node")
-
- # "root" property...
-
- def _getRoot(self):
- """Return the root node.
-
- This method is used for retrieving the \a root property.
-
- \return Root node (\c MenuNode).
- """
- p = self
- while 1:
- if p._parent==None:
- return p
- p = p._parent
-
- root = property(_getRoot, None, None, "Root node")
-
- # "text" property...
-
- def _getText(self):
- """Return the menu text which is displayed to the user.
-
- This method is used for retrieving the \a text property.
-
- \return Text (\c str).
- """
- return self._text
-
- text = property(_getText, None, None, "Menu text")
-
- # "enabled" property...
-
- def _getEnabled(self):
- """Return the enabled state.
-
- This method is used for retrieving the \a enabled property.
-
- \return True if the node is enabled.
- """
- return self._enabled
-
- def _setEnabled(self, flag=True):
- """Set the enabled state.
-
- This method is used for setting the \a enabled property.
-
- \param flag (\c bool) New enabled state.
- """
- self.setEnabled(flag)
-
- enabled = property(_getEnabled, _setEnabled, None, "Enabled state")
-
- # "visible" property...
-
- def _getVisible(self):
- """Return the visible state.
-
- This method is used for retrieving the \a visible property.
-
- \return True if the node is visible.
- """
- return self._visible
-
- def _setVisible(self, flag=True):
- """Set the visible state.
-
- This method is used for setting the \a visible property.
-
- \param flag (\c bool) New visibility state.
- """
- self.setVisibility(flag)
-
- visible = property(_getVisible, _setVisible, None, "Visibility state")
-
- # "wx" property...
-
- def _getWx(self):
- """Return the corresponding wxPython object.
-
- This method is used for retrieving the \a wx property.
-
- \return wxPython object.
- """
- return self._wx
-
- wx = property(_getWx, None, None, "Corresponding wxPython object")
-
-
-
- ######################################################################
- ######################################################################
-
- # MenuMarker
- class MenuMarker(MenuNode):
- """This class represents a position in a menu.
- """
- def __init__(self, name=None, parent=None):
- MenuNode.__init__(self, name=name, parent=parent)
- self._flags = NODE_MARKER
-
- def __repr__(self):
- return "<MenuMarker name=%s>"%(self.name)
-
- ######################################################################
- ######################################################################
-
- # MenuItem
- class MenuItem(MenuNode):
- """An individual menu item.
-
- This class represents one individual menu item which can be a
- normal item, a checkable item or a separator. A menu item object
- has the following attributes in addition to the ones inherited by
- MenuNode:
-
- - \b command (\c callable): The command to execute (may be None)
- - \b checked (\c bool): The state of a checkable menu item
- """
-
- def __init__(self, itemdef, name=None, enabled=True, visible=True):
- """Constructor.
-
- The definition \a itemdef of the item is generally composed of
- two items, the text that appears in the menu and the
- corresponding command which is to be executed whenever the
- user selects the menu item. The command must be a callable
- that takes no arguments.
-
- The text and command is given as a 2-tuple (text, command).
- It's also possible to just provide a string which is equivalent
- to (text, None).
-
- If the text starts with "[x]" then a checkable menu item is
- generated.
-
- If the text consists of 3 or more dashes ("---"), then a
- separator is generated.
-
- \param itemdef (\c 2-tuple or \c str) Item definition
- \param name (\c str) The internal name of the item
- \param enabled (\c bool) Initial enabled state
- \param visible (\c bool) Initial visibility state
- """
-
- flags = NODE_NORMAL_ITEM
-
- self._checkitem = False
- self._separator = False
- self._checked = False
-
- # Split the item definition into the text and command component
- if isinstance(itemdef, types.StringTypes):
- itemstr = itemdef
- itemcmd = None
- else:
- itemstr, itemcmd = itemdef
-
- # Is the menu item a checkable item?
- if itemstr[:3]=="[x]" or itemstr[:3]=="[X]":
- flags = NODE_CHECK_ITEM
- self._checkitem = True
- if itemstr[1]=="X":
- self._checked=True
- itemstr = itemstr[3:]
-
- # Is the item a separator?
- if len(itemstr)>2 and itemstr.count("-")==len(itemstr):
- flags = NODE_SEPARATOR
- self._separator = True
- itemcmd = None
-
- MenuNode.__init__(self, name=name, text=itemstr, enabled=enabled, visible=visible)
- self._flags = flags
-
- self._command = itemcmd
-
- def __repr__(self):
- s = 'MenuItem name=%s text="%s"'%(self.name, self.text)
- if self._checkitem:
- s+=" checkable"
- return "<%s>"%s
-
- def isSeparator(self):
- return self._separator
-
- def isCheckItem(self):
- return self._checkitem
-
-
- def setEnabled(self, flag=True):
- MenuNode.setEnabled(self, flag)
- if self._wx!=None:
- self._wx.Enable(flag)
-
- def update(self):
- if self._wx!=None:
- root = self.root
- text = self.text
- keys = root._window.keys.findCommandKeys(self._command)
- if len(keys)>0:
- text+="\t"+keys[0]
- self._wx.SetText(text)
-
-
- ######################################################################
-
- ## protected:
-
- def _wx_menu_count(self):
- if self._wx==None:
- return 0
- else:
- return 1
-
- def _create_wx(self):
-
- MenuNode._create_wx(self)
-
- root = self.root
-
- # Determine the type of MenuItem to create...
- if self.isCheckItem():
- kind = wx.ITEM_CHECK
- self._id = root._IDmanager.allocID()
- elif self.isSeparator():
- kind = wx.ITEM_SEPARATOR
- self._id = wx.ID_SEPARATOR
- else:
- kind = wx.ITEM_NORMAL
- self._id = root._IDmanager.allocID()
-
- # Get the parent which must be a wxMenu object
- parent = self._wx_parent()
- # Create the MenuItem...
- text = self.text
- keys = root._window.keys.findCommandKeys(self._command)
- if len(keys)>0:
- text+="\t"+keys[0]
- self._wx = wx.MenuItem(parent, self._id, text, self._getHelpString(), kind)
- # ...and insert it into the parent menu
- pos = self._wx_menu_pos()
- # print 'Inserting item "%s" at position %d'%(self._text, pos)
- parent.InsertItem(pos, self._wx)
- # Set initial attributes
- self._wx.Enable(self.enabled)
- if self.isCheckItem():
- self._wx.Check(self.checked)
-
- # Connect the new wxMenuItem to the menu event handler
- if not self.isSeparator():
- root._connect(self)
-
-
- def _destroy_wx(self):
-
- root = self.root
-
- # Disconnect the menu item from the event handler
- if not self.isSeparator():
- root._disconnect(self)
-
- # Remove the wxMenuItem from the parent menu
- parent = self._wx_parent()
- parent.Remove(self._id)
- # Make the ID available again
- if self._id!=-1:
- root._IDmanager.freeID(self._id)
-
- MenuNode._destroy_wx(self)
-
- def _getHelpString(self):
- doc = getattr(self._command, "__doc__", None)
- if doc==None:
- return ""
- else:
- return doc.split("\n")[0]
-
- # "command" property...
-
- def _getCommand(self):
- """Return the associated command (callable object).
-
- This method is used for retrieving the \a command property.
-
- \return Command (\c callable).
- """
- return self._command
-
- def _setCommand(self, command):
- """Set a new command.
-
- This method is used for setting the \a command property.
-
- \param command (\c callable) The new command or None
- """
- self._command = command
-
- command = property(_getCommand, _setCommand, None, "Menu item command")
-
- # "checked" property...
-
- def _getChecked(self):
- """Get the checked flag.
-
- This method is used for retrieving the \a checked property.
-
- \return Checked flag (\c bool).
- """
- return self._checked
-
- def _setChecked(self, flag=True):
- """Get the checked flag.
-
- This method is used for setting the \a checked property.
-
- \param flag (\c bool) New state.
- """
- self._checked = flag
- if self._wx!=None:
- self._wx.Check(flag)
-
- checked = property(_getChecked, _setChecked, None, "Checked flag")
-
-
- ######################################################################
- ######################################################################
-
- # Menu
- class Menu(MenuNode):
- """A menu node containing other menus, markers or menu items.
-
- This class is used as a container for MenuNode classes and it
- represents a node in the entire menu tree.
- """
-
- def __init__(self, title=None, name=None, enabled=True, visible=True,
- items=[]):
- """Constructor.
-
- \param title (\c str) Menu title which will be display in the GUI
- \param name (\c str) Node name
- \param enabled (\c bool) Initial enabled state
- \param visible (\c bool) Initial visibility state
- \param items (\c sequence) A sequence of children node descriptions
- """
-
- MenuNode.__init__(self, name=name, text=title, enabled=enabled, visible=visible)
- self._flags = NODE_MENU
-
- # Children nodes
- self._children = [MenuMarker("START", self), MenuMarker("END", self)]
-
- for item in items:
- if isinstance(item, MenuNode):
- mi = item
- else:
- mi = MenuItem(item)
- self.append(mi)
-
-
- def insertAfter(self, newnode, treenodename):
- """Insert a node after another existing node.
-
- \param newnode The node that should be inserted
- \param treenodename The node name after which newnode is to be inserted
- """
-
- # The new node must not be attached to another menu
- if newnode.isAttached() or newnode.parent!=None:
- raise MenuAlreadyInUse, "The menu node is already in use."
-
- treenode = self.findNode(treenodename)
- # If treenode is not a direct child then delegate the insert
- # operation to the parent of treenode
- if (treenode.parent!=self):
- treenode.parent.insertAfter(newnode, treenodename.split(".")[-1])
- return
-
- # Check if the name of the new node collides with an existing node
- newnodename = newnode.name
- if newnodename!=None and self.findNode(newnodename, False)!=None:
- raise DuplicateNames, 'Menu node "%s" already exists.'%newnodename
-
- # Add the new node into the children list
- idx = self._children.index(treenode)
- self._children.insert(idx+1, newnode)
- newnode._parent = self
-
- if self.isAttached():
- newnode._create_wx()
-
-
- def insertBefore(self, newnode, treenodename):
- """Insert a node before another existing node.
-
- \param newnode The node that should be inserted
- \param treenodename The node name before which newnode is to be inserted
- """
-
- # The new node must not be attached to another menu
- if newnode.isAttached() or newnode.parent!=None:
- raise MenuAlreadyInUse, "The menu node is already in use."
-
- treenode = self.findNode(treenodename)
- # If treenode is not a direct child then delegate the insert
- # operation to the parent of treenode
- if (treenode.parent!=self):
- treenode.parent.insertBefore(newnode, treenodename.split(".")[-1])
- return
-
- # Check if the name of the new node collides with an existing node
- newnodename = newnode.name
- if newnodename!=None and self.findNode(newnodename, False)!=None:
- raise DuplicateNames, 'Menu node "%s" already exists.'%newnodename
-
- # Add the new node into the children list
- idx = self._children.index(treenode)
- self._children.insert(idx, newnode)
- newnode._parent = self
-
- if self.isAttached():
- newnode._create_wx()
-
- # append
- def append(self, node):
- """Append a node at the end of the children list.
-
- The node is added right before the END marker.
-
- \param node (\c MenuNode) The node the be appended to the menu.
- """
- self.insertBefore(node, "END")
-
-
-
- def setEnabled(self, flag=True, node=""):
- if node!="":
- # Find the node n whose enabled state should be changed
- n = self.findNode(node)
- n.setEnabled(flag)
- return
-
- MenuNode.setEnabled(self, flag)
- if not self.isAttached():
- return
-
- # 1. Node = MenuBar
- if self._is_menubar():
- for n in self:
- n.setEnabled(flag)
- # 2. Node = Toplevel menu
- elif self.parent==None or self.parent._is_menubar():
- parent = self._wx_parent()
- # parent may be None if the menu is used for a popup menu
- if parent!=None:
- parent.EnableTop(self._wx_menu_pos(), flag)
- # 3. Node = Sub menu
- elif self.text!=None:
- parent = self._wx_parent()
- parent.Enable(self._wx.GetId(), flag)
- # 3. Node = Embedded menu
- else:
- for n in self:
- n.setEnabled(flag)
-
-
- ######################################################################
- ## protected:
-
- def _wx_menu_count(self):
- if self._is_embedded_menu():
- res = 0
- for n in self:
- res += n._wx_menu_count()
- return res
-
- if self._wx==None:
- return 0
- else:
- return 1
-
- def __repr__(self):
- return '<Menu name=%s title="%s">'%(self.name, self.text)
-
- def __len__(self):
- return len(self._children)
-
- def __getitem__(self, key):
- return self._children[key]
-
- def __delitem__(self, key):
- # Remove the node from the tree
- self._children.remove(key)
- key._parent = None
-
- def __getattr__(self, name):
- items = filter(lambda x: name==x.name, self._children)
- if items==[]:
- raise AttributeError, 'Menu node "%s" not found.'%(name)
- return items[0]
-
- def __setattr__(self, name, value):
- if name=="":
- return
- if name[0]=="_":
- MenuNode.__setattr__(self, name, value)
- elif isinstance(value, Menu):
- self.append(value)
- elif isinstance(value, MenuItem):
- self.append(value)
- elif (isinstance(value, types.StringTypes) or
- (isinstance(value, tuple) and len(value)==2 and
- isinstance(value[0], types.StringTypes) and callable(value[1]))):
- mi = MenuItem(value, name=name)
- self.append(mi)
- else:
- MenuNode.__setattr__(self, name, value)
-
-
- ## def _getIndex(self, name):
- ## """Return the index of the children with the given name.
-
- ## \return Index (0-based).
- ## """
-
- ## items = filter(lambda x: name==x.name, self._children)
- ## if items==[]:
- ## raise MenuNodeNotFound, 'Menu node "%s" not found.'%(name)
- ## return self._children.index(items[0])
-
- def _create_wx(self):
-
- MenuNode._create_wx(self)
-
- # 1. Node = MenuBar
- if self._is_menubar():
- # print "Menubar"
- self._create_wx_menubar()
- # 2. Node = Toplevel menu
- elif self.parent==None or self.parent._is_menubar():
- # print "Toplevel"
- self._create_wx_toplevel_menu()
- # 3. Node = Sub menu
- elif self.text!=None:
- # print "Submenu"
- self._create_wx_submenu()
- # 3. Node = Embedded menu
- else:
- # print "Embedded"
- self._create_wx_embedded_menu()
-
- self.setEnabled(self.enabled)
-
-
- def _create_wx_menubar(self):
- """Implements _create_wx() for the root node.
-
- This method just calls _create_wx() on all its children.
- (The wxMenuBar object must already be set!)
-
- \see _create_wx()
- """
- # _wx_menubar must already be initialized with a wx.MenuBar object
-
- self._wx = self._wx_menubar
-
- # Create wx objects for all menus...
- for node in self:
- node._create_wx()
-
-
- def _create_wx_toplevel_menu(self):
- """Implements _create_wx() for toplevel menus.
-
- This method creates a wxMenu object and fills it with its
- children.
-
- \see _create_wx()
- """
-
- self._wx = wx.Menu()
-
- # Create wx objects for all items...
- for node in self:
- node._create_wx()
-
- # Parent is a wx.MenuBar object or None (popup menus)
- parent = self._wx_parent()
- if parent!=None:
- pos = self._wx_menu_pos()
- parent.Insert(pos, self._wx, self.text)
-
-
- def _create_wx_submenu(self):
- """Implements _create_wx() for submenus.
-
- This method creates a wxMenu object and fills it with its
- children. Then the wxMenu object is wrapped in a wxMenuItem
- object which serves as the actual menu item.
-
- \see _create_wx()
- """
-
- # Store the menu in _wx temporarily, so that the children have a
- # valid parent
- self._wx = wx.Menu()
-
- # Create wx objects for all items...
- for node in self:
- node._create_wx()
-
- # Parent is a wx.Menu object
- parent = self._wx_parent()
- self._id = self.root._IDmanager.allocID()
- self._wx = wx.MenuItem(parent, self._id, self.text, "",
- wx.ITEM_NORMAL, self._wx)
- pos = self._wx_menu_pos()
- parent.InsertItem(pos, self._wx)
-
-
- def _create_wx_embedded_menu(self):
- """Implements _create_wx() for embedded menus.
-
- This method does not create a wx menu object but only inserts
- its children into the parent menu.
-
- \see _create_wx()
- """
-
- self._wx = None
- self._id = None
- wxmenu = self._wx_parent()
- # Create wx objects for all items...
- for node in self:
- node._create_wx()
-
-
- def _destroy_wx(self):
-
- # Destroy the wx objects for all items...
- for node in self:
- node._destroy_wx()
-
- # 1. Node = MenuBar
- if self._is_menubar():
- pass
- # 2. Node = Toplevel menu
- elif self.parent==None or self.parent._is_menubar():
- # Remove the menu from the menu bar (if it's not a popup menu)
- parent = self._wx_parent()
- if parent!=None:
- pos = self._wx_menu_pos()
- parent.Remove(pos)
- # 3. Node = Sub menu
- elif self.text!=None:
- # Remove the wxMenuItem from the parent menu
- parent = self._wx_parent()
- parent.Remove(self._id)
- # Make the ID available again
- self.root._IDmanager.freeID(self._id)
- # 3. Node = Embedded menu
- # else: pass
-
- MenuNode._destroy_wx(self)
-
-
- def _is_menubar(self):
- """Returns True if the node represents a menu bar."""
- return hasattr(self, "_wx_menubar")
-
- def _is_embedded_menu(self):
- """Returns True if the node represents an embedded menu."""
- return self.text==None and self.parent!=None and (not self._is_menubar())
-
- def _get_embedded_items(self):
- """
- May only be called on embedded menus.
- """
-
- res = []
- for cn in self._children:
- if cn._wx!=None:
- res.append(cn)
- elif isinstance(cn, Menu):
- res += cn._get_embedded_items()
- return res
-
-
- def _connect(self, node):
- """Connect a menu event with the handler.
-
- May only be called on the root node.
- """
-
- id = node._wx.GetId()
- wx.EVT_MENU(self._window, id, self._onMenuSelection)
- self._menu_id_lut[id] = node
-
- def _disconnect(self, node):
- """Disconnect a menu event from the handler.
-
- May only be called on the root node.
- """
-
- id = node._wx.GetId()
- print "Disconnecting",node.name,"ID:",id
- wx.EVT_MENU(self._window, id, None)
- del self._menu_id_lut[id]
-
-
- def _onMenuSelection(self, event):
- print "Item",event.GetId(),"selected"
- item = self._menu_id_lut.get(event.GetId(), None)
- if item==None:
- print "Menu item ID not found!"
- return
-
- cmd = item.command
- if cmd!=None:
- cmd()
-
-
- def _dump(self, depth=0):
- print "%s%s"%(2*depth*" ",self)
- for n in self._children:
- if hasattr(n, "_dump"):
- n._dump(depth+1)
- else:
- print "%s%s"%(2*(depth+1)*" ",n)
-
-