def SetLoaddir(d):
  def __init__(self, frame):
  def Add(self, flags, keycode, cmd):
  def GetTable(self):
  def Realize(self):
  def __init__(self, parent):
  def OnLabelLeftClick(self, evt):
  def GetAllSelectedRows(self):
  def quoteVal(self, val, quoteChar):
  def GetAllSelectedCellValues(self, withLabel=True):
  def __init__(self, frame, size=32, style=wx.TB_FLAT|wx.TB_NODIVIDER):
  def Enable(self, procOrId, how=None):
  def AddCheck(self, procOrCls, text=None, bitmap=None):
  def Add(self, procOrCls, text=None, bitmap=None, kind=wx.ITEM_NORMAL):
  def __init__(self, frame, config=None):
  def _currentDirectory(self):
  def _makePatterns(self, filePatterns):
  def _saveFile(self, wnd, contents, filePatterns, message, filename):
  def OpenFile(self, wnd, filePatterns, message=None, filename=None):
  def SaveFile(self, wnd, content, filePatterns, message=None):
  def SaveFileAs(self, wnd, content, filePatterns, message=None):
  def OnSelectFile(self, evt):
  def GetRecentFilesMenu(self):
  def _handleMenu(self):
  def _handleConfig(self):
def localizePath(path):
def modPath(name, mod):
def evalAsPython(val, default=None):
def GetIcon(name, module=None):
def GetBitmap(name, module=None):
  def __init__(self, wnd, proc):
  def __init__(self, menuOwner=None):
  def Popup(self, evt):
  def getId(self, something):
  def Enable(self, something, how):
  def IsEnabled(self, something):
  def Check(self, something, how):
  def IsChecked(self, something):
  def Add(self, onproc, name, desc=None, id=-1, macproc=None):
  def AddCheck(self, onproc, name, desc, how=True):
  def AppendOneMenu(self, menu, txt, help=None):
  def Dup(self):
  def getRepr(self, m, indentstr):
  def __str__(self):
def YesNo(b):
def xlt(s): # translate
def removeSmartQuote(txt):
def quoteIfNeeded(txt, quoteChar='"'):
def shlexSplit(str, sep):
def copytree(src, dst, symlinks=False, ignore=None, replace=True):
  def __init__(self, str=None):
  def setString(self, items):
  def getList(self):
  def getString(self):
def restoreSize(unused_name, unused_defSize=None, unused_defPos=None):
def breakLines(text, breakLen=80):
def splitValUnit(value):
def strToIsoDate(val):
def utc2local(value):
def isoDateToStr(value):
def timeToFloat(value):
def floatToTime(value, nk=1):
def prettyTime(val, nk=1):
def prettyDate(val, long=True):
def sizeToFloat(value):
def prettySize(val):
def floatToSize(val, resolution=0):
class AcceleratorHelper:
class Grid(wx.grid.Grid):
class ToolBar(wx.ToolBar):
class FileManager:
class Timer(wx.Timer):
class Menu(wx.Menu):
class ParamDict(dict): class ControlContainer():
  def SetAttr(self, name, value):
    object.__setattr__(self, name, value)
    
  def __init__(self, resname=None):
#    object.__setattr__(self, "_ctls", {})
    self.SetAttr("_ctls", {})
    self.module=adm.getModule(self)
    self._ctlList=[]

    if resname == None:
      self.resname=self.__class__.__name__
      if self.resname == "Dlg":
        self.resname=self.__module__[self.__module__.rfind('.')+1:]
    else:
      self.resname=resname


  def AddExtraControls(self, res):
    """
    AddExtraControls(xmlResource)
    """

  def BindAll(self, excludeCtlNames=[]):
    """
    BindAllExcept(self, ctlNames=[]):
    
    Bind standard event all Controls that are not listed
    """
    if isinstance(excludeCtlNames, StringType):
      excludeCtlNames=excludeCtlNames.split()
    excludeCtlNames=map(str.lower, excludeCtlNames)
    
    for name, ctl in self._ctls.items():
      if isinstance(ctl, wx.Button) or isinstance(ctl, wx.StaticText):
        continue
      if name not in excludeCtlNames:
        self.Bind(ctl)

  def Bind(self, ctlName, evt=None, proc=None):
    """
    Bind(controlnameList, eventID=None, eventProc=None)
    Bind(controlname, eventID=None, eventProc=None)
    Bind(control, eventID=None, eventProc=None)
    Bind(eventID, eventProc=None)

    Binds event procedure to control
    if no proc given, adm.Dialog.OnCheck is used
    if no eventID is given, the appropriate event for the control is used
    """
    if isinstance(ctlName, StringType):
      names=ctlName.split()
      if len(names) > 1:
        ctlName=names
      else:
        return self._bind(ctlName, evt, proc)
    if isinstance(ctlName, list):
      for n in ctlName:
        self._bind(n, evt, proc)
    else:
      self._bind(ctlName, evt, proc)


  def _bind(self, ctlName, evt=None, proc=None):
    if isinstance(ctlName, wx.PyEventBinder): # binding to self
      ctl=super(wx.Window, self)
      proc=evt
      evt=ctlName
    elif isinstance(ctlName, wx.Window):
      ctl=ctlName
    else:
      ctl=self[ctlName]

    if not proc:
      if not isinstance(evt, wx.PyEventBinder):
        proc=evt
        evt=None
      if not proc:
        proc=self.OnCheck

    if not evt:
      if isinstance(ctl, wx.Button):
        evt=wx.EVT_BUTTON
      elif isinstance(ctl, wx.CheckBox):
        evt=wx.EVT_CHECKBOX
      elif isinstance(ctl, wx.CheckListBox):
        evt=wx.EVT_CHECKLISTBOX
      elif isinstance(ctl, wx.RadioButton):
        evt=wx.EVT_RADIOBUTTON
      else:
        evt=wx.EVT_TEXT
        if isinstance(ctl, wx.ComboBox):
          ctl.Bind(wx.EVT_COMBOBOX, proc)
    ctl.Bind(evt, proc)

  def GetNode(self):
    if hasattr(self, "node"):
      if self.node:
        return self.node
    if hasattr(self, "parentNode"):
      return self.parentNode
    return None

  def GetDialog(self):
    if hasattr(self, "dialog"):
      return self.dialog
    return None

  def GetServer(self):
    node=self.GetNode()
    if node:
      return node.GetServer()
    dlg=self.GetDialog()
    if dlg:
      return dlg.GetServer()
    return None

  def GetConnection(self):
    node=self.GetNode()
    if node:
      return node.GetConnection()
    dlg=self.GetDialog()
    if dlg:
      return dlg.GetConnection()
    return None


  def getResource(self):
    if self.resname.startswith('.'):
      path=os.path.join(adm.loaddir, "%s.xrc" % self.resname)
      self.resname = os.path.basename(self.resname)
    elif self.resname.startswith('/'):
      path="%s.xrc" % self.resname
      self.resname = os.path.basename(self.resname)
    else:
      module=self.module.replace(".", "/")
      path = os.path.join(adm.loaddir, module, "%s.xrc" % self.resname)
    if not os.path.exists(path):
      raise Exception("Loading XRC from %s failed" % path)
    res=xrc.XmlResource(path)
    res.AddHandler(xmlres.XmlResourceHandler())
    return res

  def _addControl(self, n, res):
    ctl=xrc.XRCCTRL(self, n)

    if ctl:
      ctl.validator=None
      vi=n.find('-')
      if vi > 0:
        vp=n[vi+1:].split()
        validatorClass=Validator.Get(vp[0])
        if validatorClass:
          ctl.validator=validatorClass(ctl, vp[1:])
        else:
          adm.logger.debug("No validator for %s installed.", vp[0])
        name=n[:vi]
      else:
        name=n

      names=name.split(':')
      ctl.name=names[-1]
      ctl.flags=map(lambda x: x.lower(), names[:-1])

      self._ctlList.append(ctl.name)
      for flag in ctl.flags:
        if flag.startswith("label="):
          labelCtl=self.ctl(flag[6:])
          if labelCtl:
            ctl.labelCtl=labelCtl


      if self._ctls.get(name):
        adm.logger.debug("Duplicate Control Name %s", ctl.name)
      self._ctls[ctl.name.lower()] = ctl
    else:
      if n == "StatusBar":
        self.addStatusBar(res)

  if wx.VERSION > (2,9):
    def _addControls(self, res, xmlnode):
      if not xmlnode:
        return
      if xmlnode.GetName() == "object":
        name=xmlnode.GetAttribute("name", "")
        if name:
          self._addControl(name, res)
      self._addControls(res, xmlnode.GetChildren())
      self._addControls(res, xmlnode.GetNext())


    def addControls(self, res):
      self._addControls(res, res.GetResourceNode(self.resname).GetChildren())

  else: # wx2.8

    def addControls(self, res):
      from xmlhelp import Document as XmlDocument
      module=self.module.replace(".", "/")
      path = os.path.join(adm.loaddir, module, "%s.xrc" % self.resname)
      doc=XmlDocument.parseFile(path)
      root=doc.getElement('object')
      objects=root.getElements('object')
      for obj in objects:
        name=obj.getAttribute('name')
        if name:
          self._addControl(name, res)


  def ctl(self, name):
    if name == "_ctls":
      return self._ctls
    elif name.startswith("__"):
      return None
    ctls=self._ctls
    return ctls.get(name.lower())


  def EnableControls(self, ctlList, how=True):
    """
    EnableControls(ctlList, how=True)
    
    Enables or disables the controls listed (list of names)
    """
    if how: how=True
    else:   how=False
    if isinstance(ctlList, StringType):
      ctlList=ctlList.split()
    for cn in ctlList:
      c=self.ctl(cn)
      if c:
        c.Enable(how)
        if hasattr(c, "labelCtl"):
          c.labelCtl.Enable(how)
      else:
        adm.logger.debug("Control %s not found", cn)


  def ShowControls(self, ctlList, how=True):
    """
    ShowControls(ctlList, how=True)
    
    Show or hide the controls listed (list of names)
    """
    if how: how=True
    else:   how=False
    if isinstance(ctlList, StringType):
      ctlList=ctlList.split()
    for cn in ctlList:
      c=self.ctl(cn)
      if c:
        c.Show(how)
        if hasattr(c, "labelCtl"):
          c.labelCtl.Show(how)
      else:
        adm.logger.debug("Control %s not found", cn)
        
  def SetUnchanged(self):
    """
    SetUnchanged()

    marks all controls as unchanged
    """
    for _key, ctl in self._ctls.items():
      if hasattr(ctl, "GetValue"):
        ctl.unchangedValue=ctl.GetValue()


  def HasChanged(self, name):
    names=name.split()
    if len(names) > 1:
      return reduce(lambda x,y: x or y, map(self.HasChanged, names))

    ctl=self[name]
    if not ctl:
      raise AttributeError("No control named '%s'" % name)
    if not hasattr(ctl, "unchangedValue"):
      raise AttributeError("control '%s' has no unchangedValue" % name)

    return ctl.unchangedValue != ctl.GetValue()


  def GetChanged(self):
    """
    GetChanged()

    returns list of control names that have changed
    """
    cl=[]
    for key, ctl in self._ctls.items():
      if hasattr(ctl, "unchangedValue"):
        if ctl.unchangedValue != ctl.GetValue():
          cl.append(key)
    return cl

  def IsFilled(self, name):
    ctl=self[name]
    if not ctl:
      raise AttributeError("No control named '%s'" % name)
    return ctl.GetValue()


  def _isvalid(self, name):
    if isinstance(name, wx.Window):
      ctl=name
    else:
      ctl=self.ctl(name)
    if ctl:
      if ctl.validator and hasattr(ctl.validator, "IsValid"):
        return ctl.validator.IsValid()
      return True
    return False

  def _getattr(self, name):
    if isinstance(name, wx.Window):
      ctl=name
    else:
      ctl=self.ctl(name)
    if ctl:
      if ctl.validator:
        return ctl.validator.GetValue()
      elif isinstance(ctl, xmlres.getControlClass("whComboBox")):
        return ctl.GetKeySelection()
      elif isinstance(ctl, wx.StaticText):
        return ctl.GetLabel()
      elif isinstance(ctl, wx.RadioBox):
        return ctl.GetSelection()
      else:
        return ctl.GetValue()
    else:
      try:
        return object.__getattr__(self, name)
      except AttributeError as _e:
        if not name.startswith('_'):
          raise AttributeError("%s has no attribute '%s'" % (str(self.__class__), name))
    return None

  def _setattr(self, name, value):
    if isinstance(name, wx.Window):
      ctl=name
    else:
      ctl=self.ctl(name)
    if ctl:
      if ctl.validator:
        return ctl.validator.SetValue(value)
      elif isinstance(ctl, xmlres.getControlClass("whComboBox")):
        if value == None:
          pass
        else:
          ctl.SetKeySelection(value)
      elif isinstance(ctl, wx.ComboBox):
        if value == None:
          ctl.SetSelection(wx.NOT_FOUND)
        else:
          ctl.SetStringSelection(value)
          if ctl.GetValue() != value:
            ctl.SetValue(value)
      elif isinstance(ctl, wx.StaticText):
        if value == None:
          ctl.SetLabel("")
        else:
          ctl.SetLabel(unicode(value))
      elif isinstance(ctl, wx.RadioBox):
        if value != None:
          ctl.SetSelection(value)
      else:
        if value == None:
          return ctl.SetValue("")
        return ctl.SetValue(value)
    else:
      try:
        return object.__setattr__(self, name, value)
      except AttributeError as _e:
        if not name.startswith('_'):
          raise AttributeError("%s has no attribute '%s'" % (str(self.__class__), name))
    return None

  def __getitem__(self, name):
    ctl=self.ctl(name)
    if not ctl:
      raise AttributeError("%s has no attribute '%s'" % (str(self.__class__), name))
    return ctl class MenuOwner:
  """
  MenuOwner

  has menus
  """
  _menuIds={}
  lastid=500
  
  def GetCallArgs(self, proc):
    args,_1,_2,_3 = inspect.getargspec(proc)
    return args

  def GetMenuProc(self, id):
    if not hasattr(self, '_menuProcs'):
      self._menuProcs={}
      return None
    return self._menuProcs.get(id)
  
  
  def GetMenuId(self, proc, registerNew=False):
    id=None
    foundId=self._menuIds.get(proc)
    if not registerNew:
      id=foundId
    if not id:
      MenuOwner.lastid += 1
      id=MenuOwner.lastid
      if not foundId:
        self._menuIds[proc] = id
    return id

  def BindMenuId(self, proc, registerNew=False):
    id= self.GetMenuId(proc, registerNew)
    if not self.GetMenuProc(id):
      self._menuProcs[id] = proc
      wx.Window.Bind(self, wx.EVT_MENU, self.OnCall, id=id)
    return id

  def EnableMenu(self, menu, item, how):
    if how: how=True
    else:   how=False
    if not isinstance(item, int):
      item=self.GetMenuId(item)
    tb=self.GetToolBar()
    if menu:
      menu.Enable(item, how)
    if tb:
      tb.EnableTool(item, how)
  
  def AddMenuItem(self, menu, onproc, name, desc=None, id=-1):
    if id==-1: id=self.GetMenuId(onproc)
    if desc == None: desc=name
    item=menu.Append(id, name, desc)
    self.Bind(wx.EVT_MENU, onproc, item)
    return item

  def AddMenuCheckItem(self, menu, onproc, name, desc=None, id=-1):
    if id==-1: id=self.GetMenuId(onproc)
    if desc == None: desc=name
    item=menu.AppendCheckItem(id, name, desc)
    self.Bind(wx.EVT_MENU, onproc, item)
    return item class NodeId:
  def __init__(self, typeOrInst, name=None):
    """
    NodeId(nodeType)
    NodeId(nodeInstance, name)
    """
    if not name:
      name=typeOrInst
    if isinstance(typeOrInst,NodeType):
      self.type=typeOrInst
    else:
      self.type=NodeType(typeOrInst)
    if isinstance(name, StringType):
      self.name=name
    else:
      self.name=name.name

  def path(self):
    return  "%s:%s" % (self.type.name, self.name)

  def __str__(self):
    return  "<%s.%s>" % (self.type.name, self.name)

  def __eq__(self, o):
    return self.type == o.type and self.name == o.name class Node(object):
  """
  class adm.Node

  Representation of an object on the server or the server itself.
  could also be a collection of nodes
  May be hosted by many trees
  """

  wantIconUpdate=False

  def __init__(self, parentNode, name):
    self.treeitems={}
    self.childnodes=[]
    self.parentnodes=[]
    self.properties=[]
    self.statistics=None
    self.dependsOn=None
    self.referencedBy=None
    self.server=None
    self.connection=None
    self.comment=None
    self.detachedWindow=None

    self.parentNode=parentNode
    self.name=name
    self.module=adm.getModule(self)
    self.type=self.MakeType()
    self.id=NodeId(self)

  def __str__(self):
    return "<%s %s>" % (self.id.type.name, self.id.name)

  def moduleClass(self):
    m=self.__module__
    cls=m[:m.find('.')]
    return cls

  def CleanupDetached(self):
    pass
  
  def CheckConnection(self, connection):
    if not connection or connection.HasFailed():
      if connection and hasattr(connection, 'lastError'):
        err=connection.lastError
      else:
        err=""
      if hasattr(self, 'waitingFrame'):
        frame=self.waitingFrame
        if frame:
          adm.StopWaiting(frame)
      else:
        frame=adm.GetCurrentFrame()
      if frame:
        frame.SetStatus(xlt("disconnected: %s") % err)
      raise adm.NoConnectionException(self, None)


  def GetIcon(self):
    return self.GetImageId(self.__class__.__name__)

  def GetAddress(self):
    if hasattr(self, "address"):
      return self.address
    return self.name

  def GetComment(self):
    return self.comment

  def IsPageAvailable(self, pageClass, _detached):
    classes=self.nodeinfo().get('pages')
    if not classes:
      return False
    if not isinstance(pageClass, StringType):
      pageClass=pageClass.__name__
#    if isinstance(classes, StringType):
#      classes=classes.split(' ')
#    elif not isinstance(classes, list):
#      classes = [classes]
    for cls in classes:
#      if not isinstance(cls, StringType):
#        cls=cls.__name__
      if cls == pageClass:
        return True
    return False

  
  def IconUpdate(self, force=False):
    if self.wantIconUpdate or force:
      if self.treeitems:
        icon=self.GetIcon()
        txt=self.GetLabelText()
        for treename,itemlist in self.treeitems.items():
          tree=adm.trees[treename]
          for item in itemlist:
            if tree.GetItemImage(item) != icon:
              tree.SetItemImage(item, icon)
            if tree.GetItemText(item) != txt:
              tree.SetItemText(item, txt)

    for node in self.childnodes:
      node.IconUpdate()

  def MakeType(self, cls=None):
    if not cls:
      cls=self.__class__.__name__
    elif isinstance(cls, NodeType):
      return NodeType(cls)
    elif not isinstance(cls, StringType):
      cls=cls.__name__
    return NodeType("%s.%s" % (self.module, cls))

  def MakeCollectionType(self, cls):
    if not isinstance(cls, StringType):
      cls=cls.__name__
    return NodeType("%s.%s-coll" % (self.module, cls))

  def MayHaveChildren(self):
    return len(self.nodeinfo()['children']) > 0


  def GetImageId(self, *names):
    names=list(names)
    if isinstance(names[0], list):
      names=names[0]
    if len(names)==1:
      return adm.images.GetId(os.path.join(self.module, names[0]))

    return adm.images.GetJoinedId(map(lambda name: self.GetImageId(name), names))

  def GetInfo(self):
    return ""

  def GetServer(self):
    if self.server:
      return self.server
    if self.parentNode:
      return self.parentNode.GetServer()
    return None

  def GetConnection(self):
    if self.connection:
      self.CheckConnection(self.connection)
      return self.connection
    if self.parentNode:
      return self.parentNode.GetConnection()
    return None

  def appendChild(self, child):
    self.childnodes.append(child)
    child.parentnodes.append(self)
    for treename, itemlist in self.treeitems.items():
      tree = adm.trees[treename]
      if tree.autoChildren:
        for item in itemlist:
          tree.Append(item, child)


  def removeChild(self, child):
    if child in self.childnodes:
      self.childnodes.remove(child)
    if self in child.parentnodes:
      child.parentnodes.remove(self)
    if not self.childnodes:
      for treename, itemlist in self.treeitems.items():
        for item in itemlist:
          adm.trees[treename].Collapse(item)
      
        
        
  def RefreshVolatile(self, force=False):
    """ RefreshVolatile() performs a partial refresh of frequently changed node properties"""
    pass

  def Refresh(self):
    """ Refresh() performs a full refresh of the node on user's demand"""
    self.DoRefresh()

  def DoRefresh(self):
    """
    DoRefresh() erforms a refresh of the node display; called internally.
    It might skip some initialization code that's only called in Refresh.
    """
    self.properties=[]
    if hasattr(self, 'Init'):
      self.Init()
    
    for child in self.childnodes:
      self.removeChild(child)
    if self.GetServer().IsConnected():
      self.RefreshVolatile(True)
  
      for treename, itemlist in self.treeitems.items():
        for item in itemlist:
          adm.trees[treename].Refresh(item, self)

  def RemoveFromTree(self, doRefresh=True):
    if self.parentNode:
      self.parentNode.removeChild(self)
    for treename in self.treeitems.keys():
      tree=adm.trees[treename]
      tree.DeleteNode(self)
    if doRefresh and self.parentNode:
        self.parentNode.DoRefresh()

  # some Property helper
  def AddProperty(self, txt, value, imageid=-1):
    if not isinstance(imageid, int):
      imageid=self.GetImageId(imageid)
    if isinstance(value, list):
      value = ", ".join(value)
    self.properties.append( (txt, value, imageid) )

  def AddYesNoProperty(self, txt, value, imageid=-1):
    if value:
      v=xlt("Yes")
    else:
      v=xlt("No")
    self.AddProperty(txt, v, imageid)

  def AddSizeProperty(self, txt, value, imageid=-1):
    if not isinstance(value, float):
      value=sizeToFloat(value)
    self.AddProperty(txt, floatToSize(value), imageid)

  def AddChildrenProperty(self, childlist, txt, className, valExtractor=None):
    """
    AddChildrenProperty(self, childlist, txt, className, valExtractor=None)
    AddChildrenProperty(self, childlist, txt, iconId, valExctractor=None)

    Add <childlist> items to self.properties with txt and Bitmap from className
    items can be formatted by the valExtractor proc
    """
    if childlist == None:
      return False
    if not isinstance(childlist, list):
      childlist=[childlist]
    if isinstance(className, int):
      imageid=className
    else:
      imageid=self.GetImageId(className)
    for info in childlist:
      if valExtractor:
        info=valExtractor(info)
      self.AddProperty(txt, info, imageid)
      txt=""
      imageid=0
    return len(childlist)>0


  def GetCollection(self, cls):
    for c in self.childnodes:
      if c.nodeclass == cls:
        return c
    return None
  
  
  def FindNode(self, toFind, arg2=1, level=1):
    """
    FindNode(nodeId, level=-1)
    FindNode(nodeModule, nodeName, level=-1)

    Find a child node recursively <level> deep
    """
    if isinstance(arg2, int):
      level=arg2
    else:
      toFind=NodeId(self.MakeType(toFind), arg2)

    self.PopulateChildren()
    for cn in self.childnodes:
      if isinstance(toFind, NodeId):
        if cn.id == toFind:
          return cn
      else:
        if cn.name == toFind:
          return cn
    if level > 1:
      for cn in self.childnodes:
        rc=cn.FindNode(toFind, level-1)
        if rc:
          return rc
    return None

  def FindNodePath(self, findList):
    node=self
    for toFind in findList:
      node=node.FindNode(*toFind)
      if not node:
        logger.debug("Node path %s not found", str(toFind))
        return None
    return node

  def PopulateChildren(self):
    if len(self.childnodes) > 0:
      return

    logger.debug("Populating %s %s", self.type, self.name)
    self.childnodes=[]

    if isinstance(self, Collection):
      childlist=[self.nodeclass.__name__]
    else:
      childlist=self.nodeinfo()['children']

    if not childlist:
      return
    for nodename in childlist:
      nodeinfo=self.moduleinfo()['nodes'][nodename]
      collText=nodeinfo.get('collection')
      cls=nodeinfo['class']
      if collText and not isinstance(self, Collection):
        child=Collection(self, collText, cls)
        self.appendChild(child)
      else:
        if isinstance(self, Group):
          self.GetProperties() # make sure child list is populated
        if hasattr(cls, 'GetInstances'):
          children=cls.GetInstances(self)
        else:
          children=cls.GetInstancesFromClass(self)
        if children != None:
          for child in children:
            self.appendChild(child)


  def GetLabelText(self):
    if self.name:
      return xlt("%s \"%s\"") % (xlt(self.shortname), xlt(self.name))
    else:
      return xlt(self.typename)

  def GetPropertiesHeader(self):
    return (xlt("Property"), xlt("Value"))

  def GetProperties(self):
    return []

  def moduleinfo(self):
    return adm.modules[self.module].moduleinfo

  def nodeinfo(self, item=None):
    if item:
      if isinstance(item, Node):
        item=item.__class__.__name__
    else:
      item=self.__class__.__name__
    return self.moduleinfo()['nodes'][item]

  def menuinfos(self):
    return self.moduleinfo()['menus']

  @staticmethod
  def isValidChild(parentNode, name):
    if isinstance(parentNode, Group):
      return name in parentNode.childlist
    return True class Collection(Node):
  """
  class Collection

  A collection automatically creates a grouping node for its nodes
  
  Collections are typed after their members "<classname>-coll", and named after their parents
  """
  def __init__(self, parentNode, name, cls):
    Node.__init__(self, parentNode, name)
    self.typename=name
    self.shortname=name
    self.name=None
    self.nodeclass=cls

    tmp=cls.__module__
    self.module=tmp[:tmp.find('.')]

    self.type=self.MakeCollectionType(cls)
    self.id=NodeId(self, parentNode)

  def GetIcon(self):
    id=adm.images.GetId(os.path.join(self.module, "%ss" % self.nodeclass.__name__))
    if id == -1:
      return adm.images.GetId(os.path.join(self.module, self.nodeclass.__name__))
    return id

  def IsPageAvailable(self, cls, _detached):
    return False
  
  def nodeinfo(self, _item=None):
    return self.moduleinfo()['nodes'][self.nodeclass.__name__]

  def MayHaveChildren(self):
    return True

  def GetInfo(self):
    return xlt("%d %s") % (len(self.childnodes), self.typename)

  def GetPropertiesHeader(self):
    return (self.typename, xlt("Comment"))

  def GetProperties(self):
    if not len(self.childnodes):
      self.PopulateChildren()
    list=[]
    icon=self.GetImageId(self.nodeclass.__name__)
    for child in self.childnodes:
      list.append((child.name, child.GetComment(), icon))
    return list class Group(Node):
  def __init__(self, parentNode, name, memberclass):
    Node.__init__(self, parentNode, name)
    self.firstMemberItem=9999999
    self.childlist=[]
    self.memberclass=memberclass
    if memberclass:
      self.memberIcon=adm.images.GetId(os.path.join(self.module, memberclass.__name__))
    else:
      self.memberIcon=-1

  def GetIcon(self):
    id=-1;
    if self.memberclass:
      id=adm.images.GetId(os.path.join(self.module, "%ss" % self.memberclass.__name__))
    if id == -1:
      return self.memberIcon
    return id


  def GetItemNode(self, page, index):
    if isinstance(page, adm.PropertyPage) and index >= self.firstMemberItem:
      childname=self.childlist[index-self.firstMemberItem]
      return self.FindNode(self.memberclass, childname)
      toFind=NodeId(self.MakeType(self.memberclass), childname)
      return self.FindNode(toFind)

      self.PopulateChildren()

      for c in self.childnodes:
        if c.id == toFind:
          return c
      tree=adm.GetCurrentTree(page)
      item=tree.Find(None, toFind, 2)
      if item:
        return tree.GetNode(item)
    return None

  def GetInfo(self):
    return xlt("%d %s") % (len(self.childlist), self.shortname)

  @staticmethod
  def GetGroupInstances(parentNode, groupclass, memberlist, validproc=Node.isValidChild):
    childlist=[]
    if not isinstance(memberlist, list):
      memberlist=[memberlist]
    for name in memberlist:
      if validproc(parentNode, name):
        childlist.append(groupclass(parentNode, name))
    return childlist

  def GetGroupProperties(self, txt, memberlist=None):
    if not memberlist:
      memberlist=self.childlist

    self.properties= [
         ( xlt("Name"),self.name),
         ]
    self.firstMemberItem=len(self.properties)
    self.AddChildrenProperty(memberlist, txt, self.memberIcon)

#    imageid=self.memberIcon
#    for member in memberlist:
#      self.properties.append( (txt, member, imageid))
#      txt=""
#      imageid=0
    return self.properties class ServerNode(Node):
  findObjectIncremental=True
  
  def __init__(self, settings, _password=None):
    Node.__init__(self, None, settings['name'])

    self.registrationChanged=False
    self.server=self
    self.settings=settings
    self.address = self.settings.get('host')
    self.user=self.settings.get('user')
    self.port=self.settings.get('port')
    self.needPassword=(self.settings.get('password') != None)

  def SetCfgString(self, cmd, value):
    adm.config.Write("%s/%s" % (self.module, cmd), value)

  def GetCfgString(self, cmd, default=None):
    cfg=adm.config.Read("%s/%s" % (self.module, cmd), default)
    return cfg
  
  def GetPreference(self, key):
    prefs=self.moduleinfo()['preferences']
    return prefs.GetPreference(key)
  

  def Disconnect(self):
    self.connection=None
    return True
  
  def GetInfo(self):
    if self.IsConnected():
      le=self.GetLastError()
      if le:
        return xlt("Connection error: %s") % le
      else:
        return xlt("connected")
    else:
      return xlt("not connected")

  def IsConnected(self, _deep=False):
    return self.server != None

  def IsHealthy(self):
    return self.server != None

  def Connect(self, parentWin):
    """
    Connect(parentWin) returns
    True: connected
    False: error
    None: aborted
    """
    self.connectException=None
    self.password=self.settings.get('password')
    self.user=self.settings.get('user')
    if not self.password and self.user:
      self.password, remember = adm.AskPassword(parentWin, xlt("Password for %s:" % self.user), xlt("Enter password for %(type)s \"%(name)s\"") 
                                       % { "type": self.typename, "name": self.name }, True )
      if self.password == None:
        return None
      if remember:
        self.settings['password'] = self.password
        adm.config.storeServerSettings(self, self.settings)

    rc=self.DoConnect()
    return rc

  
  def FindStringValid(self, _find):
    return True
  
  def FindObject(self, tree, currentItem, patterns):
    "FindObject(self, tree, currentItem, pattern) matches children, sibling and parent+sibling recursively"
    for item in tree.GetChildItems(currentItem):
      found=tree.FindPattern(item, patterns)
      if found:
        return found

    item=tree.GetNextSibling(currentItem)
    while item:
      found=tree.FindPattern(item, patterns)
      if found:
        return found
      item=tree.GetNextSibling(item)
      
    parentItem=tree.GetItemParent(currentItem)
    while parentItem:
      parentNode=tree.GetNode(parentItem)
      if not parentNode or parentNode == self:
        return None
      item=tree.GetNextSibling(parentItem)
      if item:
        found=tree.FindPattern(item, patterns)
        if found:
          return found
      parentItem=tree.GetItemParent(parentItem)
      
    return None

  def ExternExecute(self, _parentWin, cmd, address, port, **kargs):
    call=self.GetCfgString(cmd)

    call=call.replace("%h", address)
    call=call.replace("%p", str(port))
    user=kargs.get('user')
    if user != None:
      call=call.replace("%u", user)
    password=kargs.get('password', "")
    if password != None:
      call=call.replace("%P", password)

    logger.debug("ExternCall %s", call)
    pid=wx.Execute(call)
    return pid class PropertyPage(NotebookPage):
  name=xlt("Properties") class NotebookPage(ControlledPage):
  """
  NotebookCPage
  
  Class implementing the Page methods used in the Notebook
  by default having a single Listview control
  """
  def __init__(self, notebook):
    lvClass=xmlres.getControlClass("whListView")
    if not lvClass:
      raise Exception("Some XMLRES problem: whListView not found")
    self.control=lvClass(notebook, "property") # !!! Module auswerten
    self.control.Bind(wx.EVT_LIST_COL_END_DRAG, self.OnListColResize)
    self.panelName=None
    self.SetOwner(notebook)

  
  def Display(self, node, _detached):
    self.lastNode=node
#    self.control.Freeze()
    self.control.ClearAll()
    if node:
      prop, val=node.GetPropertiesHeader()
      self.control.CreateColumns(prop, val, 15);
      adm.config.restoreListviewPositions(self.control, self)
      for props in node.GetProperties():
        img=-1

        if isinstance(props, tuple):
          props=list(props)
        if isinstance(props, list):
          if len(props) > 2:
            img=int(props[-1])
            del props[-1]
        self.control.AppendItem(img, props)
    else:
      self.control.CreateColumns(self.name);
      self.control.InsertStringItem(0, xlt("No properties are available for the current selection"), -1); class NotebookControlsPage(NotebookPage, NotebookPanel):
  """
  NotebookControlsPage
  
  Class implementing the Page methods used in the Notebook
  loading its controls from an xml resource 
  """
  def __init__(self, notebook):
    NotebookPanel.__init__(self, None, notebook)
    self.SetOwner(notebook) class NotebookPanel(wx.Panel, adm.ControlContainer):
  """
  NotebookPanel
  
  Class representing a panel usable in a Notebook
  which loads its controls from an xml resource
  """
  def __init__(self, dlg, notebook, resname=None):
    adm.ControlContainer.__init__(self, resname)
    self.dialog=dlg
    res=self.getResource()
    pre=wx.PrePanel()
    res.LoadOnPanel(pre, notebook, self.resname)
    self.PostCreate(pre)
    self.addControls(res)
    self.AddExtraControls(res)
    adm.logger.debug("Controls found in Panel %s/%s: %s", self.module, self.resname, ", ".join(self._ctls.keys()))

  def Bind(self, *args, **kargs):
    adm.ControlContainer.Bind(self, *args, **kargs)
    
  def OnCheck(self, evt):
    self.dialog.OnCheck(evt)
    
  def __getattr__(self, name):
    return self._getattr(name)

  def __setattr__(self, name, value):
    return self._setattr(name, value) class PreferencePanel(NotebookPanel):
  """
  PreferencePanel
  
  Class representing a panel used in the main preferences dialog
  for configuration of module specific options
  A node can retrieve a value using node.GetPreference(key)
  """

  @classmethod
  def GetPreference(cls, key):
    default=cls.configDefaults.get(key)
    return adm.config.Read(key, default, cls)

  @classmethod
  def SetPreference(cls, key, val):
    adm.config.Write(key, val, cls)
    
  def Save(self):
    for key in self.configDefaults:
      val=self._getattr(key)
      self.SetPreference(key, val)
    return True
  
  def Go(self):
    for key in self.configDefaults:
      val=self.GetPreference(key)
      self._setattr(key, val) def getAllPreferencePanelClasses():
  from AdmDialogs import Preferences
  panelclasses=[Preferences]
  for modname, mod in adm.modules.items():
    panel=mod.moduleinfo.get('preferences')
    if not panel:
      adm.logger.debug("Module %s has no preferences", modname)
      continue
    if isinstance(panel, list):
      panelclasses.extend(panel)
    else:
      panelclasses.append(panel)
  return panelclasses class Dialog(wx.Dialog, ControlContainer, MenuOwner):
  """
  class Dialog

  Handles XRC-Resource:
    loads them from file according to class name or argument 'resname'
    self.VARNAME=<value> sets control
    var=self.VARNAME reads control
    self["VARNAME"].someMethod() calls control
    VARNAME is case insensitive
    
  Handles Save/Check/OnCheck
    Usually CheckedDialog is used, which includes a status bar as well.
  """
  def __init__(self, parentWin, node=None, resname=None):
    ControlContainer.__init__(self, resname)
    self.statusbar=None
    self.node=node
    if node:
      self.parentNode=node.parentNode
    else:
      self.parentNode=None

    res=self.getResource()
    # TODO configurable from module

    pre=wx.PreDialog()
    res.LoadOnDialog(pre, parentWin, self.resname)
    self.PostCreate(pre)

    size, pos=adm.config.getWindowPositions(self)
    if pos:
      self.Move(pos)
    if size and self.HasFlag(wx.RESIZE_BORDER):
      self.SetSize(size)

    self.addControls(res)
    self.AddExtraControls(res)

    if self.module:
      modname="%s/%s" % (self.module.replace('.', '/'), self.resname)
    else:
      modname=self.resname
    adm.logger.debug("Controls found in %s: %s", modname, ", ".join(self._ctls.keys()))

    nb= self.ctl('Notebook')
    if nb:
      sel=nb.GetSelection()
      if sel >= 0:
        nb.GetPage(nb.GetSelection()).Show()

    self.Bind(wx.EVT_CLOSE, self.OnCancel)
    if self.ctl('Cancel'):
      self.Bind('Cancel', wx.EVT_BUTTON, self.OnCancel)
    if self.ctl('OK'):
      self.Bind('OK', wx.EVT_BUTTON, self.OnOK)
      self['OK'].SetDefault()


  def addStatusBar(self, res=None):
    if self.statusbar:
      return
    flags=0;
    if self.HasFlag(wx.RESIZE_BORDER):
      flags = wx.ST_SIZEGRIP
    self.statusbar = wx.StatusBar(self, -1, flags)
    if res:
      res.AttachUnknownControl("StatusBar", self.statusbar)
    else:
      sbHeight=self.statusbar.GetSize().y
      dlgSize=self.GetSize()
      self.SetSize( (dlgSize.x, dlgSize.y+sbHeight) )
      clientSize=self.GetClientSize()
      self.statusbar.SetDimensions(0, clientSize.y-sbHeight, clientSize.x, sbHeight)
    self.statusbar.Show()

  def moduleClass(self):
    m=self.__module__
    cls=m[:m.find('.')]
    return cls

  def GetImageId(self, name):
    return adm.images.GetId(os.path.join(self.module, name))

  def GetBitmap(self, name):
    id=self.GetImageId(name)
    if id > 0:
      return adm.images.GetBitmap(id)
    return None

  def BindMenuId(self, proc):
    id=self.GetMenuId(proc)
    wx.Window.Bind(self, wx.EVT_MENU, proc, id=id)
    return id

  def Check(self):
    """
    bool Check()

    should be implemented in derived class
    returns true if may save
    """
    return True

  def Save(self):
    """
    bool Save()

    must be implemented in derived class
    returns true if action performed
    Alternatively, Execute() can be implemented which skips the CheckChanged step.
    """
    if hasattr(self, "Execute"):
      return self.Execute()
    return False

#  def Go(self, parentNode=None):
#  must be implemented in derived class


  def Close(self):
    adm.config.storeWindowPositions(self)
    if hasattr(self, "dialogId"):
      try:
        del adm.dialogs[self.dialogId]
      except:
        pass
    self.Destroy()


  def OnCancel(self, _ev):
    if self.IsModal():
      self.EndModal(wx.CANCEL)
    self.Close()


  def DoSave(self):
    try:
      return self.Save()
    except adm.ServerException as e:
      self.SetStatus(xlt("Server error: %s") % e.error)
      return False


  def _OnOK(self):
    if not self.Check():
      return False
    if not self.DoSave():
      return False

    if self.IsModal():
      self.EndModal(wx.ID_OK)
    if hasattr(self, "startTime"):
      elapsed=localTimeMillis() - self.startTime
      adm.SetStatus(xlt("Ok: %s execution time.") % floatToTime(elapsed/1000.))
    else:
      adm.SetStatus(xlt("Ok."))
    return True

  def OnOK(self, _ev):
    if self._OnOK():
      self.Close()


  def OnCheck(self, _ev=None):
    ok=self.Check()
    if ok:
      self.SetStatus(None)
      if not hasattr(self, "Execute"):
        ok = self.GetChanged()

    self["OK"].Enable(bool(ok))

  def GoModal(self):
    self.Go()
    self.SetUnchanged()
    self.OnCheck(None)
    self.modalResult=self.ShowModal()
    return self.modalResult== wx.ID_OK

  def CheckValid(self, ok, cond, txt):
    if ok:
      if not cond:
        ok=False
        self.SetStatus(txt)
    return ok


  def SetStatus(self, text=None):
    if self.statusbar:
      if text:
        self.statusbar.SetStatusText(text)
      else:
        self.statusbar.SetStatusText("")


  def Bind(self, *args, **kargs):
    ControlContainer.Bind(self, *args, **kargs)

  def __getattr__(self, name):
    return self._getattr(name)

  def __setattr__(self, name, value):
    return self._setattr(name, value) class CheckedDialog(Dialog):
  """
  CheckedDialog
  
  Dialog with status bar
  """
  
  def __init__(self, parentWin, node=None, _parentNode=None, resName=None):
    Dialog.__init__(self, parentWin, node, resName)
    self.addStatusBar() class PropertyDialog(CheckedDialog):
  """
  PropertyDialog
  
  Editing properties of a node, which is represented by a treeItem 
  and thus needs a tree refresh if changed
  """
  def __init__(self, parentWin, node, parentNode=None, resName=None, title=None):
    CheckedDialog.__init__(self, parentWin, node, resName=resName)
    if parentNode:
      self.parentNode=parentNode

    self.refreshNode=None

    if title:
      self.SetTitle(title)
    elif self.node:
      self.SetTitle(xlt("Properties of %s \"%s\"") % (self.node.typename, self.node.name))
    elif parentNode:
      self.SetTitle(xlt("New %s") % parentNode.typename)
    self.Bind('OK', wx.EVT_BUTTON, self.OnOK)


  def OnOK(self, _ev):
    if not self._OnOK():
      return

    if self.refreshNode:
      self.refreshNode.DoRefresh()
    elif self.node:
      self.node.Refresh()
    elif self.parentNode:
      self.parentNode.DoRefresh()
    self.Close() class PagedPropertyDialog(PropertyDialog):
  """
  PagedPropertyDialog
  
  PropertyDialog with a notebook, distributing property items over several panels
  """
  def __init__(self, parentWin, node, parentNode, title=None):
    PropertyDialog.__init__(self, parentWin, node, parentNode, resName="./PagedPropertyDlg", title=title)
    self.panels=[]
    notebook=self['Notebook']
    if hasattr(self, 'panelClasses'):
      for cls in self.panelClasses:
        if hasattr(cls, 'CreatePanel'):
          panel=cls.CreatePanel(self, notebook)
        else:
          panel=cls(self, notebook)
        if panel:
          self.addPanel(panel)
    notebook.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPanelChange)

  def addPanel(self, panel, name=None):
    if not name:
      name=panel.name
    self.panels.append(panel)
    self['Notebook'].AddPage(panel, name)

  def OnPanelChange(self, evt):
    panel=self.panels[evt.Selection]
    panel.Show()
    if hasattr(panel, "Display"):
      panel.Display()
  
  def Check(self):
    for panel in self.panels:
      if hasattr(panel, "Check"):
        if not panel.Check():
          return False
    return True
  
  def GetChanged(self):
    cl=[]
    for panel in self.panels:
      cl.extend(panel.GetChanged())
    return cl
  
  def Go(self):
    for panel in self.panels:
      if hasattr(panel, "Go"):
        panel.Go() class ServerPropertyDialog(PropertyDialog):
  """
  ServerPropertyDialog
  
  Server Properties with a list of predefined keywords
  which are stored in the config file
  """
  keyvals= [ ("HostName", 'name') ,
             ("HostAddress", 'host'),
             "Port",
             "User",
             "Password",
             "Autoconnect",
             "SSL",
             "Security"
           ]


  def GetSettings(self, keyvals=None):
    if not keyvals:
      keyvals=self.keyvals
    if self.node:
      settings=self.node.settings.copy()
    else:
      settings={}
    for ctlname in keyvals:
      if isinstance(ctlname, tuple):
        ctlname, key = ctlname
      else:
        key=ctlname.lower()

      ctl=self.ctl(ctlname)
      if ctl:
        settings[key] = self._getattr(ctl)
    return settings

  def SetSettings(self, settings, keyvals=None):
    if not keyvals:
      keyvals=self.keyvals
    for ctlname in keyvals:
      if isinstance(ctlname, tuple):
        ctlname, key = ctlname
      else:
        key=ctlname.lower()

      val=settings.get(key)
      if val == None:
        continue

      ctl=self.ctl(ctlname)
      if ctl:
        self._setattr(ctl, val) class Frame(wx.Frame, adm.MenuOwner):
  allFrames=[]
  
  def __init__(self, parentWin, title, style, _size, _pos):
    size,pos = restoreSize("main", (600,400), None)
    wx.Frame.__init__(self, parentWin, title=title, style=style, size=size, pos=pos)
    Frame.allFrames.append(self)
    self.tree=None
    self.currentNode=None
    self.Bind(wx.EVT_CLOSE, self.OnClose)

    size, pos=adm.config.getWindowPositions(self)
    if pos:
      self.Move(pos)
    if size and self.HasFlag(wx.RESIZE_BORDER):
      self.SetSize(size)

  @classmethod
  def CloseAll(cls):
    for frame in cls.allFrames:
      frame.Destroy()


  def GetToolBar(self):
    if hasattr(self, 'toolbar'):
      return self.toolbar
    return None
  

  def registerToggles(self, toolbar, statusbar):
    """ have toolbar and/or statusbar toggle in viewmenu """
    
    if toolbar:  
      self.viewmenu.AddCheck(self.OnToggleToolBar, xlt("Toolbar"), xlt("Show or hide tool bar"), adm.config.Read("ToolbarShown", True, self))
    if statusbar:
      self.viewmenu.AddCheck(self.OnToggleStatusBar, xlt("Statusbar"), xlt("Show or hide status bar"), adm.config.Read("StatusbarShown", True, self))
  
  def OnToggleToolBar(self, evt=None):
    show=self.viewmenu.IsChecked(self.OnToggleToolBar)
    self.GetToolBar().Show(show)
    if evt:
      self.manager.Update()
      adm.config.Write("ToolbarShown", show, self)
  
  def OnToggleStatusBar(self, evt=None):
    show=self.viewmenu.IsChecked(self.OnToggleStatusBar)
    self.GetStatusBar().Show(show)
    if evt:
      self.manager.Update()
      adm.config.Write("StatusbarShown", show, self)

  
  def SetIcon(self, icon, mod=None):
    if isinstance(icon, int):
      icon=adm.images.GetBitmap(icon)
    elif isinstance(icon, StringType):
      icon=GetIcon(icon, mod)
    if isinstance(icon, wx.Bitmap):
      icon=wx.IconFromBitmap(icon)
    if icon:      
      wx.Frame.SetIcon(self, icon)
      return True
    return False


  def OnCall(self, evt):
    """
    OnCall(wx.Event)

    calls registered procedures from an event using appropriate arguments
    It handles:
      @staticmethod DoSomething(parentWindow, node) -> bool to refresh node
      @staticmethod DoSomething(node)
      @staticmethod Register(parentWindow)
      Edit(self, parentWindow)
      HandleEvent(self, evt)
    """
    id=evt.GetId()
    proc=self.GetMenuProc(id)
    if proc:
      args = self.GetCallArgs(proc)
      if len(args) and args[0] == "self":
        del args[0]
        isStatic=False
      else:
        isStatic=True
      ci=[proc.__module__]
      if hasattr(proc, "_classname_"):
        ci.append(proc._classname_)
      ci.append(proc.__name__)
      adm.logger.debug("Calling ID %d: %s", id, ".".join(ci))
      node=self.currentNode
      if not node and self.tree:
        node=self.tree.GetNode()
      if len(args) == 2:
        if proc(self, node) and node:
          node.DoRefresh()
      else:
        if isStatic:
          if proc.__name__ in ['Register']:
            proc(self)
          else:
            proc(node)
        else:
          proc(evt)
    

  def OnClose(self, evt):
    adm.config.storeWindowPositions(self)
    try: Frame.allFrames.remove(self)
    except: pass
    evt.Skip()

  def SetStatus(self, text=None):
    sb=self.GetStatusBar()
    if sb:
      if text:
        sb.SetStatusText(text, 0)
      else:
        sb.SetStatusText("", 0)

  def PushStatus(self, text, field=0):
    sb=self.GetStatusBar()
    if sb:
      sb.PushStatusText(text, field)

  def PopStatus(self):
    sb=self.GetStatusBar()
    if sb:
      sb.PopStatusText() class PasswordDlg(adm.Dialog):
  def __init__(self, parentWin, msg, caption):
    adm.Dialog.__init__(self, parentWin)
    self.SetTitle(caption)
    self.staticPassword=msg

  def Save(self):
    return True class HintDlg(adm.Dialog):

  @staticmethod
  def WantHint(hint, module):
    return adm.config.GetWantHint(hint, module)
  
  def __init__(self, parentWin, hint, hintModule, title, args):
    adm.Dialog.__init__(self, parentWin)
    self.hint=hint
    self.hintModule=hintModule
    self.title=title
    if args:
      self.args=args
    else:
      self.args={}
    args['appName'] = adm.appTitle
    
  def AddExtraControls(self, res):
    self.browser=wx.html.HtmlWindow(self)
    res.AttachUnknownControl("HtmlWindow", self.browser)
    

  def Go(self):
    f=open(localizePath(modPath(os.path.join("hints", "%s.html" % self.hint), self.hintModule)))
    html=f.read()
    f.close()
    for tag, value in self.args.items():
      html=html.replace("$%s" % tag.upper(), value.encode('utf-8'))
      
    self.browser.SetPage(html.decode('utf-8'))
    if not self.title:
      self.title=self.browser.GetOpenedPageTitle()
    if self.title:
      self.SetTitle(self.title)
    else:
      self.SetTitle(xlt("%s hint") % adm.appTitle)
    
  def Execute(self):
    adm.config.SetWantHint(self.hint, self.hintModule, not self.NeverShowAgain)
    return True
import sys, os
import wx
import wh
import logger
  import version
from wh import xlt, StringType
from controlcontainer import ControlContainer, MenuOwner  # @UnusedImport
from node import NodeId, Node, Collection, Group, ServerNode  # @UnusedImport
from page import PropertyPage, NotebookPage, NotebookControlsPage, NotebookPanel, PreferencePanel, getAllPreferencePanelClasses  # @UnusedImport
from controlcontainer import Dialog, CheckedDialog, PropertyDialog, PagedPropertyDialog, ServerPropertyDialog  # @UnusedImport
from frame import Frame
from AdmDialogs import PasswordDlg, HintDlg
    for id in ids:
      if id > 0:
        b=self.GetBitmap(id)
        dc.DrawBitmap(b, 0, 0, True)
        #self.Draw(id, dc, 0,0)
      dc.DrawBitmap(b, 0, 0, True)
    dc.SelectObject(wx.NullBitmap)

    id=self.Add(bmp)
    self.list[name]=id
    return id

  def GetId(self, name):
    if name == None:
      return -1
    id=self.list.get(name)
    if id:
      return id

    id=-1
    bmp=wh.GetBitmap(name)
    if bmp:
      if bmp.GetSize() != self.GetSize(0):
        dcs=wx.MemoryDC()
        w1,h1=bmp.GetSize()
        dcs.SelectObject(bmp)
        dc=wx.MemoryDC()
        w,h=self.GetSize(0)
        bmpneu=wx.EmptyBitmap(w,h)
        dc.SelectObject(bmpneu)
        if wx.Platform not in ("__WXMAC__"):
          b=self.GetBitmap(1)
          dc.DrawBitmap(b, 0, 0, True)
        dc.StretchBlit(0, 0, w, h, dcs, 0,0,w1,h1)
        dc.SelectObject(wx.NullBitmap)
        dcs.SelectObject(wx.NullBitmap)
        id=self.Add(bmpneu)
        logger.debug("Bitmap %s has wrong format. Need %s, is %s", name, self.GetSize(0), bmp.GetSize())
      else:
        id=self.Add(bmp)
    else:
      fn="%s.ico" % name
      if os.path.exists(fn):
        id=self.AddIcon(wx.Icon(fn))
    self.list[name]=id
    return id

  def __getitem__(self, name):
    return self.GetId(name)

images=ImageList(16,16)
images48=ImageList(48,48)



##########################################################################

class admException(Exception):
  def __init__(self, node, txt, error=None):
    if error:
      msg=error
    else:
      msg=txt
    if node and hasattr(node, 'waitingFrame'):
      StopWaiting(node.waitingFrame, msg)
    else:
      StopWaiting(None, msg)
    if error !=  None:
      super(admException, self).__init__(txt, error)
    else:
      super(admException, self).__init__(txt)
    
class NoConnectionException(admException):
  def __init__(self, node, error=None):
    if error:
      txt="still broken connection: %s" % error
    else:
      txt="still broken connection"
    super(NoConnectionException, self).__init__(node, txt)
    self.servernode=node
    self.error=error


class ServerException(admException):
  def __init__(self, node, error):
    self.error=' '.join(error.splitlines())
    self.servernode=node

    txt="%s %s" % (node.shortname, node.name)
    super(ServerException, self).__init__(node, txt, error)


class ConnectionException(admException):
  def __init__(self, node, spot, error):
    self.servernode=node
    self.spot=spot
    self.error=error

    txt="%s connection: %s" % (spot, error)
    super(ConnectionException, self).__init__(node, txt)

    wx.MessageBox("%s: %s" % (spot, error), xlt("%s \"%s\"") % (node.typename, node.name))
    node.GetServer().IconUpdate()




#########################################################################
# global helper functions

def RegisterServer(settings):
  mainframe.servers.RegisterServer(settings)

def DisplayDialog(cls, parentWin, *params):
  id="%s%s" % (cls.__name__, params)
  dlg=dialogs.get(id)
  if dlg:
    dlg.Iconize(False)
    dlg.Raise()
  else:

    while not isinstance(parentWin, (Dialog, Frame)):