"""
     qtgui/guiUtils.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2010 University of York

     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.
"""
import os,types,copy
from PyQt4 import QtGui,QtCore

LOADED_PIXMAPS = {}
ICON_EXTENSIONS= ['.svg','.png']

class mgMenu(QtGui.QMenu):

  def __init__(self,parent=None):
    QtGui.QMenu.__init__(self,parent)

  def mouseReleaseEvent(self,event):
    action = self.actionAt(QtCore.QPoint(event.x(),event.y()))
    if action:
      action.emit(QtCore.SIGNAL('mouseRelease'))
    #if event.key()!=QtCore.Qt.Key_Return:
    QtGui.QMenu.mouseReleaseEvent(self,event)
      

# bummer - need python 2.5
#from functools import partial
"""
# kludge ..
def partial(func,arg):
  #print "partial func,arg",func,arg
  def callme():
    return func(arg)
  return callme
""" 	 
class partial(object): 	 
  	 
     def __init__(*args, **kw): 	 
         self = args[0] 	 
         self.fn, self.args, self.kw = (args[1], args[2:], kw) 	 
  	 
     def __call__(self, *args, **kw): 	 
         if kw and self.kw: 	 
             d = self.kw.copy() 	 
             d.update(kw) 	 
         else: 	 
             d = kw or self.kw 	 
         return self.fn(*(self.args), **d) 	 
  	 
class partialWithSignal(object): 	 
  	 
     def __init__(*args, **kw): 	 
         self = args[0] 	 
         self.fn, self.args, self.kw = (args[1], args[2:], kw) 	 
  	 
     def __call__(self, *args, **kw): 	 
         if kw and self.kw: 	 
             d = self.kw.copy() 	 
             d.update(kw) 	 
         else: 	 
             d = kw or self.kw 	 
         return self.fn(*(self.args + args), **d)

def checkState(inp):
  if inp:
    return QtCore.Qt.Checked
  else:
    return QtCore.Qt.Unchecked

def fromCheckState(inp):
  if inp == QtCore.Qt.Unchecked:
    return 0
  else:
    return 1

#----------------------------------------------------------------------
def fromMenu(text,menu_list,alias_list):
#----------------------------------------------------------------------
  # return the short alias for a given long menu text
  if menu_list.count(text):
    return alias_list[menu_list.index(text)]
  else:
    return text


#----------------------------------------------------------------------
def createAction(name='',parent=None,definition={},icon_path='',default_icon='',existing_action=None):
#----------------------------------------------------------------------
  if definition:
    adef = definition
  else:
    adef = parent.getActionDef(name)

  #print "createAction",name,adef

  # Is it a 'build-in' action
  if adef.has_key('action'):
    #print "createAction build-in",name,adef['action']
    return adef['action']

  text = ''
  if adef.has_key('text'):
    if callable(adef['text']):
      text = adef['text']()
    else:
      text = adef['text']

 
  # Is it grouped with other actions
  if existing_action is None:
    if adef.has_key('group'):
      group=parent.findChild(QtGui.QActionGroup,adef['group'])
      if not group:
        group = QtGui.QActionGroup(parent)
        group.setObjectName(adef['group'])
      a = group.addAction(text)
    else:
      a = QtGui.QAction(text,parent)
  else:
    a = existing_action
    
  a.setObjectName(name)
  if adef.has_key('shortcut') and adef['shortcut']:
    if isinstance(adef['shortcut'],types.IntType):
      a.setShortcut(adef['shortcut'])
    else:
      a.setShortcut(QtGui.QKeySequence(adef['shortcut']))
      
  icon = createIcon(name,adef,icon_path=icon_path,default_icon=default_icon)
  if icon: 
    a.setIcon(icon)
    a.setIconVisibleInMenu(True);

  tip = adef.get('toolTip','')
  if tip:  a.setToolTip(tip)

      
  if adef.has_key('checkable') and adef['checkable']:
    a.setCheckable(1)
    if adef.has_key('checked') and callable(adef["checked"]):
      res = adef["checked"]()
      if type(res)==types.IntType or type(res)==types.BooleanType:
        a.setChecked(res)

  if adef.has_key('enabled'):
    if callable(adef["enabled"]):
      res = adef["enabled"]()
    else:
      res = adef["enabled"]
    if type(res)==types.IntType or type(res)==types.BooleanType:
      a.setEnabled(res)

  if adef.has_key('deleteLater') and adef['deleteLater']:
    actions.append(a)
    a.deleteLater()


  # Sort out a signal
  if adef.has_key('signal'):
    signal = adef['signal']
  else:
    signal = 'triggered()'

  if adef.get('slot','') and existing_action is None:
    if isinstance(adef['slot'],types.ListType) and len(adef['slot'])>1:
      parent.connect(a,QtCore.SIGNAL(signal),partial(adef['slot'][0],adef['slot'][1]))
    else:
      parent.connect(a,QtCore.SIGNAL(signal),adef['slot'])


  return a

#----------------------------------------------------------------------
def createIcon(name='',adef={},icon_path='',default_icon='unknown'):
#----------------------------------------------------------------------
  if adef.has_key('icon') and adef['icon']:
    icon_name =  str(adef['icon'])
  else:
    icon_name = str(name)
  #print "Try making icon with name",icon_name,"with path",icon_path
  if os.path.exists(icon_name) and os.path.basename(icon_name) != icon_name :
     return QtGui.QIcon(icon_name)
  if not icon_path: icon_path = os.path.join(os.path.abspath(os.environ['CCP4MG']),'qticons','actions')
  #print 'guiUtils.createIcon',icon_path,icon_name
  for ext in ICON_EXTENSIONS:
    file = os.path.join(icon_path,icon_name+ext)
    if os.path.exists(file):
        return QtGui.QIcon(file)
  if default_icon:
    file = os.path.join(os.path.abspath(os.environ['CCP4MG']),'qticons',default_icon+'.png')
    return QtGui.QIcon(file)
  else:
    return None


#----------------------------------------------------------------------
def addMenuEntry(name='',definition={},parent=None,icon_path=''):
#----------------------------------------------------------------------
    action = createAction(name,parent,definition,icon_path)
    parent.addAction(action)
    if definition.has_key('slot') and definition.has_key('signal'):
      if type(definition['slot']) == tuple:
        # Hmm, I need to know how to have arbitrary number of arguments.
        parent.connect(action,QtCore.SIGNAL(definition['signal']),partial(definition['slot'][0],definition['slot'][1]))
      else:
        parent.connect(action,QtCore.SIGNAL(definition['signal']),definition['slot'])
    return action

#----------------------------------------------------------------------
def clearMenu(menu=None):
#----------------------------------------------------------------------
   submenus = menu.findChildren(QtGui.QMenu)
   menu.clear()
   for sm in submenus: sm.clear()


actions = []
#----------------------------------------------------------------------
def populateMenu(parent=None,menuWidget=None,definition=[],
                 getActionDef=None,default_icon='',info={}):
#----------------------------------------------------------------------
  #print "populateMenu",definition
  #menuWidget.connect(menuWidget, QtCore.SIGNAL("hovered(QAction *)"),handleMenuHover)
  if not definition:
    menuWidget.addAction(createAction('dummy',parent,{ 'text' : '  --  '} ,default_icon=default_icon))
  elif not isinstance(definition,types.ListType):
    parent.connect(menuWidget,QtCore.SIGNAL("aboutToShow()"),partial(definition,menuWidget))
  else:
    for item in definition:
      a = None
      if item == 'sep':
        menuWidget.addSeparator()
      if isinstance(item,types.ListType) and len(item)>0:         
        sub_menu=menuWidget.addMenu(item[0])
        if len(item) == 1:
          # This is a sub without actions defined
          sub_menu.setEnabled(0)
        elif isinstance(item[1],types.StringType):
          populateMenu(parent=parent,menuWidget=sub_menu,definition = item[1:],getActionDef=getActionDef,default_icon=default_icon,info=info)
        elif isinstance(item[1],types.MethodType):
          parent.connect(sub_menu,QtCore.SIGNAL("aboutToShow()"),partial(item[1],(sub_menu,item[0])))
      else:
        if getActionDef:
          adef = apply(getActionDef,[item],info)
        else:
          adef = apply(parent.getActionDef,[item],info)
        if adef:
          #print "createAction adef",adef
          a = parent.findChild(QtGui.QAction,item)
          #print "populateMenu find action",item,a
          if a:
           existing_action = a
          else:
           existing_action = None
          if not a:
	    if adef.has_key("icon_path"):
            	a = createAction(item,parent,adef,icon_path=adef["icon_path"],default_icon=default_icon)
            else:
            	a = createAction(item,parent,adef,default_icon=default_icon)
          else:
	    if adef.has_key("icon_path"):
            	a = createAction(item,parent,adef,icon_path=adef["icon_path"],default_icon=default_icon,existing_action=existing_action)
            else:
            	a = createAction(item,parent,adef,default_icon=default_icon,existing_action=existing_action)
            # The action exists but lets update the checked status
            if adef.has_key('text') and callable(adef["text"]):
              a.setText(adef['text']())
            if adef.has_key('text') and not callable(adef["text"]):
              a.setText(adef['text'])
            if adef.has_key('checked') and callable(adef["checked"]):
              res = adef["checked"]()
              #print "populateMenu checked",item,res
              if type(res)==types.IntType or type(res)==types.BooleanType:
                a.setChecked(res)
            if adef.has_key('enabled'):
              #print 'reload adef enabled',item,adef["enabled"]
              if callable(adef["enabled"]):
                res = adef["enabled"]()
              else:
                res = adef["enabled"]
              #print 'reload adef enabled',item,res
              if type(res)==types.IntType or type(res)==types.BooleanType:
                a.setEnabled(res)
          
        if a: menuWidget.addAction(a)

def handleMenuHover(action):
  tip = action.toolTip()
  if not tip: return
  QtGui.QToolTip.showText(QtGui.QCursor.pos(),tip)
  

#-------------------------------------------------------------------
def loadPixmap(name='',group='actions',icon_path='',width=32,height=0):
#-------------------------------------------------------------------
  if not height: height = width
  size_key = str(width)+'_'+str(height)

  if not (LOADED_PIXMAPS.has_key(name) and LOADED_PIXMAPS[name].has_key(size_key)):
  
    if not icon_path:
      icon_path = os.path.join(os.path.abspath(os.environ['CCP4MG']),'qticons')

    file = ''
    
    for ext in ICON_EXTENSIONS:
      f = os.path.join(icon_path,group,name+ext)   
      if os.path.exists(f):
        file = f
        break
      
    if not file:
      file = os.path.join(os.environ['CCP4MG'],'qticons','unknown.png')
      if  not os.path.exists(file):
        return None

    if not LOADED_PIXMAPS.has_key(name): LOADED_PIXMAPS[name] = {}
    LOADED_PIXMAPS[name][size_key] = QtGui.QPixmap(file).scaled(width,height)
  
  return LOADED_PIXMAPS[name][size_key]
                                   


#-------------------------------------------------------------------
  def loadResource(self,url='',mode=QtGui.QTextDocument.StyleSheetResource):
#-------------------------------------------------------------------
    qu = QtCore.QUrl(url)
    self.style = self.textBrowser.loadResource(mode, qu)

