#!/usr/bin/env python """ $Id: wxnsc.py,v 1.10.2.6 2009/03/27 14:30:29 irmen Exp $ A wxPython gui to nsc (Pyro Name Server Control tool). This gui doesn't have as many features as the xnsc that ships with Pyro, but it has some nice features that the xnsc doesn't have ;) 'Pyro' - Python Remote Objects is (c) Irmen de Jong - irmen@users.sourceforge.net This file 'wxnsc.py' is (c) Jan Finell - finell@users.sourceforge.net Usage (from the commandline): # to use set PYRO environment variables or broadcasting # for finding the nameserver host... > wxnsc.py """ __author__ = "Jan Finell" __date__ = "$Date: 2009/03/27 14:30:29 $" __revision__ = "$Revision: 1.10.2.6 $" # # Standard modules # import os, sys, socket import traceback, cStringIO # # GUI modules # import wx # # Pyro modules # from Pyro.naming import NameServerLocator from Pyro.errors import NamingError, ConnectionClosedError,\ ConnectionDeniedError import Pyro.core #----------------------------------------------------------------------# # Module constants DEFAULT_GROUPNAME = ':Default' PROTECTED_GROUPS = [DEFAULT_GROUPNAME, ':Pyro'] GROUP_XPM = [ "16 16 9 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #C3C3C3", "# c #A0A0A0", "$ c #8080FF", "% c #585858", "& c #FFFFFF", "* c #808080", " +%+ ", " +%$$++ ", " +&%%$$+++++ ", " +&&@%%$$$$$+ ", " +&@&@@%$$$$% ", " +@&@@@@%%%%$+ ", " +&@@@@@@@#@+$% ", " +@@@@@@@#@#+$% ", " +@@@#@@#@##+$% ", " +@@@@@#@###+$% ", " ++*@@#@####+$% ", " ++*@#####+$% ", " ++#####+$% ", " ++###+$++", " ++#+$++", " ++++ "] GROUP_OPEN_XPM =[ "16 16 12 1", " c None", ". c #FFFFFF", "+ c #000000", "@ c #8080FF", "# c #808080", "$ c #C3C3C3", "% c #C0C0FF", "& c #A0A0A0", "* c #303030", "= c #FFFFFF", "- c #DCDCDC", "; c #585858", " +++ ", " +@#++ ", " +@%@#++++ ", "+++ +@%%%%%%@+ ", "+&&*;@@@%%%%%@+ ", "+#&&&#@@@@%%%@#+", " *&&&&##@@@@%@#+", " +#&&$$&##@@@@#+", " *&$&$$$$##@@#+", " +#$$$$-$-&@@#+", " *#-$$$-=%;@#+", " +*&--===&@#+", " +*$===%;#+", " +*$==##+", " +*$=#+", " +**+"] ITEM_XPM = [ "16 16 11 1", " c None", ". c #FFFFFF", "+ c #FFFFFF", "@ c #000000", "# c #585858", "$ c #DCDCDC", "% c #FFFFC0", "& c #FFDCA8", "* c #303030", "= c #C3C3C3", "- c #A0A0A0", " #####**@@ ", " #$$$$$=*=@ ", " #$+++++#+$@ ", " #$+++++#$+=@", " #$+++++###*@", " #$++++++$=-@", " #$++++++%+$@", " #$+++++++++@", " #$++++%+%+%@", " #$+++++++&+@", " #$++%+%+%+%@", " #$+++++&+&+@", " #$%+%+%+%+%@", " #$+++&+&+&%@", " #$%+%+%+%%%@", " *@@@@@@@@@@@"] #----------------------------------------------------------------------# # Helper functions def cmp_name(n1, n2): return cmp(n1[0], n2[0]) def show_message_dialog(parent, msg, title, style): if sys.platform[:3] == 'win': dlg = WinMessageDialog(parent, msg, title, style) else: dlg = wx.MessageDialog(parent, msg, title, style) dlg.CentreOnParent() retval = dlg.ShowModal() dlg.Destroy() return retval #----------------------------------------------------------------------# ## Classes class wx_StdoutLog(wx.TextCtrl): """ :Purpose: A simple text ctrl that can be used for logging standard out """ def write(self, data): if data.strip(): wx.TextCtrl.AppendText(self, '%s\n' % data) class wx_NSC(wx.Frame): """ :Purpose: The main frame of the GUI. """ def __init__(self, nsHost, nsPort, bcAddr): """ :Parameters: - `nsHost`: the name server host to connect to. This is the name of the host or the ip. - `nsPort`: the name server port. By default the Pyro name server port is 9090 - `bcAddr`: override for the broadcast address. """ wx.Frame.__init__(self, None, -1, 'Pyro Name Server') self.nsHost = nsHost self.nsPort = nsPort self.bcAddr = bcAddr self.NS = None self._build() imageList = wx.ImageList(16,16) self.__idGroup = imageList.Add(wx.BitmapFromXPMData(GROUP_XPM)) self.__idItem = imageList.Add(wx.BitmapFromXPMData(ITEM_XPM)) self.__idGroupOpen = imageList.Add(wx.BitmapFromXPMData(GROUP_OPEN_XPM)) self.treeCtrlItems.SetImageList(imageList) self.__imageList = imageList self._bindEvents() # binding stdout to my own txtCtrl Log. sys.stdout = self.txtCtrlLog self._log("Pyro version: "+Pyro.constants.VERSION) self.nsc_findNS() if self.NS: self.update() #-- public methods --# def enable(self, enable=True): """ Enabling/disabling some of the buttons. """ self.buttonDeleteGroup.Enable(enable) self.buttonCreateGroup.Enable(enable) self.buttonDeleteSelected.Enable(enable) self.buttonRegisterItem.Enable(enable) self.buttonShowMeta.Enable(enable) self.buttonSetMeta.Enable(enable) def update(self): """ """ tree = self.treeCtrlItems tree.DeleteAllItems() root = tree.AddRoot(':') tree.SetItemImage(root, self.__idGroup) tree.SetItemImage(root, self.__idGroupOpen, wx.TreeItemIcon_Expanded) self._populate_tree(tree, root, ':') # enabling/disabling buttons, depending on the current state. self.enable(self.NS != None) def _populate_tree(self, tree, parent, group): subgroupsL = self.nsc_list_groups(group) subgroupsL.sort() itemsL = self.nsc_list_items(group) itemsL.sort() for subgroup in subgroupsL: groupB = tree.AppendItem(parent, subgroup) tree.SetPyData(groupB, 0) tree.SetItemImage(groupB, self.__idGroup) tree.SetItemImage(groupB, self.__idGroupOpen, wx.TreeItemIcon_Expanded) self._populate_tree(tree, groupB, subgroup) for item in itemsL: itemB = tree.AppendItem(parent, item) tree.SetPyData(itemB, 1) tree.SetItemImage(itemB, self.__idItem) tree.SetItemImage(itemB, self.__idItem, wx.TreeItemIcon_Selected) #-- nsc methods --# def nsc_findNS(self, ident=None): """ Locating the Name Server by using given nsHost and nsPort """ locator = NameServerLocator(identification=ident) try: if self.nsHost: self._log('connecting to Name Server (%s:%s)' % (self.nsHost, self.nsPort)) self.NS = locator.getNS(self.nsHost, self.nsPort, trace=1, bcaddr=self.bcAddr) else: self._log('broadcasting to find Name Server') self.NS = locator.getNS(None, None, trace = 1, bcaddr=self.bcAddr) self.nsHost = self.NS.URI.address self.nsPort = self.NS.URI.port self.NS._setIdentification(ident) self._log('Name Server found, URI = %s' % self.NS.URI) self._setNSData() except ConnectionDeniedError, e: if str(e).find( Pyro.constants.deniedReasons[Pyro.constants.DENIED_SECURITY] ) != -1: msg = 'Authentication required:' dlg = wx.TextEntryDialog(self, msg, 'Authentication', style=wx.OK|wx.CANCEL|wx.TE_PASSWORD) dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: ident = dlg.GetValue() self.nsc_findNS(ident) else: self.NS = None self._log('Connection to Name Server denied!','error') else: self.NS = None self._logError('Unable to connect to Name Server') except: self.NS = None self._logError('Name Server not found!') def nsc_list_groups(self, ingroup): """ Returns a list of group names inside given group. """ return self._nsc_list(ingroup, 0) def nsc_list_items(self, ingroup): """ Returns a list of item names inside given group. """ return self._nsc_list(ingroup, 1) def _nsc_list(self, ingroup, type): """ Generic method for listing either groups or items inside a given group. type = 0 : group type = 1 : item """ items = [] if self.NS: for name, t in self.NS.list(ingroup): if t == type: if type == 1: uri = self.NS.resolve('%s.%s' % (ingroup,name)) name = '%s (%s)' % (name, uri) elif ingroup != ':': name = '%s.%s' % (ingroup, name) else: name = '%s%s' % (ingroup, name) items.append(name) return items def nsc_create_group(self, groupName): """ Creating given group """ if self.NS: try: self.NS.createGroup(groupName) self._log('created group (%s)' % (groupName)) return 1 except NamingError, e: self._logError('unable to create group %s because %s' % (groupName, e)) return 0 def nsc_delete_group(self, groupName): """ Deleting given group """ if self.NS: try: self.NS.deleteGroup(groupName) self._log('group %s deleted' % groupName) return 1 except NamingError, e: self._logError('unable to delete group %s because %s' % (groupName, e)) return 0 def nsc_ping(self): """ Ping the current Name Server """ if self.NS: try: self.NS.ping() self._log('ping Name Server (%s): up and running' % self.nsHost) except: self._logError('Name Server not responding.') else: self._logError('Name Server not responding') def nsc_delete(self, name): """Removing given name from the Name Server. :Parameters: - `name`: the name to delete from the Name Server """ try: self.NS.unregister(name) self._log('%s deleted successfully' % name) return 1 except NamingError, e: self._logError('unable to delete %s because %s' % (name, e)) except: self._logError('deletion of %s failed' % name) return 0 def nsc_register_item(self, name, uri): """ Registering new item with given name and uri """ try: self.NS.register(name, uri) uri = Pyro.core.PyroURI(uri) self._log('registered %s with %s' % (name, uri)) return 1 except NamingError, e: self._logError('unable to register,\nName Server error: %s' % e) except Exception, e: self._logError('unable to register, error: %s' % e) return 0 def nsc_set_meta(self, name, meta): """ Set user meta data """ try: self.NS.setMeta(name, meta) self._log('set user meta data on '+name) return 1 except NamingError, e: self._logError('unable to set user meta data,\nName Server error: %s' % e) except Exception, e: self._logError('unable to set user meta data, error: %s' % e) return 0 def nsc_show_meta(self, name): fullName = self.NS.fullName(name) try: self._log('"%s" system meta info: %s' % (fullName, self.NS._getSystemMeta(fullName))) self._log('"%s" user meta info: %s' % (fullName, self.NS.getMeta(name))) except NamingError, e: self._logError('unable to get meta info,\nName Server error: %s' % e) except Exception, e: self._logError('unable to get meta info, error: %s' % e) #-- gui event methods --# def OnCheckNS(self, event): if self._checkNS(): self.update() def OnClose(self, event): sys.stdout = sys.__stdout__ #restoring the stdout self.Destroy() def OnCreateGroup(self, event): """ Creating group in selected parent """ tree = self.treeCtrlItems items = tree.GetSelections() if items: if tree.GetPyData(items[0]) == 0: # use the selected group parentGroupI = items[0] parentGroupName = tree.GetItemText(parentGroupI) else: # take the parent parentGroupI = tree.GetItemParent(items[0]) parentGroupName = tree.GetItemText(parentGroupI) else: parentGroupI = tree.GetRootItem() parentGroupName = ':' msg = 'Create group in "%s", with name:' % parentGroupName dlg = wx.TextEntryDialog(self, msg, 'Enter group name') dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: if parentGroupName != ':': groupName = '%s.%s' % (parentGroupName, dlg.GetValue()) else: groupName = ':%s' % (dlg.GetValue()) if self.nsc_create_group(groupName): groupI = tree.AppendItem(parentGroupI, groupName) tree.SetPyData(groupI, 0) tree.SetItemImage(groupI, self.__idGroup) tree.SetItemImage(groupI, self.__idGroupOpen, wx.TreeItemIcon_Expanded) tree.Expand(parentGroupI) def OnSetMeta(self, ev=None): """ set user meta on selected groups + items """ tree = self.treeCtrlItems itemsL, groupsL = self._getSelections() namesL = itemsL + groupsL if namesL: namesS = ',\n '.join(namesL) msg = 'User meta data string for:\n %s' % namesS dlg = wx.TextEntryDialog(self, msg, 'Enter meta data') dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: meta=dlg.GetValue() for name in namesL: self.nsc_set_meta(name,meta) def OnDelete(self, ev=None): """ Deleting selected items. """ tree = self.treeCtrlItems itemsL = tree.GetSelections() namesL = [] deleteL = [] for i in itemsL: # only items (ie. no groups) if tree.GetPyData(i) == 1: parent = tree.GetItemParent(i) parentName = tree.GetItemText(parent) name = tree.GetItemText(i).split()[0] #only name namesL.append('%s.%s' % (parentName, name)) deleteL.append(i) if namesL: namesS = ',\n '.join(namesL) ret = show_message_dialog(self, 'Really delete following name(s)?:\n %s' % namesS, '-- Confirm --', wx.YES|wx.NO|wx.ICON_QUESTION) if ret == wx.ID_YES: for name, i in zip(namesL,deleteL): if self.nsc_delete(name): tree.Delete(i) def OnDeleteGroup(self, ev=None): """ Deleting selected groups. """ tree = self.treeCtrlItems itemsL = tree.GetSelections() namesL = [] deleteL = [] for i in itemsL: # only groups (ie. no items) if tree.GetPyData(i) == 0: name = tree.GetItemText(i) if name not in PROTECTED_GROUPS and tree.GetChildrenCount(i)==0: namesL.append(name) deleteL.append(i) if namesL: namesS = ',\n'.join(namesL) ret = show_message_dialog(self, 'Really delete following group(s)?:\n %s' % namesS, '-- Confirm --', wx.YES|wx.NO|wx.ICON_QUESTION) if ret == wx.ID_YES: for name, i in zip(namesL, deleteL): if self.nsc_delete_group(name): tree.Delete(i) def OnKeyPressed(self, event): """ Calling delete for both items and groups """ if event.GetKeyCode() == 127: # deleting both selected groups and items self.OnDelete() self.OnDeleteGroup() if event.GetKeyCode() == 105: # 105 == 'i' # showing meta information on selected item self.OnShowMeta() event.Skip() def OnPing(self, event): if self._checkNS(): self.update() self.nsc_ping() def OnRegisterItem(self, event): """ Registering item in selected parent. """ tree = self.treeCtrlItems items = tree.GetSelections() if items: if tree.GetPyData(items[0]) == 0: # use the selected group parentGroupI = items[0] parentGroupName = tree.GetItemText(parentGroupI) else: parentGroupI = tree.GetItemParent(items[0]) parentGroupName = tree.GetItemText(parentGroupI) else: parentGroupI = tree.GetRootItem() parentGroupName = ':' msg = 'Register new item in "%s", with:\n ' % parentGroupName dlg = wx.TextEntryDialog(self, msg, 'Register item') dlg.CentreOnParent() if dlg.ShowModal() == wx.ID_OK: try: itemName, uri = dlg.GetValue().split() except: self._log('Invalid arguments, use ', 'error') else: if parentGroupName != ':': itemName = '%s.%s' % (parentGroupName, itemName) else: itemName = ':%s' % (itemName) if self.nsc_register_item(itemName, uri): label = '%s (%s)' % (dlg.GetValue().split()[0], uri) itemI = tree.AppendItem(parentGroupI, label) tree.SetPyData(itemI, 1) tree.SetItemImage(itemI, self.__idItem) tree.SetItemImage(itemI, self.__idItem, wx.TreeItemIcon_Selected) tree.Expand(parentGroupI) def OnUpdate(self, event): self._checkNS() self.update() def OnShowMeta(self, event=None): itemsL, groupsL = self._getSelections() for name in itemsL + groupsL: self.nsc_show_meta(name) #-- protected methods --# def _checkNS(self): """ Reads the new values from the txtCtrlNSHost and txtCtrlNSPort. If changed, it tries to connect to the new Name Server. """ changed = 0 if self.txtCtrlNSHost.IsModified(): self.nsHost = self.txtCtrlNSHost.GetValue() changed = 1 if self.txtCtrlNSPort.IsModified(): try: port = int(self.txtCtrlNSPort.GetValue()) self.nsPort = port except ValueError: self._logError('Integer required for port') changed = 1 if changed: self.nsc_findNS() return changed def _log(self, line, status='info'): """Writing given line to the log-textCtrl. :Parameters: - `line`: text to log - `status`: status should be 'info' or 'error'. If 'info' the text will be colored blue, if 'error' the text will be red. """ start = self.txtCtrlLog.GetLastPosition() self.txtCtrlLog.AppendText('%s\n' % line) color = wx.BLACK if status == 'info': color = wx.BLUE elif status == 'error': color = wx.RED self.txtCtrlLog.SetStyle(start, self.txtCtrlLog.GetLastPosition(), wx.TextAttr(color)) def _logError(self, line): """ Getting the traceback of previous error, and logging this. """ a, b, tb = sys.exc_info() if a == ConnectionClosedError: self.NS = None self._log('Connection with Name Server lost', 'error') self.enable(False) buf = cStringIO.StringIO() traceback.print_exc(file = buf) self._log('%s:\n%s' % (line, buf.getvalue()), 'error') def _setNSData(self): """ Updates the display of current Name Server information. """ try: ns_name, t, ns_ip = socket.gethostbyaddr(self.nsHost) ns_ip = ns_ip[0] except: ns_name, ns_ip = self.nsHost, '' self.txtCtrlNSHost.SetValue('%s' % ns_name) self.txtCtrlNSPort.SetValue('%s' % self.nsPort) self.SetTitle('Pyro Name Server ( %s - %s )' % (ns_name, ns_ip)) def _getSelections(self): tree = self.treeCtrlItems selectionsL = tree.GetSelections() itemsL = [] groupsL = [] for i in selectionsL: if tree.GetPyData(i) == 0: # group groupsL.append(tree.GetItemText(i)) elif tree.GetPyData(i) == 1: # item parentName = tree.GetItemText(tree.GetItemParent(i)) name = tree.GetItemText(i).split()[0] itemsL.append('%s.%s' % (parentName, name)) return itemsL, groupsL #-- build / bind methods --# def _bindEvents(self): """ Binding events to the gui widgets. """ wx.EVT_BUTTON(self, self.buttonPing.GetId(), self.OnPing) wx.EVT_BUTTON(self, self.buttonUpdate.GetId(), self.OnUpdate) wx.EVT_BUTTON(self, self.buttonClose.GetId(), self.OnClose) wx.EVT_BUTTON(self, self.buttonDeleteGroup.GetId(), self.OnDeleteGroup) wx.EVT_BUTTON(self, self.buttonCreateGroup.GetId(), self.OnCreateGroup) wx.EVT_BUTTON(self, self.buttonDeleteSelected.GetId(), self.OnDelete) wx.EVT_BUTTON(self, self.buttonRegisterItem.GetId(), self.OnRegisterItem) wx.EVT_BUTTON(self, self.buttonShowMeta.GetId(), self.OnShowMeta) wx.EVT_BUTTON(self, self.buttonSetMeta.GetId(), self.OnSetMeta) wx.EVT_TEXT_ENTER(self, self.txtCtrlNSHost.GetId(), self.OnCheckNS) wx.EVT_TEXT_ENTER(self, self.txtCtrlNSPort.GetId(), self.OnCheckNS) wx.EVT_CHAR(self.treeCtrlItems, self.OnKeyPressed) def _build(self): """ Building widgets and setting static widget data. """ parent = wx.Panel(self, -1) sizer0 = wx.BoxSizer(wx.VERTICAL) sizer0.Add(self._buildTopBar(parent), 0, wx.ALIGN_LEFT|wx.GROW, 5) splitter = wx.SplitterWindow(parent, -1) #- TOP PART --------------------------------------------------------# topParent = wx.Panel(splitter, -1) topSizer = wx.BoxSizer(wx.VERTICAL) self.treeCtrlItems = wx.TreeCtrl(topParent, -1, style = wx.TR_TWIST_BUTTONS|wx.TR_LINES_AT_ROOT|wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_MULTIPLE) topSizer.Add(self.treeCtrlItems, 1, wx.EXPAND, 5) topParent.SetAutoLayout( True ) topParent.SetSizer(topSizer ) topSizer.Fit(topParent) topSizer.SetSizeHints(topParent) #-------------------------------------------------------------------# #- BOTTOM PART -----------------------------------------------------# bottomParent = wx.Panel(splitter,-1) bottomSizer = wx.BoxSizer(wx.VERTICAL) self.txtCtrlLog=wx_StdoutLog(bottomParent, -1, "", size= wx.Size(-1, 10), style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH) bottomSizer.Add(self.txtCtrlLog, 1, wx.EXPAND, 5) bottomParent.SetAutoLayout( True ) bottomParent.SetSizer(bottomSizer ) bottomSizer.Fit(bottomParent) bottomSizer.SetSizeHints(bottomParent) #-------------------------------------------------------------------# splitter.SplitHorizontally(topParent,bottomParent, -100) sizer0.Add(splitter, 1, wx.EXPAND|wx.ALIGN_CENTRE, 5) self.buttonClose = wx.Button(parent, -1, 'Close') # buttonClose sizer0.Add(self.buttonClose, 0, wx.ALIGN_CENTRE|wx.ALL, 5) parent.SetAutoLayout( True ) parent.SetSizer( sizer0 ) sizer0.Fit( parent) sizer0.SetSizeHints( parent) def _buildTopBar(self, parent): """ Widget building """ sizer0 = wx.BoxSizer(wx.VERTICAL) #-- sizer1 = wx.BoxSizer(wx.HORIZONTAL) txt1 = wx.StaticText(parent, -1, 'Name Server:') txt1.SetForegroundColour(wx.BLUE) sizer1.Add(txt1, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTRE|wx.ALL, 5) self.txtCtrlNSHost = wx.TextCtrl(parent, -1, '', size=wx.Size(300,-1), style=wx.TE_PROCESS_ENTER) sizer1.Add(self.txtCtrlNSHost, 0, wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.TOP|wx.BOTTOM, 5) txtColon = wx.StaticText(parent, -1, ':') txtColon.SetForegroundColour(wx.BLUE) sizer1.Add(txtColon, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTRE|wx.TOP|wx.BOTTOM, 5) self.txtCtrlNSPort = wx.TextCtrl(parent, -1, '', size=wx.Size(50,-1), style=wx.TE_PROCESS_ENTER) sizer1.Add(self.txtCtrlNSPort, 0, wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.TOP|wx.BOTTOM, 5) self.buttonUpdate = wx.Button(parent, -1, 'Update') # buttonUpdate sizer1.Add(self.buttonUpdate, 0, wx.ALIGN_LEFT|wx.ALL, 5) self.buttonPing = wx.Button(parent, -1, 'Ping') # buttonPing sizer1.Add(self.buttonPing, 0, wx.ALIGN_LEFT|wx.ALL, 5) sizer0.Add(sizer1, 0, wx.ALIGN_LEFT|wx.GROW, 5) #-- lineH1 = wx.StaticLine(parent, -1, style=wx.LI_HORIZONTAL) sizer0.Add(lineH1, 0, wx.GROW|wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT, 5) #-- sizer2 = wx.BoxSizer(wx.HORIZONTAL) self.buttonDeleteGroup = wx.Button(parent, -1, ' Delete group(s) ') sizer2.Add(self.buttonDeleteGroup, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.TOP|wx.LEFT|wx.BOTTOM, 5) self.buttonCreateGroup = wx.Button(parent, -1, ' Create group... ') sizer2.Add(self.buttonCreateGroup, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.TOP|wx.LEFT|wx.BOTTOM, 5) lineV1 = wx.StaticLine(parent, -1, style=wx.LI_VERTICAL) sizer2.Add(lineV1, 0, wx.ALL|wx.GROW, 5) self.buttonDeleteSelected = wx.Button(parent, -1, ' Delete item(s) ') sizer2.Add(self.buttonDeleteSelected, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.ALL, 5) self.buttonRegisterItem = wx.Button(parent, -1, ' Register item... ') sizer2.Add(self.buttonRegisterItem, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 5) lineV2 = wx.StaticLine(parent, -1, style=wx.LI_VERTICAL) sizer2.Add(lineV2, 0, wx.ALL|wx.GROW, 5) self.buttonShowMeta = wx.Button(parent, -1, ' Show meta ') sizer2.Add(self.buttonShowMeta, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 5) self.buttonSetMeta = wx.Button(parent, -1, ' Set meta ') sizer2.Add(self.buttonSetMeta, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.TOP|wx.BOTTOM, 5) sizer0.Add(sizer2, 0, wx.ALIGN_LEFT, 5) #-- return sizer0 #----------------------------------------------------------------------# class WinMessageDialog(wx.Dialog): ''' :Purpose: Message dialog for MS Win. The parameters are the same as for wx.MessageDialog :Detail: On Windows the native wx.MessageDialog can not be centered on top of the parent or positioned, ie. it will always be centered on the screen. ''' def __init__(self, parent=None, message='Message:', caption='Message', style=wx.OK|wx.CANCEL,pos=wx.DefaultPosition): wx.Dialog.__init__(self, parent, -1, caption, size=wx.DefaultSize, style=wx.CAPTION, pos=pos) self._build(message, style) self.Fit() def OnButton(self, ev): self.EndModal(ev.GetId()) def _build(self, msg, style): parent = wx.Panel(self, -1) sizer = wx.BoxSizer(wx.VERTICAL) #-- icon and message --# msgSizer = wx.BoxSizer(wx.HORIZONTAL) # icon # artID = None if style & wx.ICON_EXCLAMATION == wx.ICON_EXCLAMATION \ or style & wx.ICON_HAND == wx.ICON_HAND: artID = wx.ART_WARNING elif style & wx.ICON_ERROR == wx.ICON_ERROR: artID = wx.ART_ERROR elif style & wx.ICON_QUESTION == wx.ICON_QUESTION: artID = wx.ART_QUESTION elif style & wx.ICON_INFORMATION == wx.ICON_INFORMATION: artID = wx.ART_INFORMATION if artID: bmp = wx.ArtProvider_GetBitmap(artID, wx.ART_MESSAGE_BOX, (48,48)) bmpIcon = wx.StaticBitmap(parent, -1, bmp) msgSizer.Add(bmpIcon, 0, wx.ALIGN_CENTRE|wx.ALL, 5) # msg # txtMsg = wx.StaticText(parent, -1, msg, style=wx.ALIGN_CENTRE) msgSizer.Add(txtMsg, 0, wx.ALIGN_CENTRE|wx.ALL, 5) sizer.Add(msgSizer, 0, wx.ALIGN_CENTRE, 5) line = wx.StaticLine(parent, -1, style=wx.LI_HORIZONTAL) sizer.Add(line, 0, wx.GROW|wx.ALL, 5) #-- buttons --# btnSizer = wx.BoxSizer(wx.HORIZONTAL) if style & wx.YES_NO == wx.YES_NO: btnYes = wx.Button(parent, wx.ID_YES, 'Yes') btnSizer.Add(btnYes, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT, 10) btnNo = wx.Button(parent, wx.ID_NO, 'No') btnSizer.Add(btnNo, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT, 10) if style & wx.YES_DEFAULT == wx.YES_DEFAULT: btnYes.SetDefault() elif style & wx.NO_DEFAULT == wx.NO_DEFAULT: btnNo.SetDefault() wx.EVT_BUTTON(self, wx.ID_YES, self.OnButton) wx.EVT_BUTTON(self, wx.ID_NO, self.OnButton) else: if style & wx.OK == wx.OK: btnOK = wx.Button(parent, wx.ID_OK, 'OK') btnOK.SetDefault() btnSizer.Add(btnOK, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT, 10) if style & wx.CANCEL == wx.CANCEL: btnCancel = wx.Button(parent, wx.ID_CANCEL, 'Cancel') btnSizer.Add(btnCancel, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT, 10) sizer.Add(btnSizer, 0, wx.ALIGN_CENTRE|wx.TOP, 5) #-- parent.SetAutoLayout( True ) parent.SetSizer(sizer ) sizer.Fit( parent ) sizer.SetSizeHints( parent ) #----------------------------------------------------------------------# def main(argv): """ The default host will be None if the environment variable PYRO_NS_HOSTNAME is not set. The default port will be 9090 (Pyro.config.PYRO_NS_PORT) if PYRO_NS_BC_PORT environment variable is not set. """ nsHost = os.getenv('PYRO_NS_HOSTNAME') nsPort = os.getenv('PYRO_NS_BC_PORT') or Pyro.config.PYRO_NS_PORT bcAddr = Pyro.config.PYRO_NS_BC_ADDR if bcAddr: bcAddr=bcAddr.strip() bcAddr=bcAddr or None class wx_NSCApp(wx.App): def OnInit(self): Pyro.core.initClient() frame = wx_NSC(nsHost, nsPort, bcAddr) frame.SetSize(wx.Size(630,500)) frame.Show(True) return True app = wx_NSCApp(0) app.MainLoop() # allow easy usage with python -m if __name__=="__main__": main(sys.argv)