"""
     qtgui/mgFileViewer.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2011 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.
"""

'''
Functionality needed..
Scaling images
searching text
'''
import sys
import os
import functools
from PyQt4 import QtCore,QtGui
try:
  if sys.platform == 'linux2':
    from PyQt4 import phonon
    havePhonon = True
except:
  havePhonon = False
import MGSimpleDialog
from global_definitions import *

#-------------------------------------------------------------------
def addSupportedFormat(name,extensions=[],label='',viewer=''):
#-------------------------------------------------------------------
    if mgFileViewer.supported_formats.has_key(name):
      print "mgFileViewer redefining supported format",name
    mgFileViewer.supported_formats[name] = {}
    mgFileViewer.supported_formats[name]['ext_list'] = extensions
    mgFileViewer.supported_formats[name]['viewer'] = viewer
    mgFileViewer.supported_formats[name]['label'] = label


def addSupportedPlugin(name,extensions=[],label='',viewer='',arguments=''):
    if mgFileViewer.supported_plugins.has_key(name):
      print "mgFileViewer redefining supported format",name
    mgFileViewer.supported_plugins[name] = {}
    mgFileViewer.supported_plugins[name]['ext_list'] = extensions
    mgFileViewer.supported_plugins[name]['viewer'] = viewer
    mgFileViewer.supported_plugins[name]['label'] = label
    mgFileViewer.supported_plugins[name]['arguments'] = arguments
 
#-------------------------------------------------------------------
def getParams():
#-------------------------------------------------------------------
    plugins = {}
    plugins.update(mgFileViewer.supported_plugins)
    return { 'supported_plugins' : plugins }

#-------------------------------------------------------------------
def setParams(params):
#-------------------------------------------------------------------
    if params.has_key( 'supported_plugins'):
      for key,info in params['supported_plugins'].items():
        addSupportedPlugin(key,info.get('ext_list',[]),
                           info.get('label',''),info.get('viewer',''))

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgFileViewer(QtGui.QWidget):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

  supported_formats = {}
  supported_plugins = {}

#-------------------------------------------------------------------
  def __init__(self,parent=None,name='',title='CCP4mg file viewer'):
#-------------------------------------------------------------------
    #if not parent: parent = MAINWINDOW()
    QtGui.QWidget.__init__(self,parent)
    self.setWindowTitle(title)
    self.setWindowFlags(QtCore.Qt.Window)
    self.menu='Windows'
    if name: self.setObjectName(name)
    if not mgFileViewer.supported_formats:
      addSupportedFormat('text',['txt','text','log'],'Text files',mgTextViewer)
      addSupportedFormat('coords',['pdb','cif','ent'],'Coordinate files',mgCoordsViewer)
      addSupportedFormat('vector',['vector'],'Vector files',mgTextViewer)
      addSupportedFormat('html',['html','htm'],'HTML files',mgHtmlViewer)

      image_formats_c = QtGui.QMovie.supportedFormats() 
      image_formats = []
      for im in image_formats_c:
        if not image_formats.count(str(im).lower()):
          image_formats.append(str(im))
      # The QMovie widget supports animated gif and png
      addSupportedFormat('movie',image_formats,'Movie files',mgMovieViewer)
      addSupportedFormat('movie_phonon',['mpeg','mp4'],'Movie files (phonon)',mgMovieViewerPhonon)

      #import image_info
      #image_formats_c = image_info.image_info.GetSupportedWriteFormats()
      image_formats_c = QtGui.QImageReader.supportedImageFormats() 
      image_formats = []
      for im in image_formats_c:
        if not image_formats.count(str(im).lower()):
          image_formats.append(str(im))
      addSupportedFormat('image',image_formats,'Image files',mgImageViewer)

    self.saveWidget = None
    self.editPluginsWidget = None
    #self.CreateMenuEntry()
    self.draw()

#-------------------------------------------------------------------
  def draw(self):
#-------------------------------------------------------------------
      
    import guiUtils
    margin = 0
    self.tab = None
    self.menuWidget = {}

    layout = QtGui.QVBoxLayout()
    layout.setMargin(margin)
    self.setContentsMargins(margin,margin,margin,margin)
    self.menubar = QtGui.QMenuBar(self)
    for menu_name,menu_title in self.getGuiDef('menus'):
      self.menuWidget[menu_name] = self.menubar.addMenu(menu_title)
      self.connect(self.menuWidget[menu_name],QtCore.SIGNAL("aboutToShow()"),guiUtils.partial(self.updateMenu,menu_name))
    layout.addWidget(self.menubar)

    self.tab = QtGui.QTabWidget(self)
    pb = QtGui.QPushButton()
    pb.setText(self.tr("Delete tab"))
    self.tab.setCornerWidget(pb)
    pb.setAutoDefault(False)
    self.connect(pb,QtCore.SIGNAL("released()"),self.closeTab)

    self.connect(self.tab,QtCore.SIGNAL('currentChanged(int)'),self.handleTabChanged)
    layout.addWidget(self.tab)
    self.setLayout(layout)

    self.resize(QtCore.QSize(300,200))

    #self.UnClose()
    self.show()
    self.raise_()

#-------------------------------------------------------------------
  def updateMenu(self,menu_name):
#-------------------------------------------------------------------
    import guiUtils
    self.menuWidget[menu_name].clear()
    guiUtils.populateMenu(self,self.menuWidget[menu_name],self.getGuiDef(menu_name),default_icon='')

#-------------------------------------------------------------------
  def getGuiDef(self,name='',pickevent=None):
#-------------------------------------------------------------------
      if name == 'menus':
        return [['File','&File'],['Edit','&Edit']]
      elif name == 'File':
        return ['open','save','print','close_tab','close']
      elif name == 'Edit':
        return ['find','sep','edit_plugins']
      
#-------------------------------------------------------------------
  def getActionDef(self,name,**info):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    enabled = 0
    import guiUtils
    if name == 'close':
      return dict ( 
        text = 'Close file viewer',
        tip = 'Close this file viewer',
        slot = self.close  )

    if name == 'open':
      return dict (
          text = "Open file",
          tip = "Open text, image or movie file",
          slot = self.openFile,
          icon = 'fileopen'
          )
    if name == 'save':
      if widget: enabled = widget.isSaveable()
      return dict (
          text = "Save",
          tip = "Save to file",
          slot = self.handleSave,
          enabled = enabled
          )
    if name == 'print':
      if widget: enabled = widget.isPrintable()
      return dict (
          text = "Print",
          tip = "Print file",
          slot = self.handlePrint,
          enabled = enabled
          )
  
    if name == 'find':
      return dict (
          text = "Find",
          tip = "Find in file",
          slot = self.openFind,
          checkable = 1,
          checked = self.isFindFrameOpen,
          enabled = self.isCurrentWidgetText
          )
  
    if name == 'scale':
      return dict (
          text = "Scale image",
          tip = "Scale image",
          slot = self.openScale,
          enabled = self.isCurrentWidgetImage,
          checkable = 1,
          checked = self.isScaleFrameOpen
          )
  
    if name == 'scale_to_fit':
      return dict (
          text = "Scale image to fit",
          tip = "Scale image to fit the screen",
          slot = self.scaleToFit,
          enabled = self.isCurrentWidgetImage
          )
  
    if name == 'close_tab':
      return dict (
          text = "Close tab",
          tip = "Close the currently displayed file",
          slot = self.closeTab,
          enabled = 1
          )
    
    if name == 'edit_plugins':
      return dict (
          text = "Edit plugin viewers",
          tip = "Choose external programs to display data",
          slot = self.editPlugins,
          enabled = 1
          )

    return {}


#-------------------------------------------------------------------
  def resizeEvent(self,event):
#-------------------------------------------------------------------
    if self.isCurrentWidgetImage():
      self.currentWidget().fitToWindow()
      
#-------------------------------------------------------------------
  def isCurrentWidgetText(self):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    if widget and isinstance(widget,mgTextViewer):
        return 1
    else:
        return 0
#-------------------------------------------------------------------
  def isCurrentWidgetImage(self):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    if widget and isinstance(widget,mgImageViewer):
        return 1
    else:
        return 0
    
#-------------------------------------------------------------------
  def openFile(self):
#-------------------------------------------------------------------
    import mgWidgets
    win = self.findChild(mgWidgets.MGFileDialog,'win_open')
    if not win:
      win = MGSimpleDialog.MGSimpleDialog(self)
      win.setObjectName('win_open')
      win.setWindowTitle('CCP4mg file viewer')
      win.setAttribute(QtCore.Qt.WA_DeleteOnClose)
      layout = QtGui.QVBoxLayout()
      open = mgWidgets.MGFileDialog(self)
      open.setObjectName('open')
      layout.addWidget(open)
      win.setLayout(layout)
   
     
      filedialog = open.getFileDialog()
     
      filedialog.setFileMode(filedialog.ExistingFiles)

      filter_list = []
      for key,defn in mgFileViewer.supported_formats.items():
           ext_text = ''
           for ext in defn['ext_list']: ext_text = ext_text+'*.'+ext+' '
           filter_list.append(defn['label']+' ('+ext_text+')')
           #print "filter_list",filter_list
           filedialog.setNameFilters(filter_list)
      self.connect(filedialog, QtCore.SIGNAL('filesSelected (const QStringList&)'), self.handleSelection)

    win.show()

#-------------------------------------------------------------------
  def handleSelection(self,file_list):
#-------------------------------------------------------------------
    import string
    import mgWidgets
    #print "handleSelection file_list",file_list

    format = ''
    filedialog = self.findChild(mgWidgets.MGFileDialog,'open')
    if filedialog:
      filter = str(filedialog.getFileDialog().selectedFilter())
      if filter:
        #print "handleSelection filter",filter
        for name,defn in mgFileViewer.supported_formats.items():
          if string.find(filter,defn['label'])>=0:
            format = name
    

    for file in file_list:
      self.open(unicode(str(file.toUtf8()),'utf-8'),format=format)

    win = filedialog.window()
    if win: win.close()

#-------------------------------------------------------------------
  def loadText(self,text='',title='',format='text'):
#-------------------------------------------------------------------
    widget = mgTextViewer(self)
    widget.loadText(text=text)
    widget.setObjectName(title)
    idx = self.tab.addTab(widget,title)
    self.setTabIndex(idx)    
    widget.show()
    self.mgResize()
    return widget
    
#-------------------------------------------------------------------
  def open(self,filename,format='',title=''):
#-------------------------------------------------------------------
    ext = os.path.splitext(filename)
    if ext[1]:
      ext = ext[1][1:]
    else:
      ext = ''
    print "mgFileViewer.open filename",filename,format,ext, mgFileViewer.supported_plugins.items()

    # If format not recognised try if file extension is recognised
    if not format or (format and not mgFileViewer.supported_formats.has_key(format) and
                                 not mgFileViewer.supported_plugins.has_key(format)):
        format = ''
        for name,defn in mgFileViewer.supported_formats.items():
          if defn['ext_list'].count(ext):
            format = name
            break
        for name,defn in mgFileViewer.supported_plugins.items():
          if defn['ext_list'].count(ext):
            format = name
            break
          

    if not format:
      format = 'text'

    #print 'mgFileViewer.open',format

    # Is the file already displayed - force a redraw
    idx = self.fileOpenInTab(filename)
    if idx>=0:
      self.tab.setCurrentIndex(idx)
      self.tab.widget(idx).open(self.tab.widget(idx).filename)
      return self.tab.widget(idx)

    # If its a plugin format launch the plugin
    if mgFileViewer.supported_plugins.has_key(format):
      self.launch(format,filename)
      return None
    else:
      widget = mgFileViewer.supported_formats[format]['viewer'](self)
      rv = widget.open(filename)
      #print "mgFileViewer.open rv",rv
      if rv[0]:
          widget.close()
          MGGUI().WarningMessage(rv[1])
          return None
      if not title:  title = os.path.split(filename)[-1]
      widget.setObjectName(title)
      idx = self.tab.addTab(widget,title)
      self.setTabIndex(idx)    
      widget.show()
      self.mgResize()
      return widget

#-------------------------------------------------------------------
  def launch(self,format,filename):
#-------------------------------------------------------------------
    info = mgFileViewer.supported_plugins.get(format,{})
    viewer = info.get('viewer','')
    #print 'mgFileViewer.launch',format,filename,viewer
    if not viewer:
      return [-1, 'No viewer listed for format: '+format]

    # Create argent list for QProcess
    arglist = []
    for item in info.get('arguments','').split():
      arglist.append(item)
    arglist.append(filename)
    l = []
    for item in arglist: l.append(QtCore.QString(item))
    
    process = QtCore.QProcess(self)    
    process.start(viewer,QtCore.QStringList(l))

    self.Close()
    
#-------------------------------------------------------------------
  def setTabIndex(self,index=-1,filename=''):
#-------------------------------------------------------------------
      if index>=0 and index<=self.tab.count():
        self.tab.setCurrentIndex(index)
        self.setWindowTitle('CCP4mg file viewer: '+self.tab.widget(index).objectName())


#-------------------------------------------------------------------
  def currentWidget(self):
#-------------------------------------------------------------------
    if not self.tab: return None
    idx = self.tab.currentIndex()
    if idx<0: return None
    return self.tab.widget(idx)

#-------------------------------------------------------------------
  def handleTabChanged(self,index):
#-------------------------------------------------------------------
      #print "handleTabChanged index",index
      if index<0: return
      widget = self.tab.widget(index)
      if not widget: return
      self.setWindowTitle('CCP4mg file viewer: '+widget.objectName())

#-------------------------------------------------------------------
  def mgResize(self):
#-------------------------------------------------------------------
    imagesize = self.tab.currentWidget().mgSize()
    winsize = MGAPPLICATION().desktop().size()
    #print 'mgFileViewer.mgResize',imagesize.width(),imagesize.height(),'desktop',winsize.width(),winsize.height()
    reqwidth = min(imagesize.width(),winsize.width()-50)
    reqheight = min(imagesize.height(),winsize.height()-50)
    # Kludge - take 2x menubar height to allow for tabs on tab widget
    self.tab.resize(QtCore.QSize(reqwidth,reqheight-2*self.menubar.height()))
    self.resize(QtCore.QSize(reqwidth,reqheight))

#-------------------------------------------------------------------
  def closeTab(self):
#-------------------------------------------------------------------
    #print "closeTab",self.tab.currentIndex()
    idx = self.tab.currentIndex()
    if idx<0: return
    widget = self.tab.widget(idx)
    if widget: widget.close()
    self.tab.removeTab(idx)
    
#-------------------------------------------------------------------
  def fileOpenInTab(self,filename):
#-------------------------------------------------------------------
    filename = os.path.abspath(filename)
    for idx in range(0,self.tab.count()):
      if self.tab.widget(idx).filename == filename:
        return idx
    return -1


#-------------------------------------------------------------------
  def openFind(self):
#-------------------------------------------------------------------
    # Bothersomeness. This slot gets called even if there is an openFind
    # method in a subclass.  Just make this one work safely
    widget = self.currentWidget()
    if widget:
      findFrame = getattr(widget,'findFrame',None)
      if findFrame:
        if findFrame.isVisible():
          findFrame.hide()
        else:
          findFrame.show()


#-------------------------------------------------------------------
  def isFindFrameOpen(self):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    if widget:
      findFrame = getattr(widget,'findFrame',None)
      if findFrame and findFrame.isVisible(): return 1
    return 0

#-------------------------------------------------------------------
  def isScaleFrameOpen(self):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    if widget:
      scaleFrame = getattr(widget,'scaleFrame',None)
      if scaleFrame and scaleFrame.isVisible(): return 1
    return 0
  

#-------------------------------------------------------------------
  def openScale(self):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    if widget:
      scaleFrame = getattr(widget,'scaleFrame',None)
      if scaleFrame:
        if scaleFrame.isVisible():
          scaleFrame.hide()
        else:
          scaleFrame.show()


#-------------------------------------------------------------------
  def scaleToFit(self):
#-------------------------------------------------------------------
    if not self.isCurrentWidgetImage(): return
    self.currentWidget().fitToWindow()

#-------------------------------------------------------------------
  def handlePrint(self):
#-------------------------------------------------------------------
      idx = self.tab.currentIndex()
      if idx<0: return
      
      printer = QtGui.QPrinter()
      pd = QtGui.QPrintDialog(printer)
      pdret = pd.exec_()
      if pdret == QtGui.QDialog.Accepted:
          painter = QtGui.QPainter()
          painter.begin(printer)
          self.tab.widget(idx).Print(painter)
          painter.end()

#-------------------------------------------------------------------
  def handleSave(self):
#-------------------------------------------------------------------
    widget = self.currentWidget()
    if not widget: return
    import mgWidgets
    defaultSuffix = ''
    filter_list = []
    ext_list =  widget.getFileExt()
    if ext_list: defaultSuffix = ext_list[0]
    ext_text = ''
    for ext in widget.getFileExt() : ext_text = ext_text+'*.'+ext+' '
    if ext_text: filter_list.append(widget.getLabel()+' ('+ext_text+')')    
    self.saveWidget = mgWidgets.MGSaveFileDialog(self,title='Save '+widget.objectName(),filters=filter_list,defaultSuffix=defaultSuffix)
    self.connect(self.saveWidget,QtCore.SIGNAL('save'),self.currentWidget().Save)
    self.saveWidget.show()

#-------------------------------------------------------------------
  def editPlugins(self):
#-------------------------------------------------------------------
    if not self.editPluginsWidget:    
      self.editPluginsWidget = EditPlugins(self)
    self.editPluginsWidget.UnClose()

    
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#class mgAbstractViewer(QtGui.QWidget):
class mgAbstractViewer(QtGui.QScrollArea):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

#-------------------------------------------------------------------
  def __init__(self,parent,filename=''):
#-------------------------------------------------------------------
      #QtGui.QWidget.__init__(self,parent)
      QtGui.QScrollArea.__init__(self,parent)
      self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
      self.setWidgetResizable(1)
      self.filename=''

#-------------------------------------------------------------------
  def open(self,filename):
#-------------------------------------------------------------------
      pass

#-------------------------------------------------------------------
  def mgSize(self):
#-------------------------------------------------------------------

    return QtCore.QSize()

#-------------------------------------------------------------------
  def Print(self,painter):
#-------------------------------------------------------------------
    pass

#-------------------------------------------------------------------
  def Save(self,filename):
#-------------------------------------------------------------------
    pass

#-------------------------------------------------------------------
  def isPrintable(self):
#-------------------------------------------------------------------
    return 0

#-------------------------------------------------------------------
  def isSaveable(self):
#-------------------------------------------------------------------
    return 0

#-------------------------------------------------------------------
  def getFileExt(self):
#-------------------------------------------------------------------    
    for formt,defn in mgFileViewer.supported_formats.items():
      if isinstance(self,defn['viewer']):
        return defn['ext_list']

    return []

#-------------------------------------------------------------------
  def getLabel(self):
#-------------------------------------------------------------------    
    for formt,defn in mgFileViewer.supported_formats.items():
      if isinstance(self,defn['viewer']):
        return defn['label']

    return []

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgImageViewer(mgAbstractViewer):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

#-------------------------------------------------------------------
  def __init__(self,parent,filename=''):
#-------------------------------------------------------------------
      import mgWidgets
      mgAbstractViewer.__init__(self,parent)
      layout = QtGui.QVBoxLayout()
      self.label = QtGui.QLabel(self)
      layout.addWidget(self.label)

      '''
      self.scaleFrame = QtGui.QFrame(self)
      scale_layout =  QtGui.QHBoxLayout()
      scale_layout.addWidget(QtGui.QLabel('Scale',self))
      self.scaleWidget = mgWidgets.mgSlider(QtCore.Qt.Horizontal,self)
      self.scaleWidget.setRange(0.0,10.0)
      self.scaleWidget.setValue(1.0)
      self.connect(self.scaleWidget,QtCore.SIGNAL('valueChanged(double)'),self.scale)
      scale_layout.addWidget(self.scaleWidget)
      fit_to_frame = QtGui.QPushButton('Fit to frame',self)
      self.connect(fit_to_frame,QtCore.SIGNAL('released()'),self.fitToWindow)
      scale_layout.addWidget(fit_to_frame)
      close =  QtGui.QPushButton('Close',self)
      self.connect(close,QtCore.SIGNAL('released()'),self.closeScale)
      scale_layout.addWidget(close)
      self.scaleFrame.setLayout(scale_layout)
      layout.addWidget(self.scaleFrame)
      self.scaleFrame.hide()
      '''
      self.setLayout(layout)
      self.filename = ''
      self.pixmap = QtGui.QPixmap()
      if filename: self.open(filename)
      self.isZoomed = 0


#-------------------------------------------------------------------
  def fitToWindow(self):
#-------------------------------------------------------------------
        #print 'mgImageViewerfitToWindow'
        #self.isZoomed = 1 - self.isZoomed
        if not self.isZoomed:
		if self.pixmap.width()>self.width() or self.pixmap.height()>self.height():
          		self.label.setPixmap(self.pixmap.scaled(self.size(),QtCore.Qt.KeepAspectRatio,QtCore.Qt.SmoothTransformation))
        else:
          self.label.setPixmap(self.pixmap)

#-------------------------------------------------------------------
  def mousePressEvent(self,event):
#-------------------------------------------------------------------
	if self.filename != '' and self.pixmap.width()>0 and self.pixmap.height()>0:
		try:
			drag = QtGui.QDrag(self)
			mimeData = QtCore.QMimeData()
			mimeData.setText(self.filename)
			#mimeData.setImageData(QtGui.QImage(self.filename))
			mimeData.setUrls([QtCore.QUrl.fromLocalFile(self.filename)])
			drag.setMimeData(mimeData)
			drag.setPixmap(self.pixmap.scaledToHeight(150))
			drag.start()
		except:
			print "Drag and drop failed"

#-------------------------------------------------------------------
  def open(self,filename):
#-------------------------------------------------------------------
      
      try:
        self.pixmap = QtGui.QPixmap(filename)
      except:
        return [1,'Unable to read image file']

      #print "mgImageViewer pixmap",self.pixmap,self.pixmap.width(),self.pixmap.height()

      w = int(self.pixmap.width())
      if w<=0:
          return [1,'Image file apparently zero size']
      
      self.label.setPixmap(self.pixmap)
      self.filename = os.path.abspath(filename)
      self.setObjectName(os.path.split(self.filename)[-1])

      self.label.show()
      self.setWidget(self.label)

      return [0]

#-------------------------------------------------------------------
  def mgSize(self):
#-------------------------------------------------------------------
    return self.pixmap.size()

#-------------------------------------------------------------------
  def Print(self,painter):
#-------------------------------------------------------------------
    painter.drawPixmap(0,0,self.pixmap)

#-------------------------------------------------------------------
  def Save(self,filename):
#-------------------------------------------------------------------
    pass

#-------------------------------------------------------------------
  def isPrintable(self):
#-------------------------------------------------------------------
    return 1

#-------------------------------------------------------------------
  def isSaveable(self):
#-------------------------------------------------------------------
    return 1


#-------------------------------------------------------------------
  def openScale(self):
#-------------------------------------------------------------------
    self.scaleFrame.show()

#-------------------------------------------------------------------
  def closeScale(self):
#-------------------------------------------------------------------
    self.scaleFrame.hide()


#-------------------------------------------------------------------
  def scale(self,value):
#-------------------------------------------------------------------
    print 'mgImageViewer.scale',value
    if not self.pixmap or not self.filename: return
    self.label.setPixmap(self.pixmap.scaled(self.pixmap.width()*value,self.pixmap.height()*value,QtCore.Qt.KeepAspectRatio,QtCore.Qt.SmoothTransformation))
    

class mgPickableText(QtGui.QTextBrowser):

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


  
  def mouseReleaseEvent(self,event):
    #print 'mgPickableText.mouseReleaseEvent'
    pos = self.cursorRect().center()
    self.emit(QtCore.SIGNAL('mouseRelease'),pos)
    event.ignore()
    
    
    
  def mouseDoubleClickEvent(self,event):
    #print 'mgPickableText.mouseDoubleClickEvent'
    pos = self.cursorRect().center()
    self.emit(QtCore.SIGNAL('mouseDoubleClick'),pos)
    event.ignore()

  

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgTextViewer(mgAbstractViewer):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

    
#-------------------------------------------------------------------
  def __init__(self,parent,filename=''):
#-------------------------------------------------------------------
      #print 'mgTextViewer.init',self,filename
      import guiUtils
      mgAbstractViewer.__init__(self,parent)
      self.filename=''
      layout = QtGui.QVBoxLayout()
      layout.setSpacing(0)
      layout.setContentsMargins(0,0,0,0)
      #self.viewer = QtGui.QTextBrowser(self)
      self.viewer = mgPickableText(self)
      self.connect(self.viewer,QtCore.SIGNAL('mouseRelease'),self.handleMouseClick)
      self.connect(self.viewer,QtCore.SIGNAL('mouseDoubleClick'),self.handleMouseDoubleClick)
      layout.addWidget(self.viewer)
      
      self.findFrame = QtGui.QFrame(self)
      find_layout = QtGui.QHBoxLayout()
      widget = QtGui.QPushButton('Close',self)
      find_layout.addWidget(widget)
      self.connect(widget,QtCore.SIGNAL('clicked(bool)'),self.closeFind)
      find_layout.addWidget(QtGui.QLabel('Find:'))
      self.findText = QtGui.QLineEdit(self)
      find_layout.addWidget(self.findText)
      #for label in [ 'Next','Previous','Highlight all']:
      for label in [ 'Next','Previous']:
        widget = QtGui.QPushButton(label,self)
        setattr(self,'find'+label,widget)
        find_layout.addWidget(widget)
        self.connect(widget,QtCore.SIGNAL('clicked(bool)'),guiUtils.partial(self.find,label))
      self.findCase = QtGui.QCheckBox('Match case',self)
      find_layout.addWidget(self.findCase)
      find_layout.addStretch(5)
      
      self.findFrame.setLayout(find_layout)
      layout.addWidget(self.findFrame)
      self.findFrame.hide()
      
      self.document = None
      self.setLayout(layout)
      if filename:
        self.open(filename)


  def handleMouseClick(self,pos):
    text_cursor = self.viewer.cursorForPosition(pos)
    text_position = text_cursor.position()
    text_cursor.select(QtGui.QTextCursor.LineUnderCursor)
    line = str(text_cursor.selectedText())
    self.emit(QtCore.SIGNAL('lineClicked'),line)
  
    word = self.getWord(text_position)
    self.emit(QtCore.SIGNAL('wordClicked'),word)

  def handleMouseDoubleClick(self,pos):
    text_cursor = self.viewer.cursorForPosition(pos)
    text_position = text_cursor.position()
    text_cursor.select(QtGui.QTextCursor.LineUnderCursor)
    line = str(text_cursor.selectedText())
    self.emit(QtCore.SIGNAL('lineDoubleClicked'),line)
    
    word = self.getWord(text_position)
    self.emit(QtCore.SIGNAL('wordDoubleClicked'),word)

  def getWord(self,position):
    if not self.document: return ''
    text = str(self.document.toPlainText())
    fpos = position-1
    lpos = position
    while fpos>=0 and not [' ','\n'].count(text[fpos]):
      fpos = fpos -1
    while lpos<len(text) and not [' ','\n'].count(text[lpos]):
      lpos = lpos +1
      
    #print 'mgTextViewer.getWord',text[position-5:position+5],fpos,lpos,text[fpos:lpos]
    return text[fpos+1:lpos]


#-------------------------------------------------------------------
  def openFind(self):
#-------------------------------------------------------------------
    print 'mgTextViewer.openFind'
    self.findFrame.show()

#-------------------------------------------------------------------
  def closeFind(self):
#-------------------------------------------------------------------
    self.findFrame.hide()


#-------------------------------------------------------------------
  def find(self,mode):
#-------------------------------------------------------------------
    #print 'mgTextViewer.find',mode
    #print 'mgTextViewer.find',str(self.findText.text())
    if ['Next','Previous'].count(mode):
      flag = 0
      if mode == 'Previous':
        if self.findCase.isChecked():
          flag = QtGui.QTextDocument.FindBackward | QtGui.QTextDocument.FindCaseSensitively
        else:
          flag = QtGui.QTextDocument.FindBackward
      elif self.findCase.isChecked():
          flag = QtGui.QTextDocument.FindCaseSensitively
      #print 'mgTextViewer.find flag',flag
      if flag:
        found = self.viewer.find(self.findText.text(),flag)
      else:
        found = self.viewer.find(self.findText.text())
      if found: self.viewer.ensureCursorVisible()
    '''
    # This finds the instances of the search_text but there is not obvious means
    # to highlight them
    if ['Highlight all'].count(mode):
        search_text = self.findText.text()
        if not search_text: return
        self.hit_cursors = []
        start_cursor = QtGui.QTextCursor(self.viewer.document())
        start_cursor.setPosition(0)
        found_text = 'foo'
        while found_text:
           found = self.viewer.document().find(search_text,start_cursor)
           found_text = str(found.selectedText())
           if found_text:
               self.hit_cursors.append(found)
               start_cursor.setPosition(found.position()+len(search_text))
           #print 'hit_cursors',found,found_text,len(self.hit_cursors),start_cursor.position()
    '''
           
#-------------------------------------------------------------------
  def open(self,filename):
#-------------------------------------------------------------------
      try:
        f = open(filename,'r')
        text = f.read()
        f.close()
      except:
        return [1,'Error reading file']
      self.filename = os.path.abspath(filename)
      self.setObjectName(os.path.split(self.filename)[-1])


      return self.loadText(text)
      
#-------------------------------------------------------------------
  def loadText(self,text,html=0):
#-------------------------------------------------------------------
      try:
        if html:
          self.document = QtGui.QTextDocument(self.viewer)
          self.document.setHtml(text)
        else:
          self.document = QtGui.QTextDocument(text,self.viewer)
      except:
        return [1,'Error loading text into document']
      font = QtGui.QFont('Courier')
      font.setItalic(0)
      font.setBold(0)
      font.setUnderline(0)
      self.document.setDefaultFont(font)
      self.viewer.setDocument(self.document)
      
      return [0]

#-------------------------------------------------------------------
  def mgSize(self):
#-------------------------------------------------------------------
    #return QtCore.QSize(self.viewer.width(),self.viewer.height())
    return QtCore.QSize(600,400)


  def Print(self,painter):
      text = ''
      try:
        f = open(self.filename,'r')
        text = f.read()
        f.close()
      except:
        return 1
      painter.drawText(0,0,text)
    
#-------------------------------------------------------------------
  def Save(self,filename):
#-------------------------------------------------------------------
    #print 'mgTextViewer.Save',self,self.filename,filename
    import utils
    utils.saveFile(filename,str(self.document.toPlainText()))

#-------------------------------------------------------------------
  def isPrintable(self):
#-------------------------------------------------------------------
    return 1

#-------------------------------------------------------------------
  def isSaveable(self):
#-------------------------------------------------------------------
    return 1

#-------------------------------------------------------------------
  def setFont(self,font=None,style=''):
#-------------------------------------------------------------------
    if not self.document: return 1
    if font:
      self.document.setDefaultFont(font)
    elif style=='fixed_width':
      self.document.setDefaultFont(QtGui.QFont('Courier',12))
    return 0

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgMovieViewerPhonon(mgAbstractViewer):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

  def mousePressEvent(self,event):
        try:
            drag = QtGui.QDrag(self)
            mimeData = QtCore.QMimeData()
            mimeData.setText(self.mediaObject.currentSource().url().path())
            mimeData.setUrls([self.mediaObject.currentSource().url()])
            drag.setMimeData(mimeData)
            # We want to use grabWidget, but it seems that a very long standing
            # phonon bug means we have to use grabWindow.
            #pixmap = QtGui.QPixmap.grabWidget(self.videoWidget);
            pixmap = QtGui.QPixmap.grabWindow(self.videoWidget.winId());
            drag.setPixmap(pixmap.scaledToHeight(150))
            drag.start()
        except:
            print "Drag and drop failed"

#-------------------------------------------------------------------
  def __init__(self,parent,filename=''):
#-------------------------------------------------------------------
        mgAbstractViewer.__init__(self,parent)
        layout = QtGui.QVBoxLayout()
        if havePhonon:
          self.mediaObject = phonon.Phonon.MediaObject();
          self.videoWidget = phonon.Phonon.VideoWidget();
          phonon.Phonon.createPath(self.mediaObject, self.videoWidget);

          layout.addWidget(self.videoWidget)

          buttons = QtGui.QDialogButtonBox()
          pb = buttons.addButton("Play",QtGui.QDialogButtonBox.ActionRole)
          self.connect(pb,QtCore.SIGNAL("clicked(bool)"),functools.partial(self.mediaObject.seek,0))
          self.connect(pb,QtCore.SIGNAL("clicked(bool)"),self.mediaObject.play)
          pb = buttons.addButton("Stop",QtGui.QDialogButtonBox.ActionRole)
          self.connect(pb,QtCore.SIGNAL("clicked(bool)"),self.mediaObject.stop)
          layout.addWidget(buttons)
        self.setLayout(layout)
        if filename: self.open(filename)
        self.filename=filename

#-------------------------------------------------------------------
  def open(self,fn):
#-------------------------------------------------------------------
    if not havePhonon:
      return [1,'No phonon available in this version of Qt']
    self.filename=fn
    media =  phonon.Phonon.MediaSource(QtCore.QUrl.fromLocalFile(fn))
    self.mediaObject.setCurrentSource(media);
    print self.mediaObject.currentSource().url();
    return [0]

#-------------------------------------------------------------------
  def mgSize(self):
#-------------------------------------------------------------------
    print self.videoWidget.size()
    return self.videoWidget.size()

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgMovieViewer(mgAbstractViewer):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
    
#-------------------------------------------------------------------
  def __init__(self,parent,filename=''):
#-------------------------------------------------------------------
      mgAbstractViewer.__init__(self,parent)
      self.filename=''
      layout = QtGui.QVBoxLayout()
      self.label = QtGui.QLabel(self)
      layout.addWidget(self.label)
      self.setLayout(layout)
      if filename: self.open(filename)

#-------------------------------------------------------------------
  def stopMovie(self,filename):
#-------------------------------------------------------------------
   if filename == self.filename and hasattr(self,"movie") and hasattr(self.movie,"stop") and callable(self.movie.stop):
     self.movie.stop()
      
#-------------------------------------------------------------------
  def open(self,filename):
#-------------------------------------------------------------------

    try:
      self.movie = QtGui.QMovie(filename,'',self)
    except:
      return [1,'Error reading movie file']
    app = QtCore.QCoreApplication.instance()
    if app:
       self.connect(app,QtCore.SIGNAL("DeletingFile"),self.stopMovie)		

    if not self.movie.isValid():
      return [1,'Apparently invalid movie file']
  
    self.filename = os.path.abspath(filename)
    self.setObjectName(os.path.split(self.filename)[-1])

    self.label.setMovie(self.movie)
    self.movie.start()

    return [0]

#-------------------------------------------------------------------
  def mgSize(self):
#-------------------------------------------------------------------
    return self.movie.currentPixmap().size()




#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgCoordsViewer(mgTextViewer):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

  def __init__(self,parent,filename=''):
      mgTextViewer.__init__(self,parent)
      """
      font = QtGui.QFont()
      font.setFixedPitch(1)
      #print "mgCoordsViewer font",str(font.family())
      self.viewer.setCurrentFont(font)
      #self.viewer.textCursor().select(QtGui.QTextCursor.LineUnderCursor)
      """

      if filename: self.open(filename)


      
'''
#-------------------------------------------------------------------
  def open(self,filename):
#-------------------------------------------------------------------
      # This method only needed if want ot mark up thr PDB file
      status,text = self.markupPDB(filename)
      if not status:
        self.filename = os.path.abspath(filename)
        self.setObjectName(os.path.split(self.filename)[-1])
        return self.loadText(text,html=1)
      else:
        return status
      font = QtGui.QFont()
      font.setFixedPitch(1)
      self.viewer.setCurrentFont(font)


#-------------------------------------------------------------------
  def markupPDB(self,filename):
#-------------------------------------------------------------------
      # Add markup to a PDB file - very slow!!
      output = ''
      n = 0
      try:
          f = open(filename)
          lines = f.readlines()
          f.close()
      except:
          return [1,'Error reading file']
      try:
          for line in lines:
            if line[0:4] == 'ATOM':
              n = n + 1
              #output = output + '<br/><a href = "ccp4:///atom/'+str(n)+'">'+line.strip('\n')+'</a>\n'
              output = output + '<br/>' +line.strip('\n') +   '<a href = "ccp4:///atom/'+str(n)+'">go to</a>\n'
            else:
              output = output +'<br/>' + line
          print 'markupPDB',output
      except:
          return [1,'Error marking up file']

      output = '<html>\n' + output + '\n<html>i\n'
      return [0,output]
'''
          
      
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class mgHtmlViewer(mgTextViewer):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

#-------------------------------------------------------------------
  def __init__(self,parent,filename=''):
#-------------------------------------------------------------------
      mgTextViewer.__init__(self,parent,filename)

      
#-------------------------------------------------------------------
  def open(self,filename):
#-------------------------------------------------------------------
    try:
      f = open(filename,'r')
      text = f.read()
      f.close()
    except:
      return [1,'Error reading file']
    try:
      self.document = QtGui.QTextDocument()
      self.document.setHtml(text)
    except:
      return [1,'Error loading text into document']

    self.viewer.setDocument(self.document)
    self.filename = os.path.abspath(filename)
    self.setObjectName(os.path.split(self.filename)[-1])

    return [0]

#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------
class EditPlugins(MGSimpleDialog.MGSimpleDialog):
#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

#-------------------------------------------------------------------
  def __init__(self,parent):
#-------------------------------------------------------------------
    MGSimpleDialog.MGSimpleDialog.__init__(self,parent)
    self.current = -1
    self.setWindowTitle("CCP4mg File Browser Plugins")
    layout = QtGui.QVBoxLayout(self)
    layout.setSpacing(2)
    layout.setContentsMargins(2,2,2,2)
                
    self.selectPlugin= QtGui.QListWidget(self)
    self.selectPlugin.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
    self.loadSelectPlugin()

    delete_button = QtGui.QPushButton('Delete selected plugin',self)
    self.connect(delete_button,QtCore.SIGNAL('clicked()'),self.deletePlugin)
    new_button = QtGui.QPushButton('Create new plugin',self)
    self.connect(new_button,QtCore.SIGNAL('clicked()'),self.handleNew)
    
    listLayout= QtGui.QGridLayout()
    listLayout.addWidget(self.selectPlugin,0,0,2,1)
    listLayout.addWidget(new_button,0,1)
    listLayout.addWidget(delete_button,1,1)
    layout.addLayout(listLayout)

    
    editLayout= QtGui.QGridLayout()
    editLayout.addWidget(QtGui.QLabel('Plugin name',self),0,0)
    self.name = QtGui.QLineEdit(self)
    self.name.setToolTip('A one word unique name for the plugin')
    editLayout.addWidget(self.name,0,1)
    
    editLayout.addWidget(QtGui.QLabel('File extensions',self),1,0)
    self.extensions = QtGui.QLineEdit(self)
    self.extensions.setToolTip('A comma separated list of file extensions supported by the plugin')
    editLayout.addWidget(self.extensions)

    editLayout.addWidget(QtGui.QLabel('Viewer',self),2,0)
    self.viewer = QtGui.QLineEdit(self)
    self.viewer.setToolTip('The command to run the viewer')
    editLayout.addWidget(self.viewer,2,1)
    
    editLayout.addWidget(QtGui.QLabel('Arguments to viewer',self),3,0)
    self.arguments = QtGui.QLineEdit(self)
    self.arguments.setToolTip('The arguments to the the viewer')
    editLayout.addWidget(self.arguments,3,1)
    
    editLayout.addWidget(QtGui.QLabel('Label',self),4,0)
    self.plugin_label = QtGui.QLineEdit(self)
    self.plugin_label.setToolTip('A label for the plugin to be used in the interface')
    editLayout.addWidget(self.plugin_label,4,1)
    
    layout.addLayout(editLayout)


    dialog_buttons = QtGui.QDialogButtonBox()
    apply_button = dialog_buttons.addButton('Save plugin',QtGui.QDialogButtonBox.ActionRole)
    cancel_button = dialog_buttons.addButton('Close',QtGui.QDialogButtonBox.RejectRole)
    ok_button = dialog_buttons.addButton('Save plugin and close',QtGui.QDialogButtonBox.AcceptRole)
    for button in [apply_button,cancel_button,ok_button]:
      button.setAutoDefault(0)
      button.setDefault(0)
    self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.Close)
    self.connect(apply_button,QtCore.SIGNAL('clicked()'),self.Apply)
    self.connect(ok_button,QtCore.SIGNAL('clicked()'),self.ApplyAndClose)
    layout.addWidget(dialog_buttons)
    
    self.setCurrent(-1)

#----------------------------------------------------------------------
  def ApplyAndClose(self):
#----------------------------------------------------------------------
    self.Apply(1)
    
#----------------------------------------------------------------------
  def Apply(self,close=0):
#----------------------------------------------------------------------
    #print 'editPlugins.Apply',close
    name = str(self.name.text())
    name_list = name.strip().split()
    if not len(name_list):
      return
    name = name_list[0]
    for item in name_list[1:]: name = name + '_' + item
    extensions0 = (str(self.extensions.text())).split(',')
    extensions = []
    for item in extensions0:
        extentions1 = item.split(' ')
        for ext in extentions1:
          extensions.append(ext.strip().strip('.'))
    #print 'EditPlugins,Apply',extensions
    if not len(extensions):
      return
    label = str(self.plugin_label.text())
    viewer = str(self.viewer.text())
    if not viewer:
      return
    arguments = str(self.arguments.text())
    
    addSupportedPlugin(name,extensions,label,viewer,arguments)
       
    self.loadSelectPlugin()
    self.emit(QtCore.SIGNAL('changed'))
    if close: self.Close()

  def handleNew(self):
    self.setCurrent(-1)

    
#----------------------------------------------------------------------
  def deletePlugin(self):
#----------------------------------------------------------------------
    name = self.getNameFromList(self.selectPlugin.currentRow())
    if name and mgFileViewer.supported_plugins.has_key(name):
      del mgFileViewer.supported_plugins[name]
      self.loadSelectPlugin()
      self.setCurrent(-1)
      self.emit(QtCore.SIGNAL('changed'))

#----------------------------------------------------------------------
  def loadSelectPlugin(self):
#----------------------------------------------------------------------
    self.selectPlugin.blockSignals(True)
    self.selectPlugin.clear()
    for key,info in mgFileViewer.supported_plugins.items():
      #text = key + ' ' + info.get('label',' ') + ' ' + info.get('viewer',' ')
      text = key +  ' ' + info.get('viewer',' ')
      self.selectPlugin.addItem(text)
    self.selectPlugin.addItem('New plugin..')
    self.selectPlugin.blockSignals(False)
  

#----------------------------------------------------------------------
  def setCurrent(self,vid):
#----------------------------------------------------------------------
    name = self.getNameFromList(vid)
    #print 'setCurrent vid',vid,name
    if not name:
      # Out of range so set to 'new' vector
      self.setRow(self.selectPlugin.count()-1)
      self.name.setText('')
      self.extensions.setText('')
      self.plugin_label.setText('')
      self.viewer.setText('')
      self.arguments.setText('')
      self.current = -1
    else:
      self.setRow(vid)
      info = mgFileViewer.supported_plugins.get(name,{})
      self.name.setText(name)
      ext_list = info.get('ext_list',[])
      ext_text = ''
      for item in ext_list: ext_text = ext_text+item+','
      if ext_list: ext_text = ext_text[0:-1]
      self.extensions.setText(ext_text)
      self.plugin_label.setText(info.get('label',''))
      self.viewer.setText(info.get('viewer',''))
      self.arguments.setText(info.get('arguments',''))
      self.current = vid


#----------------------------------------------------------------------
  def setRow(self,irow):
#----------------------------------------------------------------------
    if irow == self.selectPlugin.currentRow(): return
    self.selectPlugin.blockSignals(True)
    self.selectPlugin.setCurrentRow(irow)
    self.selectPlugin.blockSignals(False)
            
#----------------------------------------------------------------------
  def getNameFromList(self,irow):
#----------------------------------------------------------------------
    #print 'getNameFromList',irow,self.selectPlugin.count()
    if irow<0 or irow>=self.selectPlugin.count():
      return ''
    text = str(self.selectPlugin.item(irow).text())
    #print 'getNameFromList text',text
    if text == 'New plugin..':
      return ''
    else:
      return text.split()[0]
