"""
     qtgui/displayTable.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2011 University of York
     Copyright (C) 2012 STFC

     This library is free software: you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public License
     version 3, modified in accordance with the provisions of the 
     license to address the requirements of UK law.
 
     You should have received a copy of the modified GNU Lesser General 
     Public License along with this library.  If not, copies may be 
     downloaded from http://www.ccp4.ac.uk/ccp4license.php
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU Lesser General Public License for more details.
"""



from PyQt4 import QtGui,QtCore
import sys,copy

from global_definitions import *
import rebuild
import guiUtils
import MGSimpleDialog
import functools

margin = 0

# Code like the line below can trigger a crash when Qt tries to access
# objects which have been deleted but somehow have connections elsewhere.
#
# dispobj.setParent(None)
# 
# Instead createding a dummy widget and using 
#
# dispobj.setParent(theDummy)
# 
# seems to create a much more stable system.
#
if not '-quit' in sys.argv:
  theDummy = QtGui.QWidget()

class MGDisplayTable(QtGui.QWidget):
  
  rowHeight = 21
  floatingWidth = 100
  dockedWidth = 50
  floatingBodyWidth = 12 
  dockedBodyWidth = 6
  # Try this for super-compact DT, useful with icons.
  #dockedBodyWidth = 3
  compactWidth = 6
  pixmaps = {}
  loaded_icons = {}
  label_columns = 0  # Not implemented - do we need to label columns?
  floatingMaxLabelLength = 15
  dockedMaxLabelLength = 6
  dataobj_types = {}
  dispobj_types = {}
  dataobj_hide_if_empty = []
  dispobj_make_parent = {}

  def setFloating(self):
    self.docked = False

  def setFloatingSize(self):
    MGDisplayTable.width = MGDisplayTable.floatingWidth
    MGDisplayTable.bodyWidth =  MGDisplayTable.floatingBodyWidth
    MGDisplayTable.maxLabelLength =  MGDisplayTable.floatingMaxLabelLength
    MGDisplayTable.width = (MGDisplayTable.bodyWidth+3+self.status_open)*MGDisplayTable.rowHeight

  def setDocked(self):
    self.docked = True

  def setDockedSize(self):
    MGDisplayTable.width = MGDisplayTable.dockedWidth
    MGDisplayTable.bodyWidth =  MGDisplayTable.dockedBodyWidth
    MGDisplayTable.maxLabelLength =  MGDisplayTable.dockedMaxLabelLength
    MGDisplayTable.width = (MGDisplayTable.bodyWidth+3+self.status_open)*MGDisplayTable.rowHeight

  def __init__(self,parent=None,docked=False,super_compact=False):
    self.movingObjects = []
    self.movingTargets = []
    super(MGDisplayTable,self).__init__(parent)
    self.GDataObjs = {}
    self.block_emit =0
    self.status_open = 0
    if super_compact:
      MGDisplayTable.dockedBodyWidth = 3
    else:
      MGDisplayTable.dockedBodyWidth = 6
    if docked:
      self.setDockedSize()
      self.setDocked()
    else:
      self.setFloatingSize()
      self.setFloating()
    MGDisplayTable.rowHeight = int(self.fontSize())
    MGDisplayTable.width = (MGDisplayTable.bodyWidth+3+self.status_open)*MGDisplayTable.rowHeight
    MGDisplayTable.compact_width = MGDisplayTable.compactWidth*MGDisplayTable.rowHeight
    #print "MGDisplayTable rowHeight",self,MGDisplayTable.rowHeight, MGDisplayTable.width
    
    self.loadPixmaps(width=MGDisplayTable.rowHeight)

    import displayTableObjects
    MGDisplayTable.fixed_order = ['CrystalData','MolData','MapData','VectorsData','GL2dScreen']

    MGDisplayTable.dataobj_types = { 'MolData' : displayTableObjects.GMolData,
                    'MapData' : displayTableObjects.GMapData,
                    'CrystalData' : displayTableObjects.GCrystalContainer,
                    'GL2dScreen' : displayTableObjects.GGL2dScreen,
                    'VectorsData' :displayTableObjects.GVectorsData }

    MGDisplayTable.dispobj_types = {
      'MolDisp' :  displayTableObjects.GMolDisp,
      'MapDisp' : displayTableObjects.GMapDisp,
      'SurfaceDispobj' : displayTableObjects.GSurfaceDispobj,
      'HBonds' : displayTableObjects.GHBonds,
      'Contacts' :  displayTableObjects.GContacts,
      'Annotation': displayTableObjects.GAnnotation,
      'Crystal' : displayTableObjects.GCrystal,
      'Image' : displayTableObjects.GImage,
      'Legend' : displayTableObjects.GLegend,
      'ColourLegend' : displayTableObjects.GColourLegend,
      'VectorsDispobj' : displayTableObjects.GVectorsDispobj }

    MGDisplayTable.dataobj_hide_if_empty = ['CrystalData','Legends&Images']

    MGDisplayTable.dispobj_make_parent = { 'Crystal' : 'CrystalData',
                          'Legend' : 'GL2dScreen',
                          'Image' : 'GL2dScreen' }

    
  def loadPixmaps(self,dir='',width=32,height=0):
    import os,glob,string
    if not dir: dir = os.path.join(os.environ['CCP4MG'],'qticons')
    #print "loadPixmaps",dir
    
    MGDisplayTable.pixmaps = {}
    if height<=0: height = width

    for subd in ['disptab']:
      # folder-open and folder-closed are currently 22x22 and
      # dont really want to scale them up
      #tr = QtGui.QTransform()
      #tr.translate((width-22.0)/2.0,(height-22.0)/2.0)
      #print "QTransform",tr.dx(),tr.dy()
      for ext in ['*.png','*.svg']:
        for file in glob.glob(os.path.join(dir,subd,ext)):
          name = os.path.split(file)[-1][0:-4]
          MGDisplayTable.pixmaps[name] = QtGui.QPixmap(file).scaled(32,32)

  def getIcon(self,name,visible=1,dir='',width=32,height=0):
    
    import os,glob,string
    if not dir: dir = os.path.join(os.environ['CCP4MG'],'qticons')
    if height<=0: height = width

    
    if not visible: name = name+'_off'
    #print "getIcon name",name,MGDisplayTable.loaded_icons
    if MGDisplayTable.loaded_icons.has_key(name):
      return MGDisplayTable.loaded_icons[name]

    else:
      for file in [
          os.path.join(dir,'dispobj',name+'.svg'),
          os.path.join(dir,'dispobj',name+'.png')]:
      
        if os.path.exists(file):
          pix = QtGui.QPixmap(file).scaled(width,height)
          #print "getIcon pix",pix
          MGDisplayTable.loaded_icons[name] = QtGui.QIcon(pix)
          return MGDisplayTable.loaded_icons[name]
        
      if name[0:4] != 'unkn':
         return self.getIcon('unknown',visible=1,dir=dir,height=height,width=width)
      else:
         return None

  def getWidth(self):
    return (MGDisplayTable.bodyWidth+3+self.status_open)*MGDisplayTable.rowHeight + 20

  def emitSignal(self,mode=''):
    #print "DisplayTable.emitSignal",mode, self.block_emit
    if not self.block_emit:
      self.emit(QtCore.SIGNAL(mode))
      self.emit(QtCore.SIGNAL("DisplayTableChanged"))


  def DispObjOpen(self):
    for obj in self.findChildren(GDataObj):
      if obj.isOpen(): return 1
    return 0

  def showAllDataObj(self,visible=1):
    for obj in self.findChildren(GDataObj):
      obj.set_visibility(visible,redraw=0)

    #?? should we force all display objects visible
    rebuild.UpdateDisplay()

  def deleteAllDataObj(self):
    for obj in self.findChildren(GDataObj):
      self.deleteDataObj(obj.objectName(),update=0)
    
    # Just to be sure delete any dataobj left that were
    # not on the display table
    dellist = []
    for dataobj in get_dataobj():
      if not (hasattr(dataobj,'master_application') and dataobj.master_application):
        dellist.append(dataobj)
    if dellist: print "DISPLAYTABLE.deleteAllDataObj found objects without graphical interface to delete",dellist
  
    for dataobj in dellist:
      dataobj.delete()
      #del dataobj
      if hasattr(dataobj,"close"):
        dataobj.close()

    if not self.block_emit:
      print "Emitting", "removeAllDataObj"
      self.emit(QtCore.SIGNAL('removeAllDataObj'))
    else:
      print "Emits blocked"


  def loadAllDataObj(self):
    self.block_emit = 1
    obj_list = get_dataobj()
    #print "DISPLAYTABLE.loadAllDataObj",obj_list
    for obj in obj_list:
      #print "loadAllDataObj", obj.get_dispobj(),obj.name
      if MGDisplayTable.dataobj_hide_if_empty.count(obj.name) and not obj.get_dispobj():
        pass
      elif self.findChild(GDataObj,obj.name):
        pass
      else:
        self.addDataObj(name=obj.name,label=obj.name_label,object_type=obj.object_type)
    self.block_emit = 0
    self.emitSignal('loadAllDataObj')
    

  def getDataObj(self,name=''):
    if not name: return None
    widget = self.findChild(GDataObj,name)
    #if not widget:
    #  if name == 'Legends&Images':
    #    widget =  self.findChild(GDataObj,'GL2dScreen')
    return widget
  
  def getDispObj(self,name=''):
    if not name: return None
    widget = self.findChild(GDispObj,name)
    #if not widget:
    #  if name == 'Legends&Images':
    #    widget =  self.findChild(GDataObj,'GL2dScreen')
    return widget

  def addDataObj(self,object_type='MolData',name='',label='',getDispObj=1):
    #print 'MGDisplayTable.addDataObj',object_type,name,label
    if not label: label = name+ ' '
    if not self.GDataObjs.has_key(object_type):
      self.GDataObjs[object_type] = GDataObjs(self,object_type=object_type)
    graph_obj = self.findChild(GDataObj,name)
    if not graph_obj:
      graph_obj = self.GDataObjs[object_type].addGDataObj(table=self,name=name,label=label)
    #print "addDataObj graph_obj",graph_obj
    if not graph_obj: return None
    if getDispObj: graph_obj.updateDispObj()
    self.emitSignal('addDataObj')
    return graph_obj


  def deleteDataObj(self,name='',update=1):
    self.block_emit = 1
    self.removeDataObj(name=name)
    target = get_dataobj(name=name)
    #print "deleteDataObj",name,target
    if target:
      # Are there any other objects that should be deleted
      # along with this one (eg Crystal gets deleted with map)
      dependents = target[0].getDependentsForDeletion()
      #print 'displayTable deleteDataObj dependents',dependents
      target[0].delete()
      if dependents:
        # In principle there could be a recursion here.
        for dep in dependents:
          dep_target = get_dataobj(name=dep)
          if dep_target:
            dep_target[0].delete()
            self.removeDataObj(dep)
          else:
            dep_target = get_dispobj(name=dep)
            if dep_target:
              dep_target.delete()
              self.removeDispObj(dep)
    self.block_emit = 0
    self.emitSignal('deleteDataObj')
    if update: rebuild.UpdateDisplay()
    if not self.block_emit:
      print "Emitting", "removeDataObjByName", name
      self.emit(QtCore.SIGNAL('removeDataObjByName'),name)
    else:
      print "Emits blocked"
    
    dobjs = get_dataobj(object_type='MolData')
    if len(dobjs)==0:
      import model
      model.MolData.colour_counter['bymol']=''

    # If we are using old colours from an old status file 
    # then reset to the new default colours when the last
    # object is deleted.
    remaining = self.findChildren(GDataObj)
    mapMolDataLeft = False
    import displayTableObjects
    for obj in self.findChildren(GDataObj):
      if type(obj) == displayTableObjects.GMolData or type(obj) == displayTableObjects.GMapData:
        mapMolDataLeft = True
    if not mapMolDataLeft and hasattr(MGCOLOUR(),"usingOldColours") and MGCOLOUR().usingOldColours:
      MGCOLOUR().rgbreps = []
      MGCOLOUR().RGBReps.clear()
      MGCOLOUR().load_default()
      MGCOLOUR().initialiseRGBReps()
      MGCOLOUR().usingOldColours = False

  def removeDataObj(self,name=''):
    #print 'MGDisplayTable.removeDataObj',name

    group_list = []
    if name == 'all':
      dataobj_list = self.findChildren(GDataObj)
    else:
      dataobj_list = []
      dataobj = self.findChild(GDataObj,name)
      if dataobj:  dataobj_list.append(dataobj)
    for dataobj in dataobj_list:
      if self.movingObjects.count(dataobj): self.movingObjects.remove(dataobj)
    for dataobj in dataobj_list:
      dispobjs = self.findChildren(GDispObj)
      for dispobj in dispobjs:
        if hasattr(dispobj,"statusWidget"):
          if dispobj in self.movingObjects:
            self.movingObjects.remove(dispobj)
      group = dataobj.parentWidget()
      if not group_list.count(group): group_list.append(group)
      dataobj.delete()
      #dataobj.setParent(None)
      dataobj.setParent(theDummy)
      #del dataobj
      if dataobj and hasattr(dataobj,"close"):
        dataobj.close()
    for group in group_list:
      group.setDataObjGeometry()
    self.emitSignal('removeDataObj')

  def addDispObj(self,parent_name='',object_type='',name='',resize=1):
    dataobj = self.findChild(GDataObj,parent_name)
    #print "Table.addDispObj dataobj",dataobj,parent_name
    if not dataobj:
      parent_type = MGDisplayTable.dispobj_make_parent.get(object_type,'')
      #print "Table.addDispObj calling addDataObj",parent_type
      if parent_type:
        print name, parent_type
        if parent_type == 'GL2dScreen':
          dataobj = self.addDataObj(object_type=parent_type,getDispObj=0,name='Legends&Images')
        elif parent_type == 'CrystalData':
          dataobj = self.addDataObj(object_type=parent_type,getDispObj=0,name='CrystalData')
        else:
          dataobj = self.addDataObj(object_type=parent_type,getDispObj=0)
        #print "addDispObj creating DataObj",parent_type,dataobj
      else:
        return
    obj = dataobj.addGDispObj(object_type=object_type,name=name,resize=resize)
    self.emitSignal('addDispobj')
    return obj

  def removeDispObj(self,name='',resize=1):
    dispobj = self.findChild(GDispObj,name)
    #print 'removeDispObj',name,dispobj
    if not dispobj: return
    if hasattr(dispobj,"statusWidget"):
      if dispobj in self.movingObjects:
        self.movingObjects.remove(dispobj)
    dataobj = dispobj.parent().parent()
    #dispobj.setParent(None)
    dispobj.setParent(theDummy)
    #dispobj.close()
    dispobj.delete()
    #del dispobj
    dispobj.close()
    if resize: dataobj.setBodyGeometry()
    self.emitSignal('removeDispobj')

  def deleteDispObj(self,name=''):
    import types
    if isinstance(name,types.ListType):
      namelist = name
    else:
      namelist = [name]
    for name in namelist:
      self.removeDispObj(name)
      target = get_dispobj(name=name)
      print "deleteDispObj",name,target
      if target:
        target.delete()
        #print target
        #del target
    rebuild.UpdateDisplay()

  def fontSize(self):
    font = self.font()
    #print "font",font
    fm = QtGui.QFontMetricsF(font)
    #print 'font',fm.width('W'),fm.height()
    return max(int(fm.height()),32)

  
  def sizeHint(self):
    nr = 0
    for dobjs in  self.findChildren(GDataObjs):
      for datobj in dobjs.findChildren(GDataObj):
        nr = nr+1
        if datobj.isOpen():
          nr = nr +  len(datobj.body.findChildren(GDispObj))
    w = self.getWidth()
    h = nr*MGDisplayTable.rowHeight
    return QtCore.QSize(w,h)

  def minimumSizeHint(self):
    #print "in minimumSizeHint"
    return self.sizeHint()


  def setDataObjsGeometry(self):
    nrTot = 0
    width = self.getWidth()
    height=MGDisplayTable.rowHeight

    #print "setDataObjsGeometry",self.GDataObjs
    # Draw different object types in a fixed order
    for object_type in MGDisplayTable.fixed_order:
      if self.GDataObjs.has_key(object_type):
        nr = self.GDataObjs[object_type].nRows
        self.GDataObjs[object_type].setGeometry(0,nrTot*height,width,nr*height)
        nrTot = nrTot +nr
    # Are there any object_types not in the fixed_order list
    for object_type in self.GDataObjs.keys():
      if not MGDisplayTable.fixed_order.count(object_type):
        nr = self.GDataObjs[object_type].nRows
        self.GDataObjs[object_type].setGeometry(0,nrTot*height,width,nr*height)
        nrTot = nrTot +nr

    # resize window
    required_height = height*nrTot
    self.setFixedHeight(required_height)
    current_height = self.parent().height()
    new_height = -1
    if current_height<min(required_height,300):
      new_height =min(required_height,300)
    elif current_height>required_height:
      new_height = required_height

    return
    if new_height>0:
      self.window().resize(QtCore.QSize(self.window().size().width(),new_height+20))

  def update(self,all=0):

    self.block_emit = 1
    if not all:
      #print "MGDisplayTable.update",HISTORY().update_gui

      for item in HISTORY().update_gui:

        if item[0] == 'update_DataObj':
          widget = self.getDataObj(name=item[1])
          #print "MGDisplayTable.update",item[1],widget
          if widget: widget.update()
        elif  item[0] == 'add_DataObj':
          obj = get_dataobj(name=item[1])
          if obj:
            obj = obj[0]
            self.addDataObj(object_type=obj.object_type,name=obj.name)
        elif  item[0] == 'delete_DataObj':
          self.removeDataObj(name=item[1])
    else:
      # Alternative sledgehammer update of display table..
      self.removeDataObj('all')
      self.loadAllDataObj()
    self.block_emit = 0
    if not all: self.emitSignal('update')
    

  def updateDataObjLabels(self):
    for obj in self.findChildren(GDataObj):
      obj.updateLabel()
    self.emit(QtCore.SIGNAL('update_labels'))

  def setMovingObject(self,object='',unset=1):

    if self.movingObjects.count(object):
      if unset: self.movingObjects.remove(object)
    else:
      # For now allow only one moving object - unset any
      # current selection
      for obj in self.movingObjects:
        obj.toggleMoving()
      self.movingObjects = []
      
      self.movingObjects.append(object)

    self.movingTargets = []
    for obj in self.movingObjects:
      name = obj.objectName()
      if isinstance(obj,GDataObj):
        self.movingTargets.append(get_dataobj(name=name)[0])
      else:
        self.movingTargets.append(get_dispobj(name=name))
    #print "setMovingObject",self.movingTargets

  def handleObjectMoving(self,glwidget):
    #print "MGDisplayTable.handleObjectMoving",self.movingTargets,args
    for obj in self.movingTargets:
      obj.transform(glwidget)
    for obj in  self.movingObjects:
      obj.updateAfterMoving()

    import rebuild
    rebuild.UpdateDisplay()
    MAINWINDOW().updateGLWindows()
    
  def Exit(self):
    for obj in self.findChildren(GDataObj):
      obj.Exit()

class GDataObjs(QtGui.QWidget):

  def __init__(self,parent=None,object_type=''):
    super(GDataObjs,self).__init__(parent)
    self.object_type = object_type
    self.nRows = 0

  def addGDataObj(self,table=None,name='',label=''):
    #print "GDataObjs.addGDataObj",self.object_type,name,label
    obj = None
    if MGDisplayTable.dataobj_types.has_key( self.object_type ):
      obj = MGDisplayTable.dataobj_types[self.object_type](self,table=table,name=name,label=label)
    self.setDataObjGeometry()
    return obj

  def setDataObjGeometry(self):
    self.show()
    nrTot = 0
    height = MGDisplayTable.rowHeight
    width = self.parent().getWidth()
    for datobj in self.findChildren(GDataObj):
      if datobj.isVisible():
        if datobj.isOpen():
          nr = 1 +  len(datobj.body.findChildren(GDispObj))
        else:
          nr = 1
        datobj.setGeometry(0, nrTot*height,width,nr*height)
        nrTot = nrTot + nr
    self.nRows = nrTot
    self.parentWidget().setDataObjsGeometry()
      
    
class GDataObj(QtGui.QWidget):
  
  def updateMenu(self,name='icon'):
    if name == 'icon':
      guiUtils.clearMenu(self.iconMenu)
      defn = self.getGuiDef(name='icon')
      #print 'GDataObj.updateMenu',defn
      if defn:
        guiUtils.populateMenu(self,self.iconMenu,defn,self.getActionDef,default_icon='')
        

  def toggleBodyVisibility(self,updateWidth=1):
    #Toggle the open/closed state of subframe if apt
    #print "in toggleBodyVisibility",self
    visible = 1 - self.open
    if visible:
      self.treeWidget.resetIcon('toc-minus')
    else:
      self.treeWidget.resetIcon('toc-plus')
    self.body.setVisible(visible)
    self.open = visible
    get_dataobj(name=self.objectName())[0].set_expanded(expanded=self.open)
    #self.resize(self.sizeHint())
    self.parentWidget().setDataObjGeometry()
    if updateWidth: MAINWINDOW().wMGDisplayTable.updateWidth()

  def toggleMoving(self,mode=-1):

    if mode <0:
      # This is probably from gui - just toggle the moving status
      if self.status == 1:
        self.setStatus(moving =0)
      else:
        self.setStatus(moving =1)
      self.table.setMovingObject(self,unset=1)
    else:
      # This is probably from table.setMovingObject
      self.setStatus(moving = mode)
      if mode == 0:
        self.table.setMovingObject(self,unset=1)
      else:
        self.table.setMovingObject(self,unset=0)

  def updateAfterMoving(self):
    pass
  
  def __init__(self,parent=None,table=None,name='',label='',autoClose=0):
    #print "GDataObj label",label
    #print "GDataObj name",name
    self.open = 1
    self.autoClose = autoClose
    # status:: 0=not active, 1 = moving
    self.status = 0

    self.table=table
    #super(GDataObj,self).__init__(parent,QtCore.Qt.WA_DeleteOnClose)
    super(GDataObj,self).__init__(parent)
    self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
    #print 'GDataObj.init',self,name
    self.setObjectName(name)
    # set up title and body containers
    height = MGDisplayTable.rowHeight
    self.title = QtGui.QWidget(self)
    self.body =  QtGui.QWidget(self)
    self.title.setGeometry(0,0,self.table.getWidth(),height)
    self.body.setGeometry(0,height,self.table.getWidth(),0)
    
    self.statusWidget = GTreeFeature(self,'blank')
    self.treeWidget = GTreeFeature(self,'toc-minus')
    self.connect(self.treeWidget,QtCore.SIGNAL('contextMenu'),self.drawTreeMenu)
    #print "GDataObj treeWidget",self,self.treeWidget
    self.connect(self.treeWidget,QtCore.SIGNAL('mouseRelease'),self.toggleBodyVisibility)
    object_type = self.parentWidget().object_type
    # use QToolButton sub-class to get a right-mouse signal
    target = data(name)
    if target:
      vis = target.get_visibility()
    else:
      vis = 0
    if target:
      expanded = target.get_expanded()
    else:
      expanded = 0
    if expanded == 0:
      self.toggleBodyVisibility(updateWidth=0)
    self.iconButton = mgIconButton(self,icon=table.getIcon(object_type,visible=vis))
    self.iconMenu = QtGui.QMenu(self)
    self.iconButton.setMenu(self.iconMenu)

    self.connect(self.iconMenu,QtCore.SIGNAL("aboutToShow()"),guiUtils.partial(self.updateMenu,'icon'))
    self.connect(self.iconButton,QtCore.SIGNAL("rightMouseRelease"),self.handleButtonClick)
    lab =  QtGui.QLabel(self)
    lab.setObjectName('label')
    self.updateLabel()
    self.statusWidget.setGeometry(0,0,height,height)
    self.treeWidget.setGeometry(self.table.status_open*height,0,height,height)
    self.iconButton.setGeometry((1+self.table.status_open)*height,0,height,height)
    lab.setGeometry(((2+self.table.status_open)*height)+2,0,10*height,height)

    #Layout the body
    self.body.setVisible(1)

    # Need to create the visible QAction before possiblity of
    # call to handleButtonClick which might find the DispObj QAction
    vis = guiUtils.createAction('data_visible',self)


  def Exit(self):
    pass
  
  def delete(self):
    children = self.findChildren(GDispObj)
    #print 'GDataObj.delete GDispObj children',children
    for cc in children:
      cc.delete()
    children = self.findChildren(QtGui.QDialog)
    #print 'GDataObj.delete MGSimpleDialog children',children
    for cc in children:
      cc.close()
      

  def updateLabel(self,text=''):
    lab = self.findChild( QtGui.QLabel,'label')
    if lab:
      if text:
        lab.setText(text)
      else:
        target = get_dataobj(name=self.objectName())
        if len(target)>0 and target[0] and hasattr(target[0],"molHnd"):
           if hasattr(target[0].molHnd,"StructureTitle") and callable(target[0].molHnd.StructureTitle):
              toolTip = str(target[0].molHnd.StructureTitle())[:150]
              if hasattr(target[0].molHnd,"Source") and callable(target[0].molHnd.Source):
                source = target[0].molHnd.Source()
                if 'ORGANISM_SCIENTIFIC:' in source:
                   organism = source[source.find('ORGANISM_SCIENTIFIC:')+len('ORGANISM_SCIENTIFIC:'):].split(';')[0].strip()[:150]
                   toolTip = toolTip + ' ('+organism+')'
              lab.setToolTip(toolTip)
        #print 'GDispObj.updateLabel',target[0].get_label()
        if target:
          lab.setText(target[0].get_label())

  def setStatus(self,moving=-1):
    # status probably ought to be a bitmap to accomodate multiple
    # moving/selected/highlighted flags.
    icons = ['blank','moving']
    toolTips = [ self.tr('This object is not active'), self.tr('Move this object holding down x key and left/middle mouse')]
    update = 0
    if moving>=0:
      if self.status != moving:
        update = 1
        self.status = moving

    if update:      
      self.statusWidget.resetIcon(icons[self.status])
      # bummer -labels probably cant have tool tips
      self.statusWidget.setToolTip(toolTips[self.status])
 
  def handleButtonClick(self,**args):
    # Right mouse click is shortcut for toggling visiblity
    # toggle the 'visible' QAction and call set_visibility
    vis = self.findChild(QtGui.QAction,'data_visible')
    if  vis:  vis.trigger()
    
  def isOpen(self):
    return self.open

  def drawTreeMenu(self,x,y):
    import guiUtils
    #print 'GDataObj.drawTreeMenu',x,y
    if not hasattr(self,'treeMenu'):
      self.treeMenu = QtGui.QMenu(self)
    else:
      guiUtils.clearMenu(self.treeMenu)

    if self.isOpen():   
      action = self.treeMenu.addAction(self.tr('Hide display objects'))
      action.setToolTip(self.tr('Do not show display object in the display table'))
      self.connect(action,QtCore.SIGNAL('triggered()'),guiUtils.partial(self.handleTreeMenu,'close'))
    else:
      action = self.treeMenu.addAction(self.tr('Show display objects'))
      action.setToolTip(self.tr('Show display object in the display table'))
      self.connect(action,QtCore.SIGNAL('triggered()'),guiUtils.partial(self.handleTreeMenu,'open'))
      
    action = self.treeMenu.addAction(self.tr('Show for this data only'))
    action.setToolTip(self.tr('Show display object for only this data in the display table'))
    self.connect(action,QtCore.SIGNAL('triggered()'),guiUtils.partial(self.handleTreeMenu,'open_this'))
    action = self.treeMenu.addAction(self.tr('Show all display objects'))
    action.setToolTip(self.tr('Show all display object in the display table'))
    self.connect(action,QtCore.SIGNAL('triggered()'),guiUtils.partial(self.handleTreeMenu,'open_all'))
    action = self.treeMenu.addAction(self.tr('Hide all display objects'))
    action.setToolTip(self.tr('Hide all display object in the display table'))
    self.connect(action,QtCore.SIGNAL('triggered()'),guiUtils.partial(self.handleTreeMenu,'close_all'))

    self.treeMenu.popup(QtCore.QPoint(x,y))

  def handleTreeMenu(self,mode=''):
    #print 'GDataObj.handleTreeMenu',mode
    if mode == 'open':
      if not self.isOpen(): self.toggleBodyVisibility()
    elif mode == 'close':
      if self.isOpen(): self.toggleBodyVisibility()
    elif mode == 'open_this':
      if not self.isOpen(): self.toggleBodyVisibility(updateWidth=0)
      for obj in self.table.findChildren(GDataObj):
        if obj != self and obj.isOpen(): obj.toggleBodyVisibility(updateWidth=0)
      #self.window().updateWidth()
    elif mode == 'open_all':
      for obj in self.table.findChildren(GDataObj):
        if not obj.isOpen(): obj.toggleBodyVisibility(updateWidth=0)
      #self.window().updateWidth()
    elif mode == 'close_all':
      for obj in self.table.findChildren(GDataObj):
        if obj.isOpen(): obj.toggleBodyVisibility(updateWidth=0)
      #self.window().updateWidth()
    
      
  def addGDispObj(self,object_type='',name='',resize=1):
    if MGDisplayTable.dispobj_types.has_key(object_type):
      obj = MGDisplayTable.dispobj_types[object_type](self,table=self.table,name=name)
      if resize: self.setBodyGeometry()
      return obj
    else:
      print 'Do not know how to make display table display object',object_type
      return None

  def cleanupGDispObj(self):
    disp_list = self.body.findChildren(GDispObj)
    for obj in disp_list:
      if hasattr(obj,'for_delete'):
        obj.close()
    #del  disp_list      
    self.setBodyGeometry()

  def setBodyGeometry(self):
    #if not self.isOpen(): return
    if self.autoClose and len(self.body.findChildren(GDispObj))==0:
      self.hide()
    else:
      height = MGDisplayTable.rowHeight
      width = self.table.getWidth()
      disp_list = self.body.findChildren(GDispObj)
      #print "setBodyGeometry",self,len(disp_list)
      nr = 0
      for obj in disp_list[0:-1]:
        obj.setGeometry(0,nr*height,width,height)
        obj.treeWidget.resetIcon('tjunc')
        nr = nr + 1
      if disp_list:
        disp_list[-1].setGeometry(0,nr*height,width,height)
        disp_list[-1].treeWidget.resetIcon('ljunc')
      self.body.setGeometry(0,height,width,len(disp_list)*height)

      #print "setBodyGeometry final nr",self,nr
      self.show()
    self.parentWidget().setDataObjGeometry()
    

#--------------------------------------------------------------        
  def add_dispobj(self,args=[],target=None,object_type=''):
#--------------------------------------------------------------        
    #print "add_dispobj",object_type
    '''
    Create a display object for parent 'target'  and add
    display object to the display table
    '''
    if args:
      target = args[0]
      object_type = args[1]

    if not target: target = get_dataobj(name=self.objectName())
    dobj = target.add_object(object_type=object_type)
    #print "GDataObj.add_dispobj dobj",dobj,object_type
    if dobj: 
      ndispobj = len(self.findChildren(GDispObj))
      created_obj = self.table.addDispObj(parent_name=target.name,
                     object_type=object_type,name=dobj.name)

      rebuild.UpdateDisplay()

      # If this is first display object recentre
      if ndispobj == 0:
        MAINWINDOW().handleRecentre()

      return created_obj


#-------------------------------------------------------------
  def del_dispobj(self,name=''):
#-------------------------------------------------------------
    target = get_dispobj(name=name)
    if target: target.delete()
    self.table.removeDispObj(name)

#-------------------------------------------------------------
  def updateDispObj(self):
#-------------------------------------------------------------
    for dispobj in self.body.children():
      self.table.removeDispObj(dispobj.objectName(),resize=0)
    # Update the display objects of dataobj name
    name = self.objectName()
    dataobj = get_dataobj(name=name)
    if dataobj:
      #print "updateDispObj objinsts",dataobj[0].objinsts
      for dispobj in dataobj[0].objinsts:
      #print "addDataObj dispobj",dispobj,dispobj.name,dispobj.object_type
        self.table.addDispObj(parent_name=name,name=dispobj.name,object_type=dispobj.object_type,resize=0)
    self.table.getDataObj(name).setBodyGeometry()
   
        
#---------------------------------------------------------------------
  def set_visibility(self,visible=-1,redraw=1):
#---------------------------------------------------------------------
    object_type = self.parentWidget().object_type
    if visible<0: visible = int(self.findChild(QtGui.QAction,'data_visible').isChecked())
    #print "GDispObj.set_visibility",visible,object_type

    self.iconButton.setIcon(self.table.getIcon(object_type,visible=visible))
    get_dataobj(name=self.objectName())[0].set_visibility(visibility=visible)
    DISPLAYTABLE().emit(QtCore.SIGNAL('visibilityChanged'))

    if redraw:  rebuild.UpdateDisplay()


#---------------------------------------------------------------------
  def getGuiDef(self,name='',**info):
#---------------------------------------------------------------------
    #print "GDataObj.getGuiDef name",name
    if name == 'context':
      return []
    else:
      return []
    
#---------------------------------------------------------------------
  def getActionDef(self,name,target=None,**info):
#---------------------------------------------------------------------

    #print "GDataObj getActionDef",name,target

    
    if name == 'data_visible':
      
      return dict (
      text = self.tr("Visible"),
      tip = self.tr('Toggle all of this data object visible or invisible'),
      slot = self.set_visibility,
      checkable = 1,
      checked = target.get_visibility
      )
    
    elif name == 'move':
      return dict (
      text = self.tr("Move ")+self.objectName(),
      tip = self.tr('Move this data object with the mouse'),
      slot = self.toggleMoving,
      checkable = 1,
      checked = self.isMoving,
      deleteLater = 0
      )

    elif name == 'data_delete':
      return dict (
      text = self.tr("Delete"),
      tip = self.tr('Delete this data object'),
      slot = guiUtils.partial(self.table.deleteDataObj,self.objectName()) )

    elif name == 'data_list_data':
      return dict (text = self.tr('List data'),
                   tip = self.tr('List data file in file viewer'),
                   slot = self.listData
                   )
    
    elif name == 'data_clone':
      return dict (text = self.tr('Clone'),
                   tip = self.tr('Load the data object again with one display object'),
                   slot = self.clone )

    elif name == 'data_clone_dispobj':
      return dict (text = self.tr('Clone all display'),
                   tip = self.tr('Load the data object again with the same display objects'),
                   slot = guiUtils.partial(self.clone,1) )
    else:
      return {}


#-------------------------------------------------------------
  def isMoving(self):
#-------------------------------------------------------------
    return self.status == 1
    
#-------------------------------------------------------------
  def update(self):
#-------------------------------------------------------------
    target = get_dataobj(name=self.objectName())
    if not target: return
    target = target[0]
    #print "DataObj.update",self,target.update_gui
    for item in target.update_gui:
      #print "item",item
      if item[0] == 'visible':
        object_type = self.parentWidget().object_type
        self.iconButton.setIcon(self.table.getIcon(object_type,visible=target.visible))
      elif item[0] == 'add':
        obj = get_dispobj(name=item[1])
        if obj:
          self.table.addDispObj(parent_name=self.objectName(),object_type=obj.object_type,name=item[1])
      elif item[0] == 'delete':
        self.table.removeDispObj(item[1])
      elif item[0] == 'update_DispObj':
        self.findChild(GDispObj,item[1]).update()
      elif item[0] == 'update':
        import types    
        for widget in self.findChildren(QtGui.QAction):
          if widget.parent() == self:
            name = widget.objectName()
            if not ['visible'].count(name):
              defn = self.getActionDef(name)
              if defn.has_key('checked'):
                #print "DataObj.update action",name
                if isinstance(defn['checked'],types.IntType):
                  widget.setChecked(int(defn['checked']))
                else:
                  try:
                    widget.setChecked(defn['checked']())
                  except:
                    pass
              if defn.has_key('enabled'):
                if isinstance(defn['enabled'],types.IntType):         
                  widget.setEnabled(defn['enabled'])
                else:
                  try: 
                    widget.setEnabled(defn['enabled']())
                  except:
                    pass
                    
        
    target.update_gui=[]

  def listData(self):
    target = data(self.objectName())
    if target:
      text = target.list_data()
      if text:
        viewer = FILEVIEWER('data_listing')
        window = viewer.loadText(text,target.filename[2])

  def pickInfo(self,event,text=''):

    pos = event.getPickPosition()
    pos_text = "%8.2f %8.2f %8.2f" % (pos[0],pos[1],pos[2])

    out = self.tr('Picked ')+event.getLabel(format='full')+'\n' + \
           self.tr('Position: ')+pos_text +'\n' + \
           self.tr('Display object: ')+ event.getDispObj().name+ '\n' + \
           self.tr('Data object: ') + event.getDataObj().name_label + '\n' + \
           self.tr('Data file: ') + event.getDataObj().filename[2]  + '\n\n' + \
           text + '\n'
           
    # Want a non-modal message box
    box = QtGui.QMessageBox(self)
    box.setWindowTitle('Info '+event.getLabel())
    box.setText(out)
    box.setWindowModality(QtCore.Qt.NonModal)
    box.show()
    

#-------------------------------------------------------------
  def clone(self,withDispobj=0,name=""):
#-------------------------------------------------------------
    #print 'GDataObj.clone',withDispobj
    target = get_dataobj(name=self.objectName())
    if not target: return
    target = target[0]
    new_data = target.clone(withDispobj=withDispobj,name=name)
    if not new_data: return
    #print 'GDataObj.clone',target,new_data,new_data.object_type,new_data.name

    # Create copy of DispObj
    if withDispobj:
      # Make copies of the display objects
      for disp in target.objinsts:
        new_disp = new_data.add_object(object_type=disp.object_type,visible=disp.visible,
            params=disp.params(),selparams=disp.selparams(),
            colparams=disp.colparams(),styleparams=disp.styleparams())
    else:
      # Create one default display object
      new_data.add_object()

    self.table.addDataObj(object_type=new_data.object_type,name=new_data.name,
                   label=getattr(new_data,'name_label',''),getDispObj=1)
    #print 'GDataObj.clone done table.addDataObj'
   
#-------------------------------------------------------------
#-------------------------------------------------------------
#-------------------------------------------------------------
class GDispObj(QtGui.QWidget):
#-------------------------------------------------------------
#-------------------------------------------------------------
#-------------------------------------------------------------

  
  def __init__(self,parent,table=None,name='',object_type=''):
    #print "GDispObj name",name,self,parent
    self.table=table
    self.status = 0
    super(GDispObj,self).__init__(parent.body)
    self.setObjectName(name)
    self.object_type = object_type
    # type_label is a word explaining the object type ot be used in gui
    self.type_label = ''
    # Draw the 'tree' lines and icon
    w = MGDisplayTable.rowHeight
    self.statusWidget = GTreeFeature(self,'blank')
    self.statusWidget.setGeometry(0,0,w,w)
    self.treeWidget =  GTreeFeature(self,'tjunc')
    self.treeWidget.setGeometry((1+self.table.status_open)*w,0,w,w)
    target = get_dispobj(name=name)
    if not target or target == '':
      visible = 1
    else:
      visible = target.get_visibility()
    self.iconButton =  mgIconButton(self,icon=table.getIcon(object_type,visible=visible))
    self.iconButton.setGeometry((2+self.table.status_open)*w,0,w,w)

    self.iconMenu = guiUtils.mgMenu(self)
    self.iconButton.setMenu(self.iconMenu)
    self.connect(self.iconMenu,QtCore.SIGNAL("aboutToShow()"),guiUtils.partial(self.updateMenu,'icon'))
    self.connect(self.iconButton,QtCore.SIGNAL("rightMouseRelease"),self.handleButtonClick)
    self.widgets = dict (icon = self.iconButton)   
         
    bw = MGDisplayTable.bodyWidth
    i = 0
    x = (3+self.table.status_open)*w
    format_list = self.getGuiDef()
    nslider = 0
    if bw < 6:
      for format in format_list:
        mode = format.get('mode')
        if str(mode) == "VALUESLIDER":
          nslider = nslider + 1
    if format_list:
      widthFactor = float(bw)/(len(format_list)+nslider)
    else:
      widthFactor = bw
    offset = 0
    for format in format_list:
      i = i + 1
      name = format.get('name')
      #print "format",name,format

      if format['mode'] == 'MENU':
        self.widgets[name] =  QtGui.QToolButton(self)
        self.widgets[name].setPopupMode(QtGui.QToolButton.InstantPopup)
        #self.widgets[name].setPopupMode(QtGui.QToolButton.MenuButtonPopup)
        menu = guiUtils.mgMenu(self)
        self.widgets[name].setMenu(menu)
        self.connect(menu,QtCore.SIGNAL("aboutToShow()"),guiUtils.partial(self.updateMenu,name))
      elif format['mode'] == 'VALUESLIDER':
        import mgWidgets
        minimum = 0
        maximum = 999
        if format.has_key('range'):
           minimum = format['range'][0]
           maximum = format['range'][1]
        self.widgets[name] =  mgWidgets.mgSlider(QtCore.Qt.Horizontal,self)
        self.widgets[name].setRange(format.get('minimum',minimum),format.get('maximum',maximum))
        #self.widgets[name+'_docked_'] =  QtGui.QDoubleSpinBox(self)
        self.widgets[name+'_docked_'] =  mgWidgets.DropDownSliderWithValue(QtCore.Qt.Horizontal,self)
        self.widgets[name+'_docked_'].setRange(format.get('minimum',minimum),format.get('maximum',maximum))
        if bw < 6:
          self.widgets[name+'_docked_'].setGeometry(x,0,int(widthFactor*w*2),w)
          offset = offset + int(widthFactor*w)
        else:
          self.widgets[name+'_docked_'].setGeometry(x,0,int(widthFactor*w),w)
        if self.table and self.table.docked:
          self.widgets[name+'_docked_'].show()
          self.widgets[name].hide()
        else:
          self.widgets[name+'_docked_'].hide()
          self.widgets[name].show()
        if format.get('callback',''):
          self.connect(self.widgets[name],QtCore.SIGNAL("valueChanged(double)"),format['callback'])
          self.connect(self.widgets[name+'_docked_'],QtCore.SIGNAL("valueChanged(double)"),format['callback'])
          self.connect(self.widgets[name],QtCore.SIGNAL("valueChanged(double)"),functools.partial(self.updateAlternative,self.widgets[name+'_docked_'],self.widgets[name]))
          self.connect(self.widgets[name+'_docked_'],QtCore.SIGNAL("valueChanged(double)"),functools.partial(self.updateAlternative,self.widgets[name],self.widgets[name+'_docked_']))
      elif format['mode'] == 'SLIDER':
        self.widgets[name] =  QtGui.QSlider(QtCore.Qt.Horizontal,self)
        self.widgets[name].setRange(format.get('minimum',0),format.get('maximum',999))
        if format.get('callback',''):
          self.connect(self.widgets[name],QtCore.SIGNAL("valueChanged(int)"),format['callback'])
      elif format['mode'] == 'PUSHBUTTON':
        #print "PUSHBUTTON label", self.format[name]['label']
        self.widgets[name] =  QtGui.QToolButton(self)
        if format.get('callback',''):
          self.connect(self.widgets[name],QtCore.SIGNAL("released()"),format['callback'])
      self.updateLabel(name)

      self.widgets[name].setGeometry(x,0,int(widthFactor*w),w)
      x = x + int(widthFactor*w) + offset
      toolTip = format.get('toolTip','')
      if toolTip: self.widgets[name].setToolTip(toolTip)
    self.show()

  def updateAlternative(self,toChange,changed):
      val = changed.value()
      toChange.blockSignals(True)
      toChange.setValue(val)
      toChange.blockSignals(False)

  def delete(self):
    children = self.findChildren(QtGui.QDialog)
    #print 'GDataObj.delete MGSimpleDialog children',children
    for cc in children:
      cc.close()

  def toggleMoving(self,mode=-1):

    if mode <0:
      # This is probably from gui - just toggle the moving status
      if self.status == 1:
        self.setStatus(moving =0)
      else:
        self.setStatus(moving =1)
    else:
      # This is probably from table.setMovingObject
      self.setStatus(moving = mode)
    self.table.setMovingObject(self,unset=1)
      
  def updateAfterMoving(self):
    pass

  def setStatus(self,moving=-1):
    icons = ['blank','moving']
    update = 0
    if moving>=0:
      if self.status != moving:
        update = 1
        self.status = moving

    if update:      
      self.statusWidget.resetIcon(icons[self.status])
 

#-------------------------------------------------------------
  def handleButtonClick(self,**args):
#-------------------------------------------------------------
    # Right mouse click is shortcut for toggling visiblity
    # toggle the 'visible' QAction and call set_visibility
    vis = self.findChild(QtGui.QAction,'visible')
    if not vis:
      # Need to create the QAction
      vis = guiUtils.createAction('visible',self)
    vis.trigger()

    

#-------------------------------------------------------------
  def updateMenu(self,menuName=''):
#-------------------------------------------------------------
    guiUtils.clearMenu( self.widgets[menuName].menu())
    guiUtils.populateMenu(self,self.widgets[menuName].menu(),self.getGuiDef(menuName),default_icon='')


#-------------------------------------------------------------------
  def colour_browser(self):
#-------------------------------------------------------------------
    target = get_dispobj(name=self.objectName())
    selected_colour=target.get_colour_label()
    if not hasattr(self,'colour_browser_gui'):
      import mgWidgets
      self.colour_browser_gui = mgWidgets.mgColourBrowser(MAINWINDOW(),selected_colour=selected_colour)
      self.connect(self.colour_browser_gui,QtCore.SIGNAL("ColourSelected"),self.set_browser_colour)
    self.colour_browser_gui.show()
    self.colour_browser_gui.raise_()

#----------------------------------------------------------------------
  def  set_browser_colour(self,colour=''):
#----------------------------------------------------------------------
    #print "ColourSelected set_browser_colour",colour
    if colour:
      target = get_dispobj(name=self.objectName())
      target.set_colour(colour)
      self.updateLabel('colour')
      rebuild.UpdateDisplay()

#----------------------------------------------------------------------
  def getGuiDef(self,name='',**info):
#----------------------------------------------------------------------
    return []

#--------------------------------------------------------------------
  def getActionDef(self,name='',target=None,**info):
#--------------------------------------------------------------------
    '''
    Generic action definitions for GDispObj
    '''

    #print "DispObj.getActionDef",target
  
    if name == 'visible':
      if hasattr(target,'visible'):
        return dict (
        text = self.tr("Visible"),
        tip = self.tr('Toggle this display object visible/invisible'),
        slot = self.set_visibility,
        checkable = 1,
        checked = target.get_visibility,
        deleteLater = 0
        )

    elif name[0:len('apply_biomolecule')] == 'apply_biomolecule':
      def c(): return int(target.doBiomolecule == True)
      return dict ( text = "Show biomolecule",
                    slot = guiUtils.partial(target.toggleBiomolecule),
                    checkable = 1,
                    checked = c
                    )

    elif name[0:len('apply_symmetry')] == 'apply_symmetry':
      def c(): return int(target.doSymmetry == True)
      return dict ( text = "Apply symmetry",
                    slot = guiUtils.partial(target.toggleSymmetryStatus),
                    checkable = 1,
                    checked = c
                    )

    elif name[0:len('draw_central')] == 'draw_central':
      def c(): return int(target.doCentralSymmetry == True)
      return dict ( text = "Draw central copy",
                    slot = guiUtils.partial(target.toggleCentralSymmetryStatus),
                    checkable = 1,
                    checked = c
                    )

    elif name == 'flash':
        def c(): return target.isFlashing()
        return dict (
        text = self.tr("Flash"),
        tip = self.tr('Start or stop this display object flashing'),
        slot = target.set_flashing,
        checkable = 1,
        checked = c,
        deleteLater = 0
        )

    elif name == 'transparency':
        def c(): return int(target.opacity<=0.99)
        return dict (
        text = self.tr("Set transparency"),
        tip = self.tr('Set the transparency level for this object'),
        slot = self.openTransparencyGui,
        checkable = 1,
        checked = c,
        deleteLater = 0
        )
   
            
    elif name == 'delete':
        return dict (
        text = self.tr("Delete"),
        tip = self.tr('Delete this display object'),
        slot = guiUtils.partial(self.table.deleteDispObj,self.objectName() )
      )
 
    elif name == 'clone':
      return dict (
        text = self.tr("Clone"),
        tip = self.tr('Make a new display object the same as this one'),
        slot = self.clone,
        enabled = 1)
    
    elif name == 'help':

      return dict (
        text = self.tr("Help"),
        enabled = 0)

    elif name == 'custom_drawing_style':
      def c(): return hasattr(target,'drawingStylePM')
      return dict ( text = self.tr('Custom drawing style'),
                    slot = self.displayStyleGui,
                    checkable = 1,
                    checked = c,
                    toolTip = self.tr('Customise display style of this object')
                      )

    elif name == 'list_data':
      return dict ( text =  self.tr('List data'),
                    toolTip =  self.tr('List or write to file'),
                    slot = self.listData
                    )


    return {}

#---------------------------------------------------------------------
  def set_visibility(self,visible=-1):
#---------------------------------------------------------------------
    # Not sure why the following line does not work..
    #if visible<0: visible = int(self.findChild(QtGui.QAction,'visible').isChecked())
    target = get_dispobj(name=self.objectName())
    if visible<0: visible = 1 - target.get_visibility()
    #print "GDispObj set_visibility",visible

    self.iconButton.setIcon(self.table.getIcon(self.object_type,visible=visible))
    get_dispobj(name=self.objectName()).set_visibility(visibility=visible)  
    #print "Emit visibilityChanged! dispobj"
    DISPLAYTABLE().emit(QtCore.SIGNAL('visibilityChanged'))
    rebuild.UpdateDisplay()


#-------------------------------------------------------------------
  def listData(self):
#-------------------------------------------------------------------
    target = get_dispobj(name=self.objectName())
    if not target: return
    text = target.list_data()
    viewer = FILEVIEWER('data_listing')
    if not viewer: return
    print 'GDispObj.listData',text
    window = viewer.loadText(text,title=self.type_label+' '+target.parent.name_label)
    window.setFont(style='fixed_width')


#-------------------------------------------------------------------
  def openTransparencyGui(self):
#-------------------------------------------------------------------
    if not hasattr(self,'transparencyGui'):
      import mgWidgets
      target = get_dispobj(name=self.objectName())
      self.transparencyGui = QtGui.QDialog(self)
      self.transparencyGui.setWindowTitle(self.objectName()+'transparency')
      layout = QtGui.QHBoxLayout()
      layout.addWidget(QtGui.QLabel('Opacity'))
      self.transpararencySlider = mgWidgets.mgSlider(QtCore.Qt.Horizontal,self)
      self.transpararencySlider.setImmediateMode(0)
      self.transpararencySlider.setRange(0.0,1.0)
      self.transpararencySlider.setSingleStep(0.02)
      self.transpararencySlider.setValue(target.opacity)
      self.transpararencySlider.slider.setTracking(1)
      layout.addWidget(self.transpararencySlider)
      self.transparencyGui.setLayout(layout)
      self.connect(self.transpararencySlider,QtCore.SIGNAL("valueChanged(double)"),self.setTransparency)

    self.transparencyGui.show()
    self.transparencyGui.raise_()
    
#-------------------------------------------------------------------
  def setTransparency(self,value):
#-------------------------------------------------------------------
    #print 'setTransparency',value
    if not hasattr(self,'transpararencySlider'): return
    get_dispobj(name=self.objectName()).set_opacity(value)
    rebuild.UpdateDisplay()
    
#-------------------------------------------------------------------
  def displayStyleGui(self):
#-------------------------------------------------------------------
    target = get_dispobj(name=self.objectName())
    pm = target.getDrawingStylePM(custom=1)
    #print "GDispObj.displayStyleGui",pm.name
    if not self.findChild(QtGui.QWidget,pm.name):
      import mgPreferences
      dialog = QtGui.QDialog(self)
      dialog.setAttribute(QtCore.Qt.WA_DeleteOnClose)
      dialog.setWindowTitle(pm.title)
      layout = QtGui.QVBoxLayout()
      scrollarea = QtGui.QScrollArea(self)
      layout.addWidget(scrollarea)
      # getDrawingStylePM will make a custom pm if one does not exist
      styleGui = mgPreferences.paramsManagerGui(dialog,pm=pm)
      styleGui.setObjectName(pm.name)
      scrollarea.setWidget(styleGui)
      scrollarea.setWidgetResizable(1) 
      scrollarea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
      buttons = mgPreferences.preferenceButtons(self)
      for item in ['apply','reset','help','close']:
        self.connect(buttons.findChild(QtGui.QWidget,item),QtCore.SIGNAL('released()'),guiUtils.partial(self.handleStyleGui,item))
      resetDefaults = QtGui.QPushButton("Reset to global")
      if sys.platform == "darwin":
         prefMenu = "QtMG"
      else:
         prefMenu = "Edit"
      resetDefaults.setToolTip(resetDefaults.tr("Remove custom preferences for this object\nand put back under control of global preferences.\ni.e. "+prefMenu+"->Preferences->Model display->Model drawing style"))
      self.connect(resetDefaults,QtCore.SIGNAL('clicked(bool)'),guiUtils.partial(self.handleStyleGui,"global"))
      buttons.layout().addWidget(resetDefaults)

      layout.addWidget(buttons)
      dialog.setLayout(layout)
      #if pm.apply_mode != 'on_request':
      #  self.connect(styleGui,QtCore.SIGNAL('changed'),guiUtils.partial(self.handleStyleGui,'apply'))

    
    styleGui.window().show()
    styleGui.window().raise_()

#-------------------------------------------------------------------
  def handleStyleGui(self,item=''):
#-------------------------------------------------------------------
    target = get_dispobj(name=self.objectName())
    pm = target.getDrawingStylePM()
    styleGui = self.findChild(QtGui.QWidget,pm.name)
    if item == 'apply':
      pm.setparams(styleGui.getParams())
      # NB pm.setparams should have done the redraw
      
    elif item == 'reset':
      styleGui.resetDefaults()
    elif item == 'help':
      styleGui.help()
    elif item == 'close':
      styleGui.window().close()
    elif item == 'global':
      globalPM = PM('model_drawing_style')
      styleGui.window().close()
      # Set custom params to be same as global and thus redraw
      oldpm = target.getDrawingStylePM()
      oldpm.setparams(globalPM.getparams())
      # Then remove the custom style
      target.removeCustomDrawingStyle()
      DISPLAYTABLE().emit(QtCore.SIGNAL("CustomDrawingStyleChanged"))
      
#-------------------------------------------------------------
  def updateLabel(self,widget):
#-------------------------------------------------------------
    import os
    row_defn = self.getGuiDef('row')
    icon=''
    useIcons = PM('advanced_options').getparams()['iconized_display_table']
    for defn in row_defn:
      if defn.get('name','') == widget:
        if useIcons and defn.has_key('getIcon'):
          icon = defn['getIcon']()
        if defn.has_key('getLabel'):
          text = defn['getLabel']()
        elif defn.has_key('getValue'):
          text = defn['getValue']()
        elif  defn.has_key('label'):
          text = defn['label']
        #print "DispObj.updateLabel",self,widget,text
        if ['SLIDER','VALUESLIDER'].count(defn['mode']):
          self.widgets[widget].setValue(text)
          if self.widgets.has_key(widget+'_docked_'):
             self.widgets[widget+'_docked_'].setValue(self.widgets[widget].value())
        else:
          if len(text)>MGDisplayTable.maxLabelLength:
            self.widgets[widget].setText(text[0:MGDisplayTable.maxLabelLength-2]+'..')       
          else:
            self.widgets[widget].setText(text)
          if widget == 'selection':
            self.widgets[widget].setToolTip("Select atoms to draw.<br><br>Currently: "+text)
          if widget == 'colour':
            self.widgets[widget].setToolTip("Select colour scheme.<br><br>Currently: "+text)
          if widget == 'style':
            self.widgets[widget].setToolTip("Select style.<br><br>Currently: "+text)
          if hasattr(self.widgets[widget],'setIcon'):
             if hasattr(self.widgets[widget],'setToolButtonStyle'):
               if DISPLAYTABLE().docked:
                  self.widgets[widget].setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
               else:
                  self.widgets[widget].setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
             import cprim
             if icon:
               if type(icon) == QtGui.QIcon:
                 theIcon = QtGui.QIcon(icon)
               elif os.path.exists(icon):
                 theIcon = QtGui.QIcon(icon)
               elif cprim.RGBReps().GetColourNumber(icon)>-1:
                 cols = cprim.RGBReps().GetColour(icon)
                 col = QtGui.QColor()
                 col.setRgbF(cols[0],cols[1],cols[2],1)
                 pixmap = QtGui.QPixmap(28,28)
                 pixmap.fill(col)
                 theIcon = QtGui.QIcon(pixmap)
               else:
                 theIcon = QtGui.QIcon()
               self.widgets[widget].setIcon(theIcon)
               self.widgets[widget].setIconSize(QtCore.QSize(28,28))
             else:
               theIcon = QtGui.QIcon()
               self.widgets[widget].setIcon(theIcon)
      
#-------------------------------------------------------------
  def update(self):
#-------------------------------------------------------------
    target = get_dispobj(name=self.objectName())
    #print "GDispObj.update actions",target.update_gui
    for item in target.update_gui:
      if item[0] == 'visible':
        self.iconButton.setIcon(self.table.getIcon(self.object_type,
            visible= target.visible))
      elif item[0] == 'update':
        row_def = self.getGuiDef('row')
        #print "DispObj.update",self,row_def
        for defn in row_def:
          self.updateLabel(defn['name'])

        for widget in self.findChildren(QtGui.QAction):
          name = widget.objectName()
          #print "action",name,self.getActionDef(name)
          if not ['visible'].count(name):
            defn = self.getActionDef(name)
            #print 'GDispObj.update defn',defn
            if defn.has_key('checked'):
              #print "DispObj.update action",name
              if callable(defn['checked']):
                widget.setChecked(defn['checked']())
              else:
                widget.setChecked(defn['checked'])
            if defn.has_key('enabled'):
              if callable(defn['enabled']):               
                widget.setEnabled(defn['enabled']())
              else:
                widget.setEnabled(defn['enabled'])
        
    target.update_gui =[]

#-------------------------------------------------------------
  def clone(self):
#-------------------------------------------------------------
    #print 'GDispObj.clone',self.objectName(),get_dispobj(name=self.objectName())
    target = get_dispobj(name=self.objectName())
    if not target: return

    # Create copy of DispObj
    params=copy.deepcopy(target.params())
    selparams=target.selparams()
    colparams=target.colparams()
    styleparams=target.styleparams()
    doDrawingStyle = False
    if params.has_key('drawing_style'):
      doDrawingStyle = True
      if sys.platform != 'win32':
        import uuid
        uuid._uuid_generate_time = None
        uuid._uuid_generate_random = None
        uuid_str = uuid.uuid4().get_hex()
      else:
        import msilib
        uuid_str = msilib.gen_uuid().strip('{').strip('}').replace('-','')

      pmold = PM(params['drawing_style'])
      name = params['drawing_style'] + uuid_str
      params.pop('drawing_style')
    dobj = target.parent.add_object(object_type=target.object_type,visible=1,
            params=params,selparams=selparams,
            colparams=colparams,styleparams=styleparams)
    #print 'GDispObj.clone self',target.name,'clone',dobj,dobj.name
    if not dobj: return

    # (Hack?) force redrawing of dependents.
    if doDrawingStyle:
      pm = dobj.getDrawingStylePM(name=name,custom=1)
      pm.setparams(pmold.getparams())
      

    # Add to display table
    self.table.addDispObj(parent_name=target.parent.name,
                     object_type=target.object_type,name=dobj.name)

    import rebuild
    rebuild.UpdateDisplay()

#---------------------------------------------------------------------
class GTreeFeature(QtGui.QLabel):
#---------------------------------------------------------------------  
  # Tried implementing as a QPushButton with image
  # drawn as QIcon -- could not get image right size
  # or right background colour
  def __init__(self,parent,feature):
    super(GTreeFeature,self).__init__(parent)
    pmaps = MGDisplayTable.pixmaps
    if pmaps.has_key(feature):
      self.setPixmap(pmaps[feature])
      if pmaps[feature].isQBitmap(): self.setMask(pmaps[feature].mask())

    
  def mouseReleaseEvent(self,event):
    # Reimplementing QWidget.mouseReleaseEvent because
    # QLabel does not have required signal
    if event.button() ==  QtCore.Qt.RightButton:
      event.accept()
      self.emit(QtCore.SIGNAL('contextMenu'),event.globalX(),event.globalY())
    else:
      event.accept()
      self.emit(QtCore.SIGNAL('mouseRelease'))
   
  def resetIcon(self,feature):
    #print "resetIcon",feature
    pmaps = MGDisplayTable.pixmaps
    if pmaps.has_key(feature):     
      self.setPixmap(pmaps[feature])
      if pmaps[feature].isQBitmap(): self.setMask(pmaps[feature].mask())


class DispWindowCore:

  def setObjectsChanged(self,theWidget):
    pass
    
  def setWidth(self,compact=0):
    print 'DispWindow.setWidth',self.compact,compact
    #return
    if compact == self.compact: return
    if compact:
      self.setFixedWidth(MGDisplayTable.compact_width+self.scrollWidth)
    else:
      self.setFixedWidth(MGDisplayTable.width+self.scrollWidth)
    self.compact = compact

  def updateWidth(self):

    self.setWidth(1-self.scrollarea.widget().DispObjOpen())

  def Close(self):
        self.hide()

  def populateStuffMenu(self):
    self.stuffMenu.clear()
    alldata = self.stuffMenu.addMenu("For all data")
    alldo = self.stuffMenu.addMenu("For all display objects")
    for action_name in ['all_data_hide','all_data_show']:
      action = guiUtils.createAction(action_name,self.parent())
      alldata.addAction(action)
    for action_name in ['all_disp_labels','all_disp_flashing','all_disp_transparency']:
      action = guiUtils.createAction(action_name,self.parent())
      alldo.addAction(action)

  def populateCreateMenu(self):
    self.createMenu.clear()
    for action_name in self.parent().menuDefinitions['_file_create'][0][1:]:
      action = guiUtils.createAction(action_name,self.parent())
      self.createMenu.addAction(action)

class DispWindowNoDock(DispWindowCore, MGSimpleDialog.MGSimpleDialog):

  def setObjectsChanged(self,theWidget):
    self.blockSignals(True)
    DISPLAYTABLE().update(all=1)
    self.blockSignals(False)

  def __init__(self,parent=None,MGDisplayTable=None):
    MGSimpleDialog.MGSimpleDialog.__init__(self,parent)
    self.menu = "Windows"
    self.menu_defn["shortcut"] = "Ctrl+D"

    layout = QtGui.QVBoxLayout()
    tbLayout = QtGui.QHBoxLayout()
    tb = QtGui.QToolButton(self)
    tb.setText("Create object")
    self.createMenu = QtGui.QMenu(self)
    tb.setMenu(self.createMenu)
    tb.setPopupMode(QtGui.QToolButton.InstantPopup)
    tbLayout.addWidget(tb)

    tb2 = QtGui.QToolButton(self)
    self.stuffMenu = QtGui.QMenu(self)
    tb2.setMenu(self.stuffMenu)
    tb2.setPopupMode(QtGui.QToolButton.InstantPopup)
    tb2.setText("Tools")
    tbLayout.addWidget(tb2)

    tbLayout.addStretch(2)

    layout.addLayout(tbLayout)
    self.populateCreateMenu()
    self.populateStuffMenu()
    self.setLayout(layout)

    layout.setContentsMargins(margin,margin,margin,margin)

    self.scrollarea = QtGui.QScrollArea()
    layout.addWidget(self.scrollarea)
    self.scrollarea.setWidget(MGDisplayTable)
    self.scrollarea.setWidgetResizable(1) 
    self.scrollarea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
    self.scrollWidth=self.scrollarea.verticalScrollBar().height()
    #print "scrollWidth",scrollWidth

    self.compact = -1
    self.setWidth()
    self.setWindowTitle(self.tr('Display Table'))
    self.CreateMenuEntry()

  def UnClose(self):
    #print 'DispWindow.UnClose'
    MGSimpleDialog.MGSimpleDialog.UnClose(self)
    DISPLAYTABLE().update(all=1)

#---------------------------------------------------------------------  
class DispWindowDock(DispWindowCore, MGSimpleDialog.MGSimpleDockDialog):
#---------------------------------------------------------------------  

  """
  def resizeEvent(self,e):
      if self.size().width()>=500 and e.oldSize().width()<500:
          MAINWINDOW().MGDisplayTable.setFloatingSize()
          self.redoDockFloatingSize(self.dockWidget.isTopLevel())
      if self.size().width()<500 and e.oldSize().width()>=500:
          MAINWINDOW().MGDisplayTable.setDockedSize()
          self.redoDockFloatingSize(self.dockWidget.isTopLevel())
  """

  def setWidth(self,compact=0):
    return

  def dockLocationChanged(self,loc):
    print "dockLocationChanged",loc; sys.stdout.flush()

  def topLevelChanged(self,topLevel):
    if MAINWINDOW() and hasattr(MAINWINDOW(),"MGDisplayTable"):
      if topLevel:
        MAINWINDOW().MGDisplayTable.setFloatingSize()
        MAINWINDOW().MGDisplayTable.setFloating()
      else:
        if self.width()<500:
          MAINWINDOW().MGDisplayTable.setDockedSize()
        else:
          MAINWINDOW().MGDisplayTable.setFloatingSize()
        MAINWINDOW().MGDisplayTable.setDocked()
      self.redoDockFloatingSize(topLevel)

  def redoDockFloatingSize(self,topLevel):
      widgets = MAINWINDOW().MGDisplayTable.findChildren(GDispObj)
      bw = MGDisplayTable.bodyWidth
      w = MGDisplayTable.rowHeight
      for widget in widgets:
        i = 0
        x = (3+widget.table.status_open)*w
        format_list = widget.getGuiDef()
        nslider = 0
        if bw < 6:
          for format in format_list:
            mode = format.get('mode')
            if str(mode) == "VALUESLIDER":
              nslider = nslider + 1
        if format_list:
          widthFactor = float(bw)/(len(format_list)+nslider)
        else:
          widthFactor = bw
        offset = 0
        for format in format_list:
          i = i + 1
          name = format.get('name')
          mode = format.get('mode')
          if str(mode) == "VALUESLIDER":
             if not topLevel:
               if widget.widgets.has_key(name+'_docked_'):
                 widget.widgets[name+'_docked_'].show()
                 if bw < 6:
                   widget.widgets[name+'_docked_'].setGeometry(x,0,int(widthFactor*w*2),w)
                   offset = offset + int(widthFactor*w)
                 else:
                   widget.widgets[name+'_docked_'].setGeometry(x,0,int(widthFactor*w),w)
                 widget.widgets[name+'_docked_'].update()
               widget.widgets[name].hide()
             else:
               if widget.widgets.has_key(name+'_docked_'):
                 widget.widgets[name+'_docked_'].hide()
               widget.widgets[name].show()
          widget.widgets[name].setGeometry(x,0,int(widthFactor*w),w)
          widget.widgets[name].update()
          x = x + int(widthFactor*w) + offset
          widget.updateLabel(name)
      widgets = MAINWINDOW().MGDisplayTable.findChildren(GDataObj)
      width = MAINWINDOW().MGDisplayTable.getWidth()
      height = MAINWINDOW().MGDisplayTable.height()
      for widget in widgets:
         widget.setBodyGeometry()
      if topLevel:
        self.dockWidget.resize(width+40,height+40)
      MAINWINDOW().MGDisplayTable.update()
        

  def populateStuffMenu(self):
    self.stuffMenu.clear()
    alldata = self.stuffMenu.addMenu("For all data")
    alldo = self.stuffMenu.addMenu("For all display objects")
    for action_name in ['all_data_hide','all_data_show']:
      action = guiUtils.createAction(action_name,self.parent().parent())
      alldata.addAction(action)
    for action_name in ['all_disp_labels','all_disp_flashing','all_disp_transparency']:
      action = guiUtils.createAction(action_name,self.parent().parent())
      alldo.addAction(action)
    action = guiUtils.createAction("collapse_all",self.parent().parent())
    alldata = self.stuffMenu.addAction(action)
    action = guiUtils.createAction("show_all",self.parent().parent())
    alldata = self.stuffMenu.addAction(action)

  def populateCreateMenu(self):
    self.createMenu.clear()
    for action_name in self.parent().parent().menuDefinitions['_file_create'][0][1:]:
      action = guiUtils.createAction(action_name,self.parent().parent())
      self.createMenu.addAction(action)

  def __init__(self,parent=None,MGDisplayTable=None,defaultDockArea=QtCore.Qt.RightDockWidgetArea):
    MGSimpleDialog.MGSimpleDockDialog.__init__(self,defaultDockArea=defaultDockArea)
    self.menu = "Windows"
    self.menu_defn["shortcut"] = "Ctrl+D"

    layout = QtGui.QVBoxLayout()
    tbLayout = QtGui.QToolBar()
    tb = QtGui.QToolButton(self)
    tb.setText("Create object")
    self.createMenu = QtGui.QMenu(self)
    tb.setMenu(self.createMenu)
    tb.setPopupMode(QtGui.QToolButton.InstantPopup)
    tbLayout.addWidget(tb)

    tb2 = QtGui.QToolButton(self)
    self.stuffMenu = QtGui.QMenu(self)
    tb2.setMenu(self.stuffMenu)
    tb2.setPopupMode(QtGui.QToolButton.InstantPopup)
    tb2.setText("Tools")
    tbLayout.addWidget(tb2)

    tb.setArrowType(QtCore.Qt.DownArrow)
    tb2.setArrowType(QtCore.Qt.DownArrow)
    tb.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
    tb2.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
    layout.addWidget(tbLayout)
    self.populateCreateMenu()
    self.populateStuffMenu()
    self.setLayout(layout)

    layout.setContentsMargins(margin,margin,margin,margin)

    self.scrollarea = QtGui.QScrollArea()
    layout.addWidget(self.scrollarea)
    self.scrollarea.setWidget(MGDisplayTable)
    self.scrollarea.setWidgetResizable(1) 
    self.scrollarea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
    self.scrollWidth=self.scrollarea.verticalScrollBar().height()
    #print "scrollWidth",scrollWidth

    self.connect(self.dockWidget,QtCore.SIGNAL("topLevelChanged(bool)"),self.topLevelChanged)
    #self.connect(self.dockWidget,QtCore.SIGNAL("dockLocationChanged(Qt::DockWidgetArea)"),self.dockLocationChanged)

    self.compact = -1
    self.setWidth()
    self.setWindowTitle(self.tr('Display Table'))
    self.CreateMenuEntry()
    self.needUpdateAll = False
    self.connect(self.dockWidget,QtCore.SIGNAL("visibilityChanged(bool)"),self.visibilityChanged)

  def UnCloseNoUpdate(self):
    MGSimpleDialog.MGSimpleDockDialog.UnClose(self)

  def UnClose(self):
    #print 'DispWindow.UnClose'
    self.needUpdateAll = False
    MGSimpleDialog.MGSimpleDockDialog.UnClose(self)
    DISPLAYTABLE().update(all=1)

  def visibilityChanged(self,visible):
    #print "dock changed",visible
    if self.needUpdateAll and visible:
      self.needUpdateAll = False
      self.blockSignals(True)
      #print "updating"
      DISPLAYTABLE().update(all=1)
      self.blockSignals(False)

  def showEvent(self,e):
    #print 'DispWindow.showEvent'
    if self.needUpdateAll:
      self.needUpdateAll = False
      self.blockSignals(True)
      #print "updating"
      DISPLAYTABLE().update(all=1)
      self.blockSignals(False)

  def setObjectsChanged(self,theWidget):
    if self.dockWidget.isFloating() or len(MAINWINDOW().tabifiedDockWidgets(self.dockWidget))==0 or (len(MAINWINDOW().tabifiedDockWidgets(self.dockWidget))>0 and not theWidget.dockWidget in MAINWINDOW().tabifiedDockWidgets(self.dockWidget)):
      self.blockSignals(True)
      #print "updating"
      DISPLAYTABLE().update(all=1)
      self.blockSignals(False)
    else:
      #print "setting dirty flag"
      self.needUpdateAll = True
   

#---------------------------------------------------------------------  
class mgIconButton(QtGui.QToolButton):
#---------------------------------------------------------------------  
  # Sub-class QToolButton so we can get a signal from
  # right mouse press
  def __init__(self,parent=None,icon=None):
    QtGui.QToolButton.__init__(self,parent)
    self.setPopupMode(QtGui.QToolButton.InstantPopup)
    if icon: self.setIcon(icon)
    # Force larger icons
    self.setIconSize(QtCore.QSize(32,32))

  def mouseReleaseEvent(self,event):
    #print "mouseReleaseEvent",event.button()
    if event.button() ==  QtCore.Qt.RightButton:
      event.accept()
      self.emit(QtCore.SIGNAL('rightMouseRelease'))

    else:
      event.ignore()
    
