"""
     qtgui/guiUtils.py: CCP4 Gui Project
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009 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.
"""

##@package CCP4GuiUtils (QtGui) Assorted Gui utilities
import os,types,copy,functools
from PyQt4 import QtGui,QtCore,QtSvg
import CCP4Widgets

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)
      


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=''):
#----------------------------------------------------------------------
  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 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)
    
  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)

  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.get('deleteLater',0):
    a.deleteLater()


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

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


  return a

#----------------------------------------------------------------------
def createIcon(name=None,adef={},icon_path='',default_icon='unknown'):
#----------------------------------------------------------------------

  #print 'guiUtils.createIcon',name
  if adef.has_key('icon') and adef['icon']:
    icon_name =  str(adef['icon'])
  elif name is not None:
    icon_name = str(name)
  else:
    icon_name = 'unknown'
  if not icon_path:
    for item in ['CCP4I2_TOP']:
      if os.environ.has_key(item):
        icon_path = os.path.join(os.path.abspath(os.environ[item]),'qticons')
  #print 'guiUtils.createIcon',icon_path,icon_name
  for ext in ICON_EXTENSIONS:
    filename = os.path.join(icon_path,icon_name+ext)
    if os.path.exists(filename):
        #print 'guiUtils.createIcon',filename
        if ext == '.svg':
          pix = loadSvg(filename)
        else:
          pix =  QtGui.QPixmap(filename)
        ico =  QtGui.QIcon(pix)
        return ico
  if default_icon:
    for item in ['CCP4I2_TOP']:
      if os.environ.has_key(item):
        file = os.path.join(os.path.abspath(os.environ[item]),'qticons',default_icon+'.png')
        return QtGui.QIcon(file)
  else:
    return None

def loadSvgWithSize(fileName,width,height):
     svg = QtSvg.QSvgRenderer()
     svg.load(fileName)
     pixmap = QtGui.QImage(width,height,QtGui.QImage.Format_ARGB32)
     pixmap.fill(QtGui.QColor(0, 0, 0, 0))
     painter = QtGui.QPainter(pixmap)
     painter.setRenderHints(QtGui.QPainter.Antialiasing);
     svg.render(painter)
     painter.end()
     #pixmap = pixmap.scaledToHeight(height,QtCore.Qt.SmoothTransformation)
     return QtGui.QPixmap.fromImage(pixmap)

def loadSvg(fileName):
     ICONSIZE = 24
     svg = QtSvg.QSvgRenderer()
     svg.load(fileName)
     pixmap = QtGui.QPixmap(ICONSIZE,ICONSIZE)
     pixmap.fill(QtGui.QColor(0,0,0,0))
     painter = QtGui.QPainter(pixmap)
     svg.render(painter)
     painter.end()
     return pixmap

#----------------------------------------------------------------------
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']),functools.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()


#----------------------------------------------------------------------
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()"),functools.partial(definition,menuWidget))
  else:
    for item in definition:
      a = None
      if item == 'sep':
        #print 'Not adding a menu separator',definition
        menuWidget.addSeparator()
      elif 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()"),functools.partial(item[1],(sub_menu,item[0])))
      else:
        if getActionDef:
          adef = getActionDef(item)
        else:
          adef = parent.getActionDef(item)
        #print 'populateMenu adef ',item,adef
        if adef:
          a = adef.get('action',None)
          if a is None:
            a = createAction(item,parent,adef,default_icon=default_icon)
            adef['action'] = a
          else:
            # 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('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 populateToolBar(parent=None,toolBarWidget=None,definition=[],
                 getActionDef=None,default_icon='',info={}):
#----------------------------------------------------------------------
  #print 'populateToolBar',definition
  if not definition:
    toolBarWidget.addAction(createAction('dummy',parent,{ 'text' : '  --  '} ,default_icon=default_icon))
  elif not isinstance(definition,types.ListType):
    parent.connect(toolbarWidget,QtCore.SIGNAL("aboutToShow()"),partial(definition,toolBarWidget))
  else:
    for item in definition:
      a = None
      if item == 'sep':
        # ??????????????????????????
        pass
      elif isinstance(item,types.ListType) and len(item)>0:         
        #  ?????????????  handling splitter
        pass
      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 not a:
            a = createAction(item,parent,adef,default_icon=default_icon)
          else:
            # 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('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: toolBarWidget.addAction(a)

#-------------------------------------------------------------------
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['CCP4I2_TOP']),'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['CCP4I2_TOP'],'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)


#-------------------------------------------------------------------
def setWidgetValue(widget,value):
#-------------------------------------------------------------------
    #print 'setWidgetValue',widget,value
    if isinstance(widget,QtGui.QComboBox):
      ic = widget.findText(QtCore.QString(value))
      if ic < 0:
        ic = widget.findData(QtCore.QVariant(value))
      if ic>=0: widget.setCurrentIndex(ic)
    elif isinstance(widget,QtGui.QLineEdit):
      widget.setText(str(value))
    elif isinstance(widget,QtGui.QLabel):
      widget.setText(str(value))
    elif isinstance(widget,QtGui.QAbstractButton):
      widget.setChecked(value)
    elif isinstance(widget,QtGui.QDoubleSpinBox):
      widget.setValue(float(value))
    elif isinstance(widget,QtGui.QSpinBox):
       widget.setValue(int(value))
    elif isinstance(widget,CCP4Widgets.CDataFileView):
       widget.setDataFile(value)
       
    '''
    elif isinstance(widget,mgSelectionCombo):
      widget.setText(value)
    elif isinstance(widget,mgColourCombo):
      widget.set_colour(value)
    elif isinstance(widget,mgAtomPicker):
      widget.setSelection(atomName=value)
    '''

#-------------------------------------------------------------------
def getWidgetValue(widget=None,default='',baseType='text'):
#-------------------------------------------------------------------
   value = default
   if isinstance(widget,QtGui.QComboBox):
     #value = str(widget.itemData(widget.currentIndex()).toString())
     variant = widget.itemData(widget.currentIndex())
     if variant:
       if baseType == 'int':
         value = variant.toInt()
       elif baseType == 'real':
         value = variant.toFloat()
       else:
         value = str(variant.toString())
       #print 'getWidgetValue menu variant',variant,value
     if not value: value = str(widget.currentText())
   elif isinstance(widget,QtGui.QLabel):
     value = str(widget.text())
   elif isinstance(widget,QtGui.QLineEdit):
     value = str(widget.text())
   elif isinstance(widget,QtGui.QAbstractButton):
     value = int(widget.isChecked())
   elif isinstance(widget,QtGui.QDoubleSpinBox):
     value = float(widget.value())
   elif isinstance(widget,QtGui.QSpinBox):
     value = int(widget.value())
   elif isinstance(widget,CCP4Widgets.CDataFileView):
     value = widget.getDataFile()

   '''
   elif isinstance(widget,mgSelectionCombo):
     value = str(widget.text())
   elif isinstance(widget,mgColourCombo):
     value = str(widget.get_colour())
   elif isinstance(widget,mgAtomPicker):
     value = str(widget.selection())
   '''
   return value

def getWidgetSignal(widget=None,default='clicked()'):
   signal = default
   if isinstance(widget,QtGui.QComboBox):
     signal = 'currentIndexChanged(int)'
   elif isinstance(widget,QtGui.QLabel):
     signal = 'linkActivated(const QString)'
   elif isinstance(widget,QtGui.QLineEdit):
     signal = 'editingFinished()'
   elif isinstance(widget,QtGui.QAbstractButton):
     signal = 'clicked(bool)'
   elif isinstance(widget,QtGui.QDoubleSpinBox):
     signal = 'valueChanged(double)'
   elif isinstance(widget,QtGui.QSpinBox):
     signal = 'valueChanged(int)'
   return signal


